-
Notifications
You must be signed in to change notification settings - Fork 28
Standardized Health
The standardized health system is a collection of procs and vars designed to simplify and standardize the processing of health and damage throughout the codebase. SierraKomodo designed this system to counter the pre-existing issues created by the varying implementations of health processing found throughout the codebase. These issues included inconsistent damage ratios, resistances, and in some cases, a complete inability to handle health at all for some damage sources such as explosions, fires, EMPs, or projectiles.
Reviewers will request any new form of health handling to use the standardized health system before approving unless the PR author provides a good reason not to use it.
Health damage is currently processed automatically for the following proc chains:
attackby()
bullet_act()
emp_act()
ex_act()
fire_act()
See code\game\atoms_health.dm
for additional specific details on each var and proc - This file documents every var and proc with its intended use and function. You can also find this information on the auto-generated DMDoc document for /atom
here, though DMDoc combines these with all defined vars and procs under that scope, including non-health related items.
Note that all values passed through standardized health are rounded to the nearest whole. The system does not support decimals or floating-point integers.
The most straightforward implementations of standardized health need only to do two things.
- Assign a value to
health_max
in the atom's initial definition. - Create an override for
on_death()
to handle the atom dying. I.e., if it shouldqdel()
itself, stop processing, display a message or play a sound, runupdate_icon()
, etc.
The system will handle everything else from there, including initializing current health, setting default resistance values, and handling any damage.
Here's an example from girders. Non health-related vars and procs are hidden here for example purposes:
/obj/structure/girder
health_max = 100
/obj/structure/girder/on_death()
dismantle()
This code grants girders 100 HP when they initialize and runs the dismantle()
proc when they "die" (Their HP hits 0).
This section lists every var provided by the standardized health system, their intended use, and some example uses. You can also find documentation on each var in the code\game\atoms_health.dm
file.
Note that these are listed in alphabetical order and not the order in which they appear in the file.
This var is a sound file that should play whenever the atom is hit and takes damage. The following proc chains play this sound file:
attackby()
bullet_act()
This is not used for emp_act()
, fire_act()
, or ex_act()
by default to avoid flooding clients with sound calls during those events.
This var holds the atom's current health value and is always an integer. Initialization sets this to the value of health_max
.
You should NEVER modify this var directly and do not define it in your atom. Instead, use one of the following procs depending on your intent:
- To damage the atom:
damage_health()
- To heal the atom:
restore_health()
- To kill the atom:
kill_health()
- To revive or fully heal the atom:
revive_health()
- To set a specific health value that isn't covered by any of the above:
set_health()
If you wish to reference this to determine the atom's current health value, it is recommended to instead use get_current_health()
unless you know this reference will never need to account for any additional checks certain atoms may make toward determine it's actual health value (I.e., wall rot on walls).
This var is a boolean that serves as a quick method of checking whether or not the atom is 'dead'. You can freely reference this variable for checks, but do not modify it directly. The system expects this variable to remain in sync with the actual health values.
If you wish to directly change an atom's death status, use one of these procs instead:
- To kill an atom:
kill_health()
- To revive a 'dead' atom:
revive_health()
This var holds the atom's maximum health value. Generally, this is defined in the atom's original path and never touched again. This value must be an integer.
The health system will ensure health_current
never exceeds this value, though the result of get_current_health()
may legally exceed it depending on implementations.
You should never modify this directly outside of defining it in your atom's path. Instead, use set_max_health()
.
It is also recommended to use get_max_health()
instead of referencing this var directly, as some atoms may have additional handling or overrides that may change the perceived maximum health.
This var serves as a rudimentary 'armor' system by defining a minimum damage value that must be passed in order for the atom to actually be damaged. I.e., if this is set to 50
, then any damage_health()
calls whos damage falls below this value will be skipped.
This primarily exists to prevent low-damage random items from being able to eventually break something that should be sturdy. Examples include walls and reinforced windows being immune to damage from a pair of shoes or a broken light bulb.
This var contains a LAZYLIST of all damage types and the atom's resistance value against those types. This list is formatted as:
list(
DAMAGE_TYPE = RESISTANCE_VALUE
)
Where DAMAGE_TYPE
must be one of the DAMAGE_*
type defines, and RESISTANCE_VALUE
is a positive or zero floating point integer. The resistance value is the multiplier applied to any incoming damage of the given type. A value of 1
is neither a resistance nor a weakness. A value above 1
is a weakness. A value below 1
is a resistance. A value of 0
is treated as an immunity and also causes can_damage_health()
checks for the given type to fail.
See code\__defines\health.dm
for a list of all defined damage types, and some preset damage resistances that may be useful.
You should not modify or reference this var directly outside of defining it in the atom's initial path. Instead, use the following procs:
- Retrieve the atom's resistance to a given damage type:
get_damage_resistance()
- Set an atom's resistance to a given damage type:
set_damage_resistance()
- Remove an atom's resistance to a given damage type:
remove_damage_resistance()
This section lists every proc provided by the standardized health system, their intended use, and some example uses. You can also find documentation on each proc in the code\game\atoms_health.dm
file.
Note, these are listed in alphabetical order and not the order in which they appear in the file.
This checks whether or not the atom can be damaged with the given damage value and type. By default, this check fails on the following conditions:
-
damage
is <= 0 - The atom is already dead (
health_dead
is set) -
damage
is less thanhealth_min_damage
- The atom has an immunity to
damage_type
(Thehealth_resistances
value for this type is0
) - For mobs, if the mob has the
GODMODE
flag enabled
This proc is automatically checked in damage_health()
before applying any damage.
This checks whether or not the atom is capable of having it's health restored. By default, this check only fails if no damage is provided or if current health equals max health. This proc does not directly reference health vars.
This is a global proc. This copies all health data from the source atom to the target atom.
This proc handles damaging the atom. It checks the result of can_damage_health()
before applying damage. The damage value is multiplied by the atom's resistance to the given damage type (See health_resistances
).
severity
is a direct pass of the severity parameters from ex_act()
and emp_act()
, as applicable, and should only be present if damage_type
is DAMAGE_EXPLODE
or DAMAGE_EMP
.
This proc calls the on_death()
proc as applicable if the new health value causes the atom's death state to change, unless damage_flags
includes the DAMAGE_FLAG_SKIP_DEATH_STATE_CHANGE
flag.
This proc is called during the examine()
chain if the atom's health has been initialized. It is intended to provide general information on how damaged the atom looks when examined.
Default, generic overrides are already provided for atoms and mobs. Other atoms may override this proc if they wish to provide additional information or change the wording of the examine values.
This proc is the recommended method to retrieve and reference an atom's current health in most cases. By default, it returns the value of health_current
or null
if health is not initialized for this atom, but may return a different value if an atom overrides this for any given reason.
WARNING: This proc may return 0
or null
, both of which are falsey but have different meanings. null
means the atom has no health handling initialized, while 0
means the atom's current health is considered to be 0
. It is recommended to compare == 0
instead of relying on falsey/truthy values if your logic relies on the atom having initialized health.
Overrides must call the parent proc and are recommended to utilize the parent's result instead of the health_current
var in its calculations.
This proc takes the result of get_damage_value()
and converts it to a percentage of the atom's maximum health. The result is procided as awhole number ranging from 0
to 100
, where 100
is equivalent to 100%.
If use_raw_values
is set, the comparison directly checks the variables instead of using the generally recommended procs.
Retrieves the atom's current resistance value to the given damage type from health_resistances
. If the atom does not have an explicitly defined resistance or weakness, this returns 1
instead.
This proc determines the amount of damage the atom has received by subtracting current health from maximum health. If use_raw_values
is set, the comparison directly checks the variables instead of using the generally recommended procs.
This proc may return a negative value. If so, this indicates the atom's perceived current health exceeds its perceived maximum health. This should never occur if using raw values, as the value of health_current
is clamped between 0
and health_max
.
This proc is the recommended method to retrieve and reference an atom's maximum health. By default, it returns the value of health_max
, but may return a different value if an atom overrides this for any given reason.
Overrides must call the parent proc and are recommended to utilize the parent's result instead of the health_max
var in its calculations.
This proc determines whether or not the atom has received damage, by checking if current health is less than maximum health. If use_raw_values
is set, the comparison directly checks the variables instead of using the generally recommended procs.
Overrides may exist that add additional checks and conditions for whether or not an atom is considered damaged.
This proc immediately kills the atom by setting its health to 0
.
YOU SHOULD NOT USE THIS PROC DIRECTLY UNLESS YOU KNOW WHAT YOU ARE DOING. YOU PROBABLY WANT set_health()
, damage_health()
, OR revive_health()
INSTEAD
This is an internal handler for actual health modification changes. All other procs that touch the value of health_current
come here. The value of health_mod
is added to the value of health_current
, clamped between 0
and health_max
, and then assigned back to health_current
.
If this change results in health going from a positive number to 0
, on_death()
is called. If it goes from 0
to a positive number, on_revive()
is called. These procs are skipped if skip_death_state_change
is set, but health_dead
is still set accordingly.
This returns a boolean value - TRUE
if the death state changed, FALSE
otherwise.
This proc is called by the standardized health system when the atom 'dies'. I.e., when the atom's health falls to 0
. It is called after post_health_change()
and after health_dead
is updated.
This proc is skipped if the proc chain resulting in death set the skip_death_state_change
flag.
By default, this does nothing, and exists solely for child override use.
This proc is called by the standardized health system when the atom 'revivews'. I.e., when the atom's health rises from 0
. It is called after post_health_change()
and after health_dead
is updated.
This proc is skipped if the proc chain resulting in revival set the skip_death_state_change
flag.
By default, this does nothing, and exists solely for child override use.
This proc is called by the standardized health system after every health modification event. health_mod
contains the amount the atom's health changed by, where negative numbers indicate damage and positive numbers indicate healing.
By default, this does nothing, and exists solely for child override use.
Removes the atom's resistance or weakness to the givevn damage type from health_resistances
. This effectively sets the resistance multiplier to 1
.
This proc restores the atom's health by the given amount. It checks the result of can_restore_health()
before attempted to modify current health.
This proc calls the on_revive()
proc as applicable if the new health value causes the atom's death state to change, unless skip_death_state_change
is set.
This proc fully heals the atom, including reviving it from death.
This proc force-sets the atom's current health to the new health value. This proc cannot be used to set a health value below 0
, or greater than health_max
.
This proc calls the on_death()
or on_revive()
proc as applicable if the new health value causes the atom's death state to change, unless skip_death_state_change
is set.
This updates the atom's health_resistances
to set the new resistance or weakness value for the given damage type. This value is multiplied against incoming damage in damage_health()
.
Values below 1
are resistance, values above 1
are weakness. A value of 0
is considered a full immunity and will cause can_damage_health()
checks with the provided damage type to fail.
If the new value is 1
, it calls remove_damage_resistance()
instead.
This proc sets a new maximum health value for the atom, and handles initializing health if it was not initialized before. If the new value is 0
, this effectively disables health processing for the atom and does not call any death or revival events.
If set_current_health
is set (TRUE by default), then the atom's current health is set to the new maximum health value, effectivelly fully healing the atom. Otherwise, current health is reduced to health_max
if it exceeds the new maximum health value.
Documentation regarding setting up and using Git.
Making heads or tails of specific GitHub pages, for the uninitiated.
Documentation regarding tools external to DM and Git.
Standards and guidelines regarding commenting, contributor conduct and coding standards.