diff --git a/code/__DEFINES/atom_hud.dm b/code/__DEFINES/atom_hud.dm index 0c5edf5b99..393ffce4fd 100644 --- a/code/__DEFINES/atom_hud.dm +++ b/code/__DEFINES/atom_hud.dm @@ -19,8 +19,9 @@ #define DIAG_AIRLOCK_HUD "15"//Airlock shock overlay #define DIAG_PATH_HUD "16"//Bot path indicators #define GLAND_HUD "17"//Gland indicators for abductors +#define SENTIENT_DISEASE_HUD "18" //for antag huds. these are used at the /mob level -#define ANTAG_HUD "18" +#define ANTAG_HUD "19" //by default everything in the hud_list of an atom is an image //a value in hud_list with one of these will change that behavior @@ -35,21 +36,23 @@ #define DATA_HUD_DIAGNOSTIC_BASIC 5 #define DATA_HUD_DIAGNOSTIC_ADVANCED 6 #define DATA_HUD_ABDUCTOR 7 +#define DATA_HUD_SENTIENT_DISEASE 8 + //antag HUD defines -#define ANTAG_HUD_CULT 8 -#define ANTAG_HUD_REV 9 -#define ANTAG_HUD_OPS 10 -#define ANTAG_HUD_WIZ 11 -#define ANTAG_HUD_SHADOW 12 -#define ANTAG_HUD_TRAITOR 13 -#define ANTAG_HUD_NINJA 14 -#define ANTAG_HUD_CHANGELING 15 -#define ANTAG_HUD_ABDUCTOR 16 -#define ANTAG_HUD_DEVIL 17 -#define ANTAG_HUD_SINTOUCHED 18 -#define ANTAG_HUD_SOULLESS 19 -#define ANTAG_HUD_CLOCKWORK 20 -#define ANTAG_HUD_BROTHER 21 +#define ANTAG_HUD_CULT 9 +#define ANTAG_HUD_REV 10 +#define ANTAG_HUD_OPS 11 +#define ANTAG_HUD_WIZ 12 +#define ANTAG_HUD_SHADOW 13 +#define ANTAG_HUD_TRAITOR 14 +#define ANTAG_HUD_NINJA 15 +#define ANTAG_HUD_CHANGELING 16 +#define ANTAG_HUD_ABDUCTOR 17 +#define ANTAG_HUD_DEVIL 18 +#define ANTAG_HUD_SINTOUCHED 19 +#define ANTAG_HUD_SOULLESS 20 +#define ANTAG_HUD_CLOCKWORK 21 +#define ANTAG_HUD_BROTHER 22 // Notification action types #define NOTIFY_JUMP "jump" diff --git a/code/__DEFINES/diseases.dm b/code/__DEFINES/diseases.dm index 58d8066e9c..9f96d0374f 100644 --- a/code/__DEFINES/diseases.dm +++ b/code/__DEFINES/diseases.dm @@ -1,3 +1,7 @@ + +#define DISEASE_LIMIT 1 +#define VIRUS_SYMPTOM_LIMIT 6 + //Visibility Flags #define HIDDEN_SCANNER 1 #define HIDDEN_PANDEMIC 2 @@ -8,19 +12,18 @@ #define CAN_RESIST 4 //Spread Flags -#define VIRUS_SPREAD_SPECIAL 1 -#define VIRUS_SPREAD_NON_CONTAGIOUS 2 -#define VIRUS_SPREAD_BLOOD 4 -#define VIRUS_SPREAD_CONTACT_FLUIDS 8 -#define VIRUS_SPREAD_CONTACT_SKIN 16 -#define VIRUS_SPREAD_AIRBORNE 32 - +#define DISEASE_SPREAD_SPECIAL 1 +#define DISEASE_SPREAD_NON_CONTAGIOUS 2 +#define DISEASE_SPREAD_BLOOD 4 +#define DISEASE_SPREAD_CONTACT_FLUIDS 8 +#define DISEASE_SPREAD_CONTACT_SKIN 16 +#define DISEASE_SPREAD_AIRBORNE 32 //Severity Defines -#define VIRUS_SEVERITY_POSITIVE "Positive" //Diseases that buff, heal, or at least do nothing at all -#define VIRUS_SEVERITY_NONTHREAT "Harmless" //Diseases that may have annoying effects, but nothing disruptive (sneezing) -#define VIRUS_SEVERITY_MINOR "Minor" //Diseases that can annoy in concrete ways (dizziness) -#define VIRUS_SEVERITY_MEDIUM "Medium" //Diseases that can do minor harm, or severe annoyance (vomit) -#define VIRUS_SEVERITY_HARMFUL "Harmful" //Diseases that can do significant harm, or severe disruption (brainrot) -#define VIRUS_SEVERITY_DANGEROUS "Dangerous" //Diseases that can kill or maim if left untreated (flesh eating, blindness) -#define VIRUS_SEVERITY_BIOHAZARD "BIOHAZARD" //Diseases that can quickly kill an unprepared victim (fungal tb, gbs) +#define DISEASE_SEVERITY_POSITIVE "Positive" //Diseases that buff, heal, or at least do nothing at all +#define DISEASE_SEVERITY_NONTHREAT "Harmless" //Diseases that may have annoying effects, but nothing disruptive (sneezing) +#define DISEASE_SEVERITY_MINOR "Minor" //Diseases that can annoy in concrete ways (dizziness) +#define DISEASE_SEVERITY_MEDIUM "Medium" //Diseases that can do minor harm, or severe annoyance (vomit) +#define DISEASE_SEVERITY_HARMFUL "Harmful" //Diseases that can do significant harm, or severe disruption (brainrot) +#define DISEASE_SEVERITY_DANGEROUS "Dangerous" //Diseases that can kill or maim if left untreated (flesh eating, blindness) +#define DISEASE_SEVERITY_BIOHAZARD "BIOHAZARD" //Diseases that can quickly kill an unprepared victim (fungal tb, gbs) diff --git a/code/__HELPERS/cmp.dm b/code/__HELPERS/cmp.dm index 8c4d62c6a2..e09ebcb10c 100644 --- a/code/__HELPERS/cmp.dm +++ b/code/__HELPERS/cmp.dm @@ -77,4 +77,7 @@ GLOBAL_VAR_INIT(cmp_field, "name") if(A.plane != B.plane) return A.plane - B.plane else - return A.layer - B.layer \ No newline at end of file + return A.layer - B.layer + +/proc/cmp_advdisease_resistance_asc(datum/disease/advance/A, datum/disease/advance/B) + return A.totalResistance() - B.totalResistance() diff --git a/code/__HELPERS/unsorted.dm b/code/__HELPERS/unsorted.dm index a31ec4f037..cbd73627ff 100644 --- a/code/__HELPERS/unsorted.dm +++ b/code/__HELPERS/unsorted.dm @@ -995,9 +995,9 @@ GLOBAL_LIST_INIT(WALLITEMS_INVERSE, typecacheof(list( var/mob/living/LA = A if(LA.lying) return 0 - var/goal_dir = angle2dir(dir2angle(get_dir(B,A)+180)) + var/goal_dir = get_dir(A,B) var/clockwise_A_dir = turn(A.dir, -45) - var/anticlockwise_A_dir = turn(B.dir, 45) + var/anticlockwise_A_dir = turn(A.dir, 45) if(A.dir == goal_dir || clockwise_A_dir == goal_dir || anticlockwise_A_dir == goal_dir) return 1 diff --git a/code/_globalvars/lists/mobs.dm b/code/_globalvars/lists/mobs.dm index a3d14b26ad..e32405cad5 100644 --- a/code/_globalvars/lists/mobs.dm +++ b/code/_globalvars/lists/mobs.dm @@ -25,8 +25,10 @@ GLOBAL_LIST_EMPTY(available_ai_shells) GLOBAL_LIST_INIT(simple_animals, list(list(),list(),list(),list())) // One for each AI_* status define GLOBAL_LIST_EMPTY(spidermobs) //all sentient spider mobs GLOBAL_LIST_EMPTY(bots_list) +GLOBAL_LIST_EMPTY(living_cameras) GLOBAL_LIST_EMPTY(language_datum_instances) GLOBAL_LIST_EMPTY(all_languages) -GLOBAL_LIST_EMPTY(latejoiners) //CIT CHANGE - All latejoining people, for traitor-target purposes. \ No newline at end of file +GLOBAL_LIST_EMPTY(latejoiners) //CIT CHANGE - All latejoining people, for traitor-target purposes. +GLOBAL_LIST_EMPTY(sentient_disease_instances) diff --git a/code/_onclick/other_mobs.dm b/code/_onclick/other_mobs.dm index d52a7f6fdc..587236e802 100644 --- a/code/_onclick/other_mobs.dm +++ b/code/_onclick/other_mobs.dm @@ -103,7 +103,7 @@ "[name] bites [ML]!") if(armor >= 2) return - for(var/thing in viruses) + for(var/thing in diseases) var/datum/disease/D = thing ML.ForceContractDisease(D) else diff --git a/code/controllers/subsystem/mobs.dm b/code/controllers/subsystem/mobs.dm index cd47adf476..c0837ec76b 100644 --- a/code/controllers/subsystem/mobs.dm +++ b/code/controllers/subsystem/mobs.dm @@ -21,8 +21,8 @@ SUBSYSTEM_DEF(mobs) var/seconds = wait * 0.1 if (!resumed) src.currentrun = GLOB.mob_living_list.Copy() - if (GLOB.overminds.len) // blob cameras need to Life() - src.currentrun += GLOB.overminds + if (GLOB.living_cameras.len) + src.currentrun += GLOB.living_cameras //cache for sanic speed (lists are references anyways) var/list/currentrun = src.currentrun diff --git a/code/datums/action.dm b/code/datums/action.dm index 15f62b20b7..a7437a0440 100644 --- a/code/datums/action.dm +++ b/code/datums/action.dm @@ -11,6 +11,7 @@ var/processing = FALSE var/obj/screen/movable/action_button/button = null var/buttontooltipstyle = "" + var/transparent_when_unavailable = TRUE var/button_icon = 'icons/mob/actions/backgrounds.dmi' //This is the file for the BACKGROUND icon var/background_icon_state = ACTION_BUTTON_DEFAULT_BACKGROUND //And this is the state for the background icon @@ -124,7 +125,7 @@ ApplyIcon(button, force) if(!IsAvailable()) - button.color = rgb(128,0,0,128) + button.color = transparent_when_unavailable ? rgb(128,0,0,128) : rgb(128,0,0) else button.color = rgb(255,255,255,255) return 1 @@ -572,6 +573,52 @@ call(target, procname)(usr) return 1 + +//Preset for an action with a cooldown + +/datum/action/cooldown + check_flags = 0 + transparent_when_unavailable = FALSE + var/cooldown_time = 0 + var/next_use_time = 0 + +/datum/action/cooldown/New() + ..() + button.maptext = "" + button.maptext_x = 8 + button.maptext_y = 0 + button.maptext_width = 24 + button.maptext_height = 12 + +/datum/action/cooldown/IsAvailable() + return next_use_time <= world.time + +/datum/action/cooldown/proc/StartCooldown() + next_use_time = world.time + cooldown_time + button.maptext = "[round(cooldown_time/10, 0.1)]" + UpdateButtonIcon() + START_PROCESSING(SSfastprocess, src) + +/datum/action/cooldown/process() + if(!owner) + button.maptext = "" + STOP_PROCESSING(SSfastprocess, src) + var/timeleft = max(next_use_time - world.time, 0) + if(timeleft == 0) + button.maptext = "" + UpdateButtonIcon() + STOP_PROCESSING(SSfastprocess, src) + else + button.maptext = "[round(timeleft/10, 0.1)]" + +/datum/action/cooldown/Grant(mob/M) + ..() + if(owner) + UpdateButtonIcon() + if(next_use_time > world.time) + START_PROCESSING(SSfastprocess, src) + + //Stickmemes /datum/action/item_action/stickmen name = "Summon Stick Minions" diff --git a/code/datums/brain_damage/imaginary_friend.dm b/code/datums/brain_damage/imaginary_friend.dm index 88c7d09005..a1a4c11ca6 100644 --- a/code/datums/brain_damage/imaginary_friend.dm +++ b/code/datums/brain_damage/imaginary_friend.dm @@ -142,9 +142,6 @@ var/link = FOLLOW_LINK(M, owner) to_chat(M, "[link] [dead_rendered]") -/mob/camera/imaginary_friend/emote(act,m_type=1,message = null) - return - /mob/camera/imaginary_friend/forceMove(atom/destination) dir = get_dir(get_turf(src), destination) loc = destination diff --git a/code/datums/diseases/_MobProcs.dm b/code/datums/diseases/_MobProcs.dm index 9f4fa1fe63..bc04a67308 100644 --- a/code/datums/diseases/_MobProcs.dm +++ b/code/datums/diseases/_MobProcs.dm @@ -1,17 +1,17 @@ -/mob/proc/HasDisease(datum/disease/D) - for(var/thing in viruses) +/mob/living/proc/HasDisease(datum/disease/D) + for(var/thing in diseases) var/datum/disease/DD = thing if(D.IsSame(DD)) return TRUE return FALSE -/mob/proc/CanContractDisease(datum/disease/D) +/mob/living/proc/CanContractDisease(datum/disease/D) if(stat == DEAD) return FALSE - if(D.GetDiseaseID() in resistances) + if(D.GetDiseaseID() in disease_resistances) return FALSE if(HasDisease(D)) @@ -23,38 +23,10 @@ return TRUE -/mob/proc/ContactContractDisease(datum/disease/D) +/mob/living/proc/ContactContractDisease(datum/disease/D) if(!CanContractDisease(D)) return FALSE - AddDisease(D) - - -/mob/proc/AddDisease(datum/disease/D) - for(var/datum/disease/advance/P in viruses) - if(istype(D, /datum/disease/advance)) - var/datum/disease/advance/DD = D - if (P.totalResistance() < DD.totalTransmittable()) //Overwrite virus if the attacker's Transmission is lower than the defender's Resistance. This does not grant immunity to the lost virus. - P.remove_virus() - - if (!viruses.len) //Only add the new virus if it defeated the existing one - var/datum/disease/DD = new D.type(1, D, 0) - viruses += DD - DD.affected_mob = src - SSdisease.active_diseases += DD //Add it to the active diseases list, now that it's actually in a mob and being processed. - - //Copy properties over. This is so edited diseases persist. - var/list/skipped = list("affected_mob","holder","carrier","stage","type","parent_type","vars","transformed","symptoms","processing") - for(var/V in DD.vars) - if(V in skipped) - continue - if(islist(DD.vars[V])) - var/list/L = D.vars[V] - DD.vars[V] = L.Copy() - else - DD.vars[V] = D.vars[V] - - DD.after_add() - DD.affected_mob.med_hud_set_status() + D.try_infect(src) /mob/living/carbon/ContactContractDisease(datum/disease/D, target_zone) @@ -124,28 +96,33 @@ passed = prob((Cl.permeability_coefficient*100) - 1) if(passed) - AddDisease(D) + D.try_infect(src) -/mob/proc/AirborneContractDisease(datum/disease/D) - if((D.spread_flags & VIRUS_SPREAD_AIRBORNE) && prob((50*D.permeability_mod) - 1)) +/mob/living/proc/AirborneContractDisease(datum/disease/D, force_spread) + if( ((D.spread_flags & DISEASE_SPREAD_AIRBORNE) || force_spread) && prob((50*D.permeability_mod) - 1)) ForceContractDisease(D) -/mob/living/carbon/AirborneContractDisease(datum/disease/D) +/mob/living/carbon/AirborneContractDisease(datum/disease/D, force_spread) if(internal) return if(has_trait(TRAIT_NOBREATH)) return ..() -//Proc to use when you 100% want to infect someone, as long as they aren't immune -/mob/proc/ForceContractDisease(datum/disease/D) +//Proc to use when you 100% want to try to infect someone (ignoreing protective clothing and such), as long as they aren't immune +/mob/living/proc/ForceContractDisease(datum/disease/D, make_copy = TRUE, del_on_fail = FALSE) if(!CanContractDisease(D)) + if(del_on_fail) + qdel(D) return FALSE - AddDisease(D) + if(!D.try_infect(src, make_copy)) + if(del_on_fail) + qdel(D) + return FALSE + return TRUE /mob/living/carbon/human/CanContractDisease(datum/disease/D) - if(dna) if(has_trait(TRAIT_VIRUSIMMUNE) && !D.bypasses_immunity) return FALSE @@ -161,4 +138,4 @@ for(var/thing in D.required_organs) if(!((locate(thing) in bodyparts) || (locate(thing) in internal_organs))) return FALSE - return ..() \ No newline at end of file + return ..() diff --git a/code/datums/diseases/_disease.dm b/code/datums/diseases/_disease.dm index 5d49d7a523..614cd14abb 100644 --- a/code/datums/diseases/_disease.dm +++ b/code/datums/diseases/_disease.dm @@ -2,7 +2,7 @@ //Flags var/visibility_flags = 0 var/disease_flags = CURABLE|CAN_CARRY|CAN_RESIST - var/spread_flags = VIRUS_SPREAD_AIRBORNE | VIRUS_SPREAD_CONTACT_FLUIDS | VIRUS_SPREAD_CONTACT_SKIN + var/spread_flags = DISEASE_SPREAD_AIRBORNE | DISEASE_SPREAD_CONTACT_FLUIDS | DISEASE_SPREAD_CONTACT_SKIN //Fluff var/form = "Virus" @@ -26,7 +26,7 @@ var/carrier = FALSE //If our host is only a carrier var/bypasses_immunity = FALSE //Does it skip species virus immunity check? Some things may diseases and not viruses var/permeability_mod = 1 - var/severity = VIRUS_SEVERITY_POSITIVE + var/severity = DISEASE_SEVERITY_NONTHREAT var/list/required_organs = list() var/needs_all_cures = TRUE var/list/strain_data = list() //dna_spread special bullshit @@ -34,9 +34,27 @@ var/process_dead = FALSE //if this ticks while the host is dead /datum/disease/Destroy() - affected_mob = null + . = ..() + if(affected_mob) + remove_disease() SSdisease.active_diseases.Remove(src) - return ..() + +//add this disease if the host does not already have too many +/datum/disease/proc/try_infect(var/mob/living/infectee, make_copy = TRUE) + if(infectee.diseases.len < DISEASE_LIMIT) + infect(infectee, make_copy) + return TRUE + return FALSE + +//add the disease with no checks +/datum/disease/proc/infect(var/mob/living/infectee, make_copy = TRUE) + var/datum/disease/D = make_copy ? Copy() : src + infectee.diseases += D + D.affected_mob = infectee + SSdisease.active_diseases += D //Add it to the active diseases list, now that it's actually in a mob and being processed. + + D.after_add() + infectee.med_hud_set_status() /datum/disease/proc/stage_act() var/cure = has_cure() @@ -74,7 +92,7 @@ if(!affected_mob) return - if(!(spread_flags & VIRUS_SPREAD_AIRBORNE) && !force_spread) + if(!(spread_flags & DISEASE_SPREAD_AIRBORNE) && !force_spread) return if(affected_mob.reagents.has_reagent("spaceacillin") || (affected_mob.satiety > 0 && prob(affected_mob.satiety/10))) @@ -89,24 +107,25 @@ if(istype(T)) for(var/mob/living/carbon/C in oview(spread_range, affected_mob)) var/turf/V = get_turf(C) - if(V) - while(TRUE) - if(V == T) - C.AirborneContractDisease(src) - break - var/turf/Temp = get_step_towards(V, T) - if(!CANATMOSPASS(V, Temp)) - break - V = Temp + if(disease_air_spread_walk(T, V)) + C.AirborneContractDisease(src, force_spread) + +/proc/disease_air_spread_walk(turf/start, turf/end) + if(!start || !end) + return FALSE + while(TRUE) + if(end == start) + return TRUE + var/turf/Temp = get_step_towards(end, start) + if(!CANATMOSPASS(end, Temp)) + return FALSE + end = Temp /datum/disease/proc/cure(add_resistance = TRUE) if(affected_mob) - if(disease_flags & CAN_RESIST) - var/id = GetDiseaseID() - if(add_resistance && !(id in affected_mob.resistances)) - affected_mob.resistances += id - remove_virus() + if(add_resistance && (disease_flags & CAN_RESIST)) + affected_mob.disease_resistances |= GetDiseaseID() qdel(src) /datum/disease/proc/IsSame(datum/disease/D) @@ -116,8 +135,19 @@ /datum/disease/proc/Copy() + //note that stage is not copied over - the copy starts over at stage 1 + var/static/list/copy_vars = list("name", "visibility_flags", "disease_flags", "spread_flags", "form", "desc", "agent", "spread_text", + "cure_text", "max_stages", "stage_prob", "viable_mobtypes", "cures", "infectivity", "cure_chance", + "bypasses_immunity", "permeability_mod", "severity", "required_organs", "needs_all_cures", "strain_data", + "infectable_hosts", "process_dead") + var/datum/disease/D = new type() - D.strain_data = strain_data.Copy() + for(var/V in copy_vars) + var/val = vars[V] + if(islist(val)) + var/list/L = val + val = L.Copy() + D.vars[V] = val return D /datum/disease/proc/after_add() @@ -127,7 +157,7 @@ /datum/disease/proc/GetDiseaseID() return "[type]" -//don't use this proc directly. this should only ever be called by cure() -/datum/disease/proc/remove_virus() - affected_mob.viruses -= src //remove the datum from the list +/datum/disease/proc/remove_disease() + affected_mob.diseases -= src //remove the datum from the list affected_mob.med_hud_set_status() + affected_mob = null diff --git a/code/datums/diseases/advance/advance.dm b/code/datums/diseases/advance/advance.dm index d2ded9f907..64af3bc94d 100644 --- a/code/datums/diseases/advance/advance.dm +++ b/code/datums/diseases/advance/advance.dm @@ -7,7 +7,6 @@ */ -#define SYMPTOM_LIMIT 6 @@ -31,6 +30,7 @@ var/list/symptoms = list() // The symptoms of the disease. var/id = "" var/processing = FALSE + var/mutable = TRUE //set to FALSE to prevent most in-game methods of altering the disease via virology // The order goes from easy to cure to hard to cure. var/static/list/advance_cures = list( @@ -46,23 +46,8 @@ */ -/datum/disease/advance/New(var/process = 1, var/datum/disease/advance/D) - if(!istype(D)) - D = null - // Generate symptoms if we weren't given any. - - if(!symptoms || !symptoms.len) - - if(!D || !D.symptoms || !D.symptoms.len) - symptoms = GenerateSymptoms(0, 2) - else - for(var/datum/symptom/S in D.symptoms) - var/datum/symptom/new_symp = S.Copy() - symptoms += new_symp - +/datum/disease/advance/New() Refresh() - ..(process, D) - return /datum/disease/advance/Destroy() if(processing) @@ -70,6 +55,26 @@ S.End(src) return ..() +/datum/disease/advance/try_infect(var/mob/living/infectee, make_copy = TRUE) + var/replace_num = infectee.diseases.len + 1 - DISEASE_LIMIT + if(replace_num > 0) + //see if we are more transmittable than enough diseases to replace them + //diseases replaced in this way do not confer immunity + var/list/L = list() + for(var/datum/disease/advance/P in infectee.diseases) + L += P + sortTim(L, /proc/cmp_advdisease_resistance_asc) + var/datum/disease/advance/competition = L[replace_num] + if(totalTransmittable() > competition.totalResistance()) + for(var/i in 1 to replace_num) + var/datum/disease/advance/A = L[replace_num] + A.cure(FALSE) + else + //we are not strong enough to bully our way in + return FALSE + infect(infectee, make_copy) + return TRUE + // Randomly pick a symptom to activate. /datum/disease/advance/stage_act() ..() @@ -85,8 +90,6 @@ for(var/datum/symptom/S in symptoms) S.Activate(src) - else - CRASH("We do not have any symptoms during stage_act()!") // Compares type then ID. /datum/disease/advance/IsSame(datum/disease/advance/D) @@ -99,8 +102,15 @@ return 1 // Returns the advance disease with a different reference memory. -/datum/disease/advance/Copy(process = 0) - return new /datum/disease/advance(process, src, 1) +/datum/disease/advance/Copy() + var/datum/disease/advance/A = ..() + QDEL_LIST(A.symptoms) + for(var/datum/symptom/S in symptoms) + A.symptoms += S.Copy() + A.properties = properties.Copy() + A.id = id + //this is a new disease starting over at stage 1, so processing is not copied + return A /* @@ -130,7 +140,7 @@ var/list/possible_symptoms = list() for(var/symp in SSdisease.list_symptoms) var/datum/symptom/S = new symp - if(S.level >= level_min && S.level <= level_max) + if(S.naturally_occuring && S.level >= level_min && S.level <= level_max) if(!HasSymptom(S)) possible_symptoms += S @@ -154,22 +164,18 @@ AssignProperties() id = null - if(!SSdisease.archive_diseases[GetDiseaseID()]) + var/the_id = GetDiseaseID() + if(!SSdisease.archive_diseases[the_id]) if(new_name) AssignName() - SSdisease.archive_diseases[GetDiseaseID()] = src // So we don't infinite loop - SSdisease.archive_diseases[GetDiseaseID()] = new /datum/disease/advance(0, src, 1) + SSdisease.archive_diseases[the_id] = src // So we don't infinite loop + SSdisease.archive_diseases[the_id] = Copy() - var/datum/disease/advance/A = SSdisease.archive_diseases[GetDiseaseID()] - AssignName(A.name) + var/datum/disease/advance/A = SSdisease.archive_diseases[the_id] + name = A.name //Generate disease properties based on the effects. Returns an associated list. /datum/disease/advance/proc/GenerateProperties() - - if(!symptoms || !symptoms.len) - CRASH("We did not have any symptoms before generating properties.") - return - properties = list("resistance" = 0, "stealth" = 0, "stage_rate" = 0, "transmittable" = 0, "severity" = 0) for(var/datum/symptom/S in symptoms) @@ -179,7 +185,6 @@ properties["transmittable"] += S.transmittable if(!S.neutered) properties["severity"] = max(properties["severity"], S.severity) // severity is based on the highest severity non-neutered symptom - return // Assign the properties that are in the list. /datum/disease/advance/proc/AssignProperties() @@ -188,7 +193,7 @@ if(properties["stealth"] >= 2) visibility_flags = HIDDEN_SCANNER - SetSpread(CLAMP(2 ** (properties["transmittable"] - symptoms.len), VIRUS_SPREAD_BLOOD, VIRUS_SPREAD_AIRBORNE)) + SetSpread(CLAMP(2 ** (properties["transmittable"] - symptoms.len), DISEASE_SPREAD_BLOOD, DISEASE_SPREAD_AIRBORNE)) permeability_mod = max(CEILING(0.4 * properties["transmittable"], 1), 1) cure_chance = 15 - CLAMP(properties["resistance"], -5, 5) // can be between 10 and 20 @@ -202,23 +207,23 @@ // Assign the spread type and give it the correct description. /datum/disease/advance/proc/SetSpread(spread_id) switch(spread_id) - if(VIRUS_SPREAD_NON_CONTAGIOUS) - spread_flags = VIRUS_SPREAD_NON_CONTAGIOUS + if(DISEASE_SPREAD_NON_CONTAGIOUS) + spread_flags = DISEASE_SPREAD_NON_CONTAGIOUS spread_text = "None" - if(VIRUS_SPREAD_SPECIAL) - spread_flags = VIRUS_SPREAD_SPECIAL + if(DISEASE_SPREAD_SPECIAL) + spread_flags = DISEASE_SPREAD_SPECIAL spread_text = "None" - if(VIRUS_SPREAD_BLOOD) - spread_flags = VIRUS_SPREAD_BLOOD + if(DISEASE_SPREAD_BLOOD) + spread_flags = DISEASE_SPREAD_BLOOD spread_text = "Blood" - if(VIRUS_SPREAD_CONTACT_FLUIDS) - spread_flags = VIRUS_SPREAD_BLOOD | VIRUS_SPREAD_CONTACT_FLUIDS + if(DISEASE_SPREAD_CONTACT_FLUIDS) + spread_flags = DISEASE_SPREAD_BLOOD | DISEASE_SPREAD_CONTACT_FLUIDS spread_text = "Fluids" - if(VIRUS_SPREAD_CONTACT_SKIN) - spread_flags = VIRUS_SPREAD_BLOOD | VIRUS_SPREAD_CONTACT_FLUIDS | VIRUS_SPREAD_CONTACT_SKIN + if(DISEASE_SPREAD_CONTACT_SKIN) + spread_flags = DISEASE_SPREAD_BLOOD | DISEASE_SPREAD_CONTACT_FLUIDS | DISEASE_SPREAD_CONTACT_SKIN spread_text = "On contact" - if(VIRUS_SPREAD_AIRBORNE) - spread_flags = VIRUS_SPREAD_BLOOD | VIRUS_SPREAD_CONTACT_FLUIDS | VIRUS_SPREAD_CONTACT_SKIN | VIRUS_SPREAD_AIRBORNE + if(DISEASE_SPREAD_AIRBORNE) + spread_flags = DISEASE_SPREAD_BLOOD | DISEASE_SPREAD_CONTACT_FLUIDS | DISEASE_SPREAD_CONTACT_SKIN | DISEASE_SPREAD_AIRBORNE spread_text = "Airborne" /datum/disease/advance/proc/SetSeverity(level_sev) @@ -226,19 +231,19 @@ switch(level_sev) if(-INFINITY to 0) - severity = VIRUS_SEVERITY_POSITIVE + severity = DISEASE_SEVERITY_POSITIVE if(1) - severity = VIRUS_SEVERITY_NONTHREAT + severity = DISEASE_SEVERITY_NONTHREAT if(2) - severity = VIRUS_SEVERITY_MINOR + severity = DISEASE_SEVERITY_MINOR if(3) - severity = VIRUS_SEVERITY_MEDIUM + severity = DISEASE_SEVERITY_MEDIUM if(4) - severity = VIRUS_SEVERITY_HARMFUL + severity = DISEASE_SEVERITY_HARMFUL if(5) - severity = VIRUS_SEVERITY_DANGEROUS + severity = DISEASE_SEVERITY_DANGEROUS if(6 to INFINITY) - severity = VIRUS_SEVERITY_BIOHAZARD + severity = DISEASE_SEVERITY_BIOHAZARD else severity = "Unknown" @@ -253,11 +258,10 @@ var/datum/reagent/D = GLOB.chemical_reagents_list[cures[1]] cure_text = D.name - - return - // Randomly generate a symptom, has a chance to lose or gain a symptom. -/datum/disease/advance/proc/Evolve(min_level, max_level) +/datum/disease/advance/proc/Evolve(min_level, max_level, ignore_mutable = FALSE) + if(!mutable && !ignore_mutable) + return var/s = safepick(GenerateSymptoms(min_level, max_level, 1)) if(s) AddSymptom(s) @@ -265,27 +269,32 @@ return // Randomly remove a symptom. -/datum/disease/advance/proc/Devolve() +/datum/disease/advance/proc/Devolve(ignore_mutable = FALSE) + if(!mutable && !ignore_mutable) + return if(symptoms.len > 1) var/s = safepick(symptoms) if(s) RemoveSymptom(s) Refresh(TRUE) - return // Randomly neuter a symptom. -/datum/disease/advance/proc/Neuter() +/datum/disease/advance/proc/Neuter(ignore_mutable = FALSE) + if(!mutable && !ignore_mutable) + return if(symptoms.len) var/s = safepick(symptoms) if(s) NeuterSymptom(s) Refresh(TRUE) - return // Name the disease. /datum/disease/advance/proc/AssignName(name = "Unknown") - src.name = name - return + Refresh() + var/datum/disease/advance/A = SSdisease.archive_diseases[GetDiseaseID()] + A.name = name + for(var/datum/disease/advance/AD in SSdisease.active_diseases) + AD.Refresh() // Return a unique ID of the disease. /datum/disease/advance/GetDiseaseID() @@ -309,17 +318,15 @@ if(HasSymptom(S)) return - if(symptoms.len < (SYMPTOM_LIMIT - 1) + rand(-1, 1)) + if(symptoms.len < (VIRUS_SYMPTOM_LIMIT - 1) + rand(-1, 1)) symptoms += S else RemoveSymptom(pick(symptoms)) symptoms += S - return // Simply removes the symptom. /datum/disease/advance/proc/RemoveSymptom(datum/symptom/S) symptoms -= S - return // Neuter a symptom, so it will only affect stats /datum/disease/advance/proc/NeuterSymptom(datum/symptom/S) @@ -377,7 +384,7 @@ if(!user) return - var/i = SYMPTOM_LIMIT + var/i = VIRUS_SYMPTOM_LIMIT var/datum/disease/advance/D = new(0, null) D.symptoms = list() @@ -434,5 +441,3 @@ /datum/disease/advance/proc/totalTransmittable() return properties["transmittable"] - -#undef RANDOM_STARTING_LEVEL diff --git a/code/datums/diseases/advance/presets.dm b/code/datums/diseases/advance/presets.dm index d2f6a73365..9574338b51 100644 --- a/code/datums/diseases/advance/presets.dm +++ b/code/datums/diseases/advance/presets.dm @@ -1,59 +1,52 @@ // Cold -/datum/disease/advance/cold/New(var/process = TRUE, var/datum/disease/advance/D, var/copy = FALSE) - if(!D) - name = "Cold" - symptoms = list(new/datum/symptom/sneeze) - ..(process, D, copy) +/datum/disease/advance/cold/New() + name = "Cold" + symptoms = list(new/datum/symptom/sneeze) + ..() // Flu -/datum/disease/advance/flu/New(var/process = TRUE, var/datum/disease/advance/D, var/copy = FALSE) - if(!D) - name = "Flu" - symptoms = list(new/datum/symptom/cough) - ..(process, D, copy) +/datum/disease/advance/flu/New() + name = "Flu" + symptoms = list(new/datum/symptom/cough) + ..() // Voice Changing -/datum/disease/advance/voice_change/New(var/process = TRUE, var/datum/disease/advance/D, var/copy = FALSE) - if(!D) - name = "Epiglottis Mutation" - symptoms = list(new/datum/symptom/voice_change) - ..(process, D, copy) +/datum/disease/advance/voice_change/New() + name = "Epiglottis Mutation" + symptoms = list(new/datum/symptom/voice_change) + ..() // Toxin Filter -/datum/disease/advance/heal/New(var/process = TRUE, var/datum/disease/advance/D, var/copy = FALSE) - if(!D) - name = "Liver Enhancer" - symptoms = list(new/datum/symptom/heal) - ..(process, D, copy) +/datum/disease/advance/heal/New() + name = "Liver Enhancer" + symptoms = list(new/datum/symptom/heal) + ..() // Hallucigen -/datum/disease/advance/hallucigen/New(var/process = TRUE, var/datum/disease/advance/D, var/copy = FALSE) - if(!D) - name = "Second Sight" - symptoms = list(new/datum/symptom/hallucigen) - ..(process, D, copy) +/datum/disease/advance/hallucigen/New() + name = "Second Sight" + symptoms = list(new/datum/symptom/hallucigen) + ..() // Sensory Restoration -/datum/disease/advance/mind_restoration/New(var/process = TRUE, var/datum/disease/advance/D, var/copy = FALSE) - if(!D) - name = "Intelligence Booster" - symptoms = list(new/datum/symptom/mind_restoration) - ..(process, D, copy) +/datum/disease/advance/mind_restoration/New() + name = "Intelligence Booster" + symptoms = list(new/datum/symptom/mind_restoration) + ..() // Sensory Destruction -/datum/disease/advance/narcolepsy/New(var/process = TRUE, var/datum/disease/advance/D, var/copy = FALSE) - if(!D) - name = "Experimental Insomnia Cure" - symptoms = list(new/datum/symptom/narcolepsy) - ..(process, D, copy) \ No newline at end of file +/datum/disease/advance/narcolepsy/New() + name = "Experimental Insomnia Cure" + symptoms = list(new/datum/symptom/narcolepsy) + ..() \ No newline at end of file diff --git a/code/datums/diseases/advance/symptoms/cough.dm b/code/datums/diseases/advance/symptoms/cough.dm index 323f794eee..1633b41352 100644 --- a/code/datums/diseases/advance/symptoms/cough.dm +++ b/code/datums/diseases/advance/symptoms/cough.dm @@ -40,7 +40,7 @@ BONUS return if(A.properties["stealth"] >= 4) suppress_warning = TRUE - if(A.spread_flags &= VIRUS_SPREAD_AIRBORNE) //infect bystanders + if(A.spread_flags &= DISEASE_SPREAD_AIRBORNE) //infect bystanders infective = TRUE if(A.properties["resistance"] >= 3) //strong enough to drop items power = 1.5 diff --git a/code/datums/diseases/advance/symptoms/symptoms.dm b/code/datums/diseases/advance/symptoms/symptoms.dm index 84e5884ffb..e42b68cc05 100644 --- a/code/datums/diseases/advance/symptoms/symptoms.dm +++ b/code/datums/diseases/advance/symptoms/symptoms.dm @@ -28,6 +28,7 @@ //A neutered symptom has no effect, and only affects statistics. var/neutered = FALSE var/list/thresholds + var/naturally_occuring = TRUE //if this symptom can appear from /datum/disease/advance/GenerateSymptoms() /datum/symptom/New() var/list/S = SSdisease.list_symptoms diff --git a/code/datums/diseases/anxiety.dm b/code/datums/diseases/anxiety.dm index 4673d2e980..2d96157bb0 100644 --- a/code/datums/diseases/anxiety.dm +++ b/code/datums/diseases/anxiety.dm @@ -3,13 +3,13 @@ form = "Infection" max_stages = 4 spread_text = "On contact" - spread_flags = VIRUS_SPREAD_BLOOD | VIRUS_SPREAD_CONTACT_SKIN | VIRUS_SPREAD_CONTACT_FLUIDS + spread_flags = DISEASE_SPREAD_BLOOD | DISEASE_SPREAD_CONTACT_SKIN | DISEASE_SPREAD_CONTACT_FLUIDS cure_text = "Ethanol" cures = list("ethanol") agent = "Excess Lepidopticides" viable_mobtypes = list(/mob/living/carbon/human, /mob/living/carbon/monkey) desc = "If left untreated subject will regurgitate butterflies." - severity = VIRUS_SEVERITY_MINOR + severity = DISEASE_SEVERITY_MINOR /datum/disease/anxiety/stage_act() ..() diff --git a/code/datums/diseases/appendicitis.dm b/code/datums/diseases/appendicitis.dm index 61d1519e7d..5708447542 100644 --- a/code/datums/diseases/appendicitis.dm +++ b/code/datums/diseases/appendicitis.dm @@ -7,9 +7,9 @@ viable_mobtypes = list(/mob/living/carbon/human) permeability_mod = 1 desc = "If left untreated the subject will become very weak, and may vomit often." - severity = VIRUS_SEVERITY_MEDIUM + severity = DISEASE_SEVERITY_MEDIUM disease_flags = CAN_CARRY|CAN_RESIST - spread_flags = VIRUS_SPREAD_NON_CONTAGIOUS + spread_flags = DISEASE_SPREAD_NON_CONTAGIOUS visibility_flags = HIDDEN_PANDEMIC required_organs = list(/obj/item/organ/appendix) bypasses_immunity = TRUE // Immunity is based on not having an appendix; this isn't a virus diff --git a/code/datums/diseases/beesease.dm b/code/datums/diseases/beesease.dm index dc848ab622..f6504fa464 100644 --- a/code/datums/diseases/beesease.dm +++ b/code/datums/diseases/beesease.dm @@ -3,13 +3,13 @@ form = "Infection" max_stages = 4 spread_text = "On contact" - spread_flags = VIRUS_SPREAD_BLOOD | VIRUS_SPREAD_CONTACT_SKIN | VIRUS_SPREAD_CONTACT_FLUIDS + spread_flags = DISEASE_SPREAD_BLOOD | DISEASE_SPREAD_CONTACT_SKIN | DISEASE_SPREAD_CONTACT_FLUIDS cure_text = "Sugar" cures = list("sugar") agent = "Apidae Infection" viable_mobtypes = list(/mob/living/carbon/human, /mob/living/carbon/monkey) desc = "If left untreated subject will regurgitate bees." - severity = VIRUS_SEVERITY_MEDIUM + severity = DISEASE_SEVERITY_MEDIUM infectable_hosts = list(SPECIES_ORGANIC, SPECIES_UNDEAD) //bees nesting in corpses /datum/disease/beesease/stage_act() diff --git a/code/datums/diseases/brainrot.dm b/code/datums/diseases/brainrot.dm index 49f8afcaff..0a34501763 100644 --- a/code/datums/diseases/brainrot.dm +++ b/code/datums/diseases/brainrot.dm @@ -2,7 +2,7 @@ name = "Brainrot" max_stages = 4 spread_text = "On contact" - spread_flags = VIRUS_SPREAD_BLOOD | VIRUS_SPREAD_CONTACT_SKIN | VIRUS_SPREAD_CONTACT_FLUIDS + spread_flags = DISEASE_SPREAD_BLOOD | DISEASE_SPREAD_CONTACT_SKIN | DISEASE_SPREAD_CONTACT_FLUIDS cure_text = "Mannitol" cures = list("mannitol") agent = "Cryptococcus Cosmosis" @@ -10,7 +10,7 @@ cure_chance = 15//higher chance to cure, since two reagents are required desc = "This disease destroys the braincells, causing brain fever, brain necrosis and general intoxication." required_organs = list(/obj/item/organ/brain) - severity = VIRUS_SEVERITY_HARMFUL + severity = DISEASE_SEVERITY_HARMFUL /datum/disease/brainrot/stage_act() //Removed toxloss because damaging diseases are pretty horrible. Last round it killed the entire station because the cure didn't work -- Urist -ACTUALLY Removed rather than commented out, I don't see it returning - RR ..() diff --git a/code/datums/diseases/cold.dm b/code/datums/diseases/cold.dm index e9f02b91b6..22d45ffb29 100644 --- a/code/datums/diseases/cold.dm +++ b/code/datums/diseases/cold.dm @@ -7,7 +7,7 @@ viable_mobtypes = list(/mob/living/carbon/human, /mob/living/carbon/monkey) permeability_mod = 0.5 desc = "If left untreated the subject will contract the flu." - severity = VIRUS_SEVERITY_NONTHREAT + severity = DISEASE_SEVERITY_NONTHREAT /datum/disease/cold/stage_act() ..() @@ -47,7 +47,7 @@ if(prob(1)) to_chat(affected_mob, "Mucous runs down the back of your throat.") if(prob(1) && prob(50)) - if(!affected_mob.resistances.Find(/datum/disease/flu)) - var/datum/disease/Flu = new /datum/disease/flu(0) - affected_mob.ForceContractDisease(Flu) + if(!affected_mob.disease_resistances.Find(/datum/disease/flu)) + var/datum/disease/Flu = new /datum/disease/flu() + affected_mob.ForceContractDisease(Flu, FALSE, TRUE) cure() \ No newline at end of file diff --git a/code/datums/diseases/cold9.dm b/code/datums/diseases/cold9.dm index c68ee196c1..da5e67a4fb 100644 --- a/code/datums/diseases/cold9.dm +++ b/code/datums/diseases/cold9.dm @@ -2,13 +2,13 @@ name = "The Cold" max_stages = 3 spread_text = "On contact" - spread_flags = VIRUS_SPREAD_BLOOD | VIRUS_SPREAD_CONTACT_SKIN | VIRUS_SPREAD_CONTACT_FLUIDS + spread_flags = DISEASE_SPREAD_BLOOD | DISEASE_SPREAD_CONTACT_SKIN | DISEASE_SPREAD_CONTACT_FLUIDS cure_text = "Common Cold Anti-bodies & Spaceacillin" cures = list("spaceacillin") agent = "ICE9-rhinovirus" viable_mobtypes = list(/mob/living/carbon/human) desc = "If left untreated the subject will slow, as if partly frozen." - severity = VIRUS_SEVERITY_HARMFUL + severity = DISEASE_SEVERITY_HARMFUL /datum/disease/cold9/stage_act() ..() diff --git a/code/datums/diseases/dna_spread.dm b/code/datums/diseases/dna_spread.dm index fefdabd9c8..267dd711a3 100644 --- a/code/datums/diseases/dna_spread.dm +++ b/code/datums/diseases/dna_spread.dm @@ -2,7 +2,7 @@ name = "Space Retrovirus" max_stages = 4 spread_text = "On contact" - spread_flags = VIRUS_SPREAD_BLOOD | VIRUS_SPREAD_CONTACT_SKIN | VIRUS_SPREAD_CONTACT_FLUIDS + spread_flags = DISEASE_SPREAD_BLOOD | DISEASE_SPREAD_CONTACT_SKIN | DISEASE_SPREAD_CONTACT_FLUIDS cure_text = "Mutadone" cures = list("mutadone") disease_flags = CAN_CARRY|CAN_RESIST|CURABLE @@ -11,7 +11,7 @@ var/datum/dna/original_dna = null var/transformed = 0 desc = "This disease transplants the genetic code of the initial vector into new hosts." - severity = VIRUS_SEVERITY_MEDIUM + severity = DISEASE_SEVERITY_MEDIUM /datum/disease/dnaspread/stage_act() diff --git a/code/datums/diseases/fake_gbs.dm b/code/datums/diseases/fake_gbs.dm index e62a8b491d..add60c73f1 100644 --- a/code/datums/diseases/fake_gbs.dm +++ b/code/datums/diseases/fake_gbs.dm @@ -2,13 +2,13 @@ name = "GBS" max_stages = 5 spread_text = "On contact" - spread_flags = VIRUS_SPREAD_BLOOD | VIRUS_SPREAD_CONTACT_SKIN | VIRUS_SPREAD_CONTACT_FLUIDS + spread_flags = DISEASE_SPREAD_BLOOD | DISEASE_SPREAD_CONTACT_SKIN | DISEASE_SPREAD_CONTACT_FLUIDS cure_text = "Synaptizine & Sulfur" cures = list("synaptizine","sulfur") agent = "Gravitokinetic Bipotential SADS-" viable_mobtypes = list(/mob/living/carbon/human, /mob/living/carbon/monkey) desc = "If left untreated death will occur." - severity = VIRUS_SEVERITY_BIOHAZARD + severity = DISEASE_SEVERITY_BIOHAZARD /datum/disease/fake_gbs/stage_act() ..() diff --git a/code/datums/diseases/flu.dm b/code/datums/diseases/flu.dm index 206b61fb35..e1943937ba 100644 --- a/code/datums/diseases/flu.dm +++ b/code/datums/diseases/flu.dm @@ -9,7 +9,7 @@ viable_mobtypes = list(/mob/living/carbon/human, /mob/living/carbon/monkey) permeability_mod = 0.75 desc = "If left untreated the subject will feel quite unwell." - severity = VIRUS_SEVERITY_MINOR + severity = DISEASE_SEVERITY_MINOR /datum/disease/flu/stage_act() ..() diff --git a/code/datums/diseases/fluspanish.dm b/code/datums/diseases/fluspanish.dm index 22787cc23a..9577ca43d0 100644 --- a/code/datums/diseases/fluspanish.dm +++ b/code/datums/diseases/fluspanish.dm @@ -9,7 +9,7 @@ viable_mobtypes = list(/mob/living/carbon/human) permeability_mod = 0.75 desc = "If left untreated the subject will burn to death for being a heretic." - severity = VIRUS_SEVERITY_DANGEROUS + severity = DISEASE_SEVERITY_DANGEROUS /datum/disease/fluspanish/stage_act() ..() diff --git a/code/datums/diseases/gbs.dm b/code/datums/diseases/gbs.dm index 6d77acd3ae..0487b1c815 100644 --- a/code/datums/diseases/gbs.dm +++ b/code/datums/diseases/gbs.dm @@ -2,7 +2,7 @@ name = "GBS" max_stages = 4 spread_text = "On contact" - spread_flags = VIRUS_SPREAD_BLOOD | VIRUS_SPREAD_CONTACT_SKIN | VIRUS_SPREAD_CONTACT_FLUIDS + spread_flags = DISEASE_SPREAD_BLOOD | DISEASE_SPREAD_CONTACT_SKIN | DISEASE_SPREAD_CONTACT_FLUIDS cure_text = "Synaptizine & Sulfur" cures = list("synaptizine","sulfur") cure_chance = 15//higher chance to cure, since two reagents are required @@ -10,7 +10,7 @@ viable_mobtypes = list(/mob/living/carbon/human) disease_flags = CAN_CARRY|CAN_RESIST|CURABLE permeability_mod = 1 - severity = VIRUS_SEVERITY_BIOHAZARD + severity = DISEASE_SEVERITY_BIOHAZARD /datum/disease/gbs/stage_act() ..() diff --git a/code/datums/diseases/heart_failure.dm b/code/datums/diseases/heart_failure.dm index 06687cc12d..a9adf39812 100644 --- a/code/datums/diseases/heart_failure.dm +++ b/code/datums/diseases/heart_failure.dm @@ -10,12 +10,17 @@ desc = "If left untreated the subject will die!" severity = "Dangerous!" disease_flags = CAN_CARRY|CAN_RESIST - spread_flags = VIRUS_SPREAD_NON_CONTAGIOUS + spread_flags = DISEASE_SPREAD_NON_CONTAGIOUS visibility_flags = HIDDEN_PANDEMIC required_organs = list(/obj/item/organ/heart) bypasses_immunity = TRUE // Immunity is based on not having an appendix; this isn't a virus var/sound = FALSE +/datum/disease/heart_failure/Copy() + var/datum/disease/heart_failure/D = ..() + D.sound = sound + return D + /datum/disease/heart_failure/stage_act() ..() var/obj/item/organ/heart/O = affected_mob.getorgan(/obj/item/organ/heart) diff --git a/code/datums/diseases/magnitis.dm b/code/datums/diseases/magnitis.dm index 91ce1ca71e..13959e9bda 100644 --- a/code/datums/diseases/magnitis.dm +++ b/code/datums/diseases/magnitis.dm @@ -9,7 +9,7 @@ disease_flags = CAN_CARRY|CAN_RESIST|CURABLE permeability_mod = 0.75 desc = "This disease disrupts the magnetic field of your body, making it act as if a powerful magnet. Injections of iron help stabilize the field." - severity = VIRUS_SEVERITY_MEDIUM + severity = DISEASE_SEVERITY_MEDIUM infectable_hosts = list(SPECIES_ORGANIC, SPECIES_ROBOTIC) process_dead = TRUE diff --git a/code/datums/diseases/parrotpossession.dm b/code/datums/diseases/parrotpossession.dm index 284c3bd7f2..4fe0dc21b0 100644 --- a/code/datums/diseases/parrotpossession.dm +++ b/code/datums/diseases/parrotpossession.dm @@ -2,7 +2,7 @@ name = "Parrot Possession" max_stages = 1 spread_text = "Paranormal" - spread_flags = VIRUS_SPREAD_SPECIAL + spread_flags = DISEASE_SPREAD_SPECIAL disease_flags = CURABLE cure_text = "Holy Water." cures = list("holywater") @@ -10,7 +10,7 @@ agent = "Avian Vengence" viable_mobtypes = list(/mob/living/carbon/human) desc = "Subject is possesed by the vengeful spirit of a parrot. Call the priest." - severity = VIRUS_SEVERITY_MEDIUM + severity = DISEASE_SEVERITY_MEDIUM infectable_hosts = list(SPECIES_ORGANIC, SPECIES_UNDEAD, SPECIES_INORGANIC, SPECIES_ROBOTIC) bypasses_immunity = TRUE //2spook var/mob/living/simple_animal/parrot/Poly/ghost/parrot diff --git a/code/datums/diseases/pierrot_throat.dm b/code/datums/diseases/pierrot_throat.dm index 89dce44536..8f13d2e2fa 100644 --- a/code/datums/diseases/pierrot_throat.dm +++ b/code/datums/diseases/pierrot_throat.dm @@ -9,7 +9,7 @@ viable_mobtypes = list(/mob/living/carbon/human) permeability_mod = 0.75 desc = "If left untreated the subject will probably drive others to insanity." - severity = VIRUS_SEVERITY_MEDIUM + severity = DISEASE_SEVERITY_MEDIUM /datum/disease/pierrot_throat/stage_act() ..() diff --git a/code/datums/diseases/retrovirus.dm b/code/datums/diseases/retrovirus.dm index ae5fa9655f..fe099e495b 100644 --- a/code/datums/diseases/retrovirus.dm +++ b/code/datums/diseases/retrovirus.dm @@ -2,20 +2,17 @@ name = "Retrovirus" max_stages = 4 spread_text = "Contact" - spread_flags = VIRUS_SPREAD_BLOOD | VIRUS_SPREAD_CONTACT_SKIN | VIRUS_SPREAD_CONTACT_FLUIDS + spread_flags = DISEASE_SPREAD_BLOOD | DISEASE_SPREAD_CONTACT_SKIN | DISEASE_SPREAD_CONTACT_FLUIDS cure_text = "Rest or an injection of mutadone" cure_chance = 6 agent = "" viable_mobtypes = list(/mob/living/carbon/human) desc = "A DNA-altering retrovirus that scrambles the structural and unique enzymes of a host constantly." - severity = VIRUS_SEVERITY_HARMFUL + severity = DISEASE_SEVERITY_HARMFUL permeability_mod = 0.4 stage_prob = 2 - var/SE - var/UI var/restcure = 0 - /datum/disease/dna_retrovirus/New() ..() agent = "Virus class [pick("A","B","C","D","E","F")][pick("A","B","C","D","E","F")]-[rand(50,300)]" @@ -24,6 +21,10 @@ else restcure = 1 +/datum/disease/dna_retrovirus/Copy() + var/datum/disease/dna_retrovirus/D = ..() + D.restcure = restcure + return D /datum/disease/dna_retrovirus/stage_act() ..() diff --git a/code/datums/diseases/rhumba_beat.dm b/code/datums/diseases/rhumba_beat.dm index 8217364fb5..1aee35741a 100644 --- a/code/datums/diseases/rhumba_beat.dm +++ b/code/datums/diseases/rhumba_beat.dm @@ -2,13 +2,13 @@ name = "The Rhumba Beat" max_stages = 5 spread_text = "On contact" - spread_flags = VIRUS_SPREAD_BLOOD | VIRUS_SPREAD_CONTACT_SKIN | VIRUS_SPREAD_CONTACT_FLUIDS + spread_flags = DISEASE_SPREAD_BLOOD | DISEASE_SPREAD_CONTACT_SKIN | DISEASE_SPREAD_CONTACT_FLUIDS cure_text = "Chick Chicky Boom!" cures = list("plasma") agent = "Unknown" viable_mobtypes = list(/mob/living/carbon/human) permeability_mod = 1 - severity = VIRUS_SEVERITY_BIOHAZARD + severity = DISEASE_SEVERITY_BIOHAZARD process_dead = TRUE /datum/disease/rhumba_beat/stage_act() diff --git a/code/datums/diseases/transformation.dm b/code/datums/diseases/transformation.dm index 17aebc4629..db88bd6777 100644 --- a/code/datums/diseases/transformation.dm +++ b/code/datums/diseases/transformation.dm @@ -2,11 +2,11 @@ name = "Transformation" max_stages = 5 spread_text = "Acute" - spread_flags = VIRUS_SPREAD_SPECIAL + spread_flags = DISEASE_SPREAD_SPECIAL cure_text = "A coder's love (theoretical)." agent = "Shenanigans" viable_mobtypes = list(/mob/living/carbon/human, /mob/living/carbon/monkey, /mob/living/carbon/alien) - severity = VIRUS_SEVERITY_BIOHAZARD + severity = DISEASE_SEVERITY_BIOHAZARD stage_prob = 10 visibility_flags = HIDDEN_SCANNER|HIDDEN_PANDEMIC disease_flags = CURABLE @@ -17,6 +17,16 @@ var/list/stage5 = list("Oh the humanity!") var/new_form = /mob/living/carbon/human +/datum/disease/transformation/Copy() + var/datum/disease/transformation/D = ..() + D.stage1 = stage1.Copy() + D.stage2 = stage2.Copy() + D.stage3 = stage3.Copy() + D.stage4 = stage4.Copy() + D.stage5 = stage5.Copy() + D.new_form = D.new_form + return D + /datum/disease/transformation/stage_act() ..() switch(stage) @@ -68,13 +78,13 @@ cure_text = "Death." cures = list("adminordrazine") spread_text = "Monkey Bites" - spread_flags = VIRUS_SPREAD_SPECIAL + spread_flags = DISEASE_SPREAD_SPECIAL viable_mobtypes = list(/mob/living/carbon/monkey, /mob/living/carbon/human) permeability_mod = 1 cure_chance = 1 disease_flags = CAN_CARRY|CAN_RESIST desc = "Monkeys with this disease will bite humans, causing humans to mutate into a monkey." - severity = VIRUS_SEVERITY_BIOHAZARD + severity = DISEASE_SEVERITY_BIOHAZARD stage_prob = 4 visibility_flags = 0 agent = "Kongey Vibrion M-909" @@ -131,7 +141,7 @@ cure_chance = 5 agent = "R2D2 Nanomachines" desc = "This disease, actually acute nanomachine infection, converts the victim into a cyborg." - severity = VIRUS_SEVERITY_BIOHAZARD + severity = DISEASE_SEVERITY_BIOHAZARD visibility_flags = 0 stage1 = null stage2 = list("Your joints feel stiff.", "Beep...boop..") @@ -163,7 +173,7 @@ cure_chance = 5 agent = "Rip-LEY Alien Microbes" desc = "This disease changes the victim into a xenomorph." - severity = VIRUS_SEVERITY_BIOHAZARD + severity = DISEASE_SEVERITY_BIOHAZARD visibility_flags = 0 stage1 = null stage2 = list("Your throat feels scratchy.", "Kill...") @@ -191,7 +201,7 @@ cure_chance = 80 agent = "Advanced Mutation Toxin" desc = "This highly concentrated extract converts anything into more of itself." - severity = VIRUS_SEVERITY_BIOHAZARD + severity = DISEASE_SEVERITY_BIOHAZARD visibility_flags = 0 stage1 = list("You don't feel very well.") stage2 = list("Your skin feels a little slimy.") @@ -219,7 +229,7 @@ cures = list("adminordrazine") agent = "Fell Doge Majicks" desc = "This disease transforms the victim into a corgi." - severity = VIRUS_SEVERITY_BIOHAZARD + severity = DISEASE_SEVERITY_BIOHAZARD visibility_flags = 0 stage1 = list("BARK.") stage2 = list("You feel the need to wear silly hats.") @@ -245,7 +255,7 @@ agent = "Gluttony's Blessing" desc = "A 'gift' from somewhere terrible." stage_prob = 20 - severity = VIRUS_SEVERITY_BIOHAZARD + severity = DISEASE_SEVERITY_BIOHAZARD visibility_flags = 0 stage1 = list("Your stomach rumbles.") stage2 = list("Your skin feels saggy.") diff --git a/code/datums/diseases/tuberculosis.dm b/code/datums/diseases/tuberculosis.dm index c8524fd038..e413891e75 100644 --- a/code/datums/diseases/tuberculosis.dm +++ b/code/datums/diseases/tuberculosis.dm @@ -10,7 +10,7 @@ cure_chance = 5//like hell are you getting out of hell desc = "A rare highly transmittable virulent virus. Few samples exist, rumoured to be carefully grown and cultured by clandestine bio-weapon specialists. Causes fever, blood vomiting, lung damage, weight loss, and fatigue." required_organs = list(/obj/item/organ/lungs) - severity = VIRUS_SEVERITY_BIOHAZARD + severity = DISEASE_SEVERITY_BIOHAZARD bypasses_immunity = TRUE // TB primarily impacts the lungs; it's also bacterial or fungal in nature; viral immunity should do nothing. /datum/disease/tuberculosis/stage_act() //it begins diff --git a/code/datums/diseases/wizarditis.dm b/code/datums/diseases/wizarditis.dm index 612418b1ca..cfc848000b 100644 --- a/code/datums/diseases/wizarditis.dm +++ b/code/datums/diseases/wizarditis.dm @@ -10,7 +10,7 @@ disease_flags = CAN_CARRY|CAN_RESIST|CURABLE permeability_mod = 0.75 desc = "Some speculate that this virus is the cause of the Space Wizard Federation's existence. Subjects affected show the signs of mental retardation, yelling obscure sentences or total gibberish. On late stages subjects sometime express the feelings of inner power, and, cite, 'the ability to control the forces of cosmos themselves!' A gulp of strong, manly spirits usually reverts them to normal, humanlike, condition." - severity = VIRUS_SEVERITY_HARMFUL + severity = DISEASE_SEVERITY_HARMFUL required_organs = list(/obj/item/bodypart/head) /* diff --git a/code/datums/hud.dm b/code/datums/hud.dm index 17632acba0..54b28deeee 100644 --- a/code/datums/hud.dm +++ b/code/datums/hud.dm @@ -11,6 +11,7 @@ GLOBAL_LIST_INIT(huds, list( DATA_HUD_DIAGNOSTIC_BASIC = new/datum/atom_hud/data/diagnostic/basic(), DATA_HUD_DIAGNOSTIC_ADVANCED = new/datum/atom_hud/data/diagnostic/advanced(), DATA_HUD_ABDUCTOR = new/datum/atom_hud/abductor(), + DATA_HUD_SENTIENT_DISEASE = new/datum/atom_hud/sentient_disease(), ANTAG_HUD_CULT = new/datum/atom_hud/antag(), ANTAG_HUD_REV = new/datum/atom_hud/antag(), ANTAG_HUD_OPS = new/datum/atom_hud/antag(), diff --git a/code/game/data_huds.dm b/code/game/data_huds.dm index 8024322037..24fa11eda0 100644 --- a/code/game/data_huds.dm +++ b/code/game/data_huds.dm @@ -63,6 +63,9 @@ /datum/atom_hud/abductor hud_icons = list(GLAND_HUD) +/datum/atom_hud/sentient_disease + hud_icons = list(SENTIENT_DISEASE_HUD) + /* MED/SEC/DIAG HUD HOOKS */ /* @@ -78,7 +81,7 @@ //called when a carbon changes virus /mob/living/carbon/proc/check_virus() var/threat - for(var/thing in viruses) + for(var/thing in diseases) var/datum/disease/D = thing if(!(D.visibility_flags & HIDDEN_SCANNER)) if(!threat || D.severity > threat) //a buffing virus gets an icon @@ -175,19 +178,19 @@ holder.icon_state = "huddead" else switch(virus_threat) - if(VIRUS_SEVERITY_BIOHAZARD) + if(DISEASE_SEVERITY_BIOHAZARD) holder.icon_state = "hudill5" - if(VIRUS_SEVERITY_DANGEROUS) + if(DISEASE_SEVERITY_DANGEROUS) holder.icon_state = "hudill4" - if(VIRUS_SEVERITY_HARMFUL) + if(DISEASE_SEVERITY_HARMFUL) holder.icon_state = "hudill3" - if(VIRUS_SEVERITY_MEDIUM) + if(DISEASE_SEVERITY_MEDIUM) holder.icon_state = "hudill2" - if(VIRUS_SEVERITY_MINOR) + if(DISEASE_SEVERITY_MINOR) holder.icon_state = "hudill1" - if(VIRUS_SEVERITY_NONTHREAT) + if(DISEASE_SEVERITY_NONTHREAT) holder.icon_state = "hudill0" - if(VIRUS_SEVERITY_POSITIVE) + if(DISEASE_SEVERITY_POSITIVE) holder.icon_state = "hudbuff" if(null) holder.icon_state = "hudhealthy" diff --git a/code/game/objects/effects/decals/cleanable.dm b/code/game/objects/effects/decals/cleanable.dm index f1c18f50a6..f23f13cca4 100644 --- a/code/game/objects/effects/decals/cleanable.dm +++ b/code/game/objects/effects/decals/cleanable.dm @@ -19,7 +19,7 @@ if(LAZYLEN(diseases)) var/list/datum/disease/diseases_to_add = list() for(var/datum/disease/D in diseases) - if(D.spread_flags & VIRUS_SPREAD_CONTACT_FLUIDS) + if(D.spread_flags & DISEASE_SPREAD_CONTACT_FLUIDS) diseases_to_add += D if(LAZYLEN(diseases_to_add)) AddComponent(/datum/component/infective, diseases_to_add) diff --git a/code/game/objects/items/devices/scanners.dm b/code/game/objects/items/devices/scanners.dm index 05264aaa5a..6488b4e001 100644 --- a/code/game/objects/items/devices/scanners.dm +++ b/code/game/objects/items/devices/scanners.dm @@ -262,7 +262,7 @@ GAS ANALYZER if(tdelta < (DEFIB_TIME_LIMIT * 10)) to_chat(user, "Subject died [DisplayTimeText(tdelta)] ago, defibrillation may be possible!") - for(var/thing in M.viruses) + for(var/thing in M.diseases) var/datum/disease/D = thing if(!(D.visibility_flags & HIDDEN_SCANNER)) to_chat(user, "Warning: [D.form] detected\nName: [D.name].\nType: [D.spread_text].\nStage: [D.stage]/[D.max_stages].\nPossible Cure: [D.cure_text]") diff --git a/code/modules/admin/admin_verbs.dm b/code/modules/admin/admin_verbs.dm index 51cfdbe529..f38bfdd84d 100644 --- a/code/modules/admin/admin_verbs.dm +++ b/code/modules/admin/admin_verbs.dm @@ -589,14 +589,17 @@ GLOBAL_LIST_INIT(admin_verbs_hideable, list( message_admins("[key_name_admin(usr)] removed the spell [S] from [key_name(T)].") SSblackbox.record_feedback("tally", "admin_verb", 1, "Remove Spell") //If you are copy-pasting this, ensure the 2nd parameter is unique to the new proc! -/client/proc/give_disease(mob/T in GLOB.mob_list) +/client/proc/give_disease(mob/living/T in GLOB.mob_living_list) set category = "Fun" set name = "Give Disease" set desc = "Gives a Disease to a mob." + if(!istype(T)) + to_chat(src, "You can only give a disease to a mob of type /mob/living.") + return var/datum/disease/D = input("Choose the disease to give to that guy", "ACHOO") as null|anything in SSdisease.diseases if(!D) return - T.ForceContractDisease(new D) + T.ForceContractDisease(new D, FALSE, TRUE) SSblackbox.record_feedback("tally", "admin_verb", 1, "Give Disease") //If you are copy-pasting this, ensure the 2nd parameter is unique to the new proc! log_admin("[key_name(usr)] gave [key_name(T)] the disease [D].") message_admins("[key_name_admin(usr)] gave [key_name(T)] the disease [D].") diff --git a/code/modules/antagonists/abductor/equipment/gland.dm b/code/modules/antagonists/abductor/equipment/gland.dm index faa6b6c1e3..3db66dee57 100644 --- a/code/modules/antagonists/abductor/equipment/gland.dm +++ b/code/modules/antagonists/abductor/equipment/gland.dm @@ -194,15 +194,12 @@ to_chat(owner, "You feel sick.") var/datum/disease/advance/A = random_virus(pick(2,6),6) A.carrier = TRUE - owner.viruses += A - A.affected_mob = owner - owner.med_hud_set_status() + owner.ForceContractDisease(A, FALSE, TRUE) /obj/item/organ/heart/gland/viral/proc/random_virus(max_symptoms, max_level) - if(max_symptoms > SYMPTOM_LIMIT) - max_symptoms = SYMPTOM_LIMIT - var/datum/disease/advance/A = new(FALSE, null) - A.symptoms = list() + if(max_symptoms > VIRUS_SYMPTOM_LIMIT) + max_symptoms = VIRUS_SYMPTOM_LIMIT + var/datum/disease/advance/A = new /datum/disease/advance() var/list/datum/symptom/possible_symptoms = list() for(var/symptom in subtypesof(/datum/symptom)) var/datum/symptom/S = symptom diff --git a/code/modules/antagonists/blob/blob/overmind.dm b/code/modules/antagonists/blob/blob/overmind.dm index 6c852684b2..9d31852d28 100644 --- a/code/modules/antagonists/blob/blob/overmind.dm +++ b/code/modules/antagonists/blob/blob/overmind.dm @@ -20,6 +20,7 @@ GLOBAL_LIST_EMPTY(blob_nodes) pass_flags = PASSBLOB faction = list(ROLE_BLOB) lighting_alpha = LIGHTING_PLANE_ALPHA_MOSTLY_INVISIBLE + call_life = TRUE var/obj/structure/blob/core/blob_core = null // The blob overmind's core var/blob_points = 0 var/max_blob_points = 100 @@ -67,7 +68,7 @@ GLOBAL_LIST_EMPTY(blob_nodes) if(!T) CRASH("No blobspawnpoints and blob spawned in nullspace.") forceMove(T) - + /mob/camera/blob/proc/is_valid_turf(turf/T) var/area/A = get_area(T) if((A && !A.blob_allowed) || !T || !is_station_level(T.z) || isspaceturf(T)) @@ -217,9 +218,6 @@ GLOBAL_LIST_EMPTY(blob_nodes) var/link = FOLLOW_LINK(M, src) to_chat(M, "[link] [rendered]") -/mob/camera/blob/emote(act,m_type=1,message = null) - return - /mob/camera/blob/blob_act(obj/structure/blob/B) return diff --git a/code/modules/antagonists/changeling/powers/panacea.dm b/code/modules/antagonists/changeling/powers/panacea.dm index 93a05834fe..cb5aba6c99 100644 --- a/code/modules/antagonists/changeling/powers/panacea.dm +++ b/code/modules/antagonists/changeling/powers/panacea.dm @@ -30,9 +30,11 @@ user.reagents.add_reagent("antihol", 10) user.reagents.add_reagent("mannitol", 25) - for(var/thing in user.viruses) - var/datum/disease/D = thing - if(D.severity == VIRUS_SEVERITY_POSITIVE) - continue - D.cure() + if(isliving(user)) + var/mob/living/L = user + for(var/thing in L.diseases) + var/datum/disease/D = thing + if(D.severity == DISEASE_SEVERITY_POSITIVE) + continue + D.cure() return TRUE diff --git a/code/modules/antagonists/disease/disease_abilities.dm b/code/modules/antagonists/disease/disease_abilities.dm new file mode 100644 index 0000000000..8172d58d8e --- /dev/null +++ b/code/modules/antagonists/disease/disease_abilities.dm @@ -0,0 +1,347 @@ +/* +Abilities that can be purchased by disease mobs. Most are just passive symptoms that will be +added to their disease, but some are active abilites that affect only the target the overmind +is currently following. +*/ + +GLOBAL_LIST_INIT(disease_ability_singletons, list( + new /datum/disease_ability/action/cough(), + new /datum/disease_ability/action/sneeze(), + new /datum/disease_ability/symptom/cough(), + new /datum/disease_ability/symptom/sneeze(),\ + new /datum/disease_ability/symptom/hallucigen(), + new /datum/disease_ability/symptom/choking(), + new /datum/disease_ability/symptom/confusion(), + new /datum/disease_ability/symptom/youth(), + new /datum/disease_ability/symptom/vomit(), + new /datum/disease_ability/symptom/voice_change(), + new /datum/disease_ability/symptom/visionloss(), + new /datum/disease_ability/symptom/viraladaptation(), + new /datum/disease_ability/symptom/vitiligo(), + new /datum/disease_ability/symptom/sensory_restoration(), + new /datum/disease_ability/symptom/itching(), + new /datum/disease_ability/symptom/weight_loss(), + new /datum/disease_ability/symptom/metabolism_heal(), + new /datum/disease_ability/symptom/coma_heal() + )) + +/datum/disease_ability + var/name + var/cost = 0 + var/required_total_points = 0 + var/start_with = FALSE + var/short_desc = "" + var/long_desc = "" + var/stat_block = "" + var/threshold_block = "" + var/category = "" + + var/list/symptoms + var/list/actions + +/datum/disease_ability/New() + ..() + if(symptoms) + var/stealth = 0 + var/resistance = 0 + var/stage_speed = 0 + var/transmittable = 0 + for(var/T in symptoms) + var/datum/symptom/S = T + stealth += initial(S.stealth) + resistance += initial(S.resistance) + stage_speed += initial(S.stage_speed) + transmittable += initial(S.transmittable) + threshold_block += "

