Various Delta Time Fixes (#21871)

Organs were being given ~3 seconds of DT per ~2 seconds of real time,
because they were being hit by Process() TWICE, once during processing
for the "Set of all objects", and again during processing for the "Set
of all mobs". No species was hit harder than this but IPCs, who suffered
from having wildly inconsistent temperature mechanics that seemingly
never matched the expected numbers.

I have actually tested this PR to verify that it works. I even went the
extra mile to more extensively test IPC temperature mechanics to find a
separate bug unrelated to DTs that was causing suit coolers to just
straight up not work at all (space suit or otherwise) on a majority of
all IPC subspecies. I then tested the numbers in the PR for IPC cooling
to verify that things work as intended.

<img width="969" height="623" alt="image"
src="https://github.com/user-attachments/assets/01c3aca7-b436-4e52-86f7-aed847dcba5e"
/>

I also tweaked all the subsystems to have a small performance
improvement.

---------

Signed-off-by: VMSolidus <evilexecutive@gmail.com>
This commit is contained in:
VMSolidus
2026-02-27 01:28:20 +00:00
committed by GitHub
parent 8e602afb32
commit 1423fcd04e
19 changed files with 75 additions and 74 deletions
@@ -30,18 +30,6 @@
for(var/obj/item/organ/external/Ex in organs)
bad_external_organs |= Ex
//processing internal organs is pretty cheap, do that first.
for(var/obj/item/organ/I in internal_organs)
if (QDELETED(I))
LOG_DEBUG("Organ [DEBUG_REF(src)] was not properly removed from its parent!")
internal_organs -= I
continue
if(I.status & ORGAN_DEAD)
continue
I.process(seconds_per_tick)
handle_stance()
handle_grasp()
@@ -55,7 +43,6 @@
bad_external_organs -= E
continue
else
E.process()
number_wounds += E.number_wounds
if (!lying && !buckled_to && world.time - l_move_time < 15)
+12 -13
View File
@@ -59,7 +59,7 @@
//Organs
handle_organs(seconds_per_tick)
stabilize_body_temperature() //Body temperature adjusts itself (self-regulation)
stabilize_body_temperature(seconds_per_tick) //Body temperature adjusts itself (self-regulation)
//Random events (vomiting etc)
handle_random_events()
@@ -303,7 +303,7 @@
return breath
/mob/living/carbon/human/handle_environment(datum/gas_mixture/environment)
/mob/living/carbon/human/handle_environment(datum/gas_mixture/environment, seconds_per_tick)
..()
if(!environment)
@@ -330,8 +330,10 @@
if(bodytemperature > (0.1 * HUMAN_HEAT_CAPACITY/(HUMAN_EXPOSED_SURFACE_AREA*STEFAN_BOLTZMANN_CONSTANT))**(1/4) + COSMIC_RADIATION_TEMPERATURE)
//Thermal radiation into space
var/heat_loss = HUMAN_EXPOSED_SURFACE_AREA * STEFAN_BOLTZMANN_CONSTANT * ((bodytemperature - COSMIC_RADIATION_TEMPERATURE)**4)
// Temperature loss in Watts (kgm^2/s^3)
var/temperature_loss = heat_loss/HUMAN_HEAT_CAPACITY
bodytemperature -= temperature_loss
// Since body temperature is in Joules (kgm^2/s^2), we multiply temperature loss by DT (in seconds) to convert from Watts to Joules before subtracting.
bodytemperature -= temperature_loss * seconds_per_tick
else
var/loc_temp = T0C
if(istype(loc, /obj/machinery/atmospherics/unary/cryo_cell))
@@ -437,9 +439,9 @@
baseline += clothing.body_temperature_change
return baseline
/mob/living/carbon/human/proc/stabilize_body_temperature()
/mob/living/carbon/human/proc/stabilize_body_temperature(seconds_per_tick)
if (species.passive_temp_gain) // We produce heat naturally.
species.handle_temperature_regulation(src)
species.handle_temperature_regulation(src, seconds_per_tick)
if (species.body_temperature == null)
return //this species doesn't have metabolic thermoregulation
@@ -453,19 +455,16 @@
if(bodytemperature < species.cold_level_1) //260.15 is 310.15 - 50, the temperature where you start to feel effects.
if(nutrition >= 2) //If we are very, very cold we'll use up quite a bit of nutriment to heat us up.
adjustNutritionLoss(2)
var/recovery_amt = max((body_temperature_difference / BODYTEMP_AUTORECOVERY_DIVISOR), BODYTEMP_AUTORECOVERY_MINIMUM)
bodytemperature += recovery_amt
adjustNutritionLoss(seconds_per_tick)
bodytemperature += max((body_temperature_difference / BODYTEMP_AUTORECOVERY_DIVISOR * seconds_per_tick), BODYTEMP_AUTORECOVERY_MINIMUM * seconds_per_tick)
else if(species.cold_level_1 <= bodytemperature && bodytemperature <= species.heat_level_1)
var/recovery_amt = body_temperature_difference / BODYTEMP_AUTORECOVERY_DIVISOR
bodytemperature += recovery_amt
bodytemperature += body_temperature_difference / BODYTEMP_AUTORECOVERY_DIVISOR * seconds_per_tick
else if(bodytemperature > species.heat_level_1) //360.15 is 310.15 + 50, the temperature where you start to feel effects.
if(hydration >= 2)
adjustHydrationLoss(2)
adjustHydrationLoss(seconds_per_tick)
if((species.flags & CAN_SWEAT) && fire_stacks == 0)
fire_stacks = -1
var/recovery_amt = min((body_temperature_difference / BODYTEMP_AUTORECOVERY_DIVISOR), -BODYTEMP_AUTORECOVERY_MINIMUM) //We're dealing with negative numbers
bodytemperature += recovery_amt
bodytemperature += min((body_temperature_difference * seconds_per_tick / BODYTEMP_AUTORECOVERY_DIVISOR), -BODYTEMP_AUTORECOVERY_MINIMUM * seconds_per_tick) //We're dealing with negative numbers
/**
* Returns a bitflag for the body parts currently heat-protected. Called and used by get_heat_protection()
@@ -238,7 +238,7 @@
var/heat_level_2 = 400
/// Heat damage level 3 above this point
var/heat_level_3 = 1000
/// Species will gain this much temperature every second
/// Species will gain this much temperature (in degrees kelvin per second)
var/passive_temp_gain = 0
/// Dangerously high pressure
var/hazard_high_pressure = HAZARD_HIGH_PRESSURE
@@ -1080,5 +1080,5 @@
* This proc handles the species temperature regulation. By default, it just adds `passive_temp_gain` to the human's bodytemperature.
* Can be overridden for more complex calculations.
*/
/datum/species/proc/handle_temperature_regulation(mob/living/carbon/human/human)
human.bodytemperature += passive_temp_gain
/datum/species/proc/handle_temperature_regulation(mob/living/carbon/human/human, seconds_per_tick)
human.bodytemperature += passive_temp_gain * seconds_per_tick
@@ -72,7 +72,7 @@
heat_level_3 = 2400
body_temperature = null
passive_temp_gain = 10
passive_temp_gain = 5 // Degrees kelvin per second
inherent_verbs = list(
/mob/living/carbon/human/proc/change_monitor,
@@ -171,11 +171,11 @@
var/machine_ui_theme = "hackerman"
/datum/species/machine/handle_temperature_regulation(mob/living/carbon/human/human)
/datum/species/machine/handle_temperature_regulation(mob/living/carbon/human/human, seconds_per_tick)
// No cooling unit = you're cooking. Broken cooling unit effects are handled by the organ itself.
// Here we just want to check if it's been removed.
// 500K is about 226 degrees. Spicy!
var/base_heat_gain = passive_temp_gain
var/base_heat_gain = passive_temp_gain * seconds_per_tick
var/obj/item/organ/internal/machine/cooling_unit/cooling = human.internal_organs_by_name[BP_COOLING_UNIT]
if(!cooling || (cooling?.status & ORGAN_DEAD))
base_heat_gain *= 4 //uh oh
+2 -2
View File
@@ -13,7 +13,7 @@
var/datum/gas_mixture/environment = loc.return_air()
//Handle temperature/pressure differences between body and environment
if(environment)
handle_environment(environment)
handle_environment(environment, seconds_per_tick)
blinded = 0 // Placing this here just show how out of place it is.
@@ -213,7 +213,7 @@
if(!.) // If we're under or inside shelter, use the z-level rain (for ambience)
. = SSweather.weather_by_z["[my_turf.z]"]
/mob/living/proc/handle_environment(var/datum/gas_mixture/environment)
/mob/living/proc/handle_environment(var/datum/gas_mixture/environment, seconds_per_tick)
SHOULD_CALL_PARENT(TRUE)