diff --git a/code/__DEFINES/dcs/signals.dm b/code/__DEFINES/dcs/signals.dm index a6f4b6ec8ae..de63351f90e 100644 --- a/code/__DEFINES/dcs/signals.dm +++ b/code/__DEFINES/dcs/signals.dm @@ -117,7 +117,7 @@ #define COMSIG_ATOM_UPDATE_OVERLAYS "atom_update_overlays" ///from base of [/atom/update_icon]: (signalOut, did_anything) #define COMSIG_ATOM_UPDATED_ICON "atom_updated_icon" -///from base of atom/Entered(): (atom/movable/entering, /atom) +///from base of atom/Entered(): (atom/movable/entering, /atom/oldLoc) #define COMSIG_ATOM_ENTERED "atom_entered" /// Sent from the atom that just Entered src. From base of atom/Entered(): (/atom/entered_atom, /atom/oldLoc) #define COMSIG_ATOM_ENTERING "atom_entering" @@ -230,11 +230,11 @@ #define COMSIG_REAGENTS_ADD_REAGENT "reagents_add_reagent" ///from base of [/datum/reagents/proc/del_reagent]: (/datum/reagent) #define COMSIG_REAGENTS_DEL_REAGENT "reagents_del_reagent" -///from base of [/datum/reagents/proc/clear_reagents]: () -#define COMSIG_REAGENTS_REM_REAGENT "reagents_rem_reagent" -///from base of [/datum/reagents/proc/set_temperature]: (new_temp, old_temp) -#define COMSIG_REAGENTS_CLEAR_REAGENTS "reagents_clear_reagents" ///from base of [/datum/reagents/proc/remove_reagent]: (/datum/reagent, amount) +#define COMSIG_REAGENTS_REM_REAGENT "reagents_rem_reagent" +///from base of [/datum/reagents/proc/clear_reagents]: () +#define COMSIG_REAGENTS_CLEAR_REAGENTS "reagents_clear_reagents" +///from base of [/datum/reagents/proc/set_temperature]: (new_temp, old_temp) #define COMSIG_REAGENTS_TEMP_CHANGE "reagents_temp_change" ///from base of [/datum/reagents/proc/handle_reactions]: (num_reactions) #define COMSIG_REAGENTS_REACTED "reagents_reacted" @@ -855,6 +855,8 @@ #define COMSIG_HUMAN_DISARM_HIT "human_disarm_hit" ///Whenever EquipRanked is called, called after job is set #define COMSIG_JOB_RECEIVED "job_received" +///from /mob/living/carbon/human/proc/set_coretemperature(): (oldvalue, newvalue) +#define COMSIG_HUMAN_CORETEMP_CHANGE "human_coretemp_change" // /datum/species signals diff --git a/code/datums/components/rot.dm b/code/datums/components/rot.dm index 091305df8ca..dc90ba90632 100644 --- a/code/datums/components/rot.dm +++ b/code/datums/components/rot.dm @@ -1,78 +1,132 @@ -/datum/component/rot - /// Amount of miasma we're spawning per tick - var/amount = 1 - /// Time remaining before we remove the component - var/time_remaining = 5 MINUTES +#define REAGENT_BLOCKER (1<<0) +#define TEMPERATURE_BLOCKER (1<<1) +#define HUSK_BLOCKER (1<<2) -/datum/component/rot/Initialize(new_amount) +///Makes a thing rotting, carries with it a start delay and some things that can halt the rot, along with infection logic +/datum/component/rot + ///The time we were created, allows for cheese smell + var/start_time = 0 + ///The delay in ticks between the start of rot and effects kicking in + var/start_delay = 0 + ///How strong is the rot? used for scaling different aspects of the component. Between 0 and 1 + var/strength = 0 + ///Is the component active right now? + var/active = FALSE + ///Bitfield of sources preventing the component from rotting + var/blockers = NONE + +/datum/component/rot/Initialize(delay, severity) if(!isatom(parent)) return COMPONENT_INCOMPATIBLE + if(isliving(parent)) + var/mob/living/living_parent = parent + //I think this can break in cases where someone becomes a robot post death, but I uh, I don't know how to account for that + if(!(living_parent.mob_biotypes & (MOB_ORGANIC|MOB_UNDEAD))) + return COMPONENT_INCOMPATIBLE - if(new_amount) - amount = new_amount + start_delay = delay + strength = severity - START_PROCESSING(SSprocessing, src) + RegisterSignal(parent, list(COMSIG_ATOM_HULK_ATTACK, COMSIG_ATOM_ATTACK_ANIMAL, COMSIG_ATOM_ATTACK_HAND), .proc/rot_react_touch) + RegisterSignal(parent, COMSIG_PARENT_ATTACKBY, .proc/rot_hit_react) + if(ismovable(parent)) + RegisterSignal(parent, list(COMSIG_MOVABLE_CROSSED, COMSIG_MOVABLE_BUMP), .proc/rot_react) + if(isliving(parent)) + RegisterSignal(parent, COMSIG_LIVING_REVIVE, .proc/react_to_revive) //mobs stop this when they come to life + RegisterSignal(parent, COMSIG_LIVING_GET_PULLED, .proc/rot_react_touch) + if(iscarbon(parent)) + var/mob/living/carbon/carbon_parent = parent + RegisterSignal(carbon_parent.reagents, list(COMSIG_REAGENTS_ADD_REAGENT, + COMSIG_REAGENTS_REM_REAGENT, + COMSIG_REAGENTS_DEL_REAGENT), .proc/check_reagent) + RegisterSignal(parent, list(SIGNAL_ADDTRAIT(TRAIT_HUSK), SIGNAL_REMOVETRAIT(TRAIT_HUSK)), .proc/check_husk_trait) + check_reagent(carbon_parent.reagents, null) + check_husk_trait(null) + if(ishuman(parent)) + var/mob/living/carbon/human/human_parent = parent + RegisterSignal(parent, COMSIG_HUMAN_CORETEMP_CHANGE, .proc/check_for_temperature) + check_for_temperature(null, 0, human_parent.coretemperature) -/datum/component/rot/Destroy(force, silent) - STOP_PROCESSING(SSprocessing, src) - . = ..() + start_up(NONE) //If nothing's blocking it, start -/datum/component/rot/process(delta_time) - var/atom/A = parent +///One of two procs that modifies blockers, this one handles removing a blocker and potentially restarting the rot +/datum/component/rot/proc/start_up(blocker_type) + blockers &= ~blocker_type //Yeet the type + if(blockers || active) //If it's not empty + return + start_time = world.time + active = TRUE - //SSprocessing goes off per 1 second - time_remaining -= delta_time * 1 SECONDS - if(time_remaining <= 0) - qdel(src) +///One of two procs that modifies blockers, this one handles adding a blocker and potentially ending the rot +/datum/component/rot/proc/rest(blocker_type) + var/old_blockers = blockers + blockers |= blocker_type + if(old_blockers || !active) //If it had anything before this + return + start_delay = max((start_time + start_delay) - world.time, 0) //Account for the time spent rotting + active = FALSE + +/datum/component/rot/proc/react_to_revive() + SIGNAL_HANDLER + qdel(src) + +/datum/component/rot/proc/check_reagent(datum/reagents/source, datum/reagent/modified) + SIGNAL_HANDLER + if(modified && !istype(modified, /datum/reagent/toxin/formaldehyde) && !istype(modified, /datum/reagent/cryostylane)) + return + if(source.has_reagent(/datum/reagent/toxin/formaldehyde, 15) || source.has_reagent(/datum/reagent/cryostylane)) + rest(REAGENT_BLOCKER) + return + start_up(REAGENT_BLOCKER) + +/datum/component/rot/proc/check_for_temperature(datum/source, old_temp, new_temp) + if(new_temp <= T0C-10) + rest(TEMPERATURE_BLOCKER) + return + start_up(TEMPERATURE_BLOCKER) + +/datum/component/rot/proc/check_husk_trait() + SIGNAL_HANDLER + if(HAS_TRAIT(parent, TRAIT_HUSK)) + rest(HUSK_BLOCKER) + return + start_up(HUSK_BLOCKER) + +/datum/component/rot/proc/rot_hit_react(datum/source, obj/item/hit_with, mob/living/attacker, params) + SIGNAL_HANDLER + rot_react_touch(source, attacker) + +/datum/component/rot/proc/rot_react_touch(datum/source, mob/living/react_to) + SIGNAL_HANDLER + rot_react(source, react_to, react_to.zone_selected) + +///The main bit of logic for the rot component, does a temperature check and has a chance to infect react_to +/datum/component/rot/proc/rot_react(source, mob/living/react_to, target_zone = null) + SIGNAL_HANDLER + if(!isliving(react_to)) return - var/turf/open/T = get_turf(A) - if(!istype(T) || T.planetary_atmos || T.return_air().return_pressure() > (WARNING_HIGH_PRESSURE - 10)) + // Don't infect if you're chilled (I'd like to link this with the signals, but I can't come up with a good way to pull it off) + var/atom/atom_parent = parent + var/datum/gas_mixture/our_mix = atom_parent.return_air() + if(our_mix?.temperature <= T0C-10) return - var/datum/gas_mixture/stank = new - ADD_GAS(/datum/gas/miasma, stank.gases) - stank.gases[/datum/gas/miasma][MOLES] = amount * delta_time - stank.temperature = BODYTEMP_NORMAL // otherwise we have gas below 2.7K which will break our lag generator - T.assume_air(stank) - T.air_update_turf(FALSE, FALSE) - -/datum/component/rot/corpse - amount = MIASMA_CORPSE_MOLES - time_remaining = 7 MINUTES //2 minutes more to compensate for the delay - -/datum/component/rot/corpse/Initialize() - if(!iscarbon(parent)) - return COMPONENT_INCOMPATIBLE - . = ..() - -/datum/component/rot/corpse/process() - var/mob/living/carbon/carbon_mob = parent - if(carbon_mob.stat != DEAD) - qdel(src) + if(!active) return // Wait a bit before decaying - if(world.time - carbon_mob.timeofdeath < 2 MINUTES) + if(world.time - start_time < start_delay) return - // Properly stored corpses shouldn't create miasma - if(istype(carbon_mob.loc, /obj/structure/closet/crate/coffin)|| istype(carbon_mob.loc, /obj/structure/closet/body_bag) || istype(carbon_mob.loc, /obj/structure/bodycontainer)) + if(!prob(strength * 8)) return - // No decay if formaldehyde in corpse or when the corpse is charred - if(carbon_mob.reagents.has_reagent(/datum/reagent/toxin/formaldehyde, 15) || HAS_TRAIT(carbon_mob, TRAIT_HUSK)) - return + //We're running just under the "worst disease", since we don't want these to be too strong + var/datum/disease/advance/random/rand_disease = new(rand(5 * strength), rand(strength * 7)) + rand_disease.name = "Unknown" + react_to.ContactContractDisease(rand_disease, target_zone) - // Similar to formaldehyde except it slows down surgery too - if(carbon_mob.reagents.has_reagent(/datum/reagent/cryostylane)) - return - - // Also no decay if corpse chilled or not organic/undead - if(carbon_mob.bodytemperature <= T0C-10 || !(carbon_mob.mob_biotypes & (MOB_ORGANIC|MOB_UNDEAD))) - return - - ..() - -/datum/component/rot/gibs - amount = MIASMA_GIBS_MOLES +#undef REAGENT_BLOCKER +#undef TEMPERATURE_BLOCKER +#undef HUSK_BLOCKER diff --git a/code/datums/diseases/advance/advance.dm b/code/datums/diseases/advance/advance.dm index bfed83f96ab..c4aec06d144 100644 --- a/code/datums/diseases/advance/advance.dm +++ b/code/datums/diseases/advance/advance.dm @@ -19,7 +19,7 @@ /datum/disease/advance name = "Unknown" // We will always let our Virologist name our disease. desc = "An engineered disease which can contain a multitude of symptoms." - form = "Advance Disease" // Will let med-scanners know that this disease was engineered. + form = "Advanced Disease" // Will let med-scanners know that this disease was engineered. agent = "advance microbes" max_stages = 5 spread_text = "Unknown" diff --git a/code/datums/status_effects/buffs.dm b/code/datums/status_effects/buffs.dm index 90f77167d4d..3713f0d2997 100644 --- a/code/datums/status_effects/buffs.dm +++ b/code/datums/status_effects/buffs.dm @@ -346,7 +346,7 @@ owner.bodytemperature = owner.get_body_temp_normal() if(istype(owner, /mob/living/carbon/human)) var/mob/living/carbon/human/humi = owner - humi.coretemperature = humi.get_body_temp_normal() + humi.set_coretemperature(humi.get_body_temp_normal()) return TRUE /datum/status_effect/regenerative_core/on_remove() diff --git a/code/game/objects/effects/decals/cleanable/humans.dm b/code/game/objects/effects/decals/cleanable/humans.dm index a73a0f44862..96d0ab0f1c1 100644 --- a/code/game/objects/effects/decals/cleanable/humans.dm +++ b/code/game/objects/effects/decals/cleanable/humans.dm @@ -8,12 +8,15 @@ bloodiness = BLOOD_AMOUNT_PER_DECAL beauty = -100 clean_type = CLEAN_TYPE_BLOOD + var/should_dry = TRUE var/dryname = "dried blood" //when the blood lasts long enough, it becomes dry and gets a new name var/drydesc = "Looks like it's been here a while. Eew." //as above var/drytime = 0 -/obj/effect/decal/cleanable/blood/Initialize() +/obj/effect/decal/cleanable/blood/Initialize(mapload) . = ..() + if(!should_dry) + return if(bloodiness) start_drying() else @@ -98,15 +101,13 @@ . = ..() reagents.add_reagent(/datum/reagent/liquidgibs, 5) RegisterSignal(src, COMSIG_MOVABLE_PIPE_EJECTING, .proc/on_pipe_eject) - if(mapload) //Don't rot at roundstart for the love of god - return /obj/effect/decal/cleanable/blood/gibs/replace_decal(obj/effect/decal/cleanable/C) return FALSE //Never fail to place us /obj/effect/decal/cleanable/blood/gibs/dry() . = ..() - AddComponent(/datum/component/rot/gibs) + AddComponent(/datum/component/rot, 0, 0.7) /obj/effect/decal/cleanable/blood/gibs/ex_act(severity, target) return FALSE @@ -169,6 +170,7 @@ desc = "Space Jesus, why didn't anyone clean this up? They smell terrible." icon_state = "gib1-old" bloodiness = 0 + should_dry = FALSE dryname = "old rotting gibs" drydesc = "Space Jesus, why didn't anyone clean this up? They smell terrible." @@ -177,6 +179,7 @@ setDir(pick(1,2,4,8)) add_blood_DNA(list("Non-human DNA" = random_blood_type())) AddElement(/datum/element/swabable, CELL_LINE_TABLE_SLUDGE, CELL_VIRUS_TABLE_GENERIC, rand(2,4), 10) + dry() /obj/effect/decal/cleanable/blood/drip name = "drips of blood" diff --git a/code/modules/mob/living/carbon/carbon.dm b/code/modules/mob/living/carbon/carbon.dm index 08f51d177f4..e5e6a3298cc 100644 --- a/code/modules/mob/living/carbon/carbon.dm +++ b/code/modules/mob/living/carbon/carbon.dm @@ -8,8 +8,7 @@ ADD_TRAIT(src, TRAIT_AGEUSIA, NO_TONGUE_TRAIT) GLOB.carbon_list += src - if(!mapload) //I don't want no gas leaks on my space ruin you hear? - RegisterSignal(src, COMSIG_LIVING_DEATH, .proc/attach_rot) + RegisterSignal(src, COMSIG_LIVING_DEATH, .proc/attach_rot) /mob/living/carbon/Destroy() //This must be done first, so the mob ghosts correctly before DNA etc is nulled @@ -1321,4 +1320,4 @@ /mob/living/carbon/proc/attach_rot(mapload) - AddComponent(/datum/component/rot/corpse) + AddComponent(/datum/component/rot, 6 MINUTES, 1) diff --git a/code/modules/mob/living/carbon/carbon_defines.dm b/code/modules/mob/living/carbon/carbon_defines.dm index 1ea7f1c9c32..c311bbecd39 100644 --- a/code/modules/mob/living/carbon/carbon_defines.dm +++ b/code/modules/mob/living/carbon/carbon_defines.dm @@ -51,7 +51,6 @@ var/failed_last_breath = FALSE var/co2overloadtime = null - var/temperature_resistance = T0C+75 var/obj/item/food/meat/slab/type_of_meat = /obj/item/food/meat/slab var/gib_type = /obj/effect/decal/cleanable/blood/gibs diff --git a/code/modules/mob/living/carbon/human/human.dm b/code/modules/mob/living/carbon/human/human.dm index 2bcae18e57c..f974a509e11 100644 --- a/code/modules/mob/living/carbon/human/human.dm +++ b/code/modules/mob/living/carbon/human/human.dm @@ -760,7 +760,7 @@ for(var/datum/mutation/human/HM in dna.mutations) if(HM.quality != POSITIVE) dna.remove_mutation(HM.name) - coretemperature = get_body_temp_normal(apply_change=FALSE) + set_coretemperature(get_body_temp_normal(apply_change=FALSE)) heat_exposure_stacks = 0 return ..() diff --git a/code/modules/mob/living/carbon/human/life.dm b/code/modules/mob/living/carbon/human/life.dm index a41c01d471f..0f1acc8eb8f 100644 --- a/code/modules/mob/living/carbon/human/life.dm +++ b/code/modules/mob/living/carbon/human/life.dm @@ -128,7 +128,11 @@ * * max_temp (optional) The maximum body temperature after adjustment */ /mob/living/carbon/human/proc/adjust_coretemperature(amount, min_temp=0, max_temp=INFINITY) - coretemperature = clamp(coretemperature + amount, min_temp, max_temp) + set_coretemperature(clamp(coretemperature + amount, min_temp, max_temp)) + +/mob/living/carbon/human/proc/set_coretemperature(value) + SEND_SIGNAL(src, COMSIG_HUMAN_CORETEMP_CHANGE, coretemperature, value) + coretemperature = value /** * get_body_temperature Returns the body temperature with any modifications applied