[initial(S.threshold_desc)]" + stat_block = "Resistance: [resistance]
Stealth: [stealth]
Stage Speed: [stage_speed]
Transmittability: [transmittable]

" + +/datum/disease_ability/proc/CanBuy(mob/camera/disease/D) + if(world.time < D.next_adaptation_time) + return FALSE + if(!D.unpurchased_abilities[src]) + return FALSE + return (D.points >= cost) && (D.total_points >= required_total_points) + +/datum/disease_ability/proc/Buy(mob/camera/disease/D, silent = FALSE, trigger_cooldown = TRUE) + if(!silent) + to_chat(D, "Purchased [name].") + D.points -= cost + D.unpurchased_abilities -= src + if(trigger_cooldown) + D.adapt_cooldown() + D.purchased_abilities[src] = TRUE + for(var/V in (D.disease_instances+D.disease_template)) + var/datum/disease/advance/sentient_disease/SD = V + if(symptoms) + for(var/T in symptoms) + var/datum/symptom/S = new T() + SD.symptoms += S + if(SD.processing) + S.Start(SD) + SD.Refresh() + for(var/T in actions) + var/datum/action/A = new T() + A.Grant(D) + + +/datum/disease_ability/proc/CanRefund(mob/camera/disease/D) + if(world.time < D.next_adaptation_time) + return FALSE + return D.purchased_abilities[src] + +/datum/disease_ability/proc/Refund(mob/camera/disease/D, silent = FALSE, trigger_cooldown = TRUE) + if(!silent) + to_chat(D, "Refunded [name].") + D.points += cost + D.unpurchased_abilities[src] = TRUE + if(trigger_cooldown) + D.adapt_cooldown() + D.purchased_abilities -= src + for(var/V in (D.disease_instances+D.disease_template)) + var/datum/disease/advance/sentient_disease/SD = V + if(symptoms) + for(var/T in symptoms) + var/datum/symptom/S = locate(T) in SD.symptoms + if(S) + SD.symptoms -= S + if(SD.processing) + S.End(SD) + qdel(S) + SD.Refresh() + for(var/T in actions) + var/datum/action/A = locate(T) in D.actions + qdel(A) + +//these sybtypes are for conveniently separating the different categories, they have no unique code. + +/datum/disease_ability/action + category = "Active" + +/datum/disease_ability/symptom + category = "Symptom" + +//active abilities and their associated actions + +/datum/disease_ability/action/cough + name = "Voluntary Coughing" + actions = list(/datum/action/cooldown/disease_cough) + cost = 0 + required_total_points = 0 + start_with = TRUE + short_desc = "Force the host you are following to cough, spreading your infection to those nearby." + long_desc = "Force the host you are following to cough with extra force, spreading your infection to those within two meters of your host even if your transmitability is low.
Cooldown: 10 seconds" + + +/datum/action/cooldown/disease_cough + name = "Cough" + icon_icon = 'icons/mob/actions/actions_minor_antag.dmi' + button_icon_state = "cough" + desc = "Force the host you are following to cough with extra force, spreading your infection to those within two meters of your host even if your transmitability is low.
Cooldown: 10 seconds" + cooldown_time = 100 + +/datum/action/cooldown/disease_cough/Trigger() + if(!..()) + return FALSE + var/mob/camera/disease/D = owner + var/mob/living/L = D.following_host + if(!L) + return FALSE + if(L.stat != CONSCIOUS) + to_chat(D, "Your host must be concious to cough.") + return FALSE + to_chat(D, "You force [L.real_name] to cough.") + L.emote("cough") + var/datum/disease/advance/sentient_disease/SD = D.hosts[L] + SD.spread(2) + StartCooldown() + return TRUE + + +/datum/disease_ability/action/sneeze + name = "Voluntary Sneezing" + actions = list(/datum/action/cooldown/disease_sneeze) + cost = 2 + required_total_points = 3 + short_desc = "Force the host you are following to sneeze, spreading your infection to those in front of them." + long_desc = "Force the host you are following to sneeze with extra force, spreading your infection to any victims in a 4 meter cone in front of your host.
Cooldown: 20 seconds" + + +/datum/action/cooldown/disease_sneeze + name = "Sneeze" + icon_icon = 'icons/mob/actions/actions_minor_antag.dmi' + button_icon_state = "sneeze" + desc = "Force the host you are following to sneeze with extra force, spreading your infection to any victims in a 4 meter cone in front of your host even if your transmitability is low.
Cooldown: 20 seconds" + cooldown_time = 200 + +/datum/action/cooldown/disease_sneeze/Trigger() + if(!..()) + return FALSE + var/mob/camera/disease/D = owner + var/mob/living/L = D.following_host + if(!L) + return FALSE + if(L.stat != CONSCIOUS) + to_chat(D, "Your host must be concious to sneeze.") + return FALSE + to_chat(D, "You force [L.real_name] to sneeze.") + L.emote("sneeze") + var/datum/disease/advance/sentient_disease/SD = D.hosts[L] + + for(var/mob/living/M in oview(4, SD.affected_mob)) + if(is_A_facing_B(SD.affected_mob, M) && disease_air_spread_walk(get_turf(SD.affected_mob), get_turf(M))) + M.AirborneContractDisease(SD, TRUE) + + StartCooldown() + return TRUE + +//passive symptom abilities + +/datum/disease_ability/symptom/cough + name = "Involuntary Coughing" + symptoms = list(/datum/symptom/cough) + cost = 2 + required_total_points = 4 + short_desc = "Cause victims to cough intermittently." + long_desc = "Cause victims to cough intermittently, spreading your infection if your transmitability is high." + +/datum/disease_ability/symptom/sneeze + name = "Involuntary Sneezing" + symptoms = list(/datum/symptom/sneeze) + cost = 2 + required_total_points = 4 + short_desc = "Cause victims to sneeze intermittently." + long_desc = "Cause victims to sneeze intermittently, spreading your infection and also increasing transmitability and resistance, at the cost of stealth." + +/datum/disease_ability/symptom/beard + //I don't think I need to justify the fact that this is the best symptom + name = "Beard Growth" + symptoms = list(/datum/symptom/beard) + cost = 1 + required_total_points = 8 + short_desc = "Cause all victims to grow a luscious beard." + long_desc = "Cause all victims to grow a luscious beard. Decreases stats slightly. Ineffective against Santa Claus." + +/datum/disease_ability/symptom/hallucigen + name = "Hallucinations" + symptoms = list(/datum/symptom/hallucigen) + cost = 4 + required_total_points = 8 + short_desc = "Cause victims to hallucinate." + long_desc = "Cause victims to hallucinate. Decreases stats, especially resistance." + + +/datum/disease_ability/symptom/choking + name = "Choking" + symptoms = list(/datum/symptom/choking) + cost = 4 + required_total_points = 8 + short_desc = "Cause victims to choke." + long_desc = "Cause victims to choke, threatening asphyxiation. Decreases stats, especially transmittability." + + +/datum/disease_ability/symptom/confusion + name = "Confusion" + symptoms = list(/datum/symptom/confusion) + cost = 4 + required_total_points = 8 + short_desc = "Cause victims to become confused." + long_desc = "Cause victims to become confused intermittently." + + +/datum/disease_ability/symptom/youth + name = "Eternal Youth" + symptoms = list(/datum/symptom/youth) + cost = 4 + required_total_points = 8 + short_desc = "Cause victims to become eternally young." + long_desc = "Cause victims to become eternally young. Provides boosts to all stats except transmittability." + + +/datum/disease_ability/symptom/vomit + name = "Vomiting" + symptoms = list(/datum/symptom/vomit) + cost = 4 + required_total_points = 8 + short_desc = "Cause victims to vomit." + long_desc = "Cause victims to vomit. Slightly increases transmittability. Vomiting also also causes the victims to lose nutrition and removes some toxin damage." + + +/datum/disease_ability/symptom/voice_change + name = "Voice Changing" + symptoms = list(/datum/symptom/voice_change) + cost = 4 + required_total_points = 8 + short_desc = "Change the voice of victims." + long_desc = "Change the voice of victims, causing confusion in communications." + + +/datum/disease_ability/symptom/visionloss + name = "Vision Loss" + symptoms = list(/datum/symptom/visionloss) + cost = 4 + required_total_points = 8 + short_desc = "Damage the eyes of victims, eventually causing blindness." + long_desc = "Damage the eyes of victims, eventually causing blindness. Decreases all stats." + + +/datum/disease_ability/symptom/viraladaptation + name = "Self-Adaptation" + symptoms = list(/datum/symptom/viraladaptation) + cost = 4 + required_total_points = 8 + short_desc = "Cause your infection to become more resistant to detection and eradication." + long_desc = "Cause your infection to mimic the function of normal body cells, becoming much harder to spot and to eradicate, but reducing its speed." + + +/datum/disease_ability/symptom/vitiligo + name = "Skin Paleness" + symptoms = list(/datum/symptom/vitiligo) + cost = 1 + required_total_points = 8 + short_desc = "Cause victims to become pale." + long_desc = "Cause victims to become pale. Decreases all stats." + + +/datum/disease_ability/symptom/sensory_restoration + name = "Sensory Restoration" + symptoms = list(/datum/symptom/sensory_restoration) + cost = 4 + required_total_points = 8 + short_desc = "Regenerate eye and ear damage of victims." + long_desc = "Regenerate eye and ear damage of victims." + + +/datum/disease_ability/symptom/itching + name = "Itching" + symptoms = list(/datum/symptom/itching) + cost = 4 + required_total_points = 8 + short_desc = "Cause victims to itch." + long_desc = "Cause victims to itch, increasing all stats except stealth." + + +/datum/disease_ability/symptom/weight_loss + name = "Weight Loss" + symptoms = list(/datum/symptom/weight_loss) + cost = 4 + required_total_points = 8 + short_desc = "Cause victims to lose weight." + long_desc = "Cause victims to lose weight, and make it almost immpossible for them to gain nutrition from food. Reduced nutrition allows your infection to spread more easily from hosts, especially by sneezing." + + +/datum/disease_ability/symptom/metabolism_heal + name = "Metabolic Boost" + symptoms = list(/datum/symptom/heal/metabolism) + cost = 4 + required_total_points = 16 + short_desc = "Increase the metabolism of victims, causing them to process chemicals and grow hungry faster." + long_desc = "Increase the metabolism of victims, causing them to process chemicals twice as fast and grow hungry more quickly." + + +/datum/disease_ability/symptom/coma_heal + name = "Regenerative Coma" + symptoms = list(/datum/symptom/heal/coma) + cost = 8 + required_total_points = 16 + short_desc = "Cause victims to fall into a healing coma when hurt." + long_desc = "Cause victims to fall into a healing coma when hurt." diff --git a/code/modules/antagonists/disease/disease_datum.dm b/code/modules/antagonists/disease/disease_datum.dm new file mode 100644 index 0000000000..0589b0c595 --- /dev/null +++ b/code/modules/antagonists/disease/disease_datum.dm @@ -0,0 +1,100 @@ +/datum/antagonist/disease + name = "Sentient Disease" + roundend_category = "diseases" + antagpanel_category = "Disease" + var/disease_name = "" + +/datum/antagonist/disease/on_gain() + owner.special_role = "Sentient Disease" + owner.assigned_role = "Sentient Disease" + var/datum/objective/O = new /datum/objective/disease_infect() + O.owner = owner + objectives += O + owner.objectives += O + + O = new /datum/objective/disease_infect_centcom() + O.owner = owner + objectives += O + owner.objectives += O + + . = ..() + +/datum/antagonist/disease/greet() + to_chat(owner.current, "You are the [owner.special_role]!") + to_chat(owner.current, "Infect members of the crew to gain adaptation points, and spread your infection further.") + owner.announce_objectives() + +/datum/antagonist/disease/apply_innate_effects(mob/living/mob_override) + if(!istype(owner.current, /mob/camera/disease)) + var/turf/T = get_turf(owner.current) + T = T ? T : locate(1, 1, 1) + var/mob/camera/disease/D = new /mob/camera/disease(T) + owner.transfer_to(D) + +/datum/antagonist/disease/admin_add(datum/mind/new_owner,mob/admin) + ..() + var/mob/camera/disease/D = new_owner.current + D.infect_patient_zero() + D.pick_name() + +/datum/antagonist/disease/roundend_report() + var/list/result = list() + + result += "Disease name: [disease_name]" + result += printplayer(owner) + + var/win = TRUE + var/objectives_text = "" + var/count = 1 + for(var/datum/objective/objective in objectives) + if(objective.check_completion()) + objectives_text += "
Objective #[count]: [objective.explanation_text] Success!" + else + objectives_text += "
Objective #[count]: [objective.explanation_text] Fail." + win = FALSE + count++ + + result += objectives_text + + var/special_role_text = lowertext(name) + + if(win) + result += "The [special_role_text] was successful!" + else + result += "The [special_role_text] has failed!" + + if(istype(owner.current, /mob/camera/disease)) + var/mob/camera/disease/D = owner.current + result += "[disease_name] completed the round with [D.hosts.len] infected hosts, and reached a maximum of [D.total_points] concurrent infections." + result += "[disease_name] completed the round with the following adaptations:" + var/list/adaptations = list() + for(var/V in D.purchased_abilities) + var/datum/disease_ability/A = V + adaptations += A.name + result += adaptations.Join(", ") + + return result.Join("
") + + +/datum/objective/disease_infect + explanation_text = "Survive and infect as many people as possible." + +/datum/objective/disease_infect/check_completion() + var/mob/camera/disease/D = owner.current + if(istype(D) && D.hosts.len) //theoretically it should not exist if it has no hosts, but better safe than sorry. + return TRUE + return FALSE + + +/datum/objective/disease_infect_centcom + explanation_text = "Ensure that at least one infected host escapes on the shuttle or an escape pod." + +/datum/objective/disease_infect_centcom/check_completion() + var/mob/camera/disease/D = owner.current + if(!istype(D)) + return FALSE + for(var/V in D.hosts) + var/mob/living/L = V + if(L.onCentCom() || L.onSyndieBase()) + return TRUE + return FALSE diff --git a/code/modules/antagonists/disease/disease_disease.dm b/code/modules/antagonists/disease/disease_disease.dm new file mode 100644 index 0000000000..8ee36e8829 --- /dev/null +++ b/code/modules/antagonists/disease/disease_disease.dm @@ -0,0 +1,59 @@ +/datum/disease/advance/sentient_disease + form = "Virus" + name = "Sentient Virus" + desc = "An apparently sentient virus, extremely adaptable and resistant to outside sources of mutation." + viable_mobtypes = list(/mob/living/carbon/human) + mutable = FALSE + var/mob/camera/disease/overmind + +/datum/disease/advance/sentient_disease/New() + ..() + GLOB.sentient_disease_instances += src + +/datum/disease/advance/sentient_disease/Destroy() + . = ..() + GLOB.sentient_disease_instances -= src + +/datum/disease/advance/sentient_disease/remove_disease() + if(overmind) + overmind.remove_infection(src) + ..() + +/datum/disease/advance/sentient_disease/infect(var/mob/living/infectee, make_copy = TRUE) + if(make_copy && overmind && (overmind.disease_template != src)) + overmind.disease_template.infect(infectee, TRUE) //get an updated version of the virus + else + ..() + + +/datum/disease/advance/sentient_disease/IsSame(datum/disease/D) + if(istype(src, D.type)) + var/datum/disease/advance/sentient_disease/V = D + if(V.overmind == overmind) + return TRUE + return FALSE + + +/datum/disease/advance/sentient_disease/Copy() + var/datum/disease/advance/sentient_disease/D = ..() + D.overmind = overmind + return D + +/datum/disease/advance/sentient_disease/after_add() + if(overmind) + overmind.add_infection(src) + + +/datum/disease/advance/sentient_disease/GetDiseaseID() + return "[type]|[overmind ? overmind.tag : null]" + +/datum/disease/advance/sentient_disease/GenerateCure() + if(cures.len) + return + var/list/not_used = advance_cures.Copy() + cures = list(pick_n_take(not_used), pick_n_take(not_used)) + + // Get the cure name from the cure_id + var/datum/reagent/D1 = GLOB.chemical_reagents_list[cures[1]] + var/datum/reagent/D2 = GLOB.chemical_reagents_list[cures[2]] + cure_text = "[D1.name] and [D2.name]" diff --git a/code/modules/antagonists/disease/disease_event.dm b/code/modules/antagonists/disease/disease_event.dm new file mode 100644 index 0000000000..ad9d07e95b --- /dev/null +++ b/code/modules/antagonists/disease/disease_event.dm @@ -0,0 +1,30 @@ + +/datum/round_event_control/sentient_disease + name = "Spawn Sentient Disease" + typepath = /datum/round_event/ghost_role/sentient_disease + weight = 7 + max_occurrences = 1 + min_players = 5 + + +/datum/round_event/ghost_role/sentient_disease + role_name = "sentient disease" + +/datum/round_event/ghost_role/sentient_disease/spawn_role() + var/list/candidates = get_candidates(ROLE_ALIEN, null, ROLE_ALIEN) + if(!candidates.len) + return NOT_ENOUGH_PLAYERS + + var/mob/dead/observer/selected = pick_n_take(candidates) + + var/mob/camera/disease/virus = new /mob/camera/disease(locate(1, 1, 1)) + if(!virus.infect_patient_zero()) + message_admins("Event attempted to spawn a sentient disease, but infection of patient zero failed.") + qdel(virus) + return WAITING_FOR_SOMETHING + virus.key = selected.key + INVOKE_ASYNC(virus, /mob/camera/disease/proc/pick_name) + message_admins("[key_name_admin(virus)] has been made into a sentient disease by an event.") + log_game("[key_name(virus)] was spawned as a sentient disease by an event.") + spawned_mobs += virus + return SUCCESSFUL_SPAWN diff --git a/code/modules/antagonists/disease/disease_mob.dm b/code/modules/antagonists/disease/disease_mob.dm new file mode 100644 index 0000000000..d14d34ef75 --- /dev/null +++ b/code/modules/antagonists/disease/disease_mob.dm @@ -0,0 +1,318 @@ +/* +A mob of type /mob/camera/disease is an overmind coordinating at least one instance of /datum/disease/advance/sentient_disease +that has infected a host. All instances in a host will be synchronized with the stats of the overmind's disease_template. Any +samples outside of a host will retain the stats they had when they left the host, but infecting a new host will cause +the new instance inside the host to be updated to the template's stats. +*/ + +/mob/camera/disease + name = "" + real_name = "" + desc = "" + icon = 'icons/mob/blob.dmi' + icon_state = "marker" + mouse_opacity = MOUSE_OPACITY_ICON + move_on_shuttle = 1 + see_in_dark = 8 + invisibility = INVISIBILITY_OBSERVER + layer = BELOW_MOB_LAYER + lighting_alpha = LIGHTING_PLANE_ALPHA_MOSTLY_INVISIBLE + sight = SEE_SELF + initial_language_holder = /datum/language_holder/empty + + var/datum/action/innate/disease_adapt/adaptation_menu_action + var/datum/disease_ability/examining_ability + var/datum/browser/browser + var/browser_open = FALSE + + var/mob/living/following_host + var/datum/component/redirect/move_listener + var/list/disease_instances + var/list/hosts //this list is associative, affected_mob -> disease_instance + var/datum/disease/advance/sentient_disease/disease_template + + var/total_points = 0 + var/points = 0 + + var/last_move_tick = 0 + var/move_delay = 1 + + var/next_adaptation_time = 0 + var/adaptation_cooldown = 1200 + + var/list/purchased_abilities + var/list/unpurchased_abilities + +/mob/camera/disease/Initialize(mapload) + .= ..() + adaptation_menu_action = new /datum/action/innate/disease_adapt() + adaptation_menu_action.Grant(src) + + disease_instances = list() + hosts = list() + + purchased_abilities = list() + unpurchased_abilities = list() + for(var/V in GLOB.disease_ability_singletons) + unpurchased_abilities[V] = TRUE + var/datum/disease_ability/A = V + if(A.start_with && A.CanBuy(src)) + A.Buy(src, TRUE, FALSE) + + disease_template = new /datum/disease/advance/sentient_disease() + disease_template.overmind = src + qdel(SSdisease.archive_diseases[disease_template.GetDiseaseID()]) + SSdisease.archive_diseases[disease_template.GetDiseaseID()] = disease_template //important for stuff that uses disease IDs + + var/datum/atom_hud/my_hud = GLOB.huds[DATA_HUD_SENTIENT_DISEASE] + my_hud.add_hud_to(src) + + browser = new /datum/browser(src, "disease_menu", "Adaptation Menu", 1000, 770, src) + +/mob/camera/disease/Destroy() + . = ..() + for(var/V in GLOB.sentient_disease_instances) + var/datum/disease/advance/sentient_disease/S = V + if(S.overmind == src) + S.overmind = null + +/mob/camera/disease/Stat() + ..() + if(statpanel("Status")) + stat("Adaptation Points: [points]/[total_points]") + stat("Hosts: [disease_instances.len]") + var/adapt_ready = next_adaptation_time - world.time + if(adapt_ready > 0) + stat("Adaptation Ready: [round(adapt_ready/10, 0.1)]s") + +/mob/camera/disease/say(message) + return + +/mob/camera/disease/Move(NewLoc, Dir = 0) + if(world.time > (last_move_tick + move_delay)) + follow_next(Dir & NORTHWEST) + last_move_tick = world.time + +/mob/camera/disease/mind_initialize() + . = ..() + if(!mind.has_antag_datum(/datum/antagonist/disease)) + mind.add_antag_datum(/datum/antagonist/disease) + +/mob/camera/disease/proc/pick_name() + var/static/list/taken_names + if(!taken_names) + taken_names = list("Unknown" = TRUE) + for(var/T in (subtypesof(/datum/disease) - /datum/disease/advance)) + var/datum/disease/D = T + taken_names[initial(D.name)] = TRUE + var/set_name + while(!set_name) + var/input = stripped_input(src, "Select a name for your disease", "Select Name", "", MAX_NAME_LEN) + if(!input) + set_name = "Sentient Virus" + break + if(taken_names[input]) + to_chat(src, "You cannot use the name of such a well-known disease!") + else + set_name = input + real_name = "[set_name] (Sentient Disease)" + name = "[set_name] (Sentient Disease)" + disease_template.AssignName(set_name) + var/datum/antagonist/disease/A = mind.has_antag_datum(/datum/antagonist/disease) + if(A) + A.disease_name = set_name + +/mob/camera/disease/proc/infect_patient_zero() + var/list/possible_hosts = list() + var/datum/disease/advance/sentient_disease/V = disease_template.Copy() + for(var/mob/living/carbon/human/H in GLOB.carbon_list) + if((H.stat != DEAD) && H.CanContractDisease(V)) + possible_hosts += H + if(!possible_hosts.len) + return FALSE + var/mob/living/carbon/human/H = pick(possible_hosts) + if(H.ForceContractDisease(V, FALSE, TRUE)) + return TRUE + return FALSE + +/mob/camera/disease/proc/force_infect(mob/living/L) + var/datum/disease/advance/sentient_disease/V = disease_template.Copy() + return L.ForceContractDisease(V, FALSE, TRUE) + +/mob/camera/disease/proc/add_infection(datum/disease/advance/sentient_disease/V) + disease_instances += V + hosts[V.affected_mob] = V + total_points = max(total_points, disease_instances.len) + points += 1 + + var/image/holder = V.affected_mob.hud_list[SENTIENT_DISEASE_HUD] + var/mutable_appearance/MA = new /mutable_appearance(holder) + MA.icon_state = "virus_infected" + MA.layer = BELOW_MOB_LAYER + MA.color = COLOR_GREEN_GRAY + MA.alpha = 200 + holder.appearance = MA + var/datum/atom_hud/my_hud = GLOB.huds[DATA_HUD_SENTIENT_DISEASE] + my_hud.add_to_hud(V.affected_mob) + + to_chat(src, "A new host, [V.affected_mob.real_name], has been infected.") + + if(!following_host) + set_following(V.affected_mob) + refresh_adaptation_menu() + +/mob/camera/disease/proc/remove_infection(datum/disease/advance/sentient_disease/V) + if(QDELETED(src)) + disease_instances -= V + hosts -= V.affected_mob + else + points -= 1 + to_chat(src, "One of your hosts, [V.affected_mob.real_name], has been purged of your infection.") + + var/datum/atom_hud/my_hud = GLOB.huds[DATA_HUD_SENTIENT_DISEASE] + my_hud.remove_from_hud(V.affected_mob) + + if(following_host == V.affected_mob) + follow_next() + + disease_instances -= V + hosts -= V.affected_mob + + if(!disease_instances.len) + to_chat(src, "The last of your infection has disappeared.") + set_following(null) + qdel(src) + refresh_adaptation_menu() + +/mob/camera/disease/proc/set_following(mob/living/L) + following_host = L + if(!move_listener) + move_listener = L.AddComponent(/datum/component/redirect, COMSIG_MOVABLE_MOVED, CALLBACK(src, .proc/follow_mob)) + else + L.TakeComponent(move_listener) + if(QDELING(move_listener)) + move_listener = null + follow_mob() + +/mob/camera/disease/proc/follow_next(reverse = FALSE) + var/index = hosts.Find(following_host) + if(index) + if(reverse) + index = index == 1 ? hosts.len : index - 1 + else + index = index == hosts.len ? 1 : index + 1 + set_following(hosts[index]) + +/mob/camera/disease/proc/follow_mob(newloc, dir) + var/turf/T = get_turf(following_host) + if(T) + forceMove(T) + +/mob/camera/disease/DblClickOn(var/atom/A, params) + if(hosts[A]) + set_following(A) + else + ..() + +/mob/camera/disease/proc/adapt_cooldown() + to_chat(src, "You have altered your genetic structure. You will be unable to adapt again for [adaptation_cooldown/10] seconds.") + next_adaptation_time = world.time + adaptation_cooldown + addtimer(CALLBACK(src, .proc/notify_adapt_ready), adaptation_cooldown) + +/mob/camera/disease/proc/notify_adapt_ready() + to_chat(src, "You are now ready to adapt again.") + refresh_adaptation_menu() + +/mob/camera/disease/proc/refresh_adaptation_menu() + if(browser_open) + adaptation_menu() + +/mob/camera/disease/proc/adaptation_menu() + var/datum/disease/advance/sentient_disease/DT = disease_template + if(!DT) + return + var/list/dat = list() + + if(examining_ability) + dat += "Back

