Files
JacquerelandRoxy c57341f771 Most fleshy mobs are vulnerable to stamina and stuns (#90675)
## About The Pull Request

This PR enables most mobs to take stamina damage, become slowed as a
result of taking stamina damage.
It also gives most mobs CANSTUN which not only allows them to enter
stamcrit from taking stamina damage but also makes them vulnerable to
mechanics like stun batons.

Mobs which already took stamina damage (Spiders and Space Dragons) still
work the same way.
Mechanical or artificial mobs, mining mobs, simple xenomorphs, ghosts,
and most kinds of mob closely associated with antagonists still don't
take stamina damage.

## Why It's Good For The Game

A new player armed with a disabler will probably try and use it on
aggressive animals and be disappointed, but I don't think there is any
_reason_ for them to be disappointed when it's already something they
are doing merely to delay being attacked rather than to kill the target.
It's not intuitive for these mechanics not to function against simple
mobs when they do against humans, _especially_ the kinds of mobs which
look like humans, and there isn't any technical reason why it _couldn't_
work against most mobs which it looks like they should work against.

While this reduces the threat level of some mobs against Security
players I think the greater interaction with the sandbox is beneficial.
I'm hopeful it doesn't have that much effect on many of the most common
places you encounter dangerous mobs like Space Ruins or Gateways as they
are also places where you can't reliably recharge your energy-based
stamina weapons as most that don't require energy do require getting
into melee and endangering yourself.

## Changelog

🆑
balance: Most biological mobs are now slowed by taking stamina damage,
and can be stunned. Mechanical mobs, mining mobs, and several other
special kinds (chiefly those invoked by antagonists) are unaffected. If
this seems to effect any mob it probably shouldn't, please report it as
a bug.
/🆑
2025-05-15 16:04:13 -04:00

85 lines
3.4 KiB
Plaintext

/datum/status_effect/incapacitating/stamcrit
id = "stamcrit"
status_type = STATUS_EFFECT_UNIQUE
// Lasts until we go back to 0 stamina, which is handled by the mob
duration = STATUS_EFFECT_PERMANENT
tick_interval = STATUS_EFFECT_NO_TICK
/// Cooldown between displaying warning messages that we hit diminishing returns
COOLDOWN_DECLARE(warn_cd)
/// A counter that tracks every time we've taken enough damage to trigger diminishing returns
var/diminishing_return_counter = 0
/datum/status_effect/incapacitating/stamcrit/on_creation(mob/living/new_owner, set_duration)
. = ..()
if(!.)
return .
// This should be in on apply but we need it to happen AFTER being added to the mob
// (Because we need to wait until the status effect is in their status effect list, or we'll add two)
if(owner.getStaminaLoss() < 162) // SKYRAT EDIT CHANGE
// Puts you a little further into the initial stamcrit, makes stamcrit harder to outright counter with chems.
owner.adjustStaminaLoss(30, FALSE)
// Same
RegisterSignal(owner, COMSIG_LIVING_ADJUST_STAMINA_DAMAGE, PROC_REF(update_diminishing_return))
RegisterSignal(owner, COMSIG_LIVING_STAMINA_UPDATE, PROC_REF(check_remove))
/datum/status_effect/incapacitating/stamcrit/on_apply()
if(owner.stat == DEAD)
return FALSE
if(owner.check_stun_immunity(CANSTUN))
return FALSE
if(SEND_SIGNAL(owner, COMSIG_LIVING_ENTER_STAMCRIT) & STAMCRIT_CANCELLED)
return FALSE
. = ..()
if(!.)
return .
if(owner.stat == CONSCIOUS)
to_chat(owner, span_notice("You're too exhausted to keep going..."))
owner.add_traits(list(TRAIT_INCAPACITATED, TRAIT_IMMOBILIZED, TRAIT_FLOORED), STAMINA)
return .
/datum/status_effect/incapacitating/stamcrit/on_remove()
UnregisterSignal(owner, COMSIG_LIVING_HEALTH_UPDATE)
UnregisterSignal(owner, COMSIG_LIVING_ADJUST_STAMINA_DAMAGE)
owner.remove_traits(list(TRAIT_INCAPACITATED, TRAIT_IMMOBILIZED, TRAIT_FLOORED), STAMINA)
return ..()
/datum/status_effect/incapacitating/stamcrit/proc/update_diminishing_return(datum/source, type, amount, forced)
SIGNAL_HANDLER
if(amount <= 0 || forced)
return NONE
// Here we fake the effect of having diminishing returns
// We don't actually decrease incoming stamina damage because that would be pointless, the mob is at stam damage cap anyways
// Instead we just "ignore" the damage if we have a sufficiently high diminishing return counter
var/mod_amount = ceil(sqrt(amount) / 2) - diminishing_return_counter
// We check base amount not mod_amount because we still want to up tick it even if we've already got a high counter
// We also only uptick it after calculating damage so we start ticking up after the damage and not before
switch(amount)
if(5 to INFINITY)
diminishing_return_counter += 1
if(2 to 5) // Prevent chems from skyrockting DR
diminishing_return_counter += 0.05
if(mod_amount > 0)
return NONE
if(COOLDOWN_FINISHED(src, warn_cd) && owner.stat == CONSCIOUS)
to_chat(owner, span_notice("You start to recover from the exhaustion!"))
owner.visible_message(span_warning("[owner] starts to recover from the exhaustion!"), ignored_mobs = owner)
COOLDOWN_START(src, warn_cd, 2.5 SECONDS)
return COMPONENT_IGNORE_CHANGE
/datum/status_effect/incapacitating/stamcrit/proc/check_remove(datum/source)
SIGNAL_HANDLER
if (isbasicmob(owner))
var/mob/living/basic/basic_owner = owner
if(basic_owner.staminaloss < basic_owner.stamina_crit_threshold)
qdel(src)
return
if(owner.maxHealth - owner.getStaminaLoss() > owner.crit_threshold)
qdel(src)