/mob/living/carbon/Life() set invisibility = 0 if(notransform) return if(damageoverlaytemp) damageoverlaytemp = 0 update_damage_hud() //Reagent processing needs to come before breathing, to prevent edge cases. handle_organs() . = ..() if (QDELETED(src)) return if(.) //not dead handle_blood() if(stat != DEAD) var/bprv = handle_bodyparts() if(bprv & BODYPART_LIFE_UPDATE_HEALTH) updatehealth() update_stamina() if(stat != DEAD) handle_brain_damage() /* BUG_PROBABLE_CAUSE if(stat != DEAD) handle_liver() */ if(stat == DEAD) stop_sound_channel(CHANNEL_HEARTBEAT) handle_death() rot() //Updates the number of stored chemicals for powers handle_changeling() if(stat != DEAD) return 1 //Procs called while dead /mob/living/carbon/proc/handle_death() for(var/datum/reagent/R in reagents.reagent_list) if(R.chemical_flags & REAGENT_DEAD_PROCESS) R.on_mob_dead(src) /////////////// // BREATHING // /////////////// //Start of a breath chain, calls breathe() /mob/living/carbon/handle_breathing(times_fired) var/next_breath = 4 var/obj/item/organ/lungs/L = getorganslot(ORGAN_SLOT_LUNGS) var/obj/item/organ/heart/H = getorganslot(ORGAN_SLOT_HEART) if(L) if(L.damage > L.high_threshold) next_breath-- if(H) if(H.damage > H.high_threshold) next_breath-- if((times_fired % next_breath) == 0 || failed_last_breath) breathe() //Breathe per 4 ticks if healthy, down to 2 if our lungs or heart are damaged, unless suffocating if(failed_last_breath) SEND_SIGNAL(src, COMSIG_ADD_MOOD_EVENT, "suffocation", /datum/mood_event/suffocation) else SEND_SIGNAL(src, COMSIG_CLEAR_MOOD_EVENT, "suffocation") else if(istype(loc, /obj/)) var/obj/location_as_object = loc location_as_object.handle_internal_lifeform(src,0) //Second link in a breath chain, calls check_breath() /mob/living/carbon/proc/breathe() var/obj/item/organ/lungs = getorganslot(ORGAN_SLOT_LUNGS) if(reagents.has_reagent("lexorin")) return if(istype(loc, /obj/machinery/atmospherics/components/unary/cryo_cell)) return if(istype(loc, /obj/item/dogborg/sleeper)) return if(ismob(loc)) return if(isbelly(loc)) return var/datum/gas_mixture/environment if(loc) environment = loc.return_air() var/datum/gas_mixture/breath if(!getorganslot(ORGAN_SLOT_BREATHING_TUBE)) if(health <= HEALTH_THRESHOLD_FULLCRIT || (pulledby && pulledby.grab_state >= GRAB_KILL) || HAS_TRAIT(src, TRAIT_MAGIC_CHOKE) || (lungs && lungs.organ_flags & ORGAN_FAILING)) losebreath++ //You can't breath at all when in critical or when being choked, so you're going to miss a breath else if(health <= crit_threshold) losebreath += 0.25 //You're having trouble breathing in soft crit, so you'll miss a breath one in four times //Suffocate if(losebreath >= 1) //You've missed a breath, take oxy damage losebreath-- if(prob(10)) emote("gasp") if(istype(loc, /obj/)) var/obj/loc_as_obj = loc loc_as_obj.handle_internal_lifeform(src,0) else //Breathe from internal breath = get_breath_from_internal(BREATH_VOLUME) if(isnull(breath)) //in case of 0 pressure internals if(isobj(loc)) //Breathe from loc as object var/obj/loc_as_obj = loc breath = loc_as_obj.handle_internal_lifeform(src, BREATH_VOLUME) else if(isturf(loc)) //Breathe from loc as turf var/breath_moles = 0 if(environment) breath_moles = environment.total_moles()*BREATH_PERCENTAGE breath = loc.remove_air(breath_moles) else //Breathe from loc as obj again if(istype(loc, /obj/)) var/obj/loc_as_obj = loc loc_as_obj.handle_internal_lifeform(src,0) check_breath(breath) if(breath) loc.assume_air(breath) air_update_turf() /mob/living/carbon/proc/has_smoke_protection() if(HAS_TRAIT(src, TRAIT_NOBREATH)) return TRUE return FALSE //Third link in a breath chain, calls handle_breath_temperature() /mob/living/carbon/proc/check_breath(datum/gas_mixture/breath) if((status_flags & GODMODE)) return var/obj/item/organ/lungs = getorganslot(ORGAN_SLOT_LUNGS) if(!lungs) adjustOxyLoss(2) //CRIT if(!breath || (breath.total_moles() == 0) || !lungs) if(reagents.has_reagent("epinephrine") && lungs) return adjustOxyLoss(1) failed_last_breath = 1 throw_alert("not_enough_oxy", /obj/screen/alert/not_enough_oxy) return 0 var/safe_oxy_min = 16 var/safe_oxy_max = 50 var/safe_co2_max = 10 var/safe_tox_max = 0.05 var/SA_para_min = 1 var/SA_sleep_min = 5 var/oxygen_used = 0 var/breath_pressure = (breath.total_moles()*R_IDEAL_GAS_EQUATION*breath.temperature)/BREATH_VOLUME var/list/breath_gases = breath.gases var/O2_partialpressure = (breath_gases[/datum/gas/oxygen]/breath.total_moles())*breath_pressure var/Toxins_partialpressure = (breath_gases[/datum/gas/plasma]/breath.total_moles())*breath_pressure var/CO2_partialpressure = (breath_gases[/datum/gas/carbon_dioxide]/breath.total_moles())*breath_pressure //OXYGEN if(O2_partialpressure > safe_oxy_max) // Too much Oxygen - blatant CO2 effect copy/pasta if(!o2overloadtime) o2overloadtime = world.time else if(world.time - o2overloadtime > 120) Dizzy(10) // better than a minute of you're fucked KO, but certainly a wake up call. Honk. adjustOxyLoss(3) if(world.time - o2overloadtime > 300) adjustOxyLoss(8) if(prob(20)) emote("cough") throw_alert("too_much_oxy", /obj/screen/alert/too_much_oxy) SEND_SIGNAL(src, COMSIG_ADD_MOOD_EVENT, "suffocation", /datum/mood_event/suffocation) if(O2_partialpressure < safe_oxy_min) //Not enough oxygen if(prob(20)) emote("gasp") if(O2_partialpressure > 0) var/ratio = 1 - O2_partialpressure/safe_oxy_min adjustOxyLoss(min(5*ratio, 3)) failed_last_breath = 1 oxygen_used = breath_gases[/datum/gas/oxygen]*ratio else adjustOxyLoss(3) failed_last_breath = 1 throw_alert("not_enough_oxy", /obj/screen/alert/not_enough_oxy) SEND_SIGNAL(src, COMSIG_ADD_MOOD_EVENT, "suffocation", /datum/mood_event/suffocation) else //Enough oxygen failed_last_breath = 0 o2overloadtime = 0 //reset our counter for this too if(health >= crit_threshold) adjustOxyLoss(-5) oxygen_used = breath_gases[/datum/gas/oxygen] clear_alert("not_enough_oxy") SEND_SIGNAL(src, COMSIG_CLEAR_MOOD_EVENT, "suffocation") breath_gases[/datum/gas/oxygen] -= oxygen_used breath_gases[/datum/gas/carbon_dioxide] += oxygen_used //CARBON DIOXIDE if(CO2_partialpressure > safe_co2_max) if(!co2overloadtime) co2overloadtime = world.time else if(world.time - co2overloadtime > 120) Unconscious(60) adjustOxyLoss(3) if(world.time - co2overloadtime > 300) adjustOxyLoss(8) if(prob(20)) emote("cough") else co2overloadtime = 0 //TOXINS/PLASMA if(Toxins_partialpressure > safe_tox_max) var/ratio = (breath_gases[/datum/gas/plasma]/safe_tox_max) * 10 adjustToxLoss(CLAMP(ratio, MIN_TOXIC_GAS_DAMAGE, MAX_TOXIC_GAS_DAMAGE)) throw_alert("too_much_tox", /obj/screen/alert/too_much_tox) else clear_alert("too_much_tox") //NITROUS OXIDE if(breath_gases[/datum/gas/nitrous_oxide]) var/SA_partialpressure = (breath_gases[/datum/gas/nitrous_oxide]/breath.total_moles())*breath_pressure if(SA_partialpressure > SA_para_min) Unconscious(60) if(SA_partialpressure > SA_sleep_min) Sleeping(max(AmountSleeping() + 40, 200)) else if(SA_partialpressure > 0.01) if(prob(20)) emote(pick("giggle","laugh")) SEND_SIGNAL(src, COMSIG_ADD_MOOD_EVENT, "chemical_euphoria", /datum/mood_event/chemical_euphoria) else SEND_SIGNAL(src, COMSIG_CLEAR_MOOD_EVENT, "chemical_euphoria") //BZ (Facepunch port of their Agent B) if(breath_gases[/datum/gas/bz]) var/bz_partialpressure = (breath_gases[/datum/gas/bz]/breath.total_moles())*breath_pressure if(bz_partialpressure > 1) hallucination += 10 else if(bz_partialpressure > 0.01) hallucination += 5 //TRITIUM if(breath_gases[/datum/gas/tritium]) var/tritium_partialpressure = (breath_gases[/datum/gas/tritium]/breath.total_moles())*breath_pressure radiation += tritium_partialpressure/10 //NITRYL if(breath_gases[/datum/gas/nitryl]) var/nitryl_partialpressure = (breath_gases[/datum/gas/nitryl]/breath.total_moles())*breath_pressure adjustFireLoss(nitryl_partialpressure/4) //MIASMA if(breath_gases[/datum/gas/miasma]) var/miasma_partialpressure = (breath_gases[/datum/gas/miasma]/breath.total_moles())*breath_pressure if(miasma_partialpressure > MINIMUM_MOLES_DELTA_TO_MOVE) if(prob(0.05 * miasma_partialpressure)) var/datum/disease/advance/miasma_disease = new /datum/disease/advance/random(2,3) miasma_disease.name = "Unknown" ForceContractDisease(miasma_disease, TRUE, TRUE) //Miasma side effects switch(miasma_partialpressure) if(1 to 5) // At lower pp, give out a little warning SEND_SIGNAL(src, COMSIG_CLEAR_MOOD_EVENT, "smell") if(prob(5)) to_chat(src, "There is an unpleasant smell in the air.") if(5 to 20) //At somewhat higher pp, warning becomes more obvious if(prob(15)) to_chat(src, "You smell something horribly decayed inside this room.") SEND_SIGNAL(src, COMSIG_ADD_MOOD_EVENT, "smell", /datum/mood_event/disgust/bad_smell) if(15 to 30) //Small chance to vomit. By now, people have internals on anyway if(prob(5)) to_chat(src, "The stench of rotting carcasses is unbearable!") SEND_SIGNAL(src, COMSIG_ADD_MOOD_EVENT, "smell", /datum/mood_event/disgust/nauseating_stench) vomit() if(30 to INFINITY) //Higher chance to vomit. Let the horror start if(prob(25)) to_chat(src, "The stench of rotting carcasses is unbearable!") SEND_SIGNAL(src, COMSIG_ADD_MOOD_EVENT, "smell", /datum/mood_event/disgust/nauseating_stench) vomit() else SEND_SIGNAL(src, COMSIG_CLEAR_MOOD_EVENT, "smell") //Clear all moods if no miasma at all else SEND_SIGNAL(src, COMSIG_CLEAR_MOOD_EVENT, "smell") GAS_GARBAGE_COLLECT(breath.gases) //BREATH TEMPERATURE handle_breath_temperature(breath) return 1 //Fourth and final link in a breath chain /mob/living/carbon/proc/handle_breath_temperature(datum/gas_mixture/breath) return /mob/living/carbon/proc/get_breath_from_internal(volume_needed) var/obj/item/clothing/check var/internals = FALSE for(check in GET_INTERNAL_SLOTS(src)) if(CHECK_BITFIELD(check.clothing_flags, ALLOWINTERNALS)) internals = TRUE if(internal) if(internal.loc != src) internal = null update_internals_hud_icon(0) else if (!internals && !getorganslot(ORGAN_SLOT_BREATHING_TUBE)) internal = null update_internals_hud_icon(0) else update_internals_hud_icon(1) . = internal.remove_air_volume(volume_needed) if(!.) return FALSE //to differentiate between no internals and active, but empty internals // Make corpses rot, emitting miasma /mob/living/carbon/proc/rot() // Properly stored corpses shouldn't create miasma if(istype(loc, /obj/structure/closet/crate/coffin)|| istype(loc, /obj/structure/closet/body_bag) || istype(loc, /obj/structure/bodycontainer)) return // No decay if formaldehyde in corpse or when the corpse is charred if(reagents.has_reagent("formaldehyde", 15) || HAS_TRAIT(src, TRAIT_HUSK)) return // Also no decay if corpse chilled or not organic/undead if(bodytemperature <= T0C-10 || (!(MOB_ORGANIC in mob_biotypes) && !(MOB_UNDEAD in mob_biotypes))) return // Wait a bit before decaying if(world.time - timeofdeath < 1200) return var/deceasedturf = get_turf(src) // Closed turfs don't have any air in them, so no gas building up if(!istype(deceasedturf,/turf/open)) return var/turf/open/miasma_turf = deceasedturf var/list/cached_gases = miasma_turf.air.gases cached_gases[/datum/gas/miasma] += 0.1 /mob/living/carbon/proc/handle_blood() return /mob/living/carbon/proc/handle_bodyparts() for(var/I in bodyparts) var/obj/item/bodypart/BP = I if(BP.needs_processing) . |= BP.on_life() /mob/living/carbon/proc/handle_organs() if(stat != DEAD) for(var/V in internal_organs) var/obj/item/organ/O = V if(O) O.on_life() else for(var/V in internal_organs) var/obj/item/organ/O = V if(O) O.on_death() //Needed so organs decay while inside the body. /mob/living/carbon/handle_diseases() for(var/thing in diseases) var/datum/disease/D = thing if(prob(D.infectivity)) D.spread() if(stat != DEAD || D.process_dead) D.stage_act() //todo generalize this and move hud out /mob/living/carbon/proc/handle_changeling() if(mind && hud_used && hud_used.lingchemdisplay) var/datum/antagonist/changeling/changeling = mind.has_antag_datum(/datum/antagonist/changeling) if(changeling) changeling.regenerate() hud_used.lingchemdisplay.invisibility = 0 hud_used.lingchemdisplay.maptext = "