[examining_ability.name]

[examining_ability.stat_block][examining_ability.long_desc][examining_ability.threshold_block]" + else + dat += "

Disease Statistics


\ + Resistance: [DT.totalResistance()]
\ + Stealth: [DT.totalStealth()]
\ + Stage Speed: [DT.totalStageSpeed()]
\ + Transmittability: [DT.totalTransmittable()]
\ + Cure: [DT.cure_text]" + dat += "

Adaptations

\ + Points: [points] / [total_points]\ + \ + " + for(var/V in GLOB.disease_ability_singletons) + var/datum/disease_ability/A = V + var/purchase_text + if(unpurchased_abilities[A]) + if(A.CanBuy(src)) + purchase_text = "Purchase" + else + purchase_text = "Purchase" + else + if(A.CanRefund(src)) + purchase_text = "Refund" + else + purchase_text = "Refund" + dat += "" + + dat += "
CostUnlockNameTypeDescription
[A.cost][purchase_text][A.required_total_points][A.name][A.category][A.short_desc]

Infect many hosts at once to gain adaptation points.

Infected Hosts

" + for(var/V in hosts) + var/mob/living/L = V + dat += "
[L.real_name]" + + browser.set_content(dat.Join()) + browser.open() + browser_open = TRUE + +/mob/camera/disease/Topic(href, list/href_list) + ..() + if(href_list["close"]) + browser_open = FALSE + if(usr != src) + return + if(href_list["follow_instance"]) + var/mob/living/L = locate(href_list["follow_instance"]) in hosts + set_following(L) + + if(href_list["buy_ability"]) + var/datum/disease_ability/A = locate(href_list["buy_ability"]) + if(!istype(A)) + return + if(A.CanBuy(src)) + A.Buy(src) + adaptation_menu() + + if(href_list["refund_ability"]) + var/datum/disease_ability/A = locate(href_list["refund_ability"]) + if(!istype(A)) + return + if(A.CanRefund(src)) + A.Refund(src) + adaptation_menu() + + if(href_list["examine_ability"]) + var/datum/disease_ability/A = locate(href_list["examine_ability"]) + if(!istype(A)) + return + examining_ability = A + adaptation_menu() + + if(href_list["main_menu"]) + examining_ability = null + adaptation_menu() + + +/datum/action/innate/disease_adapt + name = "Adaptation Menu" + icon_icon = 'icons/mob/actions/actions_minor_antag.dmi' + button_icon_state = "disease_menu" + +/datum/action/innate/disease_adapt/Activate() + var/mob/camera/disease/D = owner + D.adaptation_menu() diff --git a/code/modules/antagonists/monkey/monkey.dm b/code/modules/antagonists/monkey/monkey.dm index 196adf5c22..9ce28eb60d 100644 --- a/code/modules/antagonists/monkey/monkey.dm +++ b/code/modules/antagonists/monkey/monkey.dm @@ -40,11 +40,10 @@ owner.special_role = null SSticker.mode.ape_infectees -= owner - var/datum/disease/transformation/jungle_fever/D = locate() in owner.current.viruses + var/datum/disease/transformation/jungle_fever/D = locate() in owner.current.diseases if(D) - D.remove_virus() qdel(D) - + . = ..() /datum/antagonist/monkey/create_team(datum/team/monkey/new_team) diff --git a/code/modules/antagonists/revenant/revenant_abilities.dm b/code/modules/antagonists/revenant/revenant_abilities.dm index b83892dd46..f81371b504 100644 --- a/code/modules/antagonists/revenant/revenant_abilities.dm +++ b/code/modules/antagonists/revenant/revenant_abilities.dm @@ -354,12 +354,12 @@ if(H.dna && H.dna.species) H.dna.species.handle_hair(H,"#1d2953") //will be reset when blight is cured var/blightfound = FALSE - for(var/datum/disease/revblight/blight in H.viruses) + for(var/datum/disease/revblight/blight in H.diseases) blightfound = TRUE if(blight.stage < 5) blight.stage++ if(!blightfound) - H.AddDisease(new /datum/disease/revblight) + H.ForceContractDisease(new /datum/disease/revblight(), FALSE, TRUE) to_chat(H, "You feel [pick("suddenly sick", "a surge of nausea", "like your skin is wrong")].") else if(mob.reagents) diff --git a/code/modules/antagonists/revenant/revenant_blight.dm b/code/modules/antagonists/revenant/revenant_blight.dm index 21bc534f27..7037ecae86 100644 --- a/code/modules/antagonists/revenant/revenant_blight.dm +++ b/code/modules/antagonists/revenant/revenant_blight.dm @@ -2,7 +2,7 @@ name = "Unnatural Wasting" max_stages = 5 stage_prob = 10 - spread_flags = VIRUS_SPREAD_NON_CONTAGIOUS + spread_flags = DISEASE_SPREAD_NON_CONTAGIOUS cure_text = "Holy water or extensive rest." spread_text = "A burst of unholy energy" cures = list("holywater") @@ -11,7 +11,7 @@ viable_mobtypes = list(/mob/living/carbon/human) disease_flags = CURABLE permeability_mod = 1 - severity = VIRUS_SEVERITY_HARMFUL + severity = DISEASE_SEVERITY_HARMFUL var/stagedamage = 0 //Highest stage reached. var/finalstage = 0 //Because we're spawning off the cure in the final stage, we need to check if we've done the final stage's effects. diff --git a/code/modules/awaymissions/mission_code/Academy.dm b/code/modules/awaymissions/mission_code/Academy.dm index bfde6397b7..4fc3aaf55a 100644 --- a/code/modules/awaymissions/mission_code/Academy.dm +++ b/code/modules/awaymissions/mission_code/Academy.dm @@ -232,8 +232,8 @@ explosion(loc,-1,0,2, flame_range = 2) if(9) //Cold - var/datum/disease/D = new /datum/disease/cold - user.ForceContractDisease(D) + var/datum/disease/D = new /datum/disease/cold() + user.ForceContractDisease(D, FALSE, TRUE) if(10) //Nothing visible_message("[src] roll perfectly.") diff --git a/code/modules/events/disease_outbreak.dm b/code/modules/events/disease_outbreak.dm index 932a578d67..b19c8358c2 100644 --- a/code/modules/events/disease_outbreak.dm +++ b/code/modules/events/disease_outbreak.dm @@ -42,7 +42,7 @@ if(H.has_trait(TRAIT_VIRUSIMMUNE)) //Don't pick someone who's virus immune, only for it to not do anything. continue var/foundAlready = FALSE // don't infect someone that already has a disease - for(var/thing in H.viruses) + for(var/thing in H.diseases) foundAlready = TRUE break if(foundAlready) @@ -63,7 +63,7 @@ else D = make_virus(max_severity, max_severity) D.carrier = TRUE - H.AddDisease(D) + H.ForceContractDisease(D, FALSE, TRUE) if(advanced_virus) var/datum/disease/advance/A = D @@ -75,10 +75,9 @@ break /datum/round_event/disease_outbreak/proc/make_virus(max_symptoms, max_level) - if(max_symptoms > SYMPTOM_LIMIT) - max_symptoms = SYMPTOM_LIMIT - var/datum/disease/advance/A = new(FALSE, null) - A.symptoms = list() + if(max_symptoms > VIRUS_SYMPTOM_LIMIT) + max_symptoms = VIRUS_SYMPTOM_LIMIT + var/datum/disease/advance/A = new /datum/disease/advance() var/list/datum/symptom/possible_symptoms = list() for(var/symptom in subtypesof(/datum/symptom)) var/datum/symptom/S = symptom diff --git a/code/modules/events/heart_attack.dm b/code/modules/events/heart_attack.dm index ebe7dd5bfd..7f9c09dfd9 100644 --- a/code/modules/events/heart_attack.dm +++ b/code/modules/events/heart_attack.dm @@ -8,7 +8,7 @@ /datum/round_event/heart_attack/start() var/list/heart_attack_contestants = list() for(var/mob/living/carbon/human/H in shuffle(GLOB.player_list)) - if(!H.client || H.stat == DEAD || H.InCritical() || !H.can_heartattack() || H.has_status_effect(STATUS_EFFECT_EXERCISED) || (/datum/disease/heart_failure in H.viruses) || H.undergoing_cardiac_arrest()) + if(!H.client || H.stat == DEAD || H.InCritical() || !H.can_heartattack() || H.has_status_effect(STATUS_EFFECT_EXERCISED) || (/datum/disease/heart_failure in H.diseases) || H.undergoing_cardiac_arrest()) continue if(H.satiety <= -60) //Multiple junk food items recently heart_attack_contestants[H] = 3 @@ -17,6 +17,6 @@ if(LAZYLEN(heart_attack_contestants)) var/mob/living/carbon/human/winner = pickweight(heart_attack_contestants) - var/datum/disease/D = new /datum/disease/heart_failure - winner.ForceContractDisease(D) - notify_ghosts("[winner] is beginning to have a heart attack!", enter_link="(Click to orbit)", source=winner, action=NOTIFY_ORBIT) \ No newline at end of file + var/datum/disease/D = new /datum/disease/heart_failure() + winner.ForceContractDisease(D, FALSE, TRUE) + notify_ghosts("[winner] is beginning to have a heart attack!", enter_link="(Click to orbit)", source=winner, action=NOTIFY_ORBIT) diff --git a/code/modules/events/spontaneous_appendicitis.dm b/code/modules/events/spontaneous_appendicitis.dm index dfceb682cd..1407a98518 100644 --- a/code/modules/events/spontaneous_appendicitis.dm +++ b/code/modules/events/spontaneous_appendicitis.dm @@ -18,12 +18,12 @@ if(!H.getorgan(/obj/item/organ/appendix)) //Don't give the disease to some who lacks it, only for it to be auto-cured continue var/foundAlready = FALSE //don't infect someone that already has appendicitis - for(var/datum/disease/appendicitis/A in H.viruses) + for(var/datum/disease/appendicitis/A in H.diseases) foundAlready = TRUE break if(foundAlready) continue - var/datum/disease/D = new /datum/disease/appendicitis - H.ForceContractDisease(D) + var/datum/disease/D = new /datum/disease/appendicitis() + H.ForceContractDisease(D, FALSE, TRUE) break \ No newline at end of file diff --git a/code/modules/language/language_holder.dm b/code/modules/language/language_holder.dm index d15bc4c117..c1a336eb69 100644 --- a/code/modules/language/language_holder.dm +++ b/code/modules/language/language_holder.dm @@ -136,6 +136,10 @@ languages = list(/datum/language/common) shadow_languages = list(/datum/language/common, /datum/language/machine, /datum/language/draconic) +/datum/language_holder/empty + languages = list() + shadow_languages = list() + /datum/language_holder/universal/New() ..() grant_all_languages(omnitongue=TRUE) diff --git a/code/modules/mining/lavaland/necropolis_chests.dm b/code/modules/mining/lavaland/necropolis_chests.dm index e5b9ddb4e4..450c2d5d0d 100644 --- a/code/modules/mining/lavaland/necropolis_chests.dm +++ b/code/modules/mining/lavaland/necropolis_chests.dm @@ -789,7 +789,7 @@ agent = "dragon's blood" desc = "What do dragons have to do with Space Station 13?" stage_prob = 20 - severity = VIRUS_SEVERITY_BIOHAZARD + severity = DISEASE_SEVERITY_BIOHAZARD visibility_flags = 0 stage1 = list("Your bones ache.") stage2 = list("Your skin feels scaly.") diff --git a/code/modules/mob/camera/camera.dm b/code/modules/mob/camera/camera.dm index 9a95bc9a4a..5f99cd8aa2 100644 --- a/code/modules/mob/camera/camera.dm +++ b/code/modules/mob/camera/camera.dm @@ -9,10 +9,24 @@ see_in_dark = 7 invisibility = INVISIBILITY_ABSTRACT // No one can see us sight = SEE_SELF - move_on_shuttle = 0 + move_on_shuttle = FALSE + var/call_life = FALSE //TRUE if Life() should be called on this camera every tick of the mobs subystem, as if it were a living mob + +/mob/camera/Initialize() + . = ..() + if(call_life) + GLOB.living_cameras += src + +/mob/camera/Destroy() + . = ..() + if(call_life) + GLOB.living_cameras -= src /mob/camera/experience_pressure_difference() return /mob/camera/forceMove(atom/destination) loc = destination + +/mob/camera/emote(act, m_type=1, message = null) + return diff --git a/code/modules/mob/living/blood.dm b/code/modules/mob/living/blood.dm index a30fd1492e..f7b3d15155 100644 --- a/code/modules/mob/living/blood.dm +++ b/code/modules/mob/living/blood.dm @@ -140,7 +140,7 @@ if(blood_data["viruses"]) for(var/thing in blood_data["viruses"]) var/datum/disease/D = thing - if((D.spread_flags & VIRUS_SPREAD_SPECIAL) || (D.spread_flags & VIRUS_SPREAD_NON_CONTAGIOUS)) + if((D.spread_flags & DISEASE_SPREAD_SPECIAL) || (D.spread_flags & DISEASE_SPREAD_NON_CONTAGIOUS)) continue C.ForceContractDisease(D) if(!(blood_data["blood_type"] in get_safe_blood(C.dna.blood_type))) @@ -164,13 +164,13 @@ blood_data["donor"] = src blood_data["viruses"] = list() - for(var/thing in viruses) + for(var/thing in diseases) var/datum/disease/D = thing blood_data["viruses"] += D.Copy() blood_data["blood_DNA"] = copytext(dna.unique_enzymes,1,0) - if(resistances && resistances.len) - blood_data["resistances"] = resistances.Copy() + if(disease_resistances && disease_resistances.len) + blood_data["resistances"] = disease_resistances.Copy() var/list/temp_chem = list() for(var/datum/reagent/R in reagents.reagent_list) temp_chem[R.id] = R.volume diff --git a/code/modules/mob/living/carbon/alien/special/facehugger.dm b/code/modules/mob/living/carbon/alien/special/facehugger.dm index 8b8b8d5761..fe4454caeb 100644 --- a/code/modules/mob/living/carbon/alien/special/facehugger.dm +++ b/code/modules/mob/living/carbon/alien/special/facehugger.dm @@ -202,7 +202,6 @@ return if(!sterile) - //target.contract_disease(new /datum/disease/alien_embryo(0)) //so infection chance is same as virus infection chance target.visible_message("[src] falls limp after violating [target]'s face!", \ "[src] falls limp after violating [target]'s face!") diff --git a/code/modules/mob/living/carbon/carbon.dm b/code/modules/mob/living/carbon/carbon.dm index b530ab0cc0..ddc4e2e9c1 100644 --- a/code/modules/mob/living/carbon/carbon.dm +++ b/code/modules/mob/living/carbon/carbon.dm @@ -754,9 +754,9 @@ var/obj/item/organ/brain/B = getorgan(/obj/item/organ/brain) if(B) B.damaged_brain = FALSE - for(var/thing in viruses) + for(var/thing in diseases) var/datum/disease/D = thing - if(D.severity != VIRUS_SEVERITY_POSITIVE) + if(D.severity != DISEASE_SEVERITY_POSITIVE) D.cure(FALSE) if(admin_revive) regenerate_limbs() diff --git a/code/modules/mob/living/carbon/carbon_defense.dm b/code/modules/mob/living/carbon/carbon_defense.dm index 56420df35a..4995caaca0 100644 --- a/code/modules/mob/living/carbon/carbon_defense.dm +++ b/code/modules/mob/living/carbon/carbon_defense.dm @@ -110,14 +110,14 @@ /mob/living/carbon/attack_hand(mob/living/carbon/human/user) - for(var/thing in viruses) + for(var/thing in diseases) var/datum/disease/D = thing - if(D.spread_flags & VIRUS_SPREAD_CONTACT_SKIN) + if(D.spread_flags & DISEASE_SPREAD_CONTACT_SKIN) user.ContactContractDisease(D) - for(var/thing in user.viruses) + for(var/thing in user.diseases) var/datum/disease/D = thing - if(D.spread_flags & VIRUS_SPREAD_CONTACT_SKIN) + if(D.spread_flags & DISEASE_SPREAD_CONTACT_SKIN) ContactContractDisease(D) if(lying && surgeries.len) @@ -131,14 +131,14 @@ /mob/living/carbon/attack_paw(mob/living/carbon/monkey/M) if(can_inject(M, TRUE)) - for(var/thing in viruses) + for(var/thing in diseases) var/datum/disease/D = thing - if((D.spread_flags & VIRUS_SPREAD_CONTACT_SKIN) && prob(85)) + if((D.spread_flags & DISEASE_SPREAD_CONTACT_SKIN) && prob(85)) M.ContactContractDisease(D) - for(var/thing in M.viruses) + for(var/thing in M.diseases) var/datum/disease/D = thing - if(D.spread_flags & VIRUS_SPREAD_CONTACT_SKIN) + if(D.spread_flags & DISEASE_SPREAD_CONTACT_SKIN) ContactContractDisease(D) if(M.a_intent == INTENT_HELP) @@ -146,7 +146,7 @@ return 0 if(..()) //successful monkey bite. - for(var/thing in M.viruses) + for(var/thing in M.diseases) var/datum/disease/D = thing ForceContractDisease(D) return 1 diff --git a/code/modules/mob/living/carbon/human/human.dm b/code/modules/mob/living/carbon/human/human.dm index 6b5d533f11..1321c499f4 100644 --- a/code/modules/mob/living/carbon/human/human.dm +++ b/code/modules/mob/living/carbon/human/human.dm @@ -90,10 +90,10 @@ stat("Radiation Levels:","[radiation] rad") stat("Body Temperature:","[bodytemperature-T0C] degrees C ([bodytemperature*1.8-459.67] degrees F)") - //Virsuses - if(viruses.len) + //Diseases + if(diseases.len) stat("Viruses:", null) - for(var/thing in viruses) + for(var/thing in diseases) var/datum/disease/D = thing stat("*", "[D.name], Type: [D.spread_text], Stage: [D.stage]/[D.max_stages], Possible Cure: [D.cure_text]") diff --git a/code/modules/mob/living/carbon/human/human_defines.dm b/code/modules/mob/living/carbon/human/human_defines.dm index 2bc4de894e..60bb0fe497 100644 --- a/code/modules/mob/living/carbon/human/human_defines.dm +++ b/code/modules/mob/living/carbon/human/human_defines.dm @@ -1,5 +1,5 @@ /mob/living/carbon/human - hud_possible = list(HEALTH_HUD,STATUS_HUD,ID_HUD,WANTED_HUD,IMPLOYAL_HUD,IMPCHEM_HUD,IMPTRACK_HUD,ANTAG_HUD,GLAND_HUD) + hud_possible = list(HEALTH_HUD,STATUS_HUD,ID_HUD,WANTED_HUD,IMPLOYAL_HUD,IMPCHEM_HUD,IMPTRACK_HUD,ANTAG_HUD,GLAND_HUD,SENTIENT_DISEASE_HUD) possible_a_intents = list(INTENT_HELP, INTENT_DISARM, INTENT_GRAB, INTENT_HARM) pressure_resistance = 25 can_buckle = TRUE diff --git a/code/modules/mob/living/carbon/human/say.dm b/code/modules/mob/living/carbon/human/say.dm index 56ba4dff81..c008be1093 100644 --- a/code/modules/mob/living/carbon/human/say.dm +++ b/code/modules/mob/living/carbon/human/say.dm @@ -7,8 +7,8 @@ /mob/living/carbon/human/treat_message(message) message = dna.species.handle_speech(message,src) - if(viruses.len) - for(var/datum/disease/pierrot_throat/D in viruses) + if(diseases.len) + for(var/datum/disease/pierrot_throat/D in diseases) var/list/temp_message = splittext(message, " ") //List each word in the message var/list/pick_list = list() for(var/i = 1, i <= temp_message.len, i++) //Create a second list for excluding words down the line diff --git a/code/modules/mob/living/carbon/human/species.dm b/code/modules/mob/living/carbon/human/species.dm index 14e301a692..8a78c1532e 100644 --- a/code/modules/mob/living/carbon/human/species.dm +++ b/code/modules/mob/living/carbon/human/species.dm @@ -293,7 +293,7 @@ GLOBAL_LIST_EMPTY(roundstart_races) C.add_trait(X, SPECIES_TRAIT) if(TRAIT_VIRUSIMMUNE in inherent_traits) - for(var/datum/disease/A in C.viruses) + for(var/datum/disease/A in C.diseases) A.cure(FALSE) //CITADEL EDIT diff --git a/code/modules/mob/living/carbon/life.dm b/code/modules/mob/living/carbon/life.dm index 0cf7190420..bf10084758 100644 --- a/code/modules/mob/living/carbon/life.dm +++ b/code/modules/mob/living/carbon/life.dm @@ -251,7 +251,7 @@ O.on_life() /mob/living/carbon/handle_diseases() - for(var/thing in viruses) + for(var/thing in diseases) var/datum/disease/D = thing if(prob(D.infectivity)) D.spread() diff --git a/code/modules/mob/living/living.dm b/code/modules/mob/living/living.dm index c78d8b19d7..dcd3789360 100644 --- a/code/modules/mob/living/living.dm +++ b/code/modules/mob/living/living.dm @@ -48,7 +48,7 @@ staticOverlays.len = 0 remove_from_all_data_huds() GLOB.mob_living_list -= src - + QDEL_LIST(diseases) return ..() /mob/living/ghostize(can_reenter_corpse = 1) @@ -108,24 +108,24 @@ /mob/living/proc/MobCollide(mob/M) //Even if we don't push/swap places, we "touched" them, so spread fire spreadFire(M) - //Also diseases - for(var/thing in viruses) - var/datum/disease/D = thing - if(D.spread_flags & VIRUS_SPREAD_CONTACT_SKIN) - M.ContactContractDisease(D) - - for(var/thing in M.viruses) - var/datum/disease/D = thing - if(D.spread_flags & VIRUS_SPREAD_CONTACT_SKIN) - ContactContractDisease(D) if(now_pushing) return TRUE - - //Should stop you pushing a restrained person out of the way if(isliving(M)) var/mob/living/L = M + //Also spread diseases + for(var/thing in diseases) + var/datum/disease/D = thing + if(D.spread_flags & DISEASE_SPREAD_CONTACT_SKIN) + L.ContactContractDisease(D) + + for(var/thing in L.diseases) + var/datum/disease/D = thing + if(D.spread_flags & DISEASE_SPREAD_CONTACT_SKIN) + ContactContractDisease(D) + + //Should stop you pushing a restrained person out of the way if(L.pulledby && L.pulledby != src && L.restrained()) if(!(world.time % 5)) to_chat(src, "[L] is restrained, you cannot push past.") @@ -224,6 +224,60 @@ AM.setDir(current_dir) now_pushing = 0 +/mob/living/start_pulling(atom/movable/AM, supress_message = 0) + if(!AM || !src) + return FALSE + if(!(AM.can_be_pulled(src))) + return FALSE + if(throwing || incapacitated()) + return FALSE + + AM.add_fingerprint(src) + + // If we're pulling something then drop what we're currently pulling and pull this instead. + if(pulling) + // Are we trying to pull something we are already pulling? Then just stop here, no need to continue. + if(AM == pulling) + return + stop_pulling() + + changeNext_move(CLICK_CD_GRABBING) + + if(AM.pulledby) + if(!supress_message) + visible_message("[src] has pulled [AM] from [AM.pulledby]'s grip.") + add_logs(AM, AM.pulledby, "pulled from", src) + AM.pulledby.stop_pulling() //an object can't be pulled by two mobs at once. + + pulling = AM + AM.pulledby = src + if(!supress_message) + playsound(src.loc, 'sound/weapons/thudswoosh.ogg', 50, 1, -1) + update_pull_hud_icon() + + if(ismob(AM)) + var/mob/M = AM + + add_logs(src, M, "grabbed", addition="passive grab") + if(!supress_message) + visible_message("[src] has grabbed [M] passively!") + if(!iscarbon(src)) + M.LAssailant = null + else + M.LAssailant = usr + if(isliving(M)) + var/mob/living/L = M + //Share diseases that are spread by touch + for(var/thing in diseases) + var/datum/disease/D = thing + if(D.spread_flags & DISEASE_SPREAD_CONTACT_SKIN) + L.ContactContractDisease(D) + + for(var/thing in L.diseases) + var/datum/disease/D = thing + if(D.spread_flags & DISEASE_SPREAD_CONTACT_SKIN) + ContactContractDisease(D) + //mob verbs are a lot faster than object verbs //for more info on why this is not atom/pull, see examinate() in mob.dm /mob/living/verb/pulled(atom/movable/AM as mob|obj in oview(1)) @@ -235,6 +289,15 @@ else stop_pulling() +/mob/living/stop_pulling() + ..() + update_pull_hud_icon() + +/mob/living/verb/stop_pulling1() + set name = "Stop Pulling" + set category = "IC" + stop_pulling() + //same as above /mob/living/pointed(atom/A as mob|obj|turf in view()) if(incapacitated()) @@ -1074,3 +1137,54 @@ return FALSE mob_pickup(user) return TRUE + +/mob/living/proc/get_static_viruses() //used when creating blood and other infective objects + if(!LAZYLEN(diseases)) + return + var/list/datum/disease/result = list() + for(var/datum/disease/D in diseases) + var/static_virus = D.Copy() + result += static_virus + return result + +/mob/living/reset_perspective(atom/A) + if(..()) + update_sight() + if(client.eye && client.eye != src) + var/atom/AT = client.eye + AT.get_remote_view_fullscreens(src) + else + clear_fullscreen("remote_view", 0) + update_pipe_vision() + +/mob/living/vv_edit_var(var_name, var_value) + switch(var_name) + if("stat") + if((stat == DEAD) && (var_value < DEAD))//Bringing the dead back to life + GLOB.dead_mob_list -= src + GLOB.alive_mob_list += src + if((stat < DEAD) && (var_value == DEAD))//Kill he + GLOB.alive_mob_list -= src + GLOB.dead_mob_list += src + . = ..() + switch(var_name) + if("knockdown") + SetKnockdown(var_value) + if("stun") + SetStun(var_value) + if("unconscious") + SetUnconscious(var_value) + if("sleeping") + SetSleeping(var_value) + if("eye_blind") + set_blindness(var_value) + if("eye_damage") + set_eye_damage(var_value) + if("eye_blurry") + set_blurriness(var_value) + if("maxHealth") + updatehealth() + if("resize") + update_transform() + if("lighting_alpha") + sync_lighting_plane_alpha() diff --git a/code/modules/mob/living/living_defines.dm b/code/modules/mob/living/living_defines.dm index f5c00b874a..f31d95a9d7 100644 --- a/code/modules/mob/living/living_defines.dm +++ b/code/modules/mob/living/living_defines.dm @@ -107,3 +107,7 @@ var/radiation = 0 //If the mob is irradiated. var/ventcrawl_layer = PIPING_LAYER_DEFAULT var/losebreath = 0 + + //List of active diseases + var/list/diseases = list() // list of all diseases in a mob + var/list/disease_resistances = list() diff --git a/code/modules/mob/living/silicon/pai/software.dm b/code/modules/mob/living/silicon/pai/software.dm index cc17d8e4bd..2a2cda19e0 100644 --- a/code/modules/mob/living/silicon/pai/software.dm +++ b/code/modules/mob/living/silicon/pai/software.dm @@ -511,7 +511,7 @@ Structural Integrity: [M.getBruteLoss() > 50 ? "" : ""][M.getBruteLoss()]
Body Temperature: [M.bodytemperature-T0C]°C ([M.bodytemperature*1.8-459.67]°F)
"} - for(var/thing in M.viruses) + for(var/thing in M.diseases) var/datum/disease/D = thing dat += {"

