mirror of
https://github.com/goonstation/goonstation-2016.git
synced 2026-08-20 20:46:13 +01:00
534 lines
17 KiB
Plaintext
534 lines
17 KiB
Plaintext
/datum/ailment
|
|
// all the vars that don't change/are defaults go in here - these will be in a central list for referencing
|
|
var/name = "ailment"
|
|
var/scantype = "Ailment" // what type this shows up as on scanners
|
|
var/cure = "Unknown" // how do we get rid of it
|
|
var/print_name = null // printed name for health scanners
|
|
var/max_stages = 0 // how many stages the disease has overall
|
|
var/stage_prob = 5 // % chance per tick it'll advance a stage
|
|
var/list/affected_species = list() // what kind of mobs does this disease affect
|
|
var/tmp/DNA = null // no fuckin idea
|
|
var/list/reagentcure = list() // which reagents cure this disease...
|
|
var/recureprob = 8 // ...and how likely % they are per tick to do so
|
|
var/temperature_cure = 406 // bodytemperature >= this will purge the infection
|
|
var/detectability = 0 // detectors must >= this to pick up the disease
|
|
var/resistance_prob = 0 // how likely this disease is to grant immunity once cured
|
|
var/max_stacks = 1 // how many times at once you can have this ailment
|
|
|
|
proc/stage_act(var/mob/living/affected_mob,var/datum/ailment_data/D)
|
|
if (!affected_mob || !D)
|
|
return 1
|
|
return 0
|
|
|
|
proc/on_remove(var/mob/living/affected_mob,var/datum/ailment_data/D)
|
|
disposed = 1 // set to avoid bizarre interactions (such as surgerizing out a single disease multiple times)
|
|
return
|
|
|
|
proc/on_infection(var/mob/living/affected_mob,var/datum/ailment_data/D)
|
|
return
|
|
|
|
// This is still subject to serious change. For now it's mostly a mockup.
|
|
// Determines things that may happen during a surgery for different ailments
|
|
// requiring a surgeon's intervention. Currently used for the parasites.
|
|
// Returns a true value if the surgery was successful.
|
|
proc/surgery(var/mob/living/surgeon, var/mob/living/affected_mob, var/datum/ailment_data/D)
|
|
return 1
|
|
|
|
/datum/ailment/parasite
|
|
name = "Parasite"
|
|
scantype = "Parasite"
|
|
cure = "Surgery"
|
|
|
|
/datum/ailment/disability
|
|
name = "Disability"
|
|
scantype = "Disability"
|
|
cure = "Unknown"
|
|
|
|
/datum/ailment/disease
|
|
name = "Disease"
|
|
scantype = "Virus"
|
|
cure = "Unknown"
|
|
var/virulence = 100
|
|
var/develop_resist = 0
|
|
var/spread = "Unknown"
|
|
var/associated_reagent = null // associated reagent, duh
|
|
|
|
var/list/disease_data = list() // A list of things for people to research about the disease to make it
|
|
var/list/strain_data = list() // Used for Rhinovirus
|
|
|
|
// IMPLEMENT PROPER CURE PROC
|
|
|
|
/datum/ailment_data
|
|
// these will be the local thing on mobs that does all the effecting, and they store unique vars so we can still
|
|
// have unique strains of disease and whatnot
|
|
/////////////////////////////////////////////////////////////////////////
|
|
var/datum/ailment/master = null // we reference back to the ailment itself to get effects and static vars
|
|
var/tmp/mob/living/affected_mob = null // the poor sod suffering from the disease
|
|
var/name = null // an override - uses the base disease name if null - if not, it uses this
|
|
var/detectability = 0 // scans must >= this to detect the disease
|
|
var/cure = "Unknown" // how do we get rid of it
|
|
var/stage = 1 // what stage the disease is currently at
|
|
var/state = "Active" // what is this disease currently doing
|
|
var/stage_prob = 5 // how likely is this disease to advance to the next stage
|
|
var/list/reagentcure = list() // list of reagents that can cure this disease
|
|
var/recureprob = 8 // probability per tick that the reagent will cure the disease
|
|
var/temperature_cure = 406 // this temp or higher will cure the disease
|
|
var/resistance_prob = 0 // how likely this disease is to grant immunity once cured
|
|
|
|
disposing()
|
|
if (affected_mob)
|
|
if (affected_mob.ailments)
|
|
affected_mob.ailments -= src
|
|
affected_mob = null
|
|
|
|
master = null
|
|
reagentcure = null
|
|
|
|
..()
|
|
|
|
proc/stage_act()
|
|
if (!affected_mob || disposed)
|
|
return 1
|
|
|
|
if (!istype(master,/datum/ailment/))
|
|
affected_mob.cure_disease(src)
|
|
return 1
|
|
|
|
if (stage > master.max_stages)
|
|
stage = master.max_stages
|
|
|
|
if (prob(stage_prob) && stage < master.max_stages)
|
|
stage++
|
|
|
|
master.stage_act(affected_mob,src)
|
|
|
|
return 0
|
|
|
|
proc/scan_info()
|
|
var/text = "<span style=\"color:red\"><b>"
|
|
if (istype(src.master,/datum/ailment/disease))
|
|
text += "[src.state] "
|
|
text += "[src.master.scantype]:"
|
|
|
|
text += " [src.name ? src.name : src.master.name]</b> <small>(Stage [src.stage]/[src.master.max_stages])<br>"
|
|
if (istype(src.master,/datum/ailment/disease))
|
|
var/datum/ailment_data/disease/AD = src
|
|
text += "Spread: [AD.spread]<br>"
|
|
if (src.cure == "Incurable")
|
|
text += "Infection is incurable. Suggest quarantine measures."
|
|
else if (src.cure == "Unknown")
|
|
text += "No suggested remedies."
|
|
else
|
|
text += "Suggested Remedy: [src.cure]"
|
|
text += "</small></span>"
|
|
return text
|
|
|
|
proc/on_infection()
|
|
master.on_infection(affected_mob, src)
|
|
return
|
|
|
|
proc/surgery(var/mob/living/surgeon, var/mob/living/affected_mob)
|
|
if (master && istype(master, /datum/ailment))
|
|
return master.surgery(surgeon, affected_mob, src)
|
|
return 1
|
|
|
|
/datum/ailment_data/disease
|
|
var/virulence = 100 // how likely is this disease to spread
|
|
var/develop_resist = 0 // can you develop a resistance to this?
|
|
var/spread = "Unknown" // how does this disease transmit itself around?
|
|
var/cycles = 0 // does this disease have a cyclical nature? if so, how many cycles have elapsed?
|
|
|
|
stage_act()
|
|
if (!affected_mob || disposed)
|
|
return 1
|
|
|
|
if (!istype(master,/datum/ailment/))
|
|
affected_mob.ailments -= src
|
|
qdel(src)
|
|
return 1
|
|
|
|
if (stage > master.max_stages)
|
|
stage = master.max_stages
|
|
|
|
if (stage < 1) // if it's less than one just get rid of it, goddamn
|
|
affected_mob.cure_disease(src)
|
|
return 1
|
|
|
|
var/advance_prob = stage_prob
|
|
if (state == "Acute")
|
|
advance_prob *= 2
|
|
advance_prob = max(0,min(advance_prob,100))
|
|
|
|
if (prob(advance_prob))
|
|
if (state == "Remissive")
|
|
stage--
|
|
if (stage < 1)
|
|
affected_mob.cure_disease(src)
|
|
return 1
|
|
else if (stage < master.max_stages)
|
|
stage++
|
|
|
|
// Common cures
|
|
if (cure != "Incurable")
|
|
if (cure == "Sleep" && affected_mob.sleeping && prob(33))
|
|
state = "Remissive"
|
|
return 1
|
|
|
|
else if (cure == "Self-Curing" && prob(5))
|
|
state = "Remissive"
|
|
return 1
|
|
|
|
else if (cure == "Beatings" && affected_mob.get_brute_damage() >= 40)
|
|
state = "Remissive"
|
|
return 1
|
|
|
|
else if (cure == "Burnings" && (affected_mob.get_burn_damage() >= 40 || affected_mob.burning))
|
|
state = "Remissive"
|
|
return 1
|
|
|
|
else if (affected_mob.bodytemperature >= temperature_cure)
|
|
state = "Remissive"
|
|
return 1
|
|
|
|
if (reagentcure.len && affected_mob.reagents)
|
|
for(var/current_id in affected_mob.reagents.reagent_list)
|
|
if (reagentcure.Find(current_id))
|
|
if (prob(recureprob))
|
|
state = "Remissive"
|
|
return 1
|
|
|
|
if (state == "Asymptomatic" || state == "Dormant")
|
|
return 1
|
|
|
|
spawn(rand(1,5))
|
|
// vary it up a bit so the processing doesnt look quite as transparent
|
|
if (master)
|
|
master.stage_act(affected_mob,src)
|
|
|
|
return 0
|
|
|
|
/datum/ailment_data/addiction
|
|
var/associated_reagent = null
|
|
var/last_reagent_dose = 0
|
|
var/withdrawal_duration = 4800
|
|
|
|
New()
|
|
..()
|
|
master = get_disease_from_path(/datum/ailment/addiction)
|
|
|
|
/datum/ailment_data/parasite
|
|
var/was_setup = 0
|
|
var/surgery_prob = 50
|
|
|
|
var/source = null // for headspiders
|
|
var/stealth_asymptomatic = 0
|
|
proc/setup()
|
|
src.stage_prob = master.stage_prob
|
|
src.cure = master.cure
|
|
src.was_setup = 1
|
|
|
|
stage_act()
|
|
if (!affected_mob)
|
|
return
|
|
|
|
if (!istype(master, /datum/ailment/))
|
|
affected_mob.cure_disease(src)
|
|
return
|
|
|
|
if (!istype(source, /datum/mind))
|
|
affected_mob.cure_disease(src)
|
|
return
|
|
|
|
if (!was_setup)
|
|
src.setup()
|
|
|
|
if (stage > master.max_stages)
|
|
stage = master.max_stages
|
|
|
|
if (prob(stage_prob) && stage < master.max_stages)
|
|
stage++
|
|
|
|
|
|
if(!stealth_asymptomatic)
|
|
master.stage_act(affected_mob,src,source)
|
|
|
|
return
|
|
|
|
/mob/living/proc/disease_resistance_check(var/ailment_path, var/ailment_name)
|
|
if (!src)
|
|
// no mob (somehow), so fuck this shit!
|
|
return 0
|
|
|
|
if (!ispath(ailment_path) && !istext(ailment_name))
|
|
// didn't specify a disease to check against
|
|
return 0
|
|
|
|
var/datum/ailment/A = null
|
|
if (ailment_name)
|
|
A = get_disease_from_name(ailment_name)
|
|
else
|
|
A = get_disease_from_path(ailment_path)
|
|
|
|
if (!istype(A,/datum/ailment/))
|
|
// can't find shit, captain!
|
|
return 0
|
|
|
|
if (src.resistances.Find(A.type))
|
|
// If we've already got this disease or are resistant to it, then NOPE
|
|
// duplicate strain checking is in the main loop because otherwise bypass resistance ignores it
|
|
return 0
|
|
|
|
var/mob_type = null
|
|
if (ismonkey(src))
|
|
mob_type = "Monkey"
|
|
else if (ishuman(src))
|
|
//Current thought: It's really weird for a base mob proc to run istypes on itself.
|
|
var/mob/living/carbon/human/H = src
|
|
if (H.mutantrace && !H.mutantrace.human_compatible)
|
|
mob_type = capitalize(H.mutantrace.name)
|
|
else
|
|
mob_type = "Human"
|
|
if (!A.affected_species.Find(mob_type))
|
|
// Only valid vector species can get a disease.
|
|
return 0
|
|
|
|
if (src.stat == 2 && !istype(A,/datum/ailment/parasite))
|
|
//Dead folks cannot get non-parasitoid infections.
|
|
return 0
|
|
|
|
var/resist_prob = 0
|
|
if (istype(A,/datum/ailment/disease/))
|
|
var/datum/ailment/disease/D = A
|
|
resist_prob -= D.virulence
|
|
if (istype(src,/mob/living/carbon/human))
|
|
var/mob/living/carbon/human/H = src
|
|
if (D.spread == "Airborne")
|
|
if (src.wear_mask)
|
|
if (H.internal)
|
|
resist_prob += 100
|
|
// if you don't breathe it in, you're fine
|
|
else
|
|
resist_prob += 20
|
|
// mask but no air supply - still better than nothing
|
|
|
|
else if (D.spread == "Sight")
|
|
if (H.eyes_protected_from_light())
|
|
resist_prob += 190
|
|
|
|
for (var/obj/item/clothing/C in H.get_equipped_items())
|
|
resist_prob += C.disease_resistance
|
|
|
|
resist_prob = max(0,min(resist_prob,100))
|
|
if (prob(resist_prob))
|
|
// we successfully resisted it
|
|
return 0
|
|
|
|
// you caught the virus! do you want to give the captured virus a nickname? virus has been recorded in lurgydex
|
|
return 1
|
|
|
|
/mob/living/proc/contract_disease(var/ailment_path, var/ailment_name, var/datum/ailment_data/disease/strain, bypass_resistance = 0)
|
|
if (!src)
|
|
return null
|
|
if (!ailment_path && !ailment_name && !istype(strain,/datum/ailment_data/disease/))
|
|
return null
|
|
|
|
var/datum/ailment/A = null
|
|
if (strain && istype(strain.master,/datum/ailment/))
|
|
A = strain.master
|
|
else if (ailment_name)
|
|
A = get_disease_from_name(ailment_name)
|
|
else
|
|
A = get_disease_from_path(ailment_path)
|
|
|
|
if (!istype(A,/datum/ailment/))
|
|
// can't find shit, captain!
|
|
return null
|
|
|
|
var/count = 0
|
|
for (var/datum/ailment_data/D in src.ailments)
|
|
if (D.master == A)
|
|
count++
|
|
|
|
if (count >= A.max_stacks)
|
|
return null
|
|
|
|
if (ischangeling(src) || isvampire(src) || src.nodamage)
|
|
//Vampires and changelings are immune to disease, as are the godmoded.
|
|
//This is here rather than in the resistance check proc because otherwise certain things could bypass the
|
|
//hard immunity these folks are supposed to have
|
|
return null
|
|
|
|
if (!bypass_resistance && !src.disease_resistance_check(null,A.name))
|
|
return null
|
|
|
|
if (istype(A, /datum/ailment/disease/))
|
|
var/datum/ailment/disease/D = A
|
|
var/datum/ailment_data/disease/AD = new /datum/ailment_data/disease
|
|
if (istype(strain,/datum/ailment_data/disease/))
|
|
if (strain.name)
|
|
AD.name = strain.name
|
|
else
|
|
AD.name = D.name
|
|
AD.stage_prob = strain.stage_prob
|
|
AD.reagentcure = strain.reagentcure
|
|
AD.recureprob = strain.recureprob
|
|
AD.virulence = strain.virulence
|
|
AD.detectability = strain.detectability
|
|
AD.develop_resist = strain.develop_resist
|
|
AD.cure = strain.cure
|
|
AD.spread = strain.spread
|
|
AD.resistance_prob = strain.resistance_prob
|
|
AD.temperature_cure = strain.temperature_cure
|
|
else
|
|
AD.name = D.name
|
|
AD.stage_prob = D.stage_prob
|
|
AD.reagentcure = D.reagentcure
|
|
AD.recureprob = D.recureprob
|
|
AD.virulence = D.virulence
|
|
AD.detectability = D.detectability
|
|
AD.develop_resist = D.develop_resist
|
|
AD.cure = D.cure
|
|
AD.spread = D.spread
|
|
AD.resistance_prob = D.resistance_prob
|
|
AD.temperature_cure = D.temperature_cure
|
|
|
|
src.ailments += AD
|
|
AD.master = A
|
|
AD.affected_mob = src
|
|
AD.on_infection()
|
|
|
|
if (prob(5))
|
|
AD.state = "Asymptomatic"
|
|
// carrier - will spread it but won't suffer from it
|
|
return AD
|
|
else
|
|
var/datum/ailment_data/AD = new /datum/ailment_data
|
|
AD.name = A.name
|
|
AD.stage_prob = A.stage_prob
|
|
AD.cure = A.cure
|
|
AD.reagentcure = A.reagentcure
|
|
AD.recureprob = A.recureprob
|
|
AD.master = A
|
|
|
|
AD.master = A
|
|
AD.affected_mob = src
|
|
src.ailments += AD
|
|
|
|
return AD
|
|
|
|
/mob/living/proc/viral_transmission(var/mob/living/target, var/spread_type, var/two_way = 0)
|
|
if (!src || !target || !istext(spread_type))
|
|
return
|
|
|
|
if (!src.ailments || !src.ailments.len)
|
|
return
|
|
|
|
for (var/datum/ailment_data/disease/AD in src.ailments)
|
|
if (AD.spread == spread_type)
|
|
target.contract_disease(null,null,AD,0)
|
|
|
|
if (two_way)
|
|
for (var/datum/ailment_data/disease/AD in target.ailments)
|
|
if (AD.spread == spread_type)
|
|
src.contract_disease(null,null,AD,0)
|
|
|
|
return
|
|
|
|
/mob/living/proc/cure_disease(var/datum/ailment_data/AD)
|
|
if (!AD.master || !istype(AD,/datum/ailment_data/))
|
|
return 0
|
|
|
|
if (prob(AD.resistance_prob))
|
|
src.resistances += AD.master.type
|
|
src.ailments -= AD
|
|
AD.master.on_remove(src,AD)
|
|
qdel(AD)
|
|
return 1
|
|
|
|
/mob/living/proc/cure_disease_by_path(var/ailment_path)
|
|
for (var/datum/ailment_data/AD in src.ailments)
|
|
if (!AD.master)
|
|
continue
|
|
if (AD.master.type == ailment_path)
|
|
if (prob(AD.resistance_prob))
|
|
src.resistances += AD.master.type
|
|
src.ailments -= AD
|
|
AD.master.on_remove(src,AD)
|
|
qdel(AD)
|
|
return 1
|
|
return 0
|
|
|
|
/mob/living/proc/find_ailment_by_type(var/ailment_path)
|
|
if (!ispath(ailment_path))
|
|
return null
|
|
|
|
for (var/datum/ailment_data/AD in src.ailments)
|
|
if (AD.master && AD.master.type == ailment_path)
|
|
return AD
|
|
|
|
return null
|
|
|
|
/mob/living/proc/find_ailment_by_name(var/ailment_name,var/base_ailments_only = 0)
|
|
if (!istext(ailment_name))
|
|
return null
|
|
|
|
for (var/datum/ailment_data/AD in src.ailments)
|
|
if (AD.name == ailment_name && !base_ailments_only)
|
|
return AD
|
|
if (AD.master && AD.master.name == ailment_name)
|
|
return AD
|
|
|
|
return null
|
|
|
|
/mob/living/proc/Virus_ShockCure(var/probcure = 50)
|
|
for (var/datum/ailment_data/V in src.ailments)
|
|
if (V.cure == "Electric Shock" && prob(probcure))
|
|
src.cure_disease(V)
|
|
|
|
/mob/living/proc/shock_cyberheart(var/shockInput)
|
|
return
|
|
|
|
/mob/living/carbon/human/shock_cyberheart(var/shockInput)
|
|
if (!src.organHolder)
|
|
return
|
|
var/numHigh = round((1 * shockInput) / 5)
|
|
var/numMid = round((1 * shockInput) / 10)
|
|
var/numLow = round((1 * shockInput) / 20)
|
|
if (src.organHolder.heart && src.organHolder.heart.robotic && src.organHolder.heart.emagged && !src.organHolder.heart.broken)
|
|
src.add_stam_mod_regen("heart_shock", 5)
|
|
src.add_stam_mod_max("heart_shock", 20)
|
|
spawn(9000)
|
|
src.remove_stam_mod_regen("heart_shock")
|
|
src.remove_stam_mod_max("heart_shock")
|
|
if (prob(numHigh))
|
|
boutput(src, "<span style=\"color:red\">Your cyberheart spasms violently!</span>")
|
|
random_brute_damage(src, numHigh)
|
|
if (prob(numHigh))
|
|
boutput(src, "<span style=\"color:red\">Your cyberheart shocks you painfully!</span>")
|
|
random_burn_damage(src, numHigh)
|
|
if (prob(numMid))
|
|
boutput(src, "<span style=\"color:red\">Your cyberheart lurches awkwardly!</span>")
|
|
src.contract_disease(/datum/ailment/disease/heartfailure, null, null, 1)
|
|
if (prob(numMid))
|
|
boutput(src, "<span style=\"color:red\"><B>Your cyberheart stops beating!</B></span>")
|
|
src.contract_disease(/datum/ailment/disease/flatline, null, null, 1)
|
|
if (prob(numLow))
|
|
boutput(src, "<span style=\"color:red\"><B>Your cyberheart shuts down!</B></span>")
|
|
src.organHolder.heart.broken = 1
|
|
src.contract_disease(/datum/ailment/disease/flatline, null, null, 1)
|
|
else if (src.organHolder.heart && src.organHolder.heart.robotic && !src.organHolder.heart.emagged && !src.organHolder.heart.broken)
|
|
src.add_stam_mod_regen("heart_shock", 1)
|
|
src.add_stam_mod_max("heart_shock", 10)
|
|
spawn(9000)
|
|
src.remove_stam_mod_regen("heart_shock")
|
|
src.remove_stam_mod_max("heart_shock")
|
|
if (prob(numMid))
|
|
boutput(src, "<span style=\"color:red\">Your cyberheart spasms violently!</span>")
|
|
random_brute_damage(src, numMid)
|
|
if (prob(numMid))
|
|
boutput(src, "<span style=\"color:red\">Your cyberheart shocks you painfully!</span>")
|
|
random_burn_damage(src, numMid)
|
|
if (prob(numLow))
|
|
boutput(src, "<span style=\"color:red\">Your cyberheart lurches awkwardly!</span>")
|
|
src.contract_disease(/datum/ailment/disease/heartfailure, null, null, 1)
|