The Medical Stasis Refactoring (#21311)

This PR implements a variety pack of new interactions for Medical Stasis
(stasis beds, stasis bags, and cryogenics), which should broadly extend
their utility. Not all of it is necessarily a good thing to have around,
such as for instance stasis slowing down the rate at which the liver
removes toxins. A few more organs have by extension been time
differentiated to allow for this change to take place.

As a general rule of thumb, most organ effects that are handled "per
second" are proportionally slowed down by the stasis rating of a given
source of medical stasis. This can be a good or a bad thing depending on
the context.

**Good effects of Stasis:**
- Slowing down appendicitis.
- Reducing the damage organs take per second from most per-second
sources.
- Making kidneys and livers deal less dangerous effects to their owner
when severely damaged.
- (Not in this PR, but was done in a previous PR): Brains lose BA
slower.

**Bad effects of Stasis:**
- Organs also heal slower from all per-second sources, this includes
chems. So while they take less damage, they're also taking less healing.
- The liver's rate at which it filters the blood is reduced. You get to
stay black-out drunk for 10x longer if placed in stasis.
- (Not in this PR, but was done in a previous PR): Brains heal their BA
slower.

---------

Signed-off-by: VMSolidus <evilexecutive@gmail.com>
This commit is contained in:
VMSolidus
2025-11-03 08:13:03 +00:00
committed by GitHub
parent 17ffc47c64
commit e934c818c1
8 changed files with 192 additions and 60 deletions
+15 -3
View File
@@ -15,6 +15,9 @@
var/active_emissive = FALSE
var/list/possible_modifications = list("Normal","Assisted","Mechanical") //this is used in the character setup
/// The amount all organs heal themselves by per second when not being affected by chems.
var/organ_self_heal_per_second = 0.2
min_broken_damage = 10 //Internal organs are frail, man.
/obj/item/organ/internal/Destroy()
@@ -145,8 +148,17 @@
/obj/item/organ/internal/process(seconds_per_tick)
..()
if(istype(owner) && (toxin_type in owner.chem_effects))
if(!owner)
return
if(owner.stasis_value > 0)
// Putting a body in stasis will simultaneously slow down the rate at which organs die
// while also slowing down the rate at which they are healed.
seconds_per_tick /= owner.stasis_value
if(toxin_type in owner.chem_effects)
take_damage(owner.chem_effects[toxin_type] * seconds_per_tick)
handle_regeneration(seconds_per_tick)
tick_surge_damage() //Yes, this is intentional.
@@ -155,7 +167,7 @@
if(!damage || BP_IS_ROBOTIC(src) || !istype(owner) || owner.is_asystole() || (owner.chem_effects[CE_TOXIN] || (toxin_type in owner.chem_effects)))
return FALSE
var/repair_modifier = owner.chem_effects[CE_ORGANREPAIR] || 0.1
var/repair_modifier = owner.chem_effects[CE_ORGANREPAIR] || organ_self_heal_per_second
if(damage < repair_modifier*max_damage)
heal_damage(repair_modifier)
heal_damage(repair_modifier * seconds_per_tick)
return TRUE // regeneration is allowed
+35 -12
View File
@@ -4,39 +4,62 @@
parent_organ = BP_GROIN
organ_tag = BP_APPENDIX
possible_modifications = list ("Normal","Removed")
/**
* The amount of seconds that have passed since starting an appendicitis event.
* This number is set initially to 1 by the event, and increments by 1 each real life second.
* While its at 0, no appendix calculations are performed.
*/
var/inflamed = 0
/// The amount of pain to take per second while in stage 1 of appendicitis.
var/stage_one_pain_per_second = 1
/// The amount of pain to take per second while in stage 2 of appendicitis.
var/stage_two_pain_per_second = 1.5
/// The amount of damage an appendix takes per second while in stage 2 of appendicitis.
var/stage_two_organ_damage_per_second = 0.006
/obj/item/organ/internal/appendix/update_icon()
..()
if(inflamed)
icon_state = "[icon_state]inflamed"
name = "inflamed [name]"
/obj/item/organ/internal/appendix/process()
/obj/item/organ/internal/appendix/process(seconds_per_tick)
..()
if(!owner || !inflamed || !BP_IS_ROBOTIC(src))
return
if(owner.stasis_value > 0)
// Decrease the effective tickrate when in stasis.
// Basically, you die of appendicitis slower while in stasis.
seconds_per_tick /= owner.stasis_value
var/can_feel_pain = ORGAN_CAN_FEEL_PAIN(src)
inflamed++
if(can_feel_pain && prob(5))
owner.custom_pain("You feel a stinging pain in your abdomen!")
owner.visible_message("<B>\The [owner]</B> winces slightly.")
inflamed += seconds_per_tick
if(can_feel_pain)
if(prob(5))
owner.custom_pain("You feel a stinging pain in your abdomen!")
owner.visible_message("<B>\The [owner]</B> winces slightly.")
var/obj/item/organ/external/O = owner.get_organ(parent_organ)
if(O)
O.add_pain(10)
if(inflamed > 200 && prob(3))
take_internal_damage(0.1)
O.add_pain(stage_one_pain_per_second * seconds_per_tick)
if(inflamed > 400)
take_internal_damage(stage_two_organ_damage_per_second * seconds_per_tick)
if(can_feel_pain)
owner.visible_message("<B>\The [owner]</B> winces painfully.")
if(prob(3))
owner.visible_message("<B>\The [owner]</B> winces painfully.")
var/obj/item/organ/external/O = owner.get_organ(parent_organ)
if(O)
O.add_pain(25)
O.add_pain(stage_two_pain_per_second * seconds_per_tick)
owner.adjustToxLoss(1)
if(inflamed > 400 && prob(1))
if(inflamed > 800 && prob(1))
germ_level += rand(2,6)
owner.vomit()
if(inflamed > 600 && prob(1))
if(inflamed > 1200 && prob(1))
if(can_feel_pain)
owner.custom_pain("You feel a stinging pain in your abdomen!")
owner.Weaken(10)
+3 -3
View File
@@ -120,6 +120,8 @@
/obj/item/organ/internal/heart/process(seconds_per_tick)
if(!owner)
return ..()
if(owner.stasis_value > 0) // Decrease the effective tickrate when in stasis.
seconds_per_tick /= owner.stasis_value
handle_pulse()
if(pulse)
if(pulse == PULSE_2FAST)
@@ -346,9 +348,7 @@
. = "[pulsesound] pulse"
// Example heart item that has significantly higher statistics.
// Also to be used for the Galatean Bio-augments PRs.
// TODO: After refactoring the organ selector, make it so that this is a selectable heart type(For Galateans)
// Galatean boosted heart
/obj/item/organ/internal/heart/boosted_heart
name = "boosted heart"
desc = "Intended for athletes, some workers, and soldiers, this improved heart increases blood flow and circulation." \
+45 -16
View File
@@ -12,34 +12,63 @@
relative_size = 10
toxin_type = CE_NEPHROTOXIC
/obj/item/organ/internal/kidneys/process()
/// The amount of toxin damage to take per second from coffee while the kidneys are bruised.
var/bruised_tox_damage_from_coffee = 0.2
/// The amount of toxin damage to take per second from coffee while the kidneys are broken.
var/broken_tox_damage_from_coffee = 0.6
/// Bruised kidneys will leak up to this amount of potassium into the bloodstream.
var/bruised_max_potassium = 5
/**
* Damaged kidneys leak potassium into the blood when processing any medical chems.
* This is the amount of reagents of potassium per second added to the bloodstream while the kidneys are bruised.
*/
var/bruised_potassium_per_second = 0.1
/// Broken kidneys will leak up to this amount of potassium into the bloodstream. This number should generally be higher than the bruised value.
var/broken_max_potassium = 15
/**
* Damaged kidneys leak potassium into the blood when processing any medical chems.
* This is the amount of reagents of potassium per second added to the bloodstream while the kidneys are broken.
*/
var/broken_potassium_per_second = 4
/// The amount of toxin damage per second taken by a body with broken kidneys.
var/broken_toxin_accumulation_per_second = 0.33
/// The amount of toxin damage per second taken by a body with dead kidneys.
var/dead_toxin_accumulation_per_second = 0.66
/obj/item/organ/internal/kidneys/process(seconds_per_tick)
..()
if(!owner)
return
if(owner.stasis_value > 0) // Decrease the effective tickrate when in stasis.
seconds_per_tick /= owner.stasis_value
// Coffee is really bad for you with busted kidneys.
// This should probably be expanded in some way, but fucked if I know
// what else kidneys can process in our reagent list.
var/singleton/reagent/drink/coffee = REAGENT_VOLUME(owner.reagents, /singleton/reagent/drink/coffee)
if(coffee)
if(REAGENT_VOLUME(owner.reagents, /singleton/reagent/drink/coffee))
if(is_bruised())
owner.adjustToxLoss(0.1)
owner.adjustToxLoss(bruised_tox_damage_from_coffee * seconds_per_tick)
else if(is_broken())
owner.adjustToxLoss(0.3)
owner.adjustToxLoss(broken_tox_damage_from_coffee * seconds_per_tick)
if(is_bruised())
if(prob(5) && REAGENT_VOLUME(reagents, /singleton/reagent/potassium) < 5)
reagents.add_reagent(/singleton/reagent/potassium, REM*5)
if(REAGENT_VOLUME(reagents, /singleton/reagent/potassium) < bruised_max_potassium)
reagents.add_reagent(/singleton/reagent/potassium, bruised_potassium_per_second * seconds_per_tick)
if(is_broken())
if(REAGENT_VOLUME(owner.reagents, /singleton/reagent/potassium) < 15)
owner.reagents.add_reagent(/singleton/reagent/potassium, REM*2)
if(REAGENT_VOLUME(owner.reagents, /singleton/reagent/potassium) < broken_max_potassium)
owner.reagents.add_reagent(/singleton/reagent/potassium, broken_potassium_per_second * seconds_per_tick)
//If your kidneys aren't working, your body's going to have a hard time cleaning your blood.
if(!owner.chem_effects[CE_ANTITOXIN])
if(prob(33))
if(is_broken())
owner.adjustToxLoss(0.5)
if(status & ORGAN_DEAD)
owner.adjustToxLoss(1)
if(!owner.chem_effects[CE_ANTITOXIN]) // Dylovene fully prevents the toxin accumulation from kidneys.
if(is_broken())
owner.adjustToxLoss(broken_toxin_accumulation_per_second * seconds_per_tick)
if(status & ORGAN_DEAD)
owner.adjustToxLoss(dead_toxin_accumulation_per_second * seconds_per_tick)
+4
View File
@@ -76,6 +76,9 @@
if(!owner)
return
if(owner.stasis_value > 0) // Decrease the effective tickrate when in stasis.
seconds_per_tick /= owner.stasis_value
if(germ_level > INFECTION_LEVEL_ONE)
owner.notify_message(SPAN_WARNING(infection_level_one_warning), 2 MINUTES)
if(germ_level > INFECTION_LEVEL_TWO && prob(1))
@@ -160,6 +163,7 @@
return TRUE
return FALSE
// Galatean bioaugmented liver. Dramatically enhanced over a base human liver.
/obj/item/organ/internal/liver/boosted_liver
name = "boosted liver"
desc = "Designed primarily for diplomats or Galateans abroad, the boosted liver improves toxin filtering, giving a resistance to toxin damage. As a consequence, it makes it impossible for the user to get drunk."
+26 -24
View File
@@ -101,38 +101,40 @@
/obj/item/organ/internal/stomach/process()
..()
if(owner)
var/functioning = is_usable()
if(damage >= min_bruised_damage && prob((damage / max_damage) * 100))
functioning = FALSE
if(!owner)
return
if(functioning)
for(var/mob/living/M in contents)
if(M.stat == DEAD)
addtimer(CALLBACK(src, PROC_REF(digest_mob), M), 5 MINUTES, TIMER_UNIQUE)
var/functioning = is_usable()
if(damage >= min_bruised_damage && prob((damage / max_damage) * 100))
functioning = FALSE
M.adjustBruteLoss(2)
M.adjustFireLoss(2)
if(functioning)
for(var/mob/living/M in contents)
if(M.stat == DEAD)
addtimer(CALLBACK(src, PROC_REF(digest_mob), M), 5 MINUTES, TIMER_UNIQUE)
var/digestion_product = M.get_digestion_product()
if(digestion_product)
ingested.add_reagent(digestion_product, rand(1,3))
M.adjustBruteLoss(2)
M.adjustFireLoss(2)
else if(world.time >= next_cramp)
next_cramp = world.time + rand(200,800)
owner.custom_pain("Your stomach cramps agonizingly!",1)
var/digestion_product = M.get_digestion_product()
if(digestion_product)
ingested.add_reagent(digestion_product, rand(1,3))
if(should_process_alcohol)
else if(world.time >= next_cramp)
next_cramp = world.time + rand(200,800)
owner.custom_pain("Your stomach cramps agonizingly!",1)
var/alcohol_volume = REAGENT_VOLUME(ingested, /singleton/reagent/alcohol)
if(should_process_alcohol)
// Alcohol counts as double volume for the purposes of vomit probability
var/effective_volume = ingested.total_volume + alcohol_volume
var/alcohol_volume = REAGENT_VOLUME(ingested, /singleton/reagent/alcohol)
// Just over the limit, the probability will be low. It rises a lot such that at double ingested it's 64% chance.
var/vomit_probability = (effective_volume / stomach_volume) ** 6
if(prob(vomit_probability))
owner.vomit()
// Alcohol counts as double volume for the purposes of vomit probability
var/effective_volume = ingested.total_volume + alcohol_volume
// Just over the limit, the probability will be low. It rises a lot such that at double ingested it's 64% chance.
var/vomit_probability = (effective_volume / stomach_volume) ** 6
if(prob(vomit_probability))
owner.vomit()
/obj/item/organ/internal/stomach/proc/digest_mob(mob/M)
if(!QDELETED(M))