Files
Bubberstation/code/modules/mob/living/damage_procs.dm
T
57624ca1e2 Rebalances wound determination values, wounding escalation and wound armor to hopefully be less explosive (#91099)
## About The Pull Request

This is a big one so please bear with me, wounds are complicated

### Max Potential Wound Rolls

We've decreased the max contributed damage to wound rolls from 35 to 25.
This results, after the exponent, a max possible wound roll of 1 to 91
before any modifiers (assuming the attack, after armor, is 25 or above).

The minimum value to wound is still 5.

### Wound Escalation Penalties

Most wounds were contributing significant numbers per wound type to the
potential for a new wound to occur. Getting wounded once meant you were
getting wound a lot, but actually getting past that first wounding may
be the tricky part.

We have significantly reigned in the wound penalty that having a wound
contributes, and instead utilize the series wound penalty to allow same
type wounds to escalate themselves faster as a priority. Having wounds
still makes you more wound vulnerable, just not to such an extreme
degree.

The priority here for what wounds matter most for contributing to
overall wounding vulnerability is ``Infected BURNS > BURNS >
SLASH|PIERCE > BLUNT.``

### Wound Armor

Wound armor, unlike all other kinds of armor, was used as a additive
value to the wound roll modifiers rather than a multiplicative value.

We have reworked how wound armor is determined by changing how wound
modifiers are calculated.

Firstly, we're passing our entire injury roll into the
``check_woundings_mod()`` proc, as we're not treating this as a proc
that just adds values anymore.

Secondly, bare wound bonus only applies if there is no potential wound
protection from any source, as expected. But it comes last in the
calculations.

Thirdly, wound protection is applied to the injury roll last, after
wound bonuses from the attack, wound bonuses from other wounds and wound
bonuses from a disabled limb are applied. This does not include serial
wound bonuses, which are determined outside of this proc.

Wound protection comes from two sources. Clothing and limb wound
resistance. Your chest and head have an amount of wound resistance so
long as they are not mangled in any fashion. Being mangled means having
either a hairline fracture or a weeping avulsion wound.

Wound protection reduces the final injury roll by a percentage. Say our
roll is 50, and we have effectively 50% wound protection. The final roll
would be 25.

### ~~Wound Armor on Clothing~~ Reverted

~~Most clothing have had their wound armor values changed. As a loose
rule, I used the highest of melee or bomb armor, except where that value
was 100, in which case I used the lowest instead. I'm basing this
decision on how embeds are calculated, which is attack type agnostic.~~

~~Some armor have inconsistent values because they are alternative
armors to an existing armor type or are hyperspecialized armor.
Ablative, bulletproof and security vests all share a value of 35,
despite the former two not having decent melee or bomb armor.~~

~~Some clothing missing wound armor that should have had them now have
wound armor.~~

~~This may need a bit of scrutiny in case one or two seem weirdly high.
Some have maybe become too low. Its a bit hard to say.~~

### The ``bare_wound_bonus`` variable

I changed it to ``exposed_wound_bonus`` to better represent when it
applies. You can be naked and still not be affected by this bonus if the
limb has wound resistance.

## Why It's Good For The Game

I'm not promising anything with this PR, but this is an attempt to
sanity check the values on wounds so that we're not seeing what the data
that determined the removal of beheading presented. An extreme
over-representation of tier 3 wounds. ~~And, from that, maybe I can
argue for beheadings coming back. That's my goal. I think beheadings
happened so much because the numbers were in need of work.~~ Well okay I
just wanna make wounds a bit more workable actually more than I want
beheadings.

Why is it that tier 3 wounds were so over-represented? Because wounds
will often force more severe wounds of other types by merit of any
wounds existing at all on a limb. Having **_a_** wound makes you more
wound prone for any kind of wound, and not just making you more likely
to suffer a more severe type of the same wound.

The threshold mechanic was intended to simulate making a wound worse,
but oddly just made a limb broadly more prone to getting worse from any
kind of attack to such a degree that future wound rolls of different
types were often going to start at the threshold necessary to be a tier
3 wound.

Dismemberment, mind you, requires you to suffer a flesh wound while you
have a bone wound of tier 2 or higher (with tier 3 giving a bonus to
this). You can do this readily via just a sharp weapon, because having a
mangled limb causes the wound to turn into a bone wound. Technically,
this is meant to be less likely as the effective damage for this wound
is halved. But the wound bonus from having a flesh wound was almost
always significant enough to kick your new bone wound up to a tier 3.

In other words; its not surprising that you saw so many beheadings,
because the system wanted to behead you as fast as it possibly can
thanks to all these escalating values.

Wound armor was only applied as a flat reduction on the roll. The
average for wound armor was 10. After receiving a single wound, you can
expect wound rolls to reach upwards of 100, even if the actual damage
roll was not particularly high, due to wound stacking bonuses form being
wounded.

This meant that wounds, if they happened, came thick and fast after the
first, regardless of what your protection might be to wounds. It was
just a matter of getting past the initial bump.

This is why effects that forced wounds were so powerful. They basically
made a given limb more prone to taking a wound without having to deal
with the protection problem first.

Finally, this is just a broad flaw with the system that is not its
fault. It is actually a problem that isn't a problem. Most people in the
game are not wearing helmets that protect their head. So most people are
going to suffer from a higher proclivity of being wounded if people are
aiming for the head. There is this...kind of cargo cult belief that
aiming for the head means you do more damage, or can stun someone if
you're lucky or what have you. It's entirely nonsense, but it has a
grain of truth in that people rarely wear, or even have access too,
headwear that provides wound protection or any protection at all. People
have jumpsuits, which are universally wound protected, but that isn't
true of the head. Look, the point is, they're not aiming at the head
because it is usually less armored, its for other reasons but it just so
happens to become true due to wounds and how wounds roll their type.

To soften this issue, I've decided to treat wound resistance as armor
until the limb suffers a tier 3 wound. This way, hits to the head MAY
not necessarily escalate to tier 3 instantly as they would on live even
from relatively low power weapons. Some weapons have very low force, but
have extreme bare wound bonuses. This should be less likely after this
change. I doubt this will necessarily make high damage high wound
weapons like energy swords any less prone to cutting you clean open, but
it might thanks to the reduction to contributed damage to the injury
roll. The system is now _a bit more random_.

## Changelog
🆑
balance: Wounds do not make you as vulnerable to suffering wounds of all
types as before. Instead, wounds make you more vulnerable to suffering
worse versions of themselves as a priority.
balance: Wound armor is now more impactful when protecting you from
wounds when you have already been wounded.
balance: Your head and chest are more difficult to wound until they have
been mangled; either from suffering from a weeping avulsion or a
hairline fracture.
code: Changed the variable for bare_wound_bonus to exposed_wound_bonus
to better explain what that variable is doing.
/🆑

---------

Co-authored-by: Jeremiah <42397676+jlsnow301@users.noreply.github.com>
2025-06-19 17:49:59 +02:00

545 lines
18 KiB
Plaintext

/**
* Applies damage to this mob.
*
* Sends [COMSIG_MOB_APPLY_DAMAGE]
*
* Arguuments:
* * damage - Amount of damage
* * damagetype - What type of damage to do. one of [BRUTE], [BURN], [TOX], [OXY], [STAMINA], [BRAIN].
* * def_zone - What body zone is being hit. Or a reference to what bodypart is being hit.
* * blocked - Percent modifier to damage. 100 = 100% less damage dealt, 50% = 50% less damage dealt.
* * forced - "Force" exactly the damage dealt. This means it skips damage modifier from blocked.
* * spread_damage - For carbons, spreads the damage across all bodyparts rather than just the targeted zone.
* * wound_bonus - Bonus modifier for wound chance.
* * exposed_wound_bonus - Bonus modifier for wound chance on bare skin.
* * sharpness - Sharpness of the weapon.
* * attack_direction - Direction of the attack from the attacker to [src].
* * attacking_item - Item that is attacking [src].
* * wound_clothing - If this should cause damage to clothing.
*
* Returns the amount of damage dealt.
*/
/mob/living/proc/apply_damage(
damage = 0,
damagetype = BRUTE,
def_zone = null,
blocked = 0,
forced = FALSE,
spread_damage = FALSE,
wound_bonus = 0,
exposed_wound_bonus = 0,
sharpness = NONE,
attack_direction = null,
attacking_item,
wound_clothing = TRUE,
)
SHOULD_CALL_PARENT(TRUE)
var/damage_amount = damage
if(!forced)
damage_amount *= ((100 - blocked) / 100)
damage_amount *= get_incoming_damage_modifier(damage_amount, damagetype, def_zone, sharpness, attack_direction, attacking_item)
if(damage_amount <= 0)
return 0
SEND_SIGNAL(src, COMSIG_MOB_APPLY_DAMAGE, damage_amount, damagetype, def_zone, blocked, wound_bonus, exposed_wound_bonus, sharpness, attack_direction, attacking_item, wound_clothing)
var/damage_dealt = 0
switch(damagetype)
if(BRUTE)
if(isbodypart(def_zone))
var/obj/item/bodypart/actual_hit = def_zone
var/delta = actual_hit.get_damage()
if(actual_hit.receive_damage(
brute = damage_amount,
burn = 0,
forced = forced,
wound_bonus = wound_bonus,
exposed_wound_bonus = exposed_wound_bonus,
sharpness = sharpness,
attack_direction = attack_direction,
damage_source = attacking_item,
wound_clothing = wound_clothing,
))
update_damage_overlays()
damage_dealt = actual_hit.get_damage() - delta // Unfortunately bodypart receive_damage doesn't return damage dealt so we do it manually
else
damage_dealt = -1 * adjustBruteLoss(damage_amount, forced = forced)
if(BURN)
if(isbodypart(def_zone))
var/obj/item/bodypart/actual_hit = def_zone
var/delta = actual_hit.get_damage()
if(actual_hit.receive_damage(
brute = 0,
burn = damage_amount,
forced = forced,
wound_bonus = wound_bonus,
exposed_wound_bonus = exposed_wound_bonus,
sharpness = sharpness,
attack_direction = attack_direction,
damage_source = attacking_item,
wound_clothing = wound_clothing,
))
update_damage_overlays()
damage_dealt = actual_hit.get_damage() - delta // See above
else
damage_dealt = -1 * adjustFireLoss(damage_amount, forced = forced)
if(TOX)
damage_dealt = -1 * adjustToxLoss(damage_amount, forced = forced)
if(OXY)
damage_dealt = -1 * adjustOxyLoss(damage_amount, forced = forced)
if(STAMINA)
damage_dealt = -1 * adjustStaminaLoss(damage_amount, forced = forced)
if(BRAIN)
damage_dealt = -1 * adjustOrganLoss(ORGAN_SLOT_BRAIN, damage_amount)
SEND_SIGNAL(src, COMSIG_MOB_AFTER_APPLY_DAMAGE, damage_dealt, damagetype, def_zone, blocked, wound_bonus, exposed_wound_bonus, sharpness, attack_direction, attacking_item, wound_clothing)
return damage_dealt
/**
* Used in tandem with [/mob/living/proc/apply_damage] to calculate modifier applied into incoming damage
*/
/mob/living/proc/get_incoming_damage_modifier(
damage = 0,
damagetype = BRUTE,
def_zone = null,
sharpness = NONE,
attack_direction = null,
attacking_item,
)
SHOULD_CALL_PARENT(TRUE)
SHOULD_BE_PURE(TRUE)
var/list/damage_mods = list()
SEND_SIGNAL(src, COMSIG_MOB_APPLY_DAMAGE_MODIFIERS, damage_mods, damage, damagetype, def_zone, sharpness, attack_direction, attacking_item)
var/final_mod = 1
for(var/new_mod in damage_mods)
final_mod *= new_mod
return final_mod
/**
* Simply a wrapper for calling mob adjustXLoss() procs to heal a certain damage type,
* when you don't know what damage type you're healing exactly.
*/
/mob/living/proc/heal_damage_type(heal_amount = 0, damagetype = BRUTE)
heal_amount = abs(heal_amount) * -1
switch(damagetype)
if(BRUTE)
return adjustBruteLoss(heal_amount)
if(BURN)
return adjustFireLoss(heal_amount)
if(TOX)
return adjustToxLoss(heal_amount)
if(OXY)
return adjustOxyLoss(heal_amount)
if(STAMINA)
return adjustStaminaLoss(heal_amount)
/// return the damage amount for the type given
/**
* Simply a wrapper for calling mob getXLoss() procs to get a certain damage type,
* when you don't know what damage type you're getting exactly.
*/
/mob/living/proc/get_current_damage_of_type(damagetype = BRUTE)
switch(damagetype)
if(BRUTE)
return getBruteLoss()
if(BURN)
return getFireLoss()
if(TOX)
return getToxLoss()
if(OXY)
return getOxyLoss()
if(STAMINA)
return getStaminaLoss()
/// return the total damage of all types which update your health
/mob/living/proc/get_total_damage(precision = DAMAGE_PRECISION)
return round(getBruteLoss() + getFireLoss() + getToxLoss() + getOxyLoss(), precision)
/// Applies multiple damages at once via [apply_damage][/mob/living/proc/apply_damage]
/mob/living/proc/apply_damages(
brute = 0,
burn = 0,
tox = 0,
oxy = 0,
def_zone = null,
blocked = 0,
stamina = 0,
brain = 0,
)
var/total_damage = 0
if(brute)
total_damage += apply_damage(brute, BRUTE, def_zone, blocked)
if(burn)
total_damage += apply_damage(burn, BURN, def_zone, blocked)
if(tox)
total_damage += apply_damage(tox, TOX, def_zone, blocked)
if(oxy)
total_damage += apply_damage(oxy, OXY, def_zone, blocked)
if(stamina)
total_damage += apply_damage(stamina, STAMINA, def_zone, blocked)
if(brain)
total_damage += apply_damage(brain, BRAIN, def_zone, blocked)
return total_damage
/// applies various common status effects or common hardcoded mob effects
/mob/living/proc/apply_effect(effect = 0,effecttype = EFFECT_STUN, blocked = 0)
var/hit_percent = (100-blocked)/100
if(!effect || (hit_percent <= 0))
return FALSE
switch(effecttype)
if(EFFECT_STUN)
Stun(effect * hit_percent)
if(EFFECT_KNOCKDOWN)
Knockdown(effect * hit_percent)
if(EFFECT_PARALYZE)
Paralyze(effect * hit_percent)
if(EFFECT_IMMOBILIZE)
Immobilize(effect * hit_percent)
if(EFFECT_UNCONSCIOUS)
Unconscious(effect * hit_percent)
return TRUE
/**
* Applies multiple effects at once via [/mob/living/proc/apply_effect]
*
* Pretty much only used for projectiles applying effects on hit,
* don't use this for anything else please just cause the effects directly
*/
/mob/living/proc/apply_effects(
stun = 0,
knockdown = 0,
unconscious = 0,
slur = 0 SECONDS, // Speech impediment, not technically an effect
stutter = 0 SECONDS, // Ditto
eyeblur = 0 SECONDS,
drowsy = 0 SECONDS,
blocked = 0, // This one's not an effect, don't be confused - it's block chance
stamina = 0, // This one's a damage type, and not an effect
jitter = 0 SECONDS,
paralyze = 0,
immobilize = 0,
)
if(blocked >= 100)
return FALSE
if(stun)
apply_effect(stun, EFFECT_STUN, blocked)
if(knockdown)
apply_effect(knockdown, EFFECT_KNOCKDOWN, blocked)
if(unconscious)
apply_effect(unconscious, EFFECT_UNCONSCIOUS, blocked)
if(paralyze)
apply_effect(paralyze, EFFECT_PARALYZE, blocked)
if(immobilize)
apply_effect(immobilize, EFFECT_IMMOBILIZE, blocked)
if(stamina)
apply_damage(stamina, STAMINA, null, blocked)
if(drowsy)
adjust_drowsiness(drowsy)
if(eyeblur)
adjust_eye_blur_up_to(eyeblur, eyeblur)
if(jitter && !check_stun_immunity(CANSTUN))
adjust_jitter(jitter)
if(slur)
adjust_slurring(slur)
if(stutter)
adjust_stutter(stutter)
return TRUE
/// Returns a multiplier to apply to a specific kind of damage
/mob/living/proc/get_damage_mod(damage_type)
switch(damage_type)
if (OXY)
return HAS_TRAIT(src, TRAIT_NOBREATH) ? 0 : 1
if (TOX)
if (HAS_TRAIT(src, TRAIT_TOXINLOVER))
return -1
return HAS_TRAIT(src, TRAIT_TOXIMMUNE) ? 0 : 1
return 1
/mob/living/proc/getBruteLoss()
return bruteloss
/mob/living/proc/can_adjust_brute_loss(amount, forced, required_bodytype)
if(!forced && HAS_TRAIT(src, TRAIT_GODMODE))
return FALSE
if(SEND_SIGNAL(src, COMSIG_LIVING_ADJUST_BRUTE_DAMAGE, BRUTE, amount, forced) & COMPONENT_IGNORE_CHANGE)
return FALSE
return TRUE
/mob/living/proc/adjustBruteLoss(amount, updating_health = TRUE, forced = FALSE, required_bodytype = ALL)
if (!can_adjust_brute_loss(amount, forced, required_bodytype))
return 0
. = bruteloss
bruteloss = clamp((bruteloss + (amount * CONFIG_GET(number/damage_multiplier))), 0, maxHealth * 2)
. -= bruteloss
if(!.) // no change, no need to update
return 0
if(updating_health)
updatehealth()
/mob/living/proc/setBruteLoss(amount, updating_health = TRUE, forced = FALSE, required_bodytype = ALL)
if(!forced && HAS_TRAIT(src, TRAIT_GODMODE))
return FALSE
. = bruteloss
bruteloss = amount
if(!.) // no change, no need to update
return FALSE
if(updating_health)
updatehealth()
. -= bruteloss
/mob/living/proc/getOxyLoss()
return oxyloss
/mob/living/proc/can_adjust_oxy_loss(amount, forced, required_biotype, required_respiration_type)
if(!forced)
if(HAS_TRAIT(src, TRAIT_GODMODE))
return FALSE
if (required_respiration_type)
var/obj/item/organ/lungs/affected_lungs = get_organ_slot(ORGAN_SLOT_LUNGS)
if(isnull(affected_lungs))
if(!(mob_respiration_type & required_respiration_type)) // if the mob has no lungs, use mob_respiration_type
return FALSE
else
if(!(affected_lungs.respiration_type & required_respiration_type)) // otherwise use the lungs' respiration_type
return FALSE
if(SEND_SIGNAL(src, COMSIG_LIVING_ADJUST_OXY_DAMAGE, OXY, amount, forced) & COMPONENT_IGNORE_CHANGE)
return FALSE
return TRUE
/mob/living/proc/adjustOxyLoss(amount, updating_health = TRUE, forced = FALSE, required_biotype = ALL, required_respiration_type = ALL)
if(!can_adjust_oxy_loss(amount, forced, required_biotype, required_respiration_type))
return 0
. = oxyloss
oxyloss = clamp((oxyloss + (amount * CONFIG_GET(number/damage_multiplier))), 0, maxHealth * 2)
. -= oxyloss
if(!.) // no change, no need to update
return FALSE
if(updating_health)
updatehealth()
/mob/living/proc/setOxyLoss(amount, updating_health = TRUE, forced = FALSE, required_biotype = ALL, required_respiration_type = ALL)
if(!forced)
if(HAS_TRAIT(src, TRAIT_GODMODE))
return FALSE
var/obj/item/organ/lungs/affected_lungs = get_organ_slot(ORGAN_SLOT_LUNGS)
if(isnull(affected_lungs))
if(!(mob_respiration_type & required_respiration_type))
return FALSE
else
if(!(affected_lungs.respiration_type & required_respiration_type))
return FALSE
. = oxyloss
oxyloss = amount
. -= oxyloss
if(!.) // no change, no need to update
return FALSE
if(updating_health)
updatehealth()
/mob/living/proc/getToxLoss()
return toxloss
/mob/living/proc/can_adjust_tox_loss(amount, forced, required_biotype = ALL)
if(!forced && (HAS_TRAIT(src, TRAIT_GODMODE) || !(mob_biotypes & required_biotype)))
return FALSE
if(SEND_SIGNAL(src, COMSIG_LIVING_ADJUST_TOX_DAMAGE, TOX, amount, forced) & COMPONENT_IGNORE_CHANGE)
return FALSE
return TRUE
/mob/living/proc/adjustToxLoss(amount, updating_health = TRUE, forced = FALSE, required_biotype = ALL)
if(!can_adjust_tox_loss(amount, forced, required_biotype))
return 0
if(!forced && HAS_TRAIT(src, TRAIT_TOXINLOVER)) //damage becomes healing and healing becomes damage
amount = -amount
if(HAS_TRAIT(src, TRAIT_TOXIMMUNE)) //Prevents toxin damage, but not healing
amount = min(amount, 0)
if(blood_volume)
if(amount > 0)
blood_volume = max(blood_volume - (5 * amount), 0)
else
blood_volume = max(blood_volume - amount, 0)
else if(!forced && HAS_TRAIT(src, TRAIT_TOXIMMUNE)) //Prevents toxin damage, but not healing
amount = min(amount, 0)
. = toxloss
toxloss = clamp((toxloss + (amount * CONFIG_GET(number/damage_multiplier))), 0, maxHealth * 2)
. -= toxloss
if(!.) // no change, no need to update
return FALSE
if(updating_health)
updatehealth()
/mob/living/proc/setToxLoss(amount, updating_health = TRUE, forced = FALSE, required_biotype = ALL)
if(!forced && HAS_TRAIT(src, TRAIT_GODMODE))
return FALSE
if(!forced && !(mob_biotypes & required_biotype))
return FALSE
. = toxloss
toxloss = amount
. -= toxloss
if(!.) // no change, no need to update
return FALSE
if(updating_health)
updatehealth()
/mob/living/proc/getFireLoss()
return fireloss
/mob/living/proc/can_adjust_fire_loss(amount, forced, required_bodytype)
if(!forced && HAS_TRAIT(src, TRAIT_GODMODE))
return FALSE
if(SEND_SIGNAL(src, COMSIG_LIVING_ADJUST_BURN_DAMAGE, BURN, amount, forced) & COMPONENT_IGNORE_CHANGE)
return FALSE
return TRUE
/mob/living/proc/adjustFireLoss(amount, updating_health = TRUE, forced = FALSE, required_bodytype = ALL)
if(!can_adjust_fire_loss(amount, forced, required_bodytype))
return 0
. = fireloss
fireloss = clamp((fireloss + (amount * CONFIG_GET(number/damage_multiplier))), 0, maxHealth * 2)
. -= fireloss
if(. == 0) // no change, no need to update
return
if(updating_health)
updatehealth()
/mob/living/proc/setFireLoss(amount, updating_health = TRUE, forced = FALSE, required_bodytype = ALL)
if(!forced && HAS_TRAIT(src, TRAIT_GODMODE))
return 0
. = fireloss
fireloss = amount
. -= fireloss
if(. == 0) // no change, no need to update
return 0
if(updating_health)
updatehealth()
/mob/living/proc/adjustOrganLoss(slot, amount, maximum, required_organ_flag)
return
/mob/living/proc/setOrganLoss(slot, amount, maximum, required_organ_flag)
return
/mob/living/proc/get_organ_loss(slot)
return
/mob/living/proc/getStaminaLoss()
return staminaloss
/mob/living/proc/can_adjust_stamina_loss(amount, forced, required_biotype = ALL)
if(!forced && (!(mob_biotypes & required_biotype) || HAS_TRAIT(src, TRAIT_GODMODE)))
return FALSE
if(SEND_SIGNAL(src, COMSIG_LIVING_ADJUST_STAMINA_DAMAGE, STAMINA, amount, forced) & COMPONENT_IGNORE_CHANGE)
return FALSE
return TRUE
/mob/living/proc/adjustStaminaLoss(amount, updating_stamina = TRUE, forced = FALSE, required_biotype = ALL)
if(!can_adjust_stamina_loss(amount, forced, required_biotype))
return 0
var/old_amount = staminaloss
staminaloss = clamp((staminaloss + (amount * CONFIG_GET(number/damage_multiplier))), 0, max_stamina)
var/delta = old_amount - staminaloss
if(delta <= 0)
// need to check for stamcrit AFTER canadjust but BEFORE early return here
received_stamina_damage(staminaloss, -1 * delta)
if(delta == 0) // no change, no need to update
return 0
if(updating_stamina)
updatehealth()
return delta
/mob/living/proc/setStaminaLoss(amount, updating_stamina = TRUE, forced = FALSE, required_biotype = ALL)
if(!forced && HAS_TRAIT(src, TRAIT_GODMODE))
return 0
if(!forced && !(mob_biotypes & required_biotype))
return 0
var/old_amount = staminaloss
staminaloss = amount
var/delta = old_amount - staminaloss
if(delta <= 0 && amount >= DAMAGE_PRECISION)
received_stamina_damage(staminaloss, -1 * delta, amount)
if(delta == 0) // no change, no need to update
return 0
if(updating_stamina)
updatehealth()
return delta
/// The mob has received stamina damage
///
/// - current_level: The mob's current stamina damage amount (to save unnecessary getStaminaLoss() calls)
/// - amount_actual: The amount of stamina damage received, in actuality
/// For example, if you are taking 50 stamina damage but are at 90, you would actually only receive 30 stamina damage (due to the cap)
/// - amount: The amount of stamina damage received, raw
/mob/living/proc/received_stamina_damage(current_level, amount_actual, amount)
addtimer(CALLBACK(src, PROC_REF(setStaminaLoss), 0, TRUE, TRUE), stamina_regen_time, TIMER_UNIQUE|TIMER_OVERRIDE)
/**
* heal ONE external organ, organ gets randomly selected from damaged ones.
*
* returns the net change in damage
*/
/mob/living/proc/heal_bodypart_damage(brute = 0, burn = 0, updating_health = TRUE, required_bodytype = NONE, target_zone = null)
. = (adjustBruteLoss(-abs(brute), updating_health = FALSE) + adjustFireLoss(-abs(burn), updating_health = FALSE))
if(!.) // no change, no need to update
return FALSE
if(updating_health)
updatehealth()
/// damage ONE external organ, organ gets randomly selected from damaged ones.
/mob/living/proc/take_bodypart_damage(brute = 0, burn = 0, updating_health = TRUE, required_bodytype, check_armor = FALSE, wound_bonus = 0, exposed_wound_bonus = 0, sharpness = NONE)
. = (adjustBruteLoss(abs(brute), updating_health = FALSE) + adjustFireLoss(abs(burn), updating_health = FALSE))
if(!.) // no change, no need to update
return FALSE
if(updating_health)
updatehealth()
/// heal MANY bodyparts, in random order. note: stamina arg nonfunctional for carbon mobs
/mob/living/proc/heal_overall_damage(brute = 0, burn = 0, stamina = 0, required_bodytype, updating_health = TRUE, forced = FALSE)
. = (adjustBruteLoss(-abs(brute), updating_health = FALSE, forced = forced) + \
adjustFireLoss(-abs(burn), updating_health = FALSE, forced = forced) + \
adjustStaminaLoss(-abs(stamina), updating_stamina = FALSE, forced = forced))
if(!.) // no change, no need to update
return FALSE
if(updating_health)
updatehealth()
/// damage MANY bodyparts, in random order. note: stamina arg nonfunctional for carbon mobs
/mob/living/proc/take_overall_damage(brute = 0, burn = 0, stamina = 0, updating_health = TRUE, forced = FALSE, required_bodytype)
. = (adjustBruteLoss(abs(brute), updating_health = FALSE, forced = forced) + \
adjustFireLoss(abs(burn), updating_health = FALSE, forced = forced) + \
adjustStaminaLoss(abs(stamina), updating_stamina = FALSE, forced = forced))
if(!.) // no change, no need to update
return FALSE
if(updating_health)
updatehealth()
///heal up to amount damage, in a given order
/mob/living/proc/heal_ordered_damage(amount, list/damage_types)
. = 0 //we'll return the amount of damage healed
for(var/damagetype in damage_types)
var/amount_to_heal = min(abs(amount), get_current_damage_of_type(damagetype)) //heal only up to the amount of damage we have
if(amount_to_heal)
. += heal_damage_type(amount_to_heal, damagetype)
amount -= amount_to_heal //remove what we healed from our current amount
if(!amount)
break