mirror of
https://github.com/Bubberstation/Bubberstation.git
synced 2026-07-20 20:45:28 +01:00
ee99d0e5b0
## About The Pull Request Revival of https://github.com/tgstation/tgstation/pull/79691 A while back, I made this PR, but lost motivation after diving too deep into the code soup of can_breathe and related procs. Now, I have removed those parts, and have simplified that part of the code to the point I think it's ready for review. Many reviews from the previous PR have been addressed in this PR. <hr> <details> <summary>Details</summary> Asthma is a 4 point negative quirk that emulates real life asthma. It works by slowly decreasing the amount of pressure each breath you take receives, until your lungs completely seal, ensuring death if you dont get oxyloss meds/windpipe surgery. Inflammation (the tracker for intensity) increases whenever you breathe smoke, use a cigarette, metabolize histimine, or suffer an asthma attack. Asthma attacks have a low chance of happening every second, starting 10 minutes after you spawn and with a 20-30 grace period between attacks. They are "diseases" that cant be outright cured by albuterol, only put into remission. They increase inflammation at varying rates depending on their severity, with extreme asthma attacks being a immediate threat to your life while mild ones might not even cause inflammation. The response to these is always the same - use your inhaler before you start choking. Asthmatics start with a rescue inhaler, a low-capacity inhaler loaded with albuterol, which I will get to later. Albuterol is a new medicine thats a little tricky to make but still doable. It can be efficiently created with inverse convermol, or transmutated from salbutamol and convermol. The opposite is true, with albuterol able to be turned into salbutamol. Two canisters are available in chemvends. Upon use, it increases the virtual pressure of all breaths taken by 40%. This allows for you to breathe in lower pressure environments, as well as enhancing the effects of things like healium. It's OD causes your diaphram to spasm, causing sporadic losebreath and forced breathing. Inhalers are a fancy new reagent application apparatus that uses the INHALE reagent bitflag. Inhalers themselves are rather unremarkable, they are merely the method of using inhaler canisters (they also have a rotary display approximating the uses left in a canister - just like real life inhalers). Inhaler canisters are the reagent containers, and are generally low capacity. They can only be used in a inhaler, and contain aerosolized chemicals. Inhaler canisters and inhalers are unlocked from chemical synthesis, and are printable for cheap from a medlathe. In order to use a inhaler, one must uncover the mouth of a carbon and wait a few seconds (its faster if its a self-application) before a small amount of the reagents are delivered via the INHALE bitflag. This only works on things currently breathing - if theyre dead, have no lungs, or just, arent breathing - it will fail. This includes asthmatics with 100% inflammation. </details> <img width="181" height="74" alt="282863233-77a7cd6b-44d2-458e-9966-06d485df1521" src="https://github.com/user-attachments/assets/293b6659-0834-4e9a-b033-cc3b0cfde18e" /> <img width="1465" height="202" alt="282863346-2a247736-0c3a-43b0-a60b-7cff10ce4963" src="https://github.com/user-attachments/assets/5d9a13dc-b7b2-4de2-adda-8fbc8276e667" /> Sprites are not mine; they are from swanni and I can NOT sprite for the life of me ## Why It's Good For The Game 1. Asthma is just cool. One of my favorite features on bay was the fact lung damage required you to turn up the pressure on your O2 tank to survive, and this does precisely that. 2. Its always fun to add new ways to interact with atmos as a player that arent grossly broken, and I fail to see how a 40% increase of gas intake will really affect balance too badly. 3. Inhalers are badass. ## Changelog 🆑 add: Asthma quirk, based on IRL asthma add: Inhalers, a new reagent administering method that uses INHALE add: Albuterol, a new reagent that increases the amount of gas you inhale by 40% balance: Inverse convermol now forms once the reaction is done, not on metabolize /🆑 --------- Co-authored-by: SyncIt21 <110812394+SyncIt21@users.noreply.github.com> Co-authored-by: MrMelbert <51863163+MrMelbert@users.noreply.github.com> # Conflicts: # code/datums/quirks/negative_quirks/allergic.dm # code/game/objects/items/devices/scanners/health_analyzer.dm
444 lines
19 KiB
Plaintext
444 lines
19 KiB
Plaintext
/datum/disease
|
|
//Flags
|
|
var/visibility_flags = NONE
|
|
var/disease_flags = CURABLE|CAN_CARRY|CAN_RESIST
|
|
var/spread_flags = DISEASE_SPREAD_AIRBORNE | DISEASE_SPREAD_CONTACT_FLUIDS | DISEASE_SPREAD_CONTACT_SKIN
|
|
|
|
//Fluff
|
|
var/form = "Virus"
|
|
var/name = "No disease"
|
|
var/desc = ""
|
|
var/agent = "some microbes"
|
|
var/spread_text = ""
|
|
var/cure_text = ""
|
|
|
|
//Stages
|
|
var/stage = 1
|
|
var/max_stages = 0
|
|
/// The probability of this infection advancing a stage every second the cure is not present.
|
|
var/stage_prob = 2
|
|
/// How long this infection incubates (non-visible) before revealing itself
|
|
var/incubation_time
|
|
/// Has the virus hit its limit?
|
|
var/stage_peaked = FALSE
|
|
/// How many cycles has the virus been at its peak?
|
|
var/peaked_cycles = 0
|
|
/// How many cycles do we need to have been active after hitting our max stage to start rolling back?
|
|
var/cycles_to_beat = 0
|
|
/// Number of cycles we've prevented symptoms from appearing
|
|
var/symptom_offsets = 0
|
|
/// Number of cycles we've benefited from chemical or other non-resting symptom protection
|
|
var/chemical_offsets = 0
|
|
|
|
//Other
|
|
var/list/viable_mobtypes = list() //typepaths of viable mobs
|
|
var/mob/living/carbon/affected_mob = null
|
|
var/list/cures = list() //list of cures if the disease has the CURABLE flag, these are reagent ids
|
|
/// The probability of spreading through the air every second
|
|
var/infectivity = 41
|
|
/// The probability of this infection being cured every second the cure is present
|
|
var/cure_chance = 4
|
|
var/carrier = FALSE //If our host is only a carrier
|
|
var/bypasses_immunity = FALSE //Does it skip species virus immunity check? Some things may diseases and not viruses
|
|
var/spreading_modifier = 1
|
|
var/severity = DISEASE_SEVERITY_NONTHREAT
|
|
/// If the disease requires an organ for the effects to function, robotic organs are immune to disease unless inorganic biology symptom is present
|
|
var/required_organ
|
|
var/needs_all_cures = TRUE
|
|
var/list/strain_data = list() //dna_spread special bullshit
|
|
var/infectable_biotypes = MOB_ORGANIC //if the disease can spread on organics, synthetics, or undead
|
|
var/process_dead = FALSE //if this ticks while the host is dead
|
|
var/copy_type = null //if this is null, copies will use the type of the instance being copied
|
|
var/bypasses_disease_recovery = FALSE // Does it skip self recovery process, such as event diseases // BUBBER EDIT ADDITION - DISEASE OUTBREAK UPDATES
|
|
|
|
/datum/disease/Destroy()
|
|
. = ..()
|
|
if(affected_mob)
|
|
remove_disease()
|
|
if(event_disease) // BUBBER EDIT ADDITION - DISEASE OUTBREAK UPDATES
|
|
SSdisease.event_diseases -= src // BUBBER EDIT ADDITION - DISEASE OUTBREAK UPDATES
|
|
SSdisease.active_diseases.Remove(src)
|
|
|
|
//add this disease if the host does not already have too many
|
|
/datum/disease/proc/try_infect(mob/living/infectee, make_copy = TRUE)
|
|
infect(infectee, make_copy)
|
|
return TRUE
|
|
|
|
//add the disease with no checks
|
|
/datum/disease/proc/infect(mob/living/infectee, make_copy = TRUE)
|
|
var/datum/disease/D = make_copy ? Copy() : src
|
|
// BUBBER EDIT ADDITION START - DISEASE OUTBREAK UPDATES
|
|
if(D.affected_mob)
|
|
stack_trace("Disease [D.debug_id] [D] tried to infect [infectee] while already bound to an affected mob [D.affected_mob]!")
|
|
log_virus_public("Disease [D.debug_id] [D] tried to infect [infectee] while already bound to an affected mob [D.affected_mob]!")
|
|
return
|
|
if(!D.debug_id)
|
|
D.debug_id = assign_random_name()
|
|
if(!D.start_time)
|
|
D.start_time = REALTIMEOFDAY
|
|
// BUBBER EDIT ADDITION END - DISEASE OUTBREAK UPDATES
|
|
LAZYADD(infectee.diseases, D)
|
|
D.affected_mob = infectee
|
|
SSdisease.active_diseases += D //Add it to the active diseases list, now that it's actually in a mob and being processed.
|
|
if(event_disease) // BUBBER EDIT ADDITION - DISEASE OUTBREAK UPDATES
|
|
SSdisease.event_diseases += D // BUBBER EDIT ADDITION - DISEASE OUTBREAK UPDATES
|
|
|
|
D.after_add()
|
|
infectee.med_hud_set_status()
|
|
D.register_disease_signals() // BUBBER EDIT CHANGE - DISEASE OUTBREAK UPDATES
|
|
|
|
var/turf/source_turf = get_turf(infectee)
|
|
mobs_infected++ // BUBBER EDIT ADDITION - DISEASE OUTBREAK UPDATES
|
|
log_virus_public("New infectee: [infectee]. Total infected by this carrier: [mobs_infected]") // BUBBER EDIT ADDITION - DISEASE OUTBREAK UPDATES
|
|
log_virus("[key_name(infectee)] was infected by virus: [src.admin_details()] at [loc_name(source_turf)]")
|
|
|
|
/// Updates the spread flags set, ensuring signals are updated as necessary
|
|
/datum/disease/proc/update_spread_flags(new_flags)
|
|
if(spread_flags == new_flags)
|
|
return
|
|
|
|
spread_flags = new_flags
|
|
unregister_disease_signals()
|
|
register_disease_signals()
|
|
|
|
/// Register any relevant signals for the disease
|
|
/datum/disease/proc/register_disease_signals()
|
|
if(isnull(affected_mob))
|
|
return
|
|
if(spread_flags & DISEASE_SPREAD_AIRBORNE)
|
|
RegisterSignal(affected_mob, COMSIG_CARBON_PRE_BREATHE, PROC_REF(on_breath))
|
|
|
|
/// Unregister any relevant signals for the disease
|
|
/datum/disease/proc/unregister_disease_signals()
|
|
if(isnull(affected_mob))
|
|
return
|
|
UnregisterSignal(affected_mob, COMSIG_CARBON_PRE_BREATHE)
|
|
|
|
///Proc to process the disease and decide on whether to advance, cure or make the symptoms appear. Returns a boolean on whether to continue acting on the symptoms or not.
|
|
/datum/disease/proc/stage_act(seconds_per_tick, times_fired)
|
|
var/slowdown = HAS_TRAIT(affected_mob, TRAIT_VIRUS_RESISTANCE) ? 0.5 : 1 // spaceacillin slows stage speed by 50%
|
|
var/recovery_prob = 0
|
|
var/cure_mod
|
|
var/bad_immune = HAS_TRAIT(affected_mob, TRAIT_IMMUNODEFICIENCY) ? 2 : 1
|
|
|
|
if(required_organ)
|
|
if(!has_required_infectious_organ(affected_mob, required_organ))
|
|
cure(add_resistance = FALSE)
|
|
return FALSE
|
|
|
|
if(has_cure())
|
|
cure_mod = cure_chance / bad_immune
|
|
if(istype(src, /datum/disease/advance))
|
|
cure_mod = max(cure_chance, DISEASE_MINIMUM_CHEMICAL_CURE_CHANCE)
|
|
if(disease_flags & CHRONIC && SPT_PROB(cure_mod, seconds_per_tick))
|
|
update_stage(1)
|
|
to_chat(affected_mob, span_notice("Your chronic illness is alleviated a little, though it can't be cured!"))
|
|
return
|
|
if(disease_flags & CURABLE && SPT_PROB(cure_mod, seconds_per_tick))
|
|
if(disease_flags & INCREMENTAL_CURE)
|
|
if (!update_stage(stage - 1))
|
|
return FALSE
|
|
else
|
|
cure()
|
|
return FALSE
|
|
|
|
if(stage == max_stages && stage_peaked != TRUE) //mostly a sanity check in case we manually set a virus to max stages
|
|
stage_peaked = TRUE
|
|
|
|
if(SPT_PROB(stage_prob*slowdown*bad_immune, seconds_per_tick))
|
|
update_stage(min(stage + 1, max_stages))
|
|
|
|
// if(!(disease_flags & CHRONIC) && disease_flags & CURABLE && bypasses_immunity != TRUE)
|
|
if(!(disease_flags & CHRONIC) && disease_flags & CURABLE && bypasses_immunity != TRUE && bypasses_disease_recovery != TRUE) // BUBBER EDIT CHANGE - DISEASE OUTBREAK UPDATES
|
|
switch(severity)
|
|
if(DISEASE_SEVERITY_POSITIVE) //good viruses don't go anywhere after hitting max stage - you can try to get rid of them by sleeping earlier
|
|
cycles_to_beat = max(DISEASE_RECOVERY_SCALING, DISEASE_CYCLES_POSITIVE) //because of the way we later check for recovery_prob, we need to floor this at least equal to the scaling to avoid infinitely getting less likely to cure
|
|
if(((HAS_TRAIT(affected_mob, TRAIT_NOHUNGER)) || ((affected_mob.nutrition > NUTRITION_LEVEL_STARVING) && (affected_mob.satiety >= 0))) && slowdown == 1) //any sort of malnourishment/immunosuppressant opens you to losing a good virus
|
|
return TRUE
|
|
if(DISEASE_SEVERITY_NONTHREAT)
|
|
cycles_to_beat = max(DISEASE_RECOVERY_SCALING, DISEASE_CYCLES_NONTHREAT)
|
|
if(DISEASE_SEVERITY_MINOR)
|
|
cycles_to_beat = max(DISEASE_RECOVERY_SCALING, DISEASE_CYCLES_MINOR)
|
|
if(DISEASE_SEVERITY_MEDIUM)
|
|
cycles_to_beat = max(DISEASE_RECOVERY_SCALING, DISEASE_CYCLES_MEDIUM)
|
|
if(DISEASE_SEVERITY_DANGEROUS)
|
|
cycles_to_beat = max(DISEASE_RECOVERY_SCALING, DISEASE_CYCLES_DANGEROUS)
|
|
if(DISEASE_SEVERITY_HARMFUL)
|
|
cycles_to_beat = max(DISEASE_RECOVERY_SCALING, DISEASE_CYCLES_HARMFUL)
|
|
if(DISEASE_SEVERITY_BIOHAZARD)
|
|
cycles_to_beat = max(DISEASE_RECOVERY_SCALING, DISEASE_CYCLES_BIOHAZARD)
|
|
else
|
|
cycles_to_beat = max(DISEASE_RECOVERY_SCALING, DISEASE_CYCLES_NONTHREAT)
|
|
peaked_cycles += stage/max_stages //every cycle we spend sick counts towards eventually curing the virus, faster at higher stages
|
|
recovery_prob += DISEASE_RECOVERY_CONSTANT + (peaked_cycles / (cycles_to_beat / DISEASE_RECOVERY_SCALING)) //more severe viruses are beaten back more aggressively after the peak
|
|
if(stage_peaked)
|
|
recovery_prob *= DISEASE_PEAKED_RECOVERY_MULTIPLIER
|
|
if(slowdown != 1) //using spaceacillin can help get them over the finish line to kill a virus with decreasing effect over time
|
|
recovery_prob += clamp((((1 - slowdown)*(DISEASE_SLOWDOWN_RECOVERY_BONUS * 2)) * ((DISEASE_SLOWDOWN_RECOVERY_BONUS_DURATION - chemical_offsets) / DISEASE_SLOWDOWN_RECOVERY_BONUS_DURATION)), 0, DISEASE_SLOWDOWN_RECOVERY_BONUS)
|
|
chemical_offsets = min(chemical_offsets + 1, DISEASE_SLOWDOWN_RECOVERY_BONUS_DURATION)
|
|
if(!HAS_TRAIT(affected_mob, TRAIT_NOHUNGER))
|
|
if(affected_mob.satiety < 0 || affected_mob.nutrition < NUTRITION_LEVEL_STARVING) //being malnourished makes it a lot harder to defeat your illness
|
|
recovery_prob -= DISEASE_MALNUTRITION_RECOVERY_PENALTY
|
|
else
|
|
if(affected_mob.satiety >= 0)
|
|
recovery_prob += round((DISEASE_SATIETY_RECOVERY_MULTIPLIER * (affected_mob.satiety/MAX_SATIETY)), 0.1)
|
|
|
|
if(affected_mob.mob_mood) // this and most other modifiers below a shameless rip from sleeping healing buffs, but feeling good helps make it go away quicker
|
|
switch(affected_mob.mob_mood.sanity_level)
|
|
if(SANITY_LEVEL_GREAT)
|
|
recovery_prob += 0.4
|
|
if(SANITY_LEVEL_NEUTRAL)
|
|
recovery_prob += 0.2
|
|
if(SANITY_LEVEL_DISTURBED)
|
|
recovery_prob += 0
|
|
if(SANITY_LEVEL_UNSTABLE)
|
|
recovery_prob += 0
|
|
if(SANITY_LEVEL_CRAZY)
|
|
recovery_prob += -0.2
|
|
if(SANITY_LEVEL_INSANE)
|
|
recovery_prob += -0.4
|
|
|
|
if((HAS_TRAIT(affected_mob, TRAIT_NOHUNGER) || !(affected_mob.satiety < 0 || affected_mob.nutrition < NUTRITION_LEVEL_STARVING)) && HAS_TRAIT(affected_mob, TRAIT_KNOCKEDOUT)) //resting starved won't help, but resting helps
|
|
var/turf/rest_turf = get_turf(affected_mob)
|
|
var/is_sleeping_in_darkness = rest_turf.get_lumcount() <= LIGHTING_TILE_IS_DARK
|
|
|
|
if(affected_mob.is_blind_from(EYES_COVERED) || is_sleeping_in_darkness)
|
|
recovery_prob += DISEASE_GOOD_SLEEPING_RECOVERY_BONUS
|
|
|
|
// sleeping in silence is always better
|
|
if(HAS_TRAIT(affected_mob, TRAIT_DEAF))
|
|
recovery_prob += DISEASE_GOOD_SLEEPING_RECOVERY_BONUS
|
|
|
|
// check for beds
|
|
if((locate(/obj/structure/bed) in affected_mob.loc))
|
|
recovery_prob += DISEASE_GOOD_SLEEPING_RECOVERY_BONUS
|
|
else if((locate(/obj/structure/table) in affected_mob.loc))
|
|
recovery_prob += (DISEASE_GOOD_SLEEPING_RECOVERY_BONUS / 2)
|
|
|
|
// don't forget the bedsheet
|
|
if(locate(/obj/item/bedsheet) in affected_mob.loc)
|
|
recovery_prob += DISEASE_GOOD_SLEEPING_RECOVERY_BONUS
|
|
|
|
// you forgot the pillow
|
|
if(locate(/obj/item/pillow) in affected_mob.loc)
|
|
recovery_prob += DISEASE_GOOD_SLEEPING_RECOVERY_BONUS
|
|
|
|
recovery_prob *= DISEASE_SLEEPING_RECOVERY_MULTIPLIER //any form of sleeping magnifies all effects a little bit
|
|
|
|
recovery_prob = clamp(recovery_prob / bad_immune, 0, 100)
|
|
|
|
if(recovery_prob)
|
|
if(SPT_PROB(recovery_prob, seconds_per_tick))
|
|
if(stage == 1 && prob(cure_chance * DISEASE_FINAL_CURE_CHANCE_MULTIPLIER)) //if we reduce FROM stage == 1, cure the virus - after defeating its cure_chance in a final battle
|
|
if(!HAS_TRAIT(affected_mob, TRAIT_NOHUNGER) && (affected_mob.satiety < 0 || affected_mob.nutrition < NUTRITION_LEVEL_STARVING))
|
|
if(stage_peaked == FALSE) //if you didn't ride out the virus from its peak, if you're malnourished when it cures, you don't get resistance
|
|
cure(add_resistance = FALSE)
|
|
return FALSE
|
|
else if(prob(50)) //if you rode it out from the peak, challenge cure_chance on if you get resistance or not
|
|
cure(add_resistance = TRUE)
|
|
return FALSE
|
|
else
|
|
cure(add_resistance = TRUE) //stay fed and cure it at any point, you're immune
|
|
return FALSE
|
|
update_stage(max(stage - 1, 1))
|
|
|
|
if(HAS_TRAIT(affected_mob, TRAIT_KNOCKEDOUT) || slowdown != 1) //sleeping and using spaceacillin lets us nosell applicable virus symptoms firing with decreasing effectiveness over time
|
|
if(prob(100 - min((100 * (symptom_offsets / DISEASE_SYMPTOM_OFFSET_DURATION)), 100 - cure_chance * DISEASE_FINAL_CURE_CHANCE_MULTIPLIER))) //viruses with higher cure_chance will ultimately be more possible to offset symptoms on
|
|
symptom_offsets = min(symptom_offsets + 1, DISEASE_SYMPTOM_OFFSET_DURATION)
|
|
return FALSE
|
|
|
|
return !carrier
|
|
|
|
/datum/disease/proc/update_stage(new_stage)
|
|
// BUBBER EDIT ADDITION START - DISEASE OUTBREAK UPDATES
|
|
if(new_stage > stage && !isnull(affected_mob))
|
|
log_virus_public("[affected_mob.name] stage advance [stage] > [new_stage]. Time elapsed: [DisplayTimeText(REALTIMEOFDAY - start_time)] (Stage speed [stage_prob])")
|
|
stage = new_stage
|
|
if(!isnull(affected_mob))
|
|
affected_mob.med_hud_set_status()
|
|
// BUBBER EDIT ADDITION END - DISEASE OUTBREAK UPDATES
|
|
if(new_stage == max_stages && !(stage_peaked)) //once a virus has hit its peak, set it to have done so
|
|
stage_peaked = TRUE
|
|
if (stage <= 0)
|
|
cure()
|
|
return FALSE
|
|
return TRUE
|
|
|
|
/datum/disease/proc/has_cure()
|
|
if(!(disease_flags & (CURABLE | CHRONIC)))
|
|
return FALSE
|
|
|
|
. = cures.len
|
|
for(var/C_id in cures)
|
|
if(!affected_mob.reagents.has_reagent(target_reagent = C_id, check_subtypes = TRUE))
|
|
.--
|
|
if(!. || (needs_all_cures && . < cures.len))
|
|
return FALSE
|
|
|
|
/**
|
|
* Handles performing a spread-via-air
|
|
*
|
|
* Checks for stuff like "is our mouth covered" for you
|
|
*
|
|
* * spread_range - How far the disease can spread
|
|
* * force_spread - If TRUE, the disease will spread regardless of the spread_flags
|
|
* * require_facing - If TRUE, the disease will only spread if the source mob is facing the target mob
|
|
*/
|
|
/datum/disease/proc/airborne_spread(spread_range = 2, force_spread = TRUE, require_facing = FALSE)
|
|
if(isnull(affected_mob))
|
|
return FALSE
|
|
if(!(spread_flags & DISEASE_SPREAD_AIRBORNE) && !force_spread)
|
|
return FALSE
|
|
if(!affected_mob.can_spread_airborne_diseases()) // BUBBER EDIT CHANGE - DISEASE OUTBREAK UPDATES
|
|
return FALSE
|
|
if(!has_required_infectious_organ(affected_mob, ORGAN_SLOT_LUNGS)) //also if you lack lungs
|
|
return FALSE
|
|
if(HAS_TRAIT(affected_mob, TRAIT_VIRUS_RESISTANCE) || (affected_mob.satiety > 0 && prob(affected_mob.satiety / 2))) //being full or on spaceacillin makes you less likely to spread a virus
|
|
return FALSE
|
|
var/turf/mob_loc = affected_mob.loc
|
|
if(!istype(mob_loc))
|
|
return FALSE
|
|
for(var/mob/living/carbon/to_infect in oview(spread_range, affected_mob))
|
|
// BUBBER EDIT ADDITION START - DISEASE OUTBREAK UPDATES
|
|
if(!prob(infectivity))
|
|
continue
|
|
// BUBBER EDIT ADDITION END - DISEASE OUTBREAK UPDATES
|
|
var/turf/infect_loc = to_infect.loc
|
|
if(!istype(infect_loc))
|
|
continue
|
|
if(require_facing && !is_source_facing_target(affected_mob, to_infect))
|
|
continue
|
|
if(!disease_air_spread_walk(mob_loc, infect_loc))
|
|
continue
|
|
to_infect.contract_airborne_disease(src)
|
|
return TRUE
|
|
|
|
/// Helper for checking if there is an air path between two turfs
|
|
/proc/disease_air_spread_walk(turf/start, turf/end)
|
|
if(!start || !end)
|
|
return FALSE
|
|
while(TRUE)
|
|
if(end == start)
|
|
return TRUE
|
|
var/turf/Temp = get_step_towards(end, start)
|
|
if(!TURFS_CAN_SHARE(end, Temp)) //Don't go through a wall
|
|
return FALSE
|
|
end = Temp
|
|
|
|
/datum/disease/proc/cure(add_resistance = TRUE)
|
|
if(severity == DISEASE_SEVERITY_UNCURABLE) //aw man :(
|
|
return
|
|
if(affected_mob)
|
|
if(add_resistance && (disease_flags & CAN_RESIST))
|
|
LAZYOR(affected_mob.disease_resistances, GetDiseaseID())
|
|
if(affected_mob.ckey)
|
|
var/cure_turf = get_turf(affected_mob)
|
|
log_virus("[key_name(affected_mob)] was cured of virus: [src.admin_details()] at [loc_name(cure_turf)]")
|
|
qdel(src)
|
|
|
|
/datum/disease/proc/IsSame(datum/disease/D)
|
|
if(istype(D, type))
|
|
return TRUE
|
|
return FALSE
|
|
|
|
|
|
/datum/disease/proc/Copy()
|
|
//note that stage is not copied over - the copy starts over at stage 1
|
|
/* // BUBBER EDIT CHANGE START - DISEASE OUTBREAK UPDATES - ORIGINAL:
|
|
var/static/list/copy_vars = list("name", "visibility_flags", "disease_flags", "spread_flags", "form", "desc", "agent", "spread_text",
|
|
"cure_text", "max_stages", "stage_prob", "incubation_time", "viable_mobtypes", "cures", "infectivity", "cure_chance",
|
|
"required_organ", "bypasses_immunity", "spreading_modifier", "severity", "needs_all_cures", "strain_data",
|
|
"infectable_biotypes", "process_dead")
|
|
*/
|
|
var/static/list/copy_vars = list("name", "visibility_flags", "disease_flags", "spread_flags", "form", "desc", "agent", "spread_text",
|
|
"cure_text", "max_stages", "stage_prob", "viable_mobtypes", "cures", "infectivity", "cure_chance",
|
|
"required_organ", "bypasses_immunity", "bypasses_disease_recovery", "spreading_modifier", "severity", "needs_all_cures", "strain_data",
|
|
"infectable_biotypes", "process_dead", "event_disease")
|
|
// BUBBER EDIT CHANGE END - DISEASE OUTBREAK UPDATES
|
|
var/datum/disease/D = copy_type ? new copy_type() : new type()
|
|
for(var/V in copy_vars)
|
|
var/val = vars[V]
|
|
if(islist(val))
|
|
var/list/L = val
|
|
val = L.Copy()
|
|
D.vars[V] = val
|
|
return D
|
|
|
|
/datum/disease/proc/after_add()
|
|
return
|
|
|
|
|
|
/datum/disease/proc/GetDiseaseID()
|
|
return "[type]"
|
|
|
|
/datum/disease/proc/remove_disease()
|
|
unregister_disease_signals()
|
|
LAZYREMOVE(affected_mob.diseases, src) //remove the datum from the list
|
|
affected_mob.med_hud_set_status()
|
|
log_virus_public("[affected_mob] was cured of virus. Total infected by this carrier: [mobs_infected]") // BUBBER EDIT ADDITION - DISEASE OUTBREAK UPDATES
|
|
affected_mob = null
|
|
|
|
/**
|
|
* Checks the given typepath against the list of viable mobtypes.
|
|
*
|
|
* Returns TRUE if the mob_type path is derived from of any entry in the viable_mobtypes list.
|
|
* Returns FALSE otherwise.
|
|
*
|
|
* Arguments:
|
|
* * mob_type - Type path to check against the viable_mobtypes list.
|
|
*/
|
|
/datum/disease/proc/is_viable_mobtype(mob_type)
|
|
for(var/viable_type in viable_mobtypes)
|
|
if(ispath(mob_type, viable_type))
|
|
return TRUE
|
|
|
|
// Let's only do this check if it fails. Did some genius coder pass in a non-type argument?
|
|
if(!ispath(mob_type))
|
|
stack_trace("Non-path argument passed to mob_type variable: [mob_type]")
|
|
|
|
return FALSE
|
|
|
|
/// Checks if the mob has the required organ and it's not robotic or affected by inorganic biology
|
|
/datum/disease/proc/has_required_infectious_organ(mob/living/carbon/target, required_organ_slot)
|
|
if(!iscarbon(target))
|
|
return FALSE
|
|
|
|
var/obj/item/organ/target_organ = target.get_organ_slot(required_organ_slot)
|
|
if(!istype(target_organ))
|
|
return FALSE
|
|
|
|
// robotic organs are immune to disease unless 'inorganic biology' symptom is present
|
|
if(IS_ROBOTIC_ORGAN(target_organ) && !(infectable_biotypes & MOB_ROBOTIC))
|
|
return FALSE
|
|
|
|
return TRUE
|
|
|
|
/// Handles spreading via air when our mob breathes
|
|
/datum/disease/proc/on_breath(datum/source, seconds_per_tick, ...)
|
|
SIGNAL_HANDLER
|
|
|
|
/* BUBBER EDIT REMOVAL START - DISEASE OUTBREAK UPDATES
|
|
if(SPT_PROB(infectivity * 4, seconds_per_tick))
|
|
*/// BUBBER EDIT REMOVAL END - DISEASE OUTBREAK UPDATES
|
|
airborne_spread()
|
|
|
|
//Use this to compare severities
|
|
/proc/get_disease_severity_value(severity)
|
|
switch(severity)
|
|
if(DISEASE_SEVERITY_UNCURABLE)
|
|
return 0
|
|
if(DISEASE_SEVERITY_POSITIVE)
|
|
return 1
|
|
if(DISEASE_SEVERITY_NONTHREAT)
|
|
return 2
|
|
if(DISEASE_SEVERITY_MINOR)
|
|
return 3
|
|
if(DISEASE_SEVERITY_MEDIUM)
|
|
return 4
|
|
if(DISEASE_SEVERITY_HARMFUL)
|
|
return 5
|
|
if(DISEASE_SEVERITY_DANGEROUS)
|
|
return 6
|
|
if(DISEASE_SEVERITY_BIOHAZARD)
|
|
return 7
|