Files
Bubberstation/code/modules/mob/living/life.dm
T
SmArtKarandnevimer 16aa15a136 Changes human name updates to be request-based instead of being automatically done every single tick (#92393)
## About The Pull Request

Changes human name to update whenever anything that could result in
their visible name changing occurs, such as changing IDs, equipping
gasmasks, picking potted plants, etc. Currently name updates occur every
``Life()`` tick and in a few "special" cases, which causes a lot of name
changes from sources such as equipment to not apply until the mob ticks,
and makes us waste a tiiiny bit of CPU time on name updates.
I've also slighly cleaned up human /Life() and made species'
``spec_life()`` not run when the mob is dead, as it was causing certain
unintended interactions, such as slimepeople regenerating blood while
dead.

## Why It's Good For The Game

Microoptimization, ensures that correct names are always used (in case
something could update their name but the mob hasn't ticked yet), plus
its just a cleaner implementation

(cherry picked from commit 87e1ef6f64)

# Conflicts:
#	code/game/data_huds.dm
2025-08-08 15:34:22 -04:00

156 lines
6.1 KiB
Plaintext

/// This divisor controls how fast body temperature changes to match the environment
#define BODYTEMP_DIVISOR 16
/**
* Handles the biological and general over-time processes of the mob.
*
*
* Arguments:
* - seconds_per_tick: The amount of time that has elapsed since this last fired.
* - times_fired: The number of times SSmobs has fired
*/
/mob/living/proc/Life(seconds_per_tick = SSMOBS_DT, times_fired)
set waitfor = FALSE
SHOULD_NOT_SLEEP(TRUE)
var/signal_result = SEND_SIGNAL(src, COMSIG_LIVING_LIFE, seconds_per_tick, times_fired)
if(signal_result & COMPONENT_LIVING_CANCEL_LIFE_PROCESSING) // mmm less work
return
if (client)
var/turf/T = get_turf(src)
if(!T)
move_to_error_room()
var/msg = " was found to have no .loc with an attached client, if the cause is unknown it would be wise to ask how this was accomplished."
message_admins(ADMIN_LOOKUPFLW(src) + msg)
send2tgs_adminless_only("Mob", key_name_and_tag(src) + msg, R_ADMIN)
src.log_message("was found to have no .loc with an attached client.", LOG_GAME)
// This is a temporary error tracker to make sure we've caught everything
else if (registered_z != T.z)
#ifdef TESTING
message_admins("[ADMIN_LOOKUPFLW(src)] has somehow ended up in Z-level [T.z] despite being registered in Z-level [registered_z]. If you could ask them how that happened and notify coderbus, it would be appreciated.")
#endif
log_game("Z-TRACKING: [src] has somehow ended up in Z-level [T.z] despite being registered in Z-level [registered_z].")
update_z(T.z)
else if (registered_z)
log_game("Z-TRACKING: [src] of type [src.type] has a Z-registration despite not having a client.")
update_z(null)
if(isnull(loc) || HAS_TRAIT(src, TRAIT_NO_TRANSFORM))
return
if(!HAS_TRAIT(src, TRAIT_STASIS))
if(stat != DEAD)
//Mutations and radiation
handle_mutations(seconds_per_tick, times_fired)
//Breathing, if applicable
handle_breathing(seconds_per_tick, times_fired)
handle_diseases(seconds_per_tick, times_fired) // DEAD check is in the proc itself; we want it to spread even if the mob is dead, but to handle its disease-y properties only if you're not.
if (QDELETED(src)) // Diseases can qdel the mob via transformations
return
// Handle temperature/pressure differences between body and environment
var/datum/gas_mixture/environment = loc.return_air()
if(environment)
handle_environment(environment, seconds_per_tick, times_fired)
handle_gravity(seconds_per_tick, times_fired)
if(living_flags & QUEUE_NUTRITION_UPDATE)
mob_mood?.update_nutrition_moodlets()
hud_used?.hunger?.update_hunger_bar()
living_flags &= ~QUEUE_NUTRITION_UPDATE
if(stat != DEAD)
return TRUE
/mob/living/proc/handle_breathing(seconds_per_tick, times_fired)
SEND_SIGNAL(src, COMSIG_LIVING_HANDLE_BREATHING, seconds_per_tick, times_fired)
return
/mob/living/proc/handle_mutations(seconds_per_tick, times_fired)
return
/mob/living/proc/handle_diseases(seconds_per_tick, times_fired)
return
// Base mob environment handler for body temperature
/mob/living/proc/handle_environment(datum/gas_mixture/environment, seconds_per_tick, times_fired)
var/loc_temp = get_temperature(environment)
var/temp_delta = loc_temp - bodytemperature
if(ismovable(loc))
var/atom/movable/occupied_space = loc
temp_delta *= (1 - occupied_space.contents_thermal_insulation)
if(temp_delta < 0) // it is cold here
if(!on_fire) // do not reduce body temp when on fire
adjust_bodytemperature(max(max(temp_delta / BODYTEMP_DIVISOR, BODYTEMP_COOLING_MAX) * seconds_per_tick, temp_delta))
else // this is a hot place
adjust_bodytemperature(min(min(temp_delta / BODYTEMP_DIVISOR, BODYTEMP_HEATING_MAX) * seconds_per_tick, temp_delta))
/**
* Get the fullness of the mob
*
* Fullness is a representation of how much nutrition the mob has,
* including the nutrition of stuff yet to be digested (reagents in blood / stomach)
*
* * only_consumable - if TRUE, only consumable reagents are counted.
* Otherwise, all reagents contribute to fullness, despite not adding nutrition as they process.
*
* Returns a number representing fullness, scaled similarly to nutrition.
*/
/mob/living/proc/get_fullness(only_consumable)
var/fullness = nutrition
// we add the nutrition value of what we're currently digesting
for(var/datum/reagent/consumable/bits in reagents.reagent_list)
fullness += bits.get_nutriment_factor(src) * bits.volume / bits.metabolization_rate
return fullness
/**
* Check if the mob contains this reagent.
*
* This will validate the the reagent holder for the mob and any sub holders contain the requested reagent.
* Vars:
* * reagent (typepath) takes a PATH to a reagent.
* * amount (int) checks for having a specific amount of that chemical.
* * needs_metabolizing (bool) takes into consideration if the chemical is matabolizing when it's checked.
*/
/mob/living/proc/has_reagent(reagent, amount = -1, needs_metabolizing = FALSE)
return reagents?.has_reagent(reagent, amount, needs_metabolizing)
/mob/living/proc/update_damage_hud()
return
/mob/living/proc/handle_gravity(seconds_per_tick, times_fired)
if(gravity_state > STANDARD_GRAVITY)
handle_high_gravity(gravity_state, seconds_per_tick, times_fired)
/mob/living/proc/gravity_animate()
if(!get_filter("gravity"))
add_filter("gravity",1,list("type"="motion_blur", "x"=0, "y"=0))
animate(get_filter("gravity"), y = 1, time = 10, loop = -1)
animate(y = 0, time = 10)
/mob/living/proc/handle_high_gravity(gravity, seconds_per_tick, times_fired)
if(gravity < GRAVITY_DAMAGE_THRESHOLD) //Aka gravity values of 3 or more
return
var/grav_strength = gravity - GRAVITY_DAMAGE_THRESHOLD
adjustBruteLoss(min(GRAVITY_DAMAGE_SCALING * grav_strength, GRAVITY_DAMAGE_MAXIMUM) * seconds_per_tick)
/// Proc used for custom metabolization of reagents, if any
/mob/living/proc/reagent_tick(datum/reagent/chem, seconds_per_tick, times_fired)
SHOULD_CALL_PARENT(TRUE)
return SEND_SIGNAL(src, COMSIG_MOB_REAGENT_TICK, chem, seconds_per_tick, times_fired)
/// Proc used for custom reagent exposure effects, if any
/mob/living/proc/reagent_expose(datum/reagent/chem, methods = TOUCH, reac_volume, show_message = TRUE, touch_protection = 0)
return
#undef BODYTEMP_DIVISOR