diff --git a/code/datums/diseases/_MobProcs.dm b/code/datums/diseases/_MobProcs.dm index 1c4f1ac2d17..7859cf1a82a 100644 --- a/code/datums/diseases/_MobProcs.dm +++ b/code/datums/diseases/_MobProcs.dm @@ -84,14 +84,7 @@ if(nutrition > 300 && prob(nutrition/50)) return - var/list/zone_weights = list( - 1 = head_ch, - 2 = body_ch, - 3 = hands_ch, - 4 = feet_ch - ) - - var/target_zone = pick(zone_weights) + var/target_zone = pick(head_ch;1,body_ch;2,hands_ch;3,feet_ch;4) if(ishuman(src)) var/mob/living/carbon/human/H = src diff --git a/code/datums/diseases/_disease.dm b/code/datums/diseases/_disease.dm index b596f4dcbe6..4d0bae88181 100644 --- a/code/datums/diseases/_disease.dm +++ b/code/datums/diseases/_disease.dm @@ -191,8 +191,14 @@ GLOBAL_LIST_INIT(diseases, subtypesof(/datum/disease)) /datum/disease/proc/remove_virus() affected_mob.viruses -= src +// Called when a disease is added onto a mob /datum/disease/proc/Start() return +// Called when a disease is removed from a mob /datum/disease/proc/End() return + +// Called when the mob dies +/datum/disease/proc/OnDeath() + return diff --git a/code/datums/diseases/advance/disease_preset.dm b/code/datums/diseases/advance/disease_preset.dm index d30bbf2ebb5..b253db77a56 100644 --- a/code/datums/diseases/advance/disease_preset.dm +++ b/code/datums/diseases/advance/disease_preset.dm @@ -1,3 +1,49 @@ +/datum/disease/advance/random + name = "Experimental Disease" + var/randomname = TRUE + var/datum/symptom/setsymptom = null + var/max_symptoms_override + +/datum/disease/advance/random/minor + name = "Minor Experimental Disease" + max_symptoms_override = 4 + +/datum/disease/advance/random/New(max_symptoms, max_level = 6, min_level = 1, list/guaranteed_symptoms = setsymptom) + if(!max_symptoms) + max_symptoms = (2 + rand(1, (VIRUS_SYMPTOM_LIMIT - 2))) + if(max_symptoms_override) + max_symptoms = (max_symptoms_override - rand(0, 2)) + if(guaranteed_symptoms) + if(islist(guaranteed_symptoms)) + max_symptoms -= length(guaranteed_symptoms) + else + guaranteed_symptoms = list(guaranteed_symptoms) + max_symptoms -= 1 + + var/list/datum/symptom/possible_symptoms = list() + for(var/datum/symptom/symptom as anything in subtypesof(/datum/symptom)) + if(symptom in guaranteed_symptoms) + continue + if(initial(symptom.level) > max_level || initial(symptom.level) < min_level) + continue + if(initial(symptom.level) <= -1) + continue + possible_symptoms += symptom + for(var/i in 1 to max_symptoms) + var/datum/symptom/chosen_symptom = pick_n_take(possible_symptoms) + if(chosen_symptom) + symptoms += new chosen_symptom + for(var/guaranteed_symptom in guaranteed_symptoms) + symptoms += new guaranteed_symptom + +/datum/disease/advance/random/macrophage + name = "Unknown Disease" + setsymptom = /datum/symptom/macrophage + +/datum/disease/advance/random/blob + name = "Blob Spores" + setsymptom = /datum/symptom/blobspores + // Cold /datum/disease/advance/cold/New(process = 1, datum/disease/advance/D, copy = 0) @@ -14,3 +60,19 @@ name = "Flu" symptoms = list(new /datum/symptom/cough) ..(process, D, copy) + +// Macrophages + +/datum/disease/advance/macrophage/New(process = 1, datum/disease/advance/D, copy = 0) + if(!D) + name = "Macrophages" + symptoms = list(new /datum/symptom/macrophage) + ..(process, D, copy) + +// Blob Spores + +/datum/disease/advance/blobspores/New(process = 1, datum/disease/advance/D, copy = 0) + if(!D) + name = "Blob Spores" + symptoms = list(new /datum/symptom/blobspores) + ..(process, D, copy) diff --git a/code/datums/diseases/advance/symptoms/blobspores.dm b/code/datums/diseases/advance/symptoms/blobspores.dm new file mode 100644 index 00000000000..8c8ef33d620 --- /dev/null +++ b/code/datums/diseases/advance/symptoms/blobspores.dm @@ -0,0 +1,93 @@ +/* +////////////////////////////////////// +Blob Spores + + Slightly hidden + Major Increases to resistance. + Reduces stage speed. + Slight boost to transmission + Admin Level. + +BONUS + The host coughs up blob spores + +////////////////////////////////////// +*/ +/datum/symptom/blobspores + name = "Blob Spores" + stealth = 1 + resistance = 5 + stage_speed = -2 + transmittable = 1 + level = -1 + severity = 3 + + var/ready_to_pop + var/factory_blob + var/strong_blob + var/node_blob + +/datum/symptom/blobspores/Start(datum/disease/advance/A) + if(!..()) + return + + if(A.totalResistance() >= 8) + factory_blob = TRUE + if(A.totalResistance() >= 5) + strong_blob = TRUE + if(A.totalResistance() >= 10) + node_blob = TRUE + +/datum/symptom/blobspores/Activate(datum/disease/advance/A) + if(!..()) + return + var/mob/living/M = A.affected_mob + + switch(A.stage) + if(1) + if(prob(2)) + to_chat(M, span_notice("You feel bloated.")) + + if(prob(3) && !M.jitteriness) + to_chat(M, span_notice("You feel a bit jittery.")) + M.jitteriness = 10 + + if(2) + if(prob(1) && ishuman(M)) + var/mob/living/carbon/human/H = M + H.vomit(TRUE, FALSE) + if(3, 4) + if(prob(10)) + to_chat(M, span_notice("You feel blobby?")) + + if(5) + ready_to_pop = TRUE + if(prob(5)) + M.audible_emote("coughs up a small amount of blood!") + if(ishuman(M)) + var/mob/living/carbon/human/H = M + var/bleeding_rng = rand(1, 2) + H.drip(bleeding_rng) + +/datum/symptom/blobspores/OnDeath(datum/disease/advance/A) + var/mob/living/M = A.affected_mob + M.visible_message(span_danger("[M] starts swelling grotesquely!")) + addtimer(CALLBACK(src, PROC_REF(pop), A, M), 10 SECONDS) + +/datum/symptom/blobspores/proc/pop(datum/disease/advance/A, mob/living/M) + if(!A || !M) + return + var/list/blob_options = list(/obj/structure/blob/normal) + if(factory_blob) + blob_options += /obj/structure/blob/factory + if(strong_blob) + blob_options += /obj/structure/blob/shield + if(node_blob) + blob_options += /obj/structure/blob/node + var/pick_blob = pick(blob_options) + if(ready_to_pop) + for(var/i in 1 to rand(1, 6)) + new /mob/living/simple_mob/blob/spore(M.loc) + new pick_blob(M.loc) + + M.visible_message(span_danger("A huge mass of blob and blob spores burst out of [M]!")) diff --git a/code/datums/diseases/advance/symptoms/shivering.dm b/code/datums/diseases/advance/symptoms/shivering.dm index f4a3059d7c9..efe4b39f17e 100644 --- a/code/datums/diseases/advance/symptoms/shivering.dm +++ b/code/datums/diseases/advance/symptoms/shivering.dm @@ -27,10 +27,10 @@ Bonus /datum/symptom/shivering/Activate(datum/disease/advance/A) ..() if(prob(SYMPTOM_ACTIVATION_PROB)) - var/mob/living/carbon/M = A.affected_mob - to_chat(M, span_warning(pick("You feel cold.", "You start shivering."))) - if(M.bodytemperature > BODYTEMP_COLD_DAMAGE_LIMIT) - Chill(M, A) + var/mob/living/L = A.affected_mob + to_chat(L, span_warning(pick("You feel cold.", "You start shivering."))) + if(L.bodytemperature > BODYTEMP_COLD_DAMAGE_LIMIT) + Chill(L, A) return /datum/symptom/shivering/proc/Chill(mob/living/M, datum/disease/advance/A) diff --git a/code/datums/diseases/advance/symptoms/sneeze.dm b/code/datums/diseases/advance/symptoms/sneeze.dm index d2f203bba1b..571af4c6b19 100644 --- a/code/datums/diseases/advance/symptoms/sneeze.dm +++ b/code/datums/diseases/advance/symptoms/sneeze.dm @@ -87,34 +87,33 @@ Bonus return -/datum/symptom/sneeze/bluespace/proc/SneezeTeleport(datum/disease/advance/A, var/mob/living/M) +/datum/symptom/sneeze/bluespace/proc/SneezeTeleport(datum/disease/advance/A, var/mob/living/mob) var/list/destination = list() - var/mob/living/carbon/human/H = M var/place - for(var/mob/living/carbon/human/B in range(A.stage, M)) - if(B.can_be_drop_pred && H.can_be_drop_prey && H.devourable) + for(var/mob/living/carbon/human/B in range(A.stage, mob)) + if(B.can_be_drop_pred && mob.can_be_drop_prey && mob.devourable) destination += B.vore_selected - for(var/turf/T in range(A.stage, H)) + for(var/turf/T in range(A.stage, mob)) if(istype(T, /turf/space)) // No danger, this is just a fun/vore symptom continue destination += T if(isemptylist(destination)) - to_chat(H, span_warning("You go to sneeze, but can't.")) + to_chat(mob, span_warning("You go to sneeze, but can't.")) return FALSE place = safepick(destination) - var/mob/living/carbon/human/unlucky = locate() in place + var/mob/living/unlucky = locate() in place if(unlucky) - if(unlucky.can_be_drop_pred && H.can_be_drop_prey && H.devourable) + if(unlucky.can_be_drop_pred && mob.can_be_drop_prey && mob.devourable) place = unlucky.vore_selected - else if(unlucky.devourable && unlucky.can_be_drop_prey && H.can_be_drop_pred) - unlucky.forceMove(H.vore_selected) + else if(unlucky.devourable && unlucky.can_be_drop_prey && mob.can_be_drop_pred) + unlucky.forceMove(mob.vore_selected) - H.emote("sneeze") - do_teleport(H, place) + mob.emote("sneeze") + do_teleport(mob, place) return TRUE diff --git a/code/datums/diseases/advance/symptoms/symptoms.dm b/code/datums/diseases/advance/symptoms/symptoms.dm index 90b39fab3bd..df5954f97b7 100644 --- a/code/datums/diseases/advance/symptoms/symptoms.dm +++ b/code/datums/diseases/advance/symptoms/symptoms.dm @@ -32,5 +32,10 @@ GLOBAL_LIST_INIT(list_symptoms, subtypesof(/datum/symptom)) /datum/symptom/proc/End(datum/disease/advance/A) return +// Called when the disease activates. It's what makes your diseases work! /datum/symptom/proc/Activate(datum/disease/advance/A) return + +// Called when the host dies +/datum/symptom/proc/OnDeath(datum/disease/advance/A) + return diff --git a/code/datums/diseases/advance/symptoms/telepathy.dm b/code/datums/diseases/advance/symptoms/telepathy.dm index dd3424b7c69..10a42cc6ad9 100644 --- a/code/datums/diseases/advance/symptoms/telepathy.dm +++ b/code/datums/diseases/advance/symptoms/telepathy.dm @@ -25,13 +25,15 @@ Bonus severity = 0 /datum/symptom/telepathy/Start(datum/disease/advance/A) - var/mob/living/carbon/human/H = A.affected_mob - H.dna.SetSEState(REMOTETALKBLOCK, 1) - domutcheck(H, null, TRUE) - to_chat(H, span_notice("Your mind expands...")) + if(iscarbon(A)) + var/mob/living/carbon/human/H = A.affected_mob + H.dna.SetSEState(REMOTETALKBLOCK, 1) + domutcheck(H, null, TRUE) + to_chat(H, span_notice("Your mind expands...")) /datum/symptom/telepathy/End(datum/disease/advance/A) - var/mob/living/carbon/human/H = A.affected_mob - H.dna.SetSEState(REMOTETALKBLOCK, 0) - domutcheck(H, null, TRUE) - to_chat(H, span_notice("Everything feels... Normal.")) + if(iscarbon(A)) + var/mob/living/carbon/human/H = A.affected_mob + H.dna.SetSEState(REMOTETALKBLOCK, 0) + domutcheck(H, null, TRUE) + to_chat(H, span_notice("Everything feels... Normal.")) diff --git a/code/datums/diseases/advance/symptoms/vision.dm b/code/datums/diseases/advance/symptoms/vision.dm index d74b0c6a5dc..2710124db43 100644 --- a/code/datums/diseases/advance/symptoms/vision.dm +++ b/code/datums/diseases/advance/symptoms/vision.dm @@ -27,24 +27,25 @@ Bonus /datum/symptom/visionloss/Activate(datum/disease/advance/A) ..() if(prob(SYMPTOM_ACTIVATION_PROB)) - var/mob/living/carbon/M = A.affected_mob - var/obj/item/organ/internal/eyes/eyes = M.internal_organs_by_name[O_EYES] - if(!eyes) - return - switch(A.stage) - if(1, 2) - to_chat(M, span_warning("Your eyes itch.")) - if(3, 4) - to_chat(M, span_boldwarning("Your eyes burn!")) - M.eye_blurry = 20 - eyes.take_damage(1) - else - to_chat(M, span_userdanger("Your eyes burn horrificly!")) - M.eye_blurry = 40 - eyes.take_damage(5) - if(eyes.damage >= 10) - M.disabilities |= NEARSIGHTED - if(prob(eyes.damage - 10 + 1)) - if(!M.eye_blind) - to_chat(M, span_userdanger("You go blind!")) - M.Blind(20) + if(iscarbon(A)) + var/mob/living/carbon/M = A.affected_mob + var/obj/item/organ/internal/eyes/eyes = M.internal_organs_by_name[O_EYES] + if(!eyes) + return + switch(A.stage) + if(1, 2) + to_chat(M, span_warning("Your eyes itch.")) + if(3, 4) + to_chat(M, span_boldwarning("Your eyes burn!")) + M.eye_blurry = 20 + eyes.take_damage(1) + else + to_chat(M, span_userdanger("Your eyes burn horrificly!")) + M.eye_blurry = 40 + eyes.take_damage(5) + if(eyes.damage >= 10) + M.disabilities |= NEARSIGHTED + if(prob(eyes.damage - 10 + 1)) + if(!M.eye_blind) + to_chat(M, span_userdanger("You go blind!")) + M.Blind(20) diff --git a/code/datums/diseases/fake_gbs.dm b/code/datums/diseases/fake_gbs.dm index a7831689d1d..4ab932e8cde 100644 --- a/code/datums/diseases/fake_gbs.dm +++ b/code/datums/diseases/fake_gbs.dm @@ -23,7 +23,7 @@ else if(prob(5)) affected_mob.emote("gasp") if(prob(10)) - to_chat(span_danger("You're starting to feel very weak...")) + to_chat(affected_mob, span_danger("You're starting to feel very weak...")) if(4) if(prob(10)) affected_mob.emote("cough") diff --git a/code/game/machinery/pandemic.dm b/code/game/machinery/pandemic.dm index e74e62b47d4..c13fed32102 100644 --- a/code/game/machinery/pandemic.dm +++ b/code/game/machinery/pandemic.dm @@ -379,7 +379,7 @@ if(I.has_tool_quality(TOOL_SCREWDRIVER)) eject_beaker() return - if(istype(I, /obj/item/reagent_containers/glass) && I.is_open_container()) + if(istype(I, /obj/item/reagent_containers/glass) && I.is_open_container() || istype(I, /obj/item/reagent_containers/syringe)) if(stat & (NOPOWER|BROKEN)) return if(beaker) diff --git a/code/modules/mob/death.dm b/code/modules/mob/death.dm index 41e1c7824fb..04faa5b8d96 100644 --- a/code/modules/mob/death.dm +++ b/code/modules/mob/death.dm @@ -94,6 +94,16 @@ drop_r_hand() drop_l_hand() + if(viruses) + for(var/datum/disease/D in viruses) + if(istype(D, /datum/disease/advance)) + var/datum/disease/advance/AD = D + for(var/symptom in AD.symptoms) + var/datum/symptom/S = symptom + S.OnDeath(AD) + else + D.OnDeath() + if(healths) healths.overlays = null // This is specific to humans but the relevant code is here; shouldn't mess with other mobs. healths.icon_state = "health6" diff --git a/code/modules/mob/living/simple_mob/subtypes/vore/macrophage.dm b/code/modules/mob/living/simple_mob/subtypes/vore/macrophage.dm index b299bb2a82f..43746b40108 100644 --- a/code/modules/mob/living/simple_mob/subtypes/vore/macrophage.dm +++ b/code/modules/mob/living/simple_mob/subtypes/vore/macrophage.dm @@ -5,8 +5,25 @@ icon_state = "macrophage-1" faction = FACTION_MACROBACTERIA - maxHealth = 60 - health = 60 + maxHealth = 20 + health = 20 + + minbodytemp = T0C-30 + heat_damage_per_tick = 40 + cold_damage_per_tick = 40 + + min_oxy = 0 + max_oxy = 0 + min_tox = 0 + max_tox = 0 + min_co2 = 0 + max_co2 = 0 + min_n2 = 0 + max_n2 = 0 + unsuitable_atoms_damage = 0 + shock_resist = 0.5 + taser_kill = FALSE + water_resist = 1 var/datum/disease/base_disease = null var/list/infections = list() @@ -30,21 +47,36 @@ can_be_drop_prey = FALSE allow_mind_transfer = TRUE + pass_flags = PASSTABLE | PASSMOB + mob_size = MOB_TINY + ai_holder_type = /datum/ai_holder/simple_mob/melee/macrophage +/mob/living/simple_mob/vore/aggressive/macrophage/giant + name = "Giant Germ" + desc = "An incredibly huge virus!" + + maxHealth = 40 + health = 40 + + pass_flags = PASSTABLE | PASSGRILLE + +/mob/living/simple_mob/vore/aggressive/macrophage/Initialize() + . = ..() + var/datum/disease/advance/random/macrophage/D = new + health += D.totalResistance() + maxHealth += D.totalResistance() + melee_damage_lower += max(0, D.totalResistance()) + melee_damage_upper += max(0, D.totalResistance()) + infections += D + base_disease = D + /mob/living/simple_mob/vore/aggressive/macrophage/proc/deathcheck() if(locate(/mob/living/carbon/human) in vore_selected) addtimer(CALLBACK(src, TYPE_PROC_REF(/mob/living/simple_mob/vore/aggressive/macrophage, deathcheck)), 3000) else dust() -/mob/living/simple_mob/vore/aggressive/macrophage/Initialize() - . = ..() - if(base_disease) - ai_holder_type.virus = new base_disease - else - ai_holder_type.virus = new /datum/disease/cold - /mob/living/simple_mob/vore/aggressive/macrophage/green icon_state = "macrophage-2" @@ -54,6 +86,20 @@ /mob/living/simple_mob/vore/aggressive/macrophage/blue icon_state = "macrophage-4" +/mob/living/simple_mob/vore/aggressive/macrophage/do_attack(atom/A, turf/T) + . = ..() + if(iscarbon(A)) + var/mob/living/carbon/human/victim = A + victim.ContractDisease(base_disease) + +/mob/living/simple_mob/vore/aggressive/macrophage/death() + . = ..() + if(isbelly(loc)) + var/obj/belly/belly = loc + if(belly) + var/mob/living/pred = belly.owner + pred.ForceContractDisease(base_disease) + /obj/belly/macrophage name = "capsid" fancy_vore = TRUE @@ -75,24 +121,19 @@ var/obj/belly/B = new /obj/belly/macrophage(src) vore_selected = B -/mob/living/simple_mob/vore/aggressive/macrophage/do_attack(atom/A, turf/T) - . = ..() - if(iscarbon(A)) - var/mob/living/carbon/human/victim = A - A.ContractDisease(base_disease) - /datum/ai_holder/simple_mob/melee/macrophage var/datum/disease/virus = null /datum/ai_holder/simple_mob/melee/macrophage/list_targets() var/list/our_targets = ..() + var/mob/living/simple_mob/vore/aggressive/macrophage/macrophage = holder for(var/list_target in our_targets) if(!ishuman(list_target)) // Mobs? Robots? Meh. We want to INFECT. our_targets -= list_target continue var/mob/living/carbon/human/victim = list_target if(victim.viruses) - if(victim.HasDisease(virus) && prob(25)) // Less likely to be a target if you're infected + if(victim.HasDisease(macrophage.base_disease) && prob(75)) // Less likely to be a target if you're infected our_targets -= list_target continue return our_targets diff --git a/code/modules/reagents/reagent_containers/virology.dm b/code/modules/reagents/reagent_containers/virology.dm index f09c34a4aa5..79765d83b6e 100644 --- a/code/modules/reagents/reagent_containers/virology.dm +++ b/code/modules/reagents/reagent_containers/virology.dm @@ -24,3 +24,43 @@ diseases += new /datum/disease/advance/flu data["viruses"] = diseases reagents.add_reagent(REAGENT_ID_BLOOD, 10, data) + +/obj/item/reagent_containers/glass/bottle/culture/blobspores + name = "blob spores culture" + desc = "A bottle with blob spores" + +/obj/item/reagent_containers/glass/bottle/culture/blobspores/Initialize() + . = ..() + diseases += new /datum/disease/advance/blobspores + data["viruses"] = diseases + reagents.add_reagent(REAGENT_ID_BLOOD, 10, data) + +/obj/item/reagent_containers/glass/bottle/culture/macrophages + name = "macrophages culture" + desc = "A bottle with giant viruses" + +/obj/item/reagent_containers/glass/bottle/culture/macrophages/Initialize() + . = ..() + diseases += new /datum/disease/advance/macrophage + data["viruses"] = diseases + reagents.add_reagent(REAGENT_ID_BLOOD, 10, data) + +/obj/item/reagent_containers/glass/bottle/culture/random_virus + name = "experimental disease culture bottle" + desc = "A small bottle. Contains an untested viral culture." + +/obj/item/reagent_containers/glass/bottle/culture/random_virus/Initialize() + . = ..() + diseases += new /datum/disease/advance/random + data["viruses"] = diseases + reagents.add_reagent(REAGENT_ID_BLOOD, 10, data) + +/obj/item/reagent_containers/glass/bottle/culture/random_virus/minor + name = "minor experimental disease culture bottle" + desc = "A small bottle. Contains a weak version of an untested viral culture." + +/obj/item/reagent_containers/glass/bottle/culture/random_virus/minor/Initialize() + . = ..() + diseases += new /datum/disease/advance/random/minor + data["viruses"] = diseases + reagents.add_reagent(REAGENT_ID_BLOOD, 10, data) diff --git a/code/modules/reagents/reagents/other.dm b/code/modules/reagents/reagents/other.dm index c2abcbe9e92..67a44e70d71 100644 --- a/code/modules/reagents/reagents/other.dm +++ b/code/modules/reagents/reagents/other.dm @@ -445,6 +445,10 @@ var/mob/living/carbon/C = M C.clean_blood(TRUE) + if(istype(M, /mob/living/simple_mob/vore/aggressive/macrophage)) // Big ouch for viruses + var/mob/living/simple_mob/macrophage = M + macrophage.adjustToxLoss(15) + /datum/reagent/space_cleaner/touch_obj(var/obj/O) ..() O.clean_blood() @@ -463,6 +467,9 @@ for(var/mob/living/simple_mob/slime/M in T) M.adjustToxLoss(rand(5, 10)) + for(var/mob/living/simple_mob/vore/aggressive/macrophage/virus in T) + virus.adjustToxLoss(rand(5, 10)) + /datum/reagent/space_cleaner/affect_touch(var/mob/living/carbon/M, var/alien, var/removed) if(M.r_hand) M.r_hand.clean_blood() diff --git a/vorestation.dme b/vorestation.dme index b045f136067..c0c9a5e0ad5 100644 --- a/vorestation.dme +++ b/vorestation.dme @@ -484,6 +484,7 @@ #include "code\datums\diseases\magnitis.dm" #include "code\datums\diseases\advance\advance.dm" #include "code\datums\diseases\advance\disease_preset.dm" +#include "code\datums\diseases\advance\symptoms\blobspores.dm" #include "code\datums\diseases\advance\symptoms\choking.dm" #include "code\datums\diseases\advance\symptoms\confusion.dm" #include "code\datums\diseases\advance\symptoms\cough.dm"