diff --git a/code/modules/medical/pathology/pathogen.dm b/code/modules/medical/pathology/pathogen.dm
index 5dbc67e436339..b8158a43f7531 100644
--- a/code/modules/medical/pathology/pathogen.dm
+++ b/code/modules/medical/pathology/pathogen.dm
@@ -22,6 +22,28 @@
// And for all:
// RARITY_ABSTRACT: Used strictly for categorization. ABSTRACT symptoms will never appear.
// ie. if lingual is a symptom category with multiple subsymptoms (for easy mutex), it should be abstract.
+
+// --SYMPTOM THREAT--
+// All symptoms are catagorized with a threat value to describe the scope of their impact.
+// Benign symptoms are negative. Malign symptoms are positive.
+// THREAT_BENETYPE2: This symptom provides significant health benefits to infected individuals.
+// THREAT_BENETYPE1: This symptom provides marginal benefits to infected individuals.
+// THREAT_NEUTRAL: The symptom causes no impactful harm or good to infected individuals.
+// THREAT_TYPE1: This symptom causes barely noticable, nonfatal harm to infected individuals. Should not affect gameplay mechanically.
+// THREAT_TYPE2: This symptom causes noticable, but nonfatal harm to infected individuals. Should not significantly impede gameplay.
+// THREAT_TYPE3: This symptom causes significant, but nonfatal harm to infected individuals. May damage the player or impede mechanical gameplay.
+// THREAT_TYPE4: This symptom causes severe and potentially fatal harm to infected individuals. Critting from full should take at least 5 minutes unattended. Short stuns are OK.
+// THREAT_TYPE5: This symptom is extremely dangerous and will certainly cause fatal harm to infected individuals. Anything that causes incapacitation goes HERE. Critting should take at least 3 minutes. Instant death and adjacent go here.
+
+#define THREAT_BENETYPE2 = -2
+#define THREAT_BENETYPE1 = -1
+#define THREAT_NEUTRAL = 0
+#define THREAT_TYPE1 = 1
+#define THREAT_TYPE2 = 2
+#define THREAT_TYPE3 = 3
+#define THREAT_TYPE4 = 4
+#define THREAT_TYPE5 = 5
+
#define RARITY_VERY_COMMON 1
#define RARITY_COMMON 2
#define RARITY_UNCOMMON 3
diff --git a/code/modules/medical/pathology/pathogen_benevolent.dm b/code/modules/medical/pathology/pathogen_benevolent.dm
deleted file mode 100644
index e3b1e4336010a..0000000000000
--- a/code/modules/medical/pathology/pathogen_benevolent.dm
+++ /dev/null
@@ -1,470 +0,0 @@
-
-
-datum/pathogeneffects/benevolent
- name = "Benevolent"
- rarity = RARITY_ABSTRACT
- beneficial = 1
-
-datum/pathogeneffects/benevolent/mending
- name = "Wound Mending"
- desc = "Slow paced brute damage healing."
- rarity = RARITY_COMMON
-
- disease_act(var/mob/M as mob, var/datum/pathogen/origin)
- if (!origin.symptomatic)
- return
- //if (prob(origin.stage * 5))
- M.HealDamage("All", origin.stage / 2, 0)
-
- react_to(var/R, var/zoom)
- if (R == "synthflesh")
- if (zoom)
- return "Microscopic damage on the synthetic flesh appears to be mended by the pathogen."
-
- may_react_to()
- return "The pathogen appears to have the ability to bond with organic tissue."
-
-datum/pathogeneffects/benevolent/healing
- name = "Burn Healing"
- desc = "Slow paced burn damage healing."
- rarity = RARITY_COMMON
-
- disease_act(var/mob/M as mob, var/datum/pathogen/origin)
- if (!origin.symptomatic)
- return
- //if (prob(origin.stage * 5))
- M.HealDamage("All", 0, origin.stage / 2)
-
- react_to(var/R, var/zoom)
- if (R == "synthflesh")
- if (zoom)
- return "The pathogen does not appear to mend the synthetic flesh. Perhaps something that might cause other types of injuries might help."
- if (R == "infernite")
- if (zoom)
- return "The pathogen repels the scalding hot chemical and quickly repairs any damage caused by it to organic tissue."
-
- may_react_to()
- return "The pathogen appears to have the ability to bond with organic tissue."
-
-datum/pathogeneffects/benevolent/fleshrestructuring
- name = "Flesh Restructuring"
- desc = "Fast paced general healing."
- rarity = RARITY_RARE
-
- disease_act(var/mob/M as mob, var/datum/pathogen/origin)
- if (!origin.symptomatic)
- return
- if (prob(origin.stage * 5))
- M.HealDamage("All", origin.stage, origin.stage)
- if(ishuman(M))
- var/mob/living/carbon/human/H = M
- if(H.bleeding)
- repair_bleeding_damage(M, 80, 2)
- if (prob(50))
- M.show_message("You feel your wounds closing by themselves.")
-
- react_to(var/R, var/zoom)
- if (R == "synthflesh")
- if (zoom)
- return "The pathogen appears to mimic the behavior of the synthflesh."
- if (R == "acid")
- if (zoom)
- return "The pathogen becomes agitated and works to repair the damage caused by the sulfuric acid."
-
- may_react_to()
- return "The pathogen appears to be rapidly repairing the other cells around it."
- //podrickequus's first code, yay
-
-datum/pathogeneffects/benevolent/detoxication
- name = "Detoxication"
- desc = "The pathogen aids the host body in metabolizing ethanol."
- rarity = RARITY_COMMON
-
- disease_act(var/mob/M as mob, var/datum/pathogen/origin)
- if (!origin.symptomatic)
- return
- var/times = 1
- if (origin.stage > 3)
- times++
- if (origin.stage > 4)
- times++
- var/met = 0
- for (var/rid in M.reagents.reagent_list)
- var/datum/reagent/R = M.reagents.reagent_list[rid]
- if (rid == "ethanol" || istype(R, /datum/reagent/fooddrink/alcoholic))
- met = 1
- for (var/i = 1, i <= times, i++)
- if (R) //Wire: Fix for Cannot execute null.on mob life().
- R.on_mob_life()
- if (!R || R.disposed)
- break
- if (R && !R.disposed)
- M.reagents.remove_reagent(rid, R.depletion_rate * times)
- if (met)
- M.reagents.update_total()
-
- react_to(var/R, var/zoom)
- if (R == "ethanol")
- return "The pathogen appears to have entirely metabolized the ethanol."
-
- may_react_to()
- return "The pathogen appears to react with a pure intoxicant."
-
-datum/pathogeneffects/benevolent/metabolisis
- name = "Accelerated Metabolisis"
- desc = "The pathogen accelerates the metabolisis of all chemicals present in the host body."
- rarity = RARITY_RARE
-
- disease_act(var/mob/M as mob, var/datum/pathogen/origin)
- if (!origin.symptomatic)
- return
- var/times = 1
- if (origin.stage > 3)
- times++
- if (origin.stage > 4)
- times++
- var/met = 0
- for (var/rid in M.reagents.reagent_list)
- var/datum/reagent/R = M.reagents.reagent_list[rid]
- met = 1
- for (var/i = 1, i <= times, i++)
- if (R) //Wire: Fix for Cannot execute null.on mob life().
- R.on_mob_life()
- if (!R || R.disposed)
- break
- if (R && !R.disposed)
- M.reagents.remove_reagent(rid, R.depletion_rate * times)
- if (met)
- M.reagents.update_total()
-
-
- react_to(var/R, var/zoom)
- return "The pathogen appears to have entirely metabolized... all chemical agents in the dish."
-
- may_react_to()
- return "The pathogen appears to be rapidly breaking down certain materials around it."
-
-datum/pathogeneffects/benevolent/cleansing
- name = "Cleansing"
- desc = "The pathogen cleans the body of damage caused by toxins."
- rarity = RARITY_UNCOMMON
-
- disease_act(var/mob/M as mob, var/datum/pathogen/origin)
- if (!origin.symptomatic)
- return
- //if (prob(origin.stage * 5) && M.get_toxin_damage())
- if (M.get_toxin_damage())
- M.take_toxin_damage(-origin.stage / 2)
- if (prob(12))
- M.show_message("You feel cleansed.")
-
- react_to(var/R, var/zoom)
- return "The pathogen appears to have entirely metabolized... all chemical agents in the dish."
-
- may_react_to()
- return "The pathogen seems to be much cleaner than normal."
-
-datum/pathogeneffects/benevolent/oxygenconversion
- name = "Oxygen Conversion"
- desc = "The pathogen converts organic tissue into oxygen when required by the host."
- rarity = RARITY_RARE
-
- may_react_to()
- return "The pathogen appears to radiate oxygen."
-
- react_to(var/R, var/zoom)
- if (R == "synthflesh")
- return "The pathogen consumes the synthflesh and converts it into oxygen."
-
- disease_act(var/mob/M as mob, var/datum/pathogen/origin)
- if (!origin.symptomatic)
- return
- var/mob/living/carbon/C = M
- if (C.get_oxygen_deprivation())
- C.setStatus("patho_oxy_speed_bad", duration = INFINITE_STATUS, optional = origin.stage/2.5)
-
-datum/pathogeneffects/benevolent/oxygenstorage
- name = "Oxygen Storage"
- desc = "The pathogen stores oxygen and releases it when needed by the host."
- rarity = RARITY_RARE
-
- may_react_to()
- return "The pathogen appears to have a bubble of oxygen around it."
-
- disease_act(var/mob/M as mob, var/datum/pathogen/origin)
- if (!origin.symptomatic)
- return
- if(!origin.symptom_data["oxygen_storage"]) // if not yet set, initialize
- origin.symptom_data["oxygen_storage"] = 0
-
- var/mob/living/carbon/C = M
- if (C.get_oxygen_deprivation())
- if(origin.symptom_data["oxygen_storage"] > 10)
- C.setStatus("patho_oxy_speed", duration = INFINITE_STATUS, optional = origin.symptom_data["oxygen_storage"])
- origin.symptom_data["oxygen_storage"] = 0
- else
- // faster reserve replenishment at higher stages
- origin.symptom_data["oxygen_storage"] = min(100, origin.symptom_data["oxygen_storage"] + origin.stage*2)
-
-
-datum/pathogeneffects/benevolent/resurrection
- name = "Necrotic Resurrection"
- desc = "The pathogen will resurrect you if it procs while you are dead."
- rarity = RARITY_VERY_RARE
- var/cooldown = 20 MINUTES
-
- may_react_to()
- return "Some of the pathogen's dead cells seem to remain active."
-
- disease_act_dead(var/mob/M as mob, var/datum/pathogen/origin)
- if (!origin.symptomatic)
- return
- if (origin.stage < 3)
- return
- if(!origin.symptom_data["resurrect_cd"]) // if not yet set, initialize it so that it is off cooldown
- origin.symptom_data["resurrect_cd"] = -cooldown
- if(TIME-origin.symptom_data["resurrect_cd"] < cooldown)
- return
- // Shamelessly stolen from Strange Reagent
- if (isdead(M) || istype(get_area(M),/area/afterlife/bar))
- origin.symptom_data["resurrect_cd"] = TIME
- // range from 65 to 45. This is applied to both brute and burn, so the total max damage after resurrection is 130 to 90.
- var/cap = 95 - origin.stage * 10
- var/brute = min(cap, M.get_brute_damage())
- var/burn = min(cap, M.get_burn_damage())
-
- // let's heal them before we put some of the damage back
- // but they don't get back organs/limbs/whatever, so I don't use full_heal
- M.HealDamage("All", 100000, 100000)
- if(ishuman(M))
- var/mob/living/carbon/human/H = M
- H.blood_volume = 500 // let's not have people immediately suffocate from being exsanguinated
- H.take_toxin_damage(-INFINITY)
- H.take_oxygen_deprivation(-INFINITY)
- H.take_brain_damage(-INFINITY)
-
- M.TakeDamage("chest", brute, burn)
- M.take_brain_damage(70) // and a lot of brain damage
- setalive(M)
- M.changeStatus("paralysis", 15 SECONDS) // paralyze the person for a while, because coming back to life is hard work
- M.change_misstep_chance(40) // even after getting up they still have some grogginess for a while
- M.stuttering = 15
- if (M.ghost && M.ghost.mind && !(M.mind && M.mind.dnr)) // if they have dnr set don't bother shoving them back in their body
- M.ghost.show_text("You feel yourself being dragged out of the afterlife!")
- M.ghost.mind.transfer_to(M)
- qdel(M.ghost)
- if (ishuman(M))
- var/mob/living/carbon/human/H = M
- H.contract_disease(/datum/ailment/disease/tissue_necrosis, null, null, 1) // this disease will make the person more and more rotten even while alive
- H.visible_message("[H] suddenly starts moving again!","You feel the pathogen weakening as you rise from the dead.")
-
- react_to(var/R, var/zoom)
- if (R == "synthflesh")
- return "Dead parts of the synthflesh seem to still be transferring blood."
-
-
-datum/pathogeneffects/benevolent/brewery
- name = "Auto-Brewery"
- desc = "The pathogen aids the host body in metabolizing chemicals into ethanol."
- rarity = RARITY_RARE
- beneficial = 0
-
- disease_act(var/mob/M as mob, var/datum/pathogen/origin)
- if (!origin.symptomatic)
- return
- var/times = 1
- if (origin.stage > 3)
- times++
- if (origin.stage > 4)
- times++
- var/met = 0
- for (var/rid in M.reagents.reagent_list)
- var/datum/reagent/R = M.reagents.reagent_list[rid]
- if (!(rid == "ethanol" || istype(R, /datum/reagent/fooddrink/alcoholic)))
- met = 1
- for (var/i = 1, i <= times, i++)
- if (R) //Wire: Fix for Cannot execute null.on mob life().
- R.on_mob_life()
- if (!R || R.disposed)
- break
- if (R && !R.disposed)
- var/amt = R.depletion_rate * times
- M.reagents.remove_reagent(rid, amt)
- M.reagents.add_reagent("ethanol", amt)
- if (met)
- M.reagents.update_total()
-
- react_to(var/R, var/zoom)
- if (!(R == "ethanol"))
- return "The pathogen appears to have entirely metabolized all chemical agents in the dish into... ethanol."
-
- may_react_to()
- return "The pathogen appears to react with anything but a pure intoxicant."
-
-datum/pathogeneffects/benevolent/oxytocinproduction
- name = "Oxytocin Production"
- desc = "The pathogen produces Pure Love within the infected."
- infect_type = INFECT_TOUCH
- rarity = RARITY_COMMON
- spread = SPREAD_BODY | SPREAD_HANDS
- infect_message = "You can't help but feel loved."
- infect_attempt_message = "Their touch is suspiciously soft..."
-
- onemote(mob/M as mob, act, voluntary, param, datum/pathogen/origin)
- if (!origin.symptomatic)
- return
- if (act != "hug" && act != "sidehug") // not a hug
- return
- if (param == null) // weirdo is just hugging themselves
- return
- for (var/mob/living/carbon/human/H in view(1, M))
- if (ckey(param) == ckey(H.name) && prob(origin.spread*2))
- SPAWN(0.5)
- infect_direct(H, origin, "hug")
- return
-
- disease_act(var/mob/M as mob, var/datum/pathogen/origin)
- if (!origin.symptomatic)
- return
- var/check_amount = M.reagents.get_reagent_amount("love")
- if (!check_amount || check_amount < 5)
- M.reagents.add_reagent("love", origin.stage / 3)
-
- may_react_to()
- return "The pathogen's cells appear to be... hugging each other?"
-
-datum/pathogeneffects/benevolent/neuronrestoration
- name = "Neuron Restoration"
- desc = "Infection slowly repairs nerve cells in the brain."
- rarity = RARITY_UNCOMMON
- infect_type = INFECT_NONE
- disease_act(var/mob/M as mob, var/datum/pathogen/origin)
- if (!origin.symptomatic)
- return
- switch (origin.stage)
- if (2)
- if (prob(5))
- M.take_brain_damage(-1)
- if (3)
- if (prob(10))
- M.take_brain_damage(-1)
- if (4)
- if (prob(15))
- M.take_brain_damage(-2)
- if (5)
- if (prob(20))
- M.take_brain_damage(-2)
-
- react_to(var/R, var/zoom)
- if (!(R == "neurotoxin"))
- return "The pathogen releases a chemical in an attempt to counteract the effects of the neurotoxin."
-
- may_react_to()
- return "The pathogen appears to have a gland that may affect neural functions."
-
-datum/pathogeneffects/benevolent/sunglass
- name = "Sunglass Glands"
- desc = "The infected grew sunglass glands."
- infect_type = INFECT_NONE
- rarity = RARITY_UNCOMMON
-
- proc/glasses(var/mob/living/carbon/human/M as mob)
- var/obj/item/clothing/glasses/G = M.glasses
- var/obj/item/clothing/glasses/N = new/obj/item/clothing/glasses/sunglasses()
- M.show_message({"[pick("You feel cooler!", "You find yourself wearing sunglasses.", "A pair of sunglasses grow onto your face.")][G?" But you were already wearing glasses!":""]"})
- if (G)
- N.set_loc(M.loc)
- var/turf/T = get_edge_target_turf(M, pick(alldirs))
- N.throw_at(T,rand(0,5),1)
- else
- N.set_loc(M)
- N.layer = M.layer
- N.master = M
- M.glasses = N
- M.update_clothing()
-
- disease_act(var/mob/M as mob, var/datum/pathogen/origin)
- if (!origin.symptomatic)
- return
- if (ishuman(M))
- var/mob/living/carbon/human/H = M
- if (!(H.glasses) || (!(istype(H.glasses, /obj/item/clothing/glasses/sunglasses)) && prob(50)))
- switch(origin.stage)
- if (2 to 4)
- if (prob(15))
- glasses(M)
- if (5)
- if (prob(25))
- glasses(M)
-
- may_react_to()
- return "The pathogen appears to be sensitive to sudden flashes of light."
-
- react_to(var/R, var/zoom)
- if (R == "flashpowder")
- if (zoom)
- return "The individual microbodies appear to be wearing sunglasses."
- else
- return "The pathogen appears to have developed a resistance to the flash powder."
-
-datum/pathogeneffects/benevolent/genetictemplate
- name = "Genetic Template"
- desc = "Spreads a mutation from patient zero to other afflicted."
- rarity = RARITY_VERY_RARE
- infect_type = INFECT_NONE
- var/list/mutationMap = list() // stores the kind of mutation with the index being the pathogen's name (which is something like "L41D9")
-
- disease_act(var/mob/M as mob, var/datum/pathogen/origin)
- if (!origin.symptomatic || !M.bioHolder)
- return
- if(mutationMap[origin.name_base] == null) // if no mutation has been picked yet, go for a random one from this person
- var/list/filtered = new/list()
- for(var/T in M.bioHolder.effects)
- var/datum/bioEffect/instance = M.bioHolder.effects[T]
- if(!instance || istype(instance, /datum/bioEffect/hidden)) continue // hopefully this catches all non-mutation bioeffects?
- filtered.Add(instance)
- if(!filtered.len) return // wow, this nerd has no mutations, screw this
- mutationMap[origin.name_base] = pick(filtered)
- boutput(M, "You somehow feel more attuned to your [mutationMap[origin.name_base]].") // So patient zero will know when the mutation has been chosen
-
- if(origin.symptom_data["genetictemplate"] == origin.stage) // early return if we would just put the same mutation anyway
- return
-
- var/datum/bioEffect/BEE = mutationMap[origin.name_base] // remove old version of mutation
- M.bioHolder.RemoveEffect(BEE.id)
-
- var/datum/bioEffect/BE = BEE.GetCopy()
- var/datum/dna_chromosome/chromo = new /datum/dna_chromosome/anti_mutadone() // reinforce always
- chromo.apply(BE)
- if (origin.stage >= 2)
- BE.altered = 0 // this lets us apply another chromosome. yay!
- chromo = new /datum/dna_chromosome() // stabilize after stage 2
- chromo.apply(BE)
- if (origin.stage >= 3)
- BE.altered = 0
- chromo = new /datum/dna_chromosome/safety() // synchronize starting at stage 3
- chromo.apply(BE)
- if (origin.stage >= 4)
- BE.altered = 0
- chromo = new /datum/dna_chromosome/power_enhancer() // empower starting at stage 4
- chromo.apply(BE)
- if (origin.stage >= 5)
- BE.altered = 0
- chromo = new /datum/dna_chromosome/cooldown_reducer() // reduce cooldown starting at stage 5
- chromo.apply(BE)
- M.bioHolder.AddEffectInstance(BE) // add updated version of mutation!
- origin.symptom_data["genetictemplate"] = origin.stage // save the last stage that we added the mutation with
-
- oncured(mob/M as mob, var/datum/pathogen/origin)
- if (!origin.symptomatic)
- return
- var/datum/bioEffect/BE = mutationMap[origin.name_base] // cure the mutation when the pathogen is cured
- M.bioHolder.RemoveEffect(BE.id)
-
- react_to(var/R, var/zoom)
- if (R == "mutadone")
- if (zoom)
- return "Approximately 0% of the individual microbodies appear to have returned to genetic normalcy." // it always reinforces
-
- may_react_to()
- return "The pathogen cells all look exactly alike."
diff --git a/code/modules/medical/pathology/pathogen_symptoms.dm b/code/modules/medical/pathology/pathogen_symptoms.dm
index 0f23129986cef..9e2a97e3d8b7b 100644
--- a/code/modules/medical/pathology/pathogen_symptoms.dm
+++ b/code/modules/medical/pathology/pathogen_symptoms.dm
@@ -1,164 +1,4 @@
-
-
datum/pathogeneffects
- var/name
- var/desc
- var/infect_type = 0
-
- var/spread = SPREAD_FACE | SPREAD_BODY | SPREAD_HANDS | SPREAD_AIR
-
- var/rarity = RARITY_ABSTRACT
- var/infect_message = null
- var/infect_attempt_message = null // shown to person when an attempt to directly infect them is made
-
- var/beneficial = 0
-
- // This is a list of mutual exclusive symptom TYPES.
- // If this contains any symptoms, none of these symptoms will be picked upon mutation or initial raffle.
- // Mutexes cut the ENTIRE object tree - for example, if symptoms a/b, a/c and a/d all exist, then mutexing
- // symptom a will also mutex b, c and d.
- var/list/mutex = list()
-
- // A symptom might not always infect everyone around. This is a flat probability: 0 means never infect to 1 means always infect. This is checked PER MOB, not per infect call.
- var/infection_coefficient = 1
-
- // disease_act(mob, datum/pathogen) : void
- // This is the center of pathogen symptoms.
- // On every Life() tick, this will be called for every symptom attached to the pathogen. Most pathogens should express their malevolence here, unless they are specifically tailored
- // to only work on events like human interaction or external effects. A symptom therefore should override this proc.
- // disease_act is also responsible for handling the symptom's ability to suppress the pathogen. Check the documentation on suppression in pathogen.dm.
- // OVERRIDE: A subclass (direct or otherwise) is expected to override this.
- proc/disease_act(var/mob/M as mob, var/datum/pathogen/origin)
-
- // disease_act_dead(mob, datum/pathogen) : void
- // This functions identically to disease_act, except it is only called when the mob is dead. (disease_act is not called if that is the case.)
- // OVERRIDE: Only override this if if it needed for the symptom.
- proc/disease_act_dead(var/mob/M as mob, var/datum/pathogen/origin)
-
- // does an infectious snap
- // makes others snap, should possibly infect you in the future if you are made to snap a certain amount of times
- proc/infect_snap(var/mob/M as mob, var/datum/pathogen/origin, var/range = 5)
- for (var/mob/I in view(range, M.loc))
- if (I != M && ((isturf(I.loc) && isturf(M.loc) && can_line_airborne(get_turf(M), I, 5)) || I.loc == M.loc))
- if(istype(M, /mob/living/carbon/human))
- var/mob/living/carbon/human/H = I
- if(prob(100-H.get_disease_protection()))
- SPAWN(rand(0.5,2) SECONDS)
- H.show_message("Pretty catchy tune...")
- H.emote("snap") // consider yourself lucky I haven't implemented snap infection yet, human
-
- // creates an infective cloud
- // this should give people better feedback about how be infected and how to avoid it
- proc/infect_cloud(var/mob/M as mob, var/datum/pathogen/origin, var/amount = 5)
- var/turf/T = get_turf(M)
- var/obj/decal/cleanable/pathogen_cloud/D = make_cleanable(/obj/decal/cleanable/pathogen_cloud,T)
-
- var/datum/reagent/blood/pathogen/Q = new /datum/reagent/blood/pathogen()
- D.reagents = new /datum/reagents(amount)
- Q.volume = amount
- Q.pathogens += origin.pathogen_uid
- Q.pathogens[origin.pathogen_uid] = origin
- D.reagents.reagent_list += "pathogen"
- D.reagents.reagent_list["pathogen"] = Q
- Q.holder = D.reagents
- D.reagents.update_total()
-
- // creates an infective puddle
- // this should give people better feedback about how be infected and how to avoid it
- proc/infect_puddle(var/mob/M as mob, var/datum/pathogen/origin, var/amount = 5)
- var/turf/T = get_turf(M)
- var/obj/decal/cleanable/pathogen_sweat/D = make_cleanable(/obj/decal/cleanable/pathogen_sweat,T)
-
- var/datum/reagent/blood/pathogen/Q = new /datum/reagent/blood/pathogen()
- D.reagents = new /datum/reagents(amount)
- Q.volume = amount
- Q.pathogens += origin.pathogen_uid
- Q.pathogens[origin.pathogen_uid] = origin
- D.reagents.reagent_list += "pathogen"
- D.reagents.reagent_list["pathogen"] = Q
- Q.holder = D.reagents
- D.reagents.update_total()
-
- // infect_direct(mob, datum/pathogen) : void
- // This is the proc that handles direct transmission of the pathogen from one mob to another. This should be called in particular infection scenarios. For example, a sweating person
- // gets his bodily fluids onto another when they directly disarm, punch, or grab a person.
- // For INFECT_TOUCH diseases this is automatically called on a successful disarm, punch or grab. When overriding any of these events, use ..() to keep this behaviour.
- // OVERRIDE: Generally, you do not need to override this.
- proc/infect_direct(var/mob/target as mob, var/datum/pathogen/origin, contact_type = "touch")
- if (infect_attempt_message)
- target.show_message("[infect_attempt_message]")
- if(istype(target, /mob/living/carbon/human))
- var/mob/living/carbon/human/H = target
- if(prob(100-H.get_disease_protection()))
- if (target.infected(origin))
- if (infect_message)
- target.show_message(infect_message)
- logTheThing("pathology", origin.infected, target, "infects [constructTarget(target,"pathology")] with [origin.name] due to symptom [name] through direct contact ([contact_type]).")
- return 1
-
- proc/onadd(var/datum/pathogen/origin)
- return
-
- // ====
- // Events from this point on. Their exact behaviour is documented in pathogen.dm. Please do not add any event definitions outside this block.
- // ondisarm(mob, mob, boolean, datum/pathogen) : float
- // OVERRIDE: Overriding this is situational. ..() is expected to be called.
- proc/ondisarm(var/mob/M as mob, var/mob/V as mob, isPushDown, var/datum/pathogen/origin)
- if (infect_type == INFECT_TOUCH && prob(origin.spread*2))
- infect_direct(V, origin, "disarm")
- return 1
-
- // ongrab(mob, mob, datum/pathogen) : void
- // TODO: Make this a veto event.
- // OVERRIDE: Overriding this is situational. ..() is expected to be called.
- proc/ongrab(var/mob/M as mob, var/mob/V as mob, var/datum/pathogen/origin)
- if (infect_type == INFECT_TOUCH && prob(origin.spread*2))
- infect_direct(V, origin, "grab")
- return
-
- // onpunch(mob, mob, string, datum/pathogen) : float
- // OVERRIDE: Overriding this is situational. ..() is expected to be called.
- proc/onpunch(var/mob/M as mob, var/mob/V as mob, zone, var/datum/pathogen/origin)
- if (infect_type == INFECT_TOUCH && prob(origin.spread*2))
- infect_direct(V, origin, "punching")
- return 1
-
- // onpunched(mob, mob, string, datum/pathogen) : float
- // OVERRIDE: Overriding this is situational. ..() is expected to be called.
- proc/onpunched(var/mob/M as mob, var/mob/A as mob, zone, var/datum/pathogen/origin)
- if (infect_type == INFECT_TOUCH && prob(origin.spread*2))
- infect_direct(A, origin, "being punched")
- return 1
-
- // onshocked(mob, mob, datum/shockparam, datum/pathogen) : datum/shockparam
- // OVERRIDE: Overriding this is situational.
- proc/onshocked(var/mob/M as mob, var/datum/shockparam/ret, var/datum/pathogen/origin)
- return ret
-
- // onsay(mob, string, datum/pathogen) : string
- // OVERRIDE: Overriding this is situational.
- proc/onsay(var/mob/M as mob, message, var/datum/pathogen/origin)
- return message
-
- // onemote(mob, string, number, string, datum/pathogen) : string
- // OVERRIDE: Overriding this is situational.
- proc/onemote(var/mob/M as mob, act, voluntary, param, var/datum/pathogen/P)
- return 1
-
- // ondeath(mob, datum/pathogen) : void
- // OVERRIDE: Overriding this is situational.
- proc/ondeath(var/mob/M as mob, var/datum/pathogen/origin)
- return
-
- // oncured(mob, datum/pathogen) : void
- // OVERRIDE: Overriding this is situational.
- proc/oncured(var/mob/M as mob, var/datum/pathogen/origin)
- return
-
-
- // End of events: please do not add any event definitions outside this block.
- // ====
-
// may_react_to() : string | null
// A set of features that you can observe through a microscope and what it might suggest.
// This will be used to NARROW DOWN what chemicals the pathogen might react to, so that you only need to try a finite set of reagents to determine exactly what symptoms the pathogen has.
@@ -206,6 +46,511 @@ datum/pathogeneffects
proc/react_to(var/R, var/zoom)
return null
+ //THE ICD-13: Catalog of All Pathogen Symptoms
+ //Parody of the ICD-10, the IRL disease identification manual from the World Health Organization
+
+ //Symptoms should be organized as follows:
+ //name: The name of the symptom
+ //desc: A description of the symptom
+ //threattype: Replacing RARITY, threattype describes how benign/dangerous the symptom is.
+ //Using threattype because Beepsky and the guardbots use threat
+ //value: The credit value to be summed in a CDC bounty for a pathogen containing this symptom
+ //transmissiontypes: A list(...) containing 'flags' that enable the pathogen to spread according to functions from pathogen_transmission.dm
+ //effect: Place the front-end effects here. This section may be extensive.
+
+// --SYMPTOM THREAT--
+// All symptoms are catagorized with a threat value to describe the scope of their impact.
+// Benign symptoms are negative. Malign symptoms are positive.
+// THREAT_BENETYPE2: This symptom provides significant health benefits to infected individuals.
+// THREAT_BENETYPE1: This symptom provides marginal benefits to infected individuals.
+// THREAT_NEUTRAL: The symptom causes no impactful harm or good to infected individuals.
+// THREAT_TYPE1: This symptom causes barely noticable, nonfatal harm to infected individuals. Should not affect gameplay mechanically.
+// THREAT_TYPE2: This symptom causes noticable, but nonfatal harm to infected individuals. Should not significantly impede gameplay.
+// THREAT_TYPE3: This symptom causes significant, but nonfatal harm to infected individuals. May damage the player or impede mechanical gameplay.
+// THREAT_TYPE4: This symptom causes severe and potentially fatal harm to infected individuals. Critting from full should take at least 5 minutes unattended. Short stuns are OK.
+// THREAT_TYPE5: This symptom is extremely dangerous and will certainly cause fatal harm to infected individuals. Anything that causes incapacitation goes HERE. Critting should take at least 3 minutes. Instant death and adjacent go here.
+
+//Examples for each:
+// BT2: ressurection, flesh restructuring, detox, teperone production?
+// BT1: mending, brewery, cleansing
+// NEUTRAL: oxytocin, sunglass, beesneeze, deathgasp
+// T1: hiccuping, shivering, sweating
+// T2: cough(nodamage), sneezing, aches(nodamage), indigestion(nodamage)
+// T3: violent cough, fever/chills, shakespearian, gasping, disorientation
+// T4: senility, fever2/chills2, organ damage in general
+// T5: radiation, necrotic detonation
+// T?: gibbing, Thor's Wrath, other dangerous joke symptoms
+
+datum/pathogeneffects/benevolent
+ name = "Benevolent"
+ rarity = RARITY_ABSTRACT
+ beneficial = 1
+
+datum/pathogeneffects/benevolent/mending
+ name = "Wound Mending"
+ desc = "Slow paced brute damage healing."
+ rarity = RARITY_COMMON
+
+ disease_act(var/mob/M as mob, var/datum/pathogen/origin)
+ if (!origin.symptomatic)
+ return
+ //if (prob(origin.stage * 5))
+ M.HealDamage("All", origin.stage / 2, 0)
+
+ react_to(var/R, var/zoom)
+ if (R == "synthflesh")
+ if (zoom)
+ return "Microscopic damage on the synthetic flesh appears to be mended by the pathogen."
+
+ may_react_to()
+ return "The pathogen appears to have the ability to bond with organic tissue."
+
+datum/pathogeneffects/benevolent/healing
+ name = "Burn Healing"
+ desc = "Slow paced burn damage healing."
+ rarity = RARITY_COMMON
+
+ disease_act(var/mob/M as mob, var/datum/pathogen/origin)
+ if (!origin.symptomatic)
+ return
+ //if (prob(origin.stage * 5))
+ M.HealDamage("All", 0, origin.stage / 2)
+
+ react_to(var/R, var/zoom)
+ if (R == "synthflesh")
+ if (zoom)
+ return "The pathogen does not appear to mend the synthetic flesh. Perhaps something that might cause other types of injuries might help."
+ if (R == "infernite")
+ if (zoom)
+ return "The pathogen repels the scalding hot chemical and quickly repairs any damage caused by it to organic tissue."
+
+ may_react_to()
+ return "The pathogen appears to have the ability to bond with organic tissue."
+
+datum/pathogeneffects/benevolent/fleshrestructuring
+ name = "Flesh Restructuring"
+ desc = "Fast paced general healing."
+ rarity = RARITY_RARE
+
+ disease_act(var/mob/M as mob, var/datum/pathogen/origin)
+ if (!origin.symptomatic)
+ return
+ if (prob(origin.stage * 5))
+ M.HealDamage("All", origin.stage, origin.stage)
+ if(ishuman(M))
+ var/mob/living/carbon/human/H = M
+ if(H.bleeding)
+ repair_bleeding_damage(M, 80, 2)
+ if (prob(50))
+ M.show_message("You feel your wounds closing by themselves.")
+
+ react_to(var/R, var/zoom)
+ if (R == "synthflesh")
+ if (zoom)
+ return "The pathogen appears to mimic the behavior of the synthflesh."
+ if (R == "acid")
+ if (zoom)
+ return "The pathogen becomes agitated and works to repair the damage caused by the sulfuric acid."
+
+ may_react_to()
+ return "The pathogen appears to be rapidly repairing the other cells around it."
+ //podrickequus's first code, yay
+
+datum/pathogeneffects/benevolent/detoxication
+ name = "Detoxication"
+ desc = "The pathogen aids the host body in metabolizing ethanol."
+ rarity = RARITY_COMMON
+
+ disease_act(var/mob/M as mob, var/datum/pathogen/origin)
+ if (!origin.symptomatic)
+ return
+ var/times = 1
+ if (origin.stage > 3)
+ times++
+ if (origin.stage > 4)
+ times++
+ var/met = 0
+ for (var/rid in M.reagents.reagent_list)
+ var/datum/reagent/R = M.reagents.reagent_list[rid]
+ if (rid == "ethanol" || istype(R, /datum/reagent/fooddrink/alcoholic))
+ met = 1
+ for (var/i = 1, i <= times, i++)
+ if (R) //Wire: Fix for Cannot execute null.on mob life().
+ R.on_mob_life()
+ if (!R || R.disposed)
+ break
+ if (R && !R.disposed)
+ M.reagents.remove_reagent(rid, R.depletion_rate * times)
+ if (met)
+ M.reagents.update_total()
+
+ react_to(var/R, var/zoom)
+ if (R == "ethanol")
+ return "The pathogen appears to have entirely metabolized the ethanol."
+
+ may_react_to()
+ return "The pathogen appears to react with a pure intoxicant."
+
+datum/pathogeneffects/benevolent/metabolisis
+ name = "Accelerated Metabolisis"
+ desc = "The pathogen accelerates the metabolisis of all chemicals present in the host body."
+ rarity = RARITY_RARE
+
+ disease_act(var/mob/M as mob, var/datum/pathogen/origin)
+ if (!origin.symptomatic)
+ return
+ var/times = 1
+ if (origin.stage > 3)
+ times++
+ if (origin.stage > 4)
+ times++
+ var/met = 0
+ for (var/rid in M.reagents.reagent_list)
+ var/datum/reagent/R = M.reagents.reagent_list[rid]
+ met = 1
+ for (var/i = 1, i <= times, i++)
+ if (R) //Wire: Fix for Cannot execute null.on mob life().
+ R.on_mob_life()
+ if (!R || R.disposed)
+ break
+ if (R && !R.disposed)
+ M.reagents.remove_reagent(rid, R.depletion_rate * times)
+ if (met)
+ M.reagents.update_total()
+
+
+ react_to(var/R, var/zoom)
+ return "The pathogen appears to have entirely metabolized... all chemical agents in the dish."
+
+ may_react_to()
+ return "The pathogen appears to be rapidly breaking down certain materials around it."
+
+datum/pathogeneffects/benevolent/cleansing
+ name = "Cleansing"
+ desc = "The pathogen cleans the body of damage caused by toxins."
+ rarity = RARITY_UNCOMMON
+
+ disease_act(var/mob/M as mob, var/datum/pathogen/origin)
+ if (!origin.symptomatic)
+ return
+ //if (prob(origin.stage * 5) && M.get_toxin_damage())
+ if (M.get_toxin_damage())
+ M.take_toxin_damage(-origin.stage / 2)
+ if (prob(12))
+ M.show_message("You feel cleansed.")
+
+ react_to(var/R, var/zoom)
+ return "The pathogen appears to have entirely metabolized... all chemical agents in the dish."
+
+ may_react_to()
+ return "The pathogen seems to be much cleaner than normal."
+
+datum/pathogeneffects/benevolent/oxygenconversion
+ name = "Oxygen Conversion"
+ desc = "The pathogen converts organic tissue into oxygen when required by the host."
+ rarity = RARITY_RARE
+
+ may_react_to()
+ return "The pathogen appears to radiate oxygen."
+
+ react_to(var/R, var/zoom)
+ if (R == "synthflesh")
+ return "The pathogen consumes the synthflesh and converts it into oxygen."
+
+ disease_act(var/mob/M as mob, var/datum/pathogen/origin)
+ if (!origin.symptomatic)
+ return
+ var/mob/living/carbon/C = M
+ if (C.get_oxygen_deprivation())
+ C.setStatus("patho_oxy_speed_bad", duration = INFINITE_STATUS, optional = origin.stage/2.5)
+
+datum/pathogeneffects/benevolent/oxygenstorage
+ name = "Oxygen Storage"
+ desc = "The pathogen stores oxygen and releases it when needed by the host."
+ rarity = RARITY_RARE
+
+ may_react_to()
+ return "The pathogen appears to have a bubble of oxygen around it."
+
+ disease_act(var/mob/M as mob, var/datum/pathogen/origin)
+ if (!origin.symptomatic)
+ return
+ if(!origin.symptom_data["oxygen_storage"]) // if not yet set, initialize
+ origin.symptom_data["oxygen_storage"] = 0
+
+ var/mob/living/carbon/C = M
+ if (C.get_oxygen_deprivation())
+ if(origin.symptom_data["oxygen_storage"] > 10)
+ C.setStatus("patho_oxy_speed", duration = INFINITE_STATUS, optional = origin.symptom_data["oxygen_storage"])
+ origin.symptom_data["oxygen_storage"] = 0
+ else
+ // faster reserve replenishment at higher stages
+ origin.symptom_data["oxygen_storage"] = min(100, origin.symptom_data["oxygen_storage"] + origin.stage*2)
+
+
+datum/pathogeneffects/benevolent/resurrection
+ name = "Necrotic Resurrection"
+ desc = "The pathogen will resurrect you if it procs while you are dead."
+ rarity = RARITY_VERY_RARE
+ var/cooldown = 20 MINUTES
+
+ may_react_to()
+ return "Some of the pathogen's dead cells seem to remain active."
+
+ disease_act_dead(var/mob/M as mob, var/datum/pathogen/origin)
+ if (!origin.symptomatic)
+ return
+ if (origin.stage < 3)
+ return
+ if(!origin.symptom_data["resurrect_cd"]) // if not yet set, initialize it so that it is off cooldown
+ origin.symptom_data["resurrect_cd"] = -cooldown
+ if(TIME-origin.symptom_data["resurrect_cd"] < cooldown)
+ return
+ // Shamelessly stolen from Strange Reagent
+ if (isdead(M) || istype(get_area(M),/area/afterlife/bar))
+ origin.symptom_data["resurrect_cd"] = TIME
+ // range from 65 to 45. This is applied to both brute and burn, so the total max damage after resurrection is 130 to 90.
+ var/cap = 95 - origin.stage * 10
+ var/brute = min(cap, M.get_brute_damage())
+ var/burn = min(cap, M.get_burn_damage())
+
+ // let's heal them before we put some of the damage back
+ // but they don't get back organs/limbs/whatever, so I don't use full_heal
+ M.HealDamage("All", 100000, 100000)
+ if(ishuman(M))
+ var/mob/living/carbon/human/H = M
+ H.blood_volume = 500 // let's not have people immediately suffocate from being exsanguinated
+ H.take_toxin_damage(-INFINITY)
+ H.take_oxygen_deprivation(-INFINITY)
+ H.take_brain_damage(-INFINITY)
+
+ M.TakeDamage("chest", brute, burn)
+ M.take_brain_damage(70) // and a lot of brain damage
+ setalive(M)
+ M.changeStatus("paralysis", 15 SECONDS) // paralyze the person for a while, because coming back to life is hard work
+ M.change_misstep_chance(40) // even after getting up they still have some grogginess for a while
+ M.stuttering = 15
+ if (M.ghost && M.ghost.mind && !(M.mind && M.mind.dnr)) // if they have dnr set don't bother shoving them back in their body
+ M.ghost.show_text("You feel yourself being dragged out of the afterlife!")
+ M.ghost.mind.transfer_to(M)
+ qdel(M.ghost)
+ if (ishuman(M))
+ var/mob/living/carbon/human/H = M
+ H.contract_disease(/datum/ailment/disease/tissue_necrosis, null, null, 1) // this disease will make the person more and more rotten even while alive
+ H.visible_message("[H] suddenly starts moving again!","You feel the pathogen weakening as you rise from the dead.")
+
+ react_to(var/R, var/zoom)
+ if (R == "synthflesh")
+ return "Dead parts of the synthflesh seem to still be transferring blood."
+
+
+datum/pathogeneffects/benevolent/brewery
+ name = "Auto-Brewery"
+ desc = "The pathogen aids the host body in metabolizing chemicals into ethanol."
+ rarity = RARITY_RARE
+ beneficial = 0
+
+ disease_act(var/mob/M as mob, var/datum/pathogen/origin)
+ if (!origin.symptomatic)
+ return
+ var/times = 1
+ if (origin.stage > 3)
+ times++
+ if (origin.stage > 4)
+ times++
+ var/met = 0
+ for (var/rid in M.reagents.reagent_list)
+ var/datum/reagent/R = M.reagents.reagent_list[rid]
+ if (!(rid == "ethanol" || istype(R, /datum/reagent/fooddrink/alcoholic)))
+ met = 1
+ for (var/i = 1, i <= times, i++)
+ if (R) //Wire: Fix for Cannot execute null.on mob life().
+ R.on_mob_life()
+ if (!R || R.disposed)
+ break
+ if (R && !R.disposed)
+ var/amt = R.depletion_rate * times
+ M.reagents.remove_reagent(rid, amt)
+ M.reagents.add_reagent("ethanol", amt)
+ if (met)
+ M.reagents.update_total()
+
+ react_to(var/R, var/zoom)
+ if (!(R == "ethanol"))
+ return "The pathogen appears to have entirely metabolized all chemical agents in the dish into... ethanol."
+
+ may_react_to()
+ return "The pathogen appears to react with anything but a pure intoxicant."
+
+datum/pathogeneffects/benevolent/oxytocinproduction
+ name = "Oxytocin Production"
+ desc = "The pathogen produces Pure Love within the infected."
+ infect_type = INFECT_TOUCH
+ rarity = RARITY_COMMON
+ spread = SPREAD_BODY | SPREAD_HANDS
+ infect_message = "You can't help but feel loved."
+ infect_attempt_message = "Their touch is suspiciously soft..."
+
+ onemote(mob/M as mob, act, voluntary, param, datum/pathogen/origin)
+ if (!origin.symptomatic)
+ return
+ if (act != "hug" && act != "sidehug") // not a hug
+ return
+ if (param == null) // weirdo is just hugging themselves
+ return
+ for (var/mob/living/carbon/human/H in view(1, M))
+ if (ckey(param) == ckey(H.name) && prob(origin.spread*2))
+ SPAWN(0.5)
+ infect_direct(H, origin, "hug")
+ return
+
+ disease_act(var/mob/M as mob, var/datum/pathogen/origin)
+ if (!origin.symptomatic)
+ return
+ var/check_amount = M.reagents.get_reagent_amount("love")
+ if (!check_amount || check_amount < 5)
+ M.reagents.add_reagent("love", origin.stage / 3)
+
+ may_react_to()
+ return "The pathogen's cells appear to be... hugging each other?"
+
+datum/pathogeneffects/benevolent/neuronrestoration
+ name = "Neuron Restoration"
+ desc = "Infection slowly repairs nerve cells in the brain."
+ rarity = RARITY_UNCOMMON
+ infect_type = INFECT_NONE
+ disease_act(var/mob/M as mob, var/datum/pathogen/origin)
+ if (!origin.symptomatic)
+ return
+ switch (origin.stage)
+ if (2)
+ if (prob(5))
+ M.take_brain_damage(-1)
+ if (3)
+ if (prob(10))
+ M.take_brain_damage(-1)
+ if (4)
+ if (prob(15))
+ M.take_brain_damage(-2)
+ if (5)
+ if (prob(20))
+ M.take_brain_damage(-2)
+
+ react_to(var/R, var/zoom)
+ if (!(R == "neurotoxin"))
+ return "The pathogen releases a chemical in an attempt to counteract the effects of the neurotoxin."
+
+ may_react_to()
+ return "The pathogen appears to have a gland that may affect neural functions."
+
+datum/pathogeneffects/benevolent/sunglass
+ name = "Sunglass Glands"
+ desc = "The infected grew sunglass glands."
+ infect_type = INFECT_NONE
+ rarity = RARITY_UNCOMMON
+
+ proc/glasses(var/mob/living/carbon/human/M as mob)
+ var/obj/item/clothing/glasses/G = M.glasses
+ var/obj/item/clothing/glasses/N = new/obj/item/clothing/glasses/sunglasses()
+ M.show_message({"[pick("You feel cooler!", "You find yourself wearing sunglasses.", "A pair of sunglasses grow onto your face.")][G?" But you were already wearing glasses!":""]"})
+ if (G)
+ N.set_loc(M.loc)
+ var/turf/T = get_edge_target_turf(M, pick(alldirs))
+ N.throw_at(T,rand(0,5),1)
+ else
+ N.set_loc(M)
+ N.layer = M.layer
+ N.master = M
+ M.glasses = N
+ M.update_clothing()
+
+ disease_act(var/mob/M as mob, var/datum/pathogen/origin)
+ if (!origin.symptomatic)
+ return
+ if (ishuman(M))
+ var/mob/living/carbon/human/H = M
+ if (!(H.glasses) || (!(istype(H.glasses, /obj/item/clothing/glasses/sunglasses)) && prob(50)))
+ switch(origin.stage)
+ if (2 to 4)
+ if (prob(15))
+ glasses(M)
+ if (5)
+ if (prob(25))
+ glasses(M)
+
+ may_react_to()
+ return "The pathogen appears to be sensitive to sudden flashes of light."
+
+ react_to(var/R, var/zoom)
+ if (R == "flashpowder")
+ if (zoom)
+ return "The individual microbodies appear to be wearing sunglasses."
+ else
+ return "The pathogen appears to have developed a resistance to the flash powder."
+
+datum/pathogeneffects/benevolent/genetictemplate
+ name = "Genetic Template"
+ desc = "Spreads a mutation from patient zero to other afflicted."
+ rarity = RARITY_VERY_RARE
+ infect_type = INFECT_NONE
+ var/list/mutationMap = list() // stores the kind of mutation with the index being the pathogen's name (which is something like "L41D9")
+
+ disease_act(var/mob/M as mob, var/datum/pathogen/origin)
+ if (!origin.symptomatic || !M.bioHolder)
+ return
+ if(mutationMap[origin.name_base] == null) // if no mutation has been picked yet, go for a random one from this person
+ var/list/filtered = new/list()
+ for(var/T in M.bioHolder.effects)
+ var/datum/bioEffect/instance = M.bioHolder.effects[T]
+ if(!instance || istype(instance, /datum/bioEffect/hidden)) continue // hopefully this catches all non-mutation bioeffects?
+ filtered.Add(instance)
+ if(!filtered.len) return // wow, this nerd has no mutations, screw this
+ mutationMap[origin.name_base] = pick(filtered)
+ boutput(M, "You somehow feel more attuned to your [mutationMap[origin.name_base]].") // So patient zero will know when the mutation has been chosen
+
+ if(origin.symptom_data["genetictemplate"] == origin.stage) // early return if we would just put the same mutation anyway
+ return
+
+ var/datum/bioEffect/BEE = mutationMap[origin.name_base] // remove old version of mutation
+ M.bioHolder.RemoveEffect(BEE.id)
+
+ var/datum/bioEffect/BE = BEE.GetCopy()
+ var/datum/dna_chromosome/chromo = new /datum/dna_chromosome/anti_mutadone() // reinforce always
+ chromo.apply(BE)
+ if (origin.stage >= 2)
+ BE.altered = 0 // this lets us apply another chromosome. yay!
+ chromo = new /datum/dna_chromosome() // stabilize after stage 2
+ chromo.apply(BE)
+ if (origin.stage >= 3)
+ BE.altered = 0
+ chromo = new /datum/dna_chromosome/safety() // synchronize starting at stage 3
+ chromo.apply(BE)
+ if (origin.stage >= 4)
+ BE.altered = 0
+ chromo = new /datum/dna_chromosome/power_enhancer() // empower starting at stage 4
+ chromo.apply(BE)
+ if (origin.stage >= 5)
+ BE.altered = 0
+ chromo = new /datum/dna_chromosome/cooldown_reducer() // reduce cooldown starting at stage 5
+ chromo.apply(BE)
+ M.bioHolder.AddEffectInstance(BE) // add updated version of mutation!
+ origin.symptom_data["genetictemplate"] = origin.stage // save the last stage that we added the mutation with
+
+ oncured(mob/M as mob, var/datum/pathogen/origin)
+ if (!origin.symptomatic)
+ return
+ var/datum/bioEffect/BE = mutationMap[origin.name_base] // cure the mutation when the pathogen is cured
+ M.bioHolder.RemoveEffect(BE.id)
+
+ react_to(var/R, var/zoom)
+ if (R == "mutadone")
+ if (zoom)
+ return "Approximately 0% of the individual microbodies appear to have returned to genetic normalcy." // it always reinforces
+
+ may_react_to()
+ return "The pathogen cells all look exactly alike."
+
+
datum/pathogeneffects/malevolent
name = "Malevolent"
rarity = RARITY_ABSTRACT
diff --git a/code/modules/medical/pathology/pathogen_transmission.dm b/code/modules/medical/pathology/pathogen_transmission.dm
new file mode 100644
index 0000000000000..e7436d74360da
--- /dev/null
+++ b/code/modules/medical/pathology/pathogen_transmission.dm
@@ -0,0 +1,158 @@
+datum/pathogeneffects
+ var/name
+ var/desc
+ var/infect_type = 0
+
+ var/spread = SPREAD_FACE | SPREAD_BODY | SPREAD_HANDS | SPREAD_AIR
+
+ var/rarity = RARITY_ABSTRACT
+ var/infect_message = null
+ var/infect_attempt_message = null // shown to person when an attempt to directly infect them is made
+
+ var/beneficial = 0
+
+ // This is a list of mutual exclusive symptom TYPES.
+ // If this contains any symptoms, none of these symptoms will be picked upon mutation or initial raffle.
+ // Mutexes cut the ENTIRE object tree - for example, if symptoms a/b, a/c and a/d all exist, then mutexing
+ // symptom a will also mutex b, c and d.
+ var/list/mutex = list()
+
+ // A symptom might not always infect everyone around. This is a flat probability: 0 means never infect to 1 means always infect. This is checked PER MOB, not per infect call.
+ var/infection_coefficient = 1
+
+ // disease_act(mob, datum/pathogen) : void
+ // This is the center of pathogen symptoms.
+ // On every Life() tick, this will be called for every symptom attached to the pathogen. Most pathogens should express their malevolence here, unless they are specifically tailored
+ // to only work on events like human interaction or external effects. A symptom therefore should override this proc.
+ // disease_act is also responsible for handling the symptom's ability to suppress the pathogen. Check the documentation on suppression in pathogen.dm.
+ // OVERRIDE: A subclass (direct or otherwise) is expected to override this.
+ proc/disease_act(var/mob/M as mob, var/datum/pathogen/origin)
+
+ // disease_act_dead(mob, datum/pathogen) : void
+ // This functions identically to disease_act, except it is only called when the mob is dead. (disease_act is not called if that is the case.)
+ // OVERRIDE: Only override this if if it needed for the symptom.
+ proc/disease_act_dead(var/mob/M as mob, var/datum/pathogen/origin)
+
+ // does an infectious snap
+ // makes others snap, should possibly infect you in the future if you are made to snap a certain amount of times
+ proc/infect_snap(var/mob/M as mob, var/datum/pathogen/origin, var/range = 5)
+ for (var/mob/I in view(range, M.loc))
+ if (I != M && ((isturf(I.loc) && isturf(M.loc) && can_line_airborne(get_turf(M), I, 5)) || I.loc == M.loc))
+ if(istype(M, /mob/living/carbon/human))
+ var/mob/living/carbon/human/H = I
+ if(prob(100-H.get_disease_protection()))
+ SPAWN(rand(0.5,2) SECONDS)
+ H.show_message("Pretty catchy tune...")
+ H.emote("snap") // consider yourself lucky I haven't implemented snap infection yet, human
+
+ // creates an infective cloud
+ // this should give people better feedback about how be infected and how to avoid it
+ proc/infect_cloud(var/mob/M as mob, var/datum/pathogen/origin, var/amount = 5)
+ var/turf/T = get_turf(M)
+ var/obj/decal/cleanable/pathogen_cloud/D = make_cleanable(/obj/decal/cleanable/pathogen_cloud,T)
+
+ var/datum/reagent/blood/pathogen/Q = new /datum/reagent/blood/pathogen()
+ D.reagents = new /datum/reagents(amount)
+ Q.volume = amount
+ Q.pathogens += origin.pathogen_uid
+ Q.pathogens[origin.pathogen_uid] = origin
+ D.reagents.reagent_list += "pathogen"
+ D.reagents.reagent_list["pathogen"] = Q
+ Q.holder = D.reagents
+ D.reagents.update_total()
+
+ // creates an infective puddle
+ // this should give people better feedback about how be infected and how to avoid it
+ proc/infect_puddle(var/mob/M as mob, var/datum/pathogen/origin, var/amount = 5)
+ var/turf/T = get_turf(M)
+ var/obj/decal/cleanable/pathogen_sweat/D = make_cleanable(/obj/decal/cleanable/pathogen_sweat,T)
+
+ var/datum/reagent/blood/pathogen/Q = new /datum/reagent/blood/pathogen()
+ D.reagents = new /datum/reagents(amount)
+ Q.volume = amount
+ Q.pathogens += origin.pathogen_uid
+ Q.pathogens[origin.pathogen_uid] = origin
+ D.reagents.reagent_list += "pathogen"
+ D.reagents.reagent_list["pathogen"] = Q
+ Q.holder = D.reagents
+ D.reagents.update_total()
+
+ // infect_direct(mob, datum/pathogen) : void
+ // This is the proc that handles direct transmission of the pathogen from one mob to another. This should be called in particular infection scenarios. For example, a sweating person
+ // gets his bodily fluids onto another when they directly disarm, punch, or grab a person.
+ // For INFECT_TOUCH diseases this is automatically called on a successful disarm, punch or grab. When overriding any of these events, use ..() to keep this behaviour.
+ // OVERRIDE: Generally, you do not need to override this.
+ proc/infect_direct(var/mob/target as mob, var/datum/pathogen/origin, contact_type = "touch")
+ if (infect_attempt_message)
+ target.show_message("[infect_attempt_message]")
+ if(istype(target, /mob/living/carbon/human))
+ var/mob/living/carbon/human/H = target
+ if(prob(100-H.get_disease_protection()))
+ if (target.infected(origin))
+ if (infect_message)
+ target.show_message(infect_message)
+ logTheThing("pathology", origin.infected, target, "infects [constructTarget(target,"pathology")] with [origin.name] due to symptom [name] through direct contact ([contact_type]).")
+ return 1
+
+ proc/onadd(var/datum/pathogen/origin)
+ return
+
+ // ====
+ // Events from this point on. Their exact behaviour is documented in pathogen.dm. Please do not add any event definitions outside this block.
+ // ondisarm(mob, mob, boolean, datum/pathogen) : float
+ // OVERRIDE: Overriding this is situational. ..() is expected to be called.
+ proc/ondisarm(var/mob/M as mob, var/mob/V as mob, isPushDown, var/datum/pathogen/origin)
+ if (infect_type == INFECT_TOUCH && prob(origin.spread*2))
+ infect_direct(V, origin, "disarm")
+ return 1
+
+ // ongrab(mob, mob, datum/pathogen) : void
+ // TODO: Make this a veto event.
+ // OVERRIDE: Overriding this is situational. ..() is expected to be called.
+ proc/ongrab(var/mob/M as mob, var/mob/V as mob, var/datum/pathogen/origin)
+ if (infect_type == INFECT_TOUCH && prob(origin.spread*2))
+ infect_direct(V, origin, "grab")
+ return
+
+ // onpunch(mob, mob, string, datum/pathogen) : float
+ // OVERRIDE: Overriding this is situational. ..() is expected to be called.
+ proc/onpunch(var/mob/M as mob, var/mob/V as mob, zone, var/datum/pathogen/origin)
+ if (infect_type == INFECT_TOUCH && prob(origin.spread*2))
+ infect_direct(V, origin, "punching")
+ return 1
+
+ // onpunched(mob, mob, string, datum/pathogen) : float
+ // OVERRIDE: Overriding this is situational. ..() is expected to be called.
+ proc/onpunched(var/mob/M as mob, var/mob/A as mob, zone, var/datum/pathogen/origin)
+ if (infect_type == INFECT_TOUCH && prob(origin.spread*2))
+ infect_direct(A, origin, "being punched")
+ return 1
+
+ // onshocked(mob, mob, datum/shockparam, datum/pathogen) : datum/shockparam
+ // OVERRIDE: Overriding this is situational.
+ proc/onshocked(var/mob/M as mob, var/datum/shockparam/ret, var/datum/pathogen/origin)
+ return ret
+
+ // onsay(mob, string, datum/pathogen) : string
+ // OVERRIDE: Overriding this is situational.
+ proc/onsay(var/mob/M as mob, message, var/datum/pathogen/origin)
+ return message
+
+ // onemote(mob, string, number, string, datum/pathogen) : string
+ // OVERRIDE: Overriding this is situational.
+ proc/onemote(var/mob/M as mob, act, voluntary, param, var/datum/pathogen/P)
+ return 1
+
+ // ondeath(mob, datum/pathogen) : void
+ // OVERRIDE: Overriding this is situational.
+ proc/ondeath(var/mob/M as mob, var/datum/pathogen/origin)
+ return
+
+ // oncured(mob, datum/pathogen) : void
+ // OVERRIDE: Overriding this is situational.
+ proc/oncured(var/mob/M as mob, var/datum/pathogen/origin)
+ return
+
+
+ // End of events: please do not add any event definitions outside this block.
+ // ====
diff --git a/goonstation.dme b/goonstation.dme
index 387fc7e33d260..a18b95e437274 100644
--- a/goonstation.dme
+++ b/goonstation.dme
@@ -1016,7 +1016,6 @@ var/datum/preMapLoad/preMapLoad = new
#include "code\modules\medical\pathology\_pathogen_constants.dm"
#include "code\modules\medical\pathology\pathogen.dm"
#include "code\modules\medical\pathology\pathogen_ailments.dm"
-#include "code\modules\medical\pathology\pathogen_benevolent.dm"
#include "code\modules\medical\pathology\pathogen_dna.dm"
#include "code\modules\medical\pathology\pathogen_helpers.dm"
#include "code\modules\medical\pathology\pathogen_machines.dm"
@@ -1024,6 +1023,7 @@ var/datum/preMapLoad/preMapLoad = new
#include "code\modules\medical\pathology\pathogen_suppressants.dm"
#include "code\modules\medical\pathology\pathogen_symptoms.dm"
#include "code\modules\medical\pathology\pathogen_tools.dm"
+#include "code\modules\medical\pathology\pathogen_transmission.dm"
#include "code\modules\mining\mining_encounters.dm"
#include "code\modules\mining\ore.dm"
#include "code\modules\mining\tile_events.dm"