Infection Detected.


Name: [D.name]
diff --git a/code/modules/mob/living/simple_animal/bot/medbot.dm b/code/modules/mob/living/simple_animal/bot/medbot.dm index 6946c8992f..4cf1f6b13f 100644 --- a/code/modules/mob/living/simple_animal/bot/medbot.dm +++ b/code/modules/mob/living/simple_animal/bot/medbot.dm @@ -383,12 +383,12 @@ return TRUE if(treat_virus && !C.reagents.has_reagent(treatment_virus_avoid) && !C.reagents.has_reagent(treatment_virus)) - for(var/thing in C.viruses) + for(var/thing in C.diseases) var/datum/disease/D = thing //the medibot can't detect viruses that are undetectable to Health Analyzers or Pandemic machines. if(!(D.visibility_flags & HIDDEN_SCANNER || D.visibility_flags & HIDDEN_PANDEMIC) \ - && D.severity != VIRUS_SEVERITY_POSITIVE \ - && (D.stage > 1 || (D.spread_flags & VIRUS_SPREAD_AIRBORNE))) // medibot can't detect a virus in its initial stage unless it spreads airborne. + && D.severity != DISEASE_SEVERITY_POSITIVE \ + && (D.stage > 1 || (D.spread_flags & DISEASE_SPREAD_AIRBORNE))) // medibot can't detect a virus in its initial stage unless it spreads airborne. return TRUE //STOP DISEASE FOREVER return FALSE @@ -435,12 +435,12 @@ else if(treat_virus) var/virus = 0 - for(var/thing in C.viruses) + for(var/thing in C.diseases) var/datum/disease/D = thing //detectable virus if((!(D.visibility_flags & HIDDEN_SCANNER)) || (!(D.visibility_flags & HIDDEN_PANDEMIC))) - if(D.severity != VIRUS_SEVERITY_POSITIVE) //virus is harmful - if((D.stage > 1) || (D.spread_flags & VIRUS_SPREAD_AIRBORNE)) + if(D.severity != DISEASE_SEVERITY_POSITIVE) //virus is harmful + if((D.stage > 1) || (D.spread_flags & DISEASE_SPREAD_AIRBORNE)) virus = 1 if(!reagent_id && (virus)) diff --git a/code/modules/mob/mob.dm b/code/modules/mob/mob.dm index 4b53435b86..7deed01390 100644 --- a/code/modules/mob/mob.dm +++ b/code/modules/mob/mob.dm @@ -11,7 +11,6 @@ var/mob/dead/observe = M observe.reset_perspective(null) qdel(hud_used) - QDEL_LIST(viruses) for(var/cc in client_colours) qdel(cc) client_colours = null @@ -287,16 +286,6 @@ client.eye = loc return 1 -/mob/living/reset_perspective(atom/A) - if(..()) - update_sight() - if(client.eye && client.eye != src) - var/atom/AT = client.eye - AT.get_remote_view_fullscreens(src) - else - clear_fullscreen("remote_view", 0) - update_pipe_vision() - /mob/proc/show_inv(mob/user) return @@ -333,60 +322,6 @@ return 1 -//this and stop_pulling really ought to be /mob/living procs -/mob/start_pulling(atom/movable/AM, supress_message = 0) - if(!AM || !src) - return FALSE - if(!(AM.can_be_pulled(src))) - return FALSE - if(throwing || incapacitated()) - return FALSE - - AM.add_fingerprint(src) - - // If we're pulling something then drop what we're currently pulling and pull this instead. - if(pulling) - // Are we trying to pull something we are already pulling? Then just stop here, no need to continue. - if(AM == pulling) - return - stop_pulling() - - changeNext_move(CLICK_CD_GRABBING) - - if(AM.pulledby) - if(!supress_message) - visible_message("[src] has pulled [AM] from [AM.pulledby]'s grip.") - add_logs(AM, AM.pulledby, "pulled from", src) - AM.pulledby.stop_pulling() //an object can't be pulled by two mobs at once. - - pulling = AM - AM.pulledby = src - if(!supress_message) - playsound(src.loc, 'sound/weapons/thudswoosh.ogg', 50, 1, -1) - update_pull_hud_icon() - - if(ismob(AM)) - var/mob/M = AM - - //Share diseases that are spread by touch - for(var/thing in viruses) - var/datum/disease/D = thing - if(D.spread_flags & VIRUS_SPREAD_CONTACT_SKIN) - M.ContactContractDisease(D) - - for(var/thing in M.viruses) - var/datum/disease/D = thing - if(D.spread_flags & VIRUS_SPREAD_CONTACT_SKIN) - ContactContractDisease(D) - - add_logs(src, M, "grabbed", addition="passive grab") - if(!supress_message) - visible_message("[src] has grabbed [M][(zone_selected == "l_arm" || zone_selected == "r_arm")? " by their hands":" passively"]!") - if(!iscarbon(src)) - M.LAssailant = null - else - M.LAssailant = usr - /mob/proc/can_resist() return FALSE //overridden in living.dm @@ -409,15 +344,6 @@ setDir(D) spintime -= speed -/mob/stop_pulling() - ..() - update_pull_hud_icon() - -/mob/verb/stop_pulling1() - set name = "Stop Pulling" - set category = "IC" - stop_pulling() - /mob/proc/update_pull_hud_icon() if(hud_used) if(hud_used.pull_icon) @@ -927,39 +853,6 @@ if (L) L.alpha = lighting_alpha -/mob/living/vv_edit_var(var_name, var_value) - switch(var_name) - if("stat") - if((stat == DEAD) && (var_value < DEAD))//Bringing the dead back to life - GLOB.dead_mob_list -= src - GLOB.alive_mob_list += src - if((stat < DEAD) && (var_value == DEAD))//Kill he - GLOB.alive_mob_list -= src - GLOB.dead_mob_list += src - . = ..() - switch(var_name) - if("knockdown") - SetKnockdown(var_value) - if("stun") - SetStun(var_value) - if("unconscious") - SetUnconscious(var_value) - if("sleeping") - SetSleeping(var_value) - if("eye_blind") - set_blindness(var_value) - if("eye_damage") - set_eye_damage(var_value) - if("eye_blurry") - set_blurriness(var_value) - if("maxHealth") - updatehealth() - if("resize") - update_transform() - if("lighting_alpha") - sync_lighting_plane_alpha() - - /mob/proc/is_literate() return 0 @@ -969,15 +862,6 @@ /mob/proc/get_idcard() return -/mob/proc/get_static_viruses() //used when creating blood and other infective objects - if(!LAZYLEN(viruses)) - return - var/list/datum/disease/diseases = list() - for(var/datum/disease/D in viruses) - var/static_virus = D.Copy() - diseases += static_virus - return diseases - /mob/vv_get_dropdown() . = ..() diff --git a/code/modules/mob/mob_defines.dm b/code/modules/mob/mob_defines.dm index d4bebd6303..0088e09515 100644 --- a/code/modules/mob/mob_defines.dm +++ b/code/modules/mob/mob_defines.dm @@ -82,10 +82,6 @@ var/list/mob_spell_list = list() //construct spells and mime spells. Spells that do not transfer from one mob to another and can not be lost in mindswap. -//List of active diseases - - var/list/viruses = list() // list of all diseases in a mob - var/list/resistances = list() var/status_flags = CANSTUN|CANKNOCKDOWN|CANUNCONSCIOUS|CANPUSH //bitflags defining which status effects can be inflicted (replaces canknockdown, canstun, etc) diff --git a/code/modules/mob/mob_helpers.dm b/code/modules/mob/mob_helpers.dm index 989c8278a5..3b9930faa9 100644 --- a/code/modules/mob/mob_helpers.dm +++ b/code/modules/mob/mob_helpers.dm @@ -363,8 +363,10 @@ It's fairly easy to fix if dealing with single letters but not so much with comp if(M.mind in SSticker.mode.apprentices) return 2 if("monkey") - if(M.viruses && (locate(/datum/disease/transformation/jungle_fever) in M.viruses)) - return 2 + if(isliving(M)) + var/mob/living/L = M + if(L.diseases && (locate(/datum/disease/transformation/jungle_fever) in L.diseases)) + return 2 return TRUE if(M.mind && LAZYLEN(M.mind.antag_datums)) //they have an antag datum! return TRUE diff --git a/code/modules/mob/transform_procs.dm b/code/modules/mob/transform_procs.dm index 64454b130e..240c4edd9f 100644 --- a/code/modules/mob/transform_procs.dm +++ b/code/modules/mob/transform_procs.dm @@ -62,9 +62,9 @@ //keep viruses? if (tr_flags & TR_KEEPVIRUS) - O.viruses = viruses - viruses = list() - for(var/thing in O.viruses) + O.diseases = diseases + diseases = list() + for(var/thing in O.diseases) var/datum/disease/D = thing D.affected_mob = O @@ -218,9 +218,9 @@ //keep viruses? if (tr_flags & TR_KEEPVIRUS) - O.viruses = viruses - viruses = list() - for(var/thing in O.viruses) + O.diseases = diseases + diseases = list() + for(var/thing in O.diseases) var/datum/disease/D = thing D.affected_mob = O O.med_hud_set_status() diff --git a/code/modules/reagents/chemistry/machinery/pandemic.dm b/code/modules/reagents/chemistry/machinery/pandemic.dm index b14d436df5..00a3f0effd 100644 --- a/code/modules/reagents/chemistry/machinery/pandemic.dm +++ b/code/modules/reagents/chemistry/machinery/pandemic.dm @@ -57,7 +57,7 @@ if(istype(D, /datum/disease/advance)) var/datum/disease/advance/A = D var/disease_name = SSdisease.get_disease_name(A.GetDiseaseID()) - if(disease_name == "Unknown") + if(disease_name == "Unknown" && A.mutable) this["can_rename"] = TRUE this["name"] = disease_name this["is_adv"] = TRUE @@ -180,17 +180,21 @@ if("rename_disease") var/id = get_virus_id_by_index(text2num(params["index"])) var/datum/disease/advance/A = SSdisease.archive_diseases[id] + if(!A.mutable) + return if(A) var/new_name = stripped_input(usr, "Name the disease", "New name", "", MAX_NAME_LEN) if(!new_name || ..()) return A.AssignName(new_name) - for(var/datum/disease/advance/AD in SSdisease.active_diseases) - AD.Refresh() . = TRUE if("create_culture_bottle") var/id = get_virus_id_by_index(text2num(params["index"])) - var/datum/disease/advance/A = new(FALSE, SSdisease.archive_diseases[id]) + var/datum/disease/advance/A = SSdisease.archive_diseases[id] + if(!A.mutable) + to_chat(usr, "ERROR: Cannot replicate virus strain.") + return + A = A.Copy() var/list/data = list("viruses" = list(A)) var/obj/item/reagent_containers/glass/bottle/B = new(drop_location()) B.name = "[A.name] culture bottle" diff --git a/code/modules/reagents/chemistry/reagents/medicine_reagents.dm b/code/modules/reagents/chemistry/reagents/medicine_reagents.dm index a3726897b3..2f7f9eaa08 100644 --- a/code/modules/reagents/chemistry/reagents/medicine_reagents.dm +++ b/code/modules/reagents/chemistry/reagents/medicine_reagents.dm @@ -60,9 +60,9 @@ M.SetSleeping(0, 0) M.jitteriness = 0 M.cure_all_traumas(TRUE, TRAUMA_RESILIENCE_MAGIC) - for(var/thing in M.viruses) + for(var/thing in M.diseases) var/datum/disease/D = thing - if(D.severity == VIRUS_SEVERITY_POSITIVE) + if(D.severity == DISEASE_SEVERITY_POSITIVE) continue D.cure() ..() diff --git a/code/modules/reagents/chemistry/reagents/other_reagents.dm b/code/modules/reagents/chemistry/reagents/other_reagents.dm index 75b4552a58..1ecf22627a 100644 --- a/code/modules/reagents/chemistry/reagents/other_reagents.dm +++ b/code/modules/reagents/chemistry/reagents/other_reagents.dm @@ -16,13 +16,15 @@ for(var/thing in data["viruses"]) var/datum/disease/D = thing - if((D.spread_flags & VIRUS_SPREAD_SPECIAL) || (D.spread_flags & VIRUS_SPREAD_NON_CONTAGIOUS)) + if((D.spread_flags & DISEASE_SPREAD_SPECIAL) || (D.spread_flags & DISEASE_SPREAD_NON_CONTAGIOUS)) continue - if((method == TOUCH || method == VAPOR) && (D.spread_flags & VIRUS_SPREAD_CONTACT_FLUIDS)) - M.ContactContractDisease(D) - else //ingest, patch or inject - M.ForceContractDisease(D) + if(isliving(M)) + var/mob/living/L = M + if((method == TOUCH || method == VAPOR) && (D.spread_flags & DISEASE_SPREAD_CONTACT_FLUIDS)) + L.ContactContractDisease(D) + else //ingest, patch or inject + L.ForceContractDisease(D) if(iscarbon(M)) var/mob/living/carbon/C = M @@ -97,12 +99,15 @@ taste_description = "slime" /datum/reagent/vaccine/reaction_mob(mob/M, method=TOUCH, reac_volume) + if(!isliving(M)) + return + var/mob/living/L = M if(islist(data) && (method == INGEST || method == INJECT)) - for(var/thing in M.viruses) + for(var/thing in L.diseases) var/datum/disease/D = thing if(D.GetDiseaseID() in data) D.cure() - M.resistances |= data + L.disease_resistances |= data /datum/reagent/vaccine/on_merge(list/data) if(istype(data)) @@ -623,8 +628,11 @@ taste_description = "slime" /datum/reagent/aslimetoxin/reaction_mob(mob/M, method=TOUCH, reac_volume) + if(!isliving(M)) + return + var/mob/living/L = M if(method != TOUCH) - M.ForceContractDisease(new /datum/disease/transformation/slime(0)) + L.ForceContractDisease(new /datum/disease/transformation/slime(), FALSE, TRUE) /datum/reagent/gluttonytoxin name = "Gluttony's Blessing" @@ -635,7 +643,10 @@ taste_description = "decay" /datum/reagent/gluttonytoxin/reaction_mob(mob/M, method=TOUCH, reac_volume) - M.ForceContractDisease(new /datum/disease/transformation/morph(0)) + if(!isliving(M)) + return + var/mob/living/L = M + L.ForceContractDisease(new /datum/disease/transformation/morph(), FALSE, TRUE) /datum/reagent/serotrotium name = "Serotrotium" @@ -1103,8 +1114,11 @@ taste_description = "sludge" /datum/reagent/nanites/reaction_mob(mob/M, method=TOUCH, reac_volume, show_message = 1, touch_protection = 0) + if(!isliving(M)) + return + var/mob/living/L = M if(method==PATCH || method==INGEST || method==INJECT || (method == VAPOR && prob(min(reac_volume,100)*(1 - touch_protection)))) - M.ForceContractDisease(new /datum/disease/transformation/robot(0)) + L.ForceContractDisease(new /datum/disease/transformation/robot(), FALSE, TRUE) /datum/reagent/xenomicrobes name = "Xenomicrobes" @@ -1115,8 +1129,11 @@ taste_description = "sludge" /datum/reagent/xenomicrobes/reaction_mob(mob/M, method=TOUCH, reac_volume, show_message = 1, touch_protection = 0) + if(!isliving(M)) + return + var/mob/living/L = M if(method==PATCH || method==INGEST || method==INJECT || (method == VAPOR && prob(min(reac_volume,100)*(1 - touch_protection)))) - M.ForceContractDisease(new /datum/disease/transformation/xeno(0)) + L.ForceContractDisease(new /datum/disease/transformation/xeno(), FALSE, TRUE) /datum/reagent/fungalspores name = "Tubercle bacillus Cosmosis microbes" @@ -1127,8 +1144,11 @@ taste_description = "slime" /datum/reagent/fungalspores/reaction_mob(mob/M, method=TOUCH, reac_volume, show_message = 1, touch_protection = 0) + if(!isliving(M)) + return + var/mob/living/L = M if(method==PATCH || method==INGEST || method==INJECT || (method == VAPOR && prob(min(reac_volume,100)*(1 - touch_protection)))) - M.ForceContractDisease(new /datum/disease/tuberculosis(0)) + L.ForceContractDisease(new /datum/disease/tuberculosis(), FALSE, TRUE) /datum/reagent/fluorosurfactant//foam precursor name = "Fluorosurfactant" diff --git a/code/modules/reagents/reagent_containers.dm b/code/modules/reagents/reagent_containers.dm index d6213a391b..054fe077c3 100644 --- a/code/modules/reagents/reagent_containers.dm +++ b/code/modules/reagents/reagent_containers.dm @@ -18,7 +18,7 @@ volume = vol create_reagents(volume) if(spawned_disease) - var/datum/disease/F = new spawned_disease(0) + var/datum/disease/F = new spawned_disease() var/list/data = list("viruses"= list(F)) reagents.add_reagent("blood", disease_amount, data) diff --git a/code/modules/research/xenobiology/xenobiology.dm b/code/modules/research/xenobiology/xenobiology.dm index e8937b5dae..f240e0b6af 100644 --- a/code/modules/research/xenobiology/xenobiology.dm +++ b/code/modules/research/xenobiology/xenobiology.dm @@ -350,7 +350,7 @@ switch(activation_type) if(SLIME_ACTIVATE_MINOR) to_chat(user, "You feel something wrong inside you...") - user.ForceContractDisease(new /datum/disease/transformation/slime(0)) + user.ForceContractDisease(new /datum/disease/transformation/slime(), FALSE, TRUE) return 100 if(SLIME_ACTIVATE_MAJOR) diff --git a/code/modules/surgery/advanced/viral_bonding.dm b/code/modules/surgery/advanced/viral_bonding.dm index f661373acd..da42e4fdb9 100644 --- a/code/modules/surgery/advanced/viral_bonding.dm +++ b/code/modules/surgery/advanced/viral_bonding.dm @@ -17,7 +17,7 @@ /datum/surgery/advanced/viral_bonding/can_start(mob/user, mob/living/carbon/target) if(!..()) return FALSE - if(!LAZYLEN(target.viruses)) + if(!LAZYLEN(target.diseases)) return FALSE return TRUE @@ -38,7 +38,7 @@ /datum/surgery_step/viral_bond/success(mob/user, mob/living/carbon/target, target_zone, obj/item/tool, datum/surgery/surgery) user.visible_message("[target]'s bone marrow begins pulsing slowly.", "[target]'s bone marrow begins pulsing slowly. The viral bonding is complete.") - for(var/X in target.viruses) + for(var/X in target.diseases) var/datum/disease/D = X D.carrier = TRUE return TRUE \ No newline at end of file diff --git a/code/modules/surgery/organs/appendix.dm b/code/modules/surgery/organs/appendix.dm index 35a2d851e3..4494148082 100644 --- a/code/modules/surgery/organs/appendix.dm +++ b/code/modules/surgery/organs/appendix.dm @@ -14,7 +14,7 @@ name = "appendix" /obj/item/organ/appendix/Remove(mob/living/carbon/M, special = 0) - for(var/datum/disease/appendicitis/A in M.viruses) + for(var/datum/disease/appendicitis/A in M.diseases) A.cure() inflamed = 1 update_icon() @@ -23,7 +23,7 @@ /obj/item/organ/appendix/Insert(mob/living/carbon/M, special = 0) ..() if(inflamed) - M.AddDisease(new /datum/disease/appendicitis) + M.ForceContractDisease(new /datum/disease/appendicitis(), FALSE, TRUE) /obj/item/organ/appendix/prepare_eat() var/obj/S = ..() diff --git a/icons/mob/actions/actions_minor_antag.dmi b/icons/mob/actions/actions_minor_antag.dmi index 4e5806f2fb..20daacd32c 100644 Binary files a/icons/mob/actions/actions_minor_antag.dmi and b/icons/mob/actions/actions_minor_antag.dmi differ diff --git a/icons/mob/hud.dmi b/icons/mob/hud.dmi index c275e66752..c27834de5c 100644 Binary files a/icons/mob/hud.dmi and b/icons/mob/hud.dmi differ diff --git a/tgstation.dme b/tgstation.dme index 70fc644736..5690081ec3 100755 --- a/tgstation.dme +++ b/tgstation.dme @@ -400,7 +400,6 @@ #include "code\datums\diseases\advance\symptoms\fever.dm" #include "code\datums\diseases\advance\symptoms\fire.dm" #include "code\datums\diseases\advance\symptoms\flesh_eating.dm" -#include "code\datums\diseases\advance\symptoms\genetics.dm" #include "code\datums\diseases\advance\symptoms\hallucigen.dm" #include "code\datums\diseases\advance\symptoms\headache.dm" #include "code\datums\diseases\advance\symptoms\heal.dm" @@ -1220,6 +1219,11 @@ #include "code\modules\antagonists\devil\sintouched\objectives.dm" #include "code\modules\antagonists\devil\true_devil\_true_devil.dm" #include "code\modules\antagonists\devil\true_devil\inventory.dm" +#include "code\modules\antagonists\disease\disease_abilities.dm" +#include "code\modules\antagonists\disease\disease_datum.dm" +#include "code\modules\antagonists\disease\disease_disease.dm" +#include "code\modules\antagonists\disease\disease_event.dm" +#include "code\modules\antagonists\disease\disease_mob.dm" #include "code\modules\antagonists\ert\ert.dm" #include "code\modules\antagonists\greentext\greentext.dm" #include "code\modules\antagonists\highlander\highlander.dm"