mirror of
https://github.com/Bubberstation/Bubberstation.git
synced 2026-08-29 16:18:01 +01:00
## 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>
545 lines
18 KiB
Plaintext
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
|