mirror of
https://github.com/Bubberstation/Bubberstation.git
synced 2026-06-05 22:31:04 +01:00
0e85aa3220
## About The Pull Request Fixes #76665 `fakedeath` early returned if the mob was dead, I guess it assumed if you were dead dead you wouldn't want to become fake dead as well I removed that because it's definitely a valid use case, in my eyes, that you would be able to apply the fakedeath traits to a mob who is dead, for the event they are revived at some point (to still appear dead) ## Why It's Good For The Game Lings rely on this ## Changelog 🆑 Melbert fix: Fix ling revival for full-dead lings /🆑
725 lines
26 KiB
Plaintext
725 lines
26 KiB
Plaintext
|
|
/**
|
|
* Checks if we have stun immunity. Godmode always passes this check.
|
|
*
|
|
* * check_flags - bitflag of status flags that must be set in order for the stun to succeed. Passing NONE will always return false.
|
|
* * force_stun - whether we ignore stun immunity with the exception of godmode
|
|
*
|
|
* returns TRUE if stun immune, FALSE otherwise
|
|
*/
|
|
/mob/living/proc/check_stun_immunity(check_flags = CANSTUN, force_stun = FALSE)
|
|
SHOULD_CALL_PARENT(TRUE)
|
|
|
|
if(status_flags & GODMODE)
|
|
return TRUE
|
|
|
|
if(force_stun) // Does not take priority over god mode? I guess
|
|
return FALSE
|
|
|
|
if(SEND_SIGNAL(src, COMSIG_LIVING_GENERIC_STUN_CHECK, check_flags, force_stun) & COMPONENT_NO_STUN)
|
|
return TRUE
|
|
|
|
if(HAS_TRAIT(src, TRAIT_STUNIMMUNE))
|
|
return TRUE
|
|
|
|
// Do we have the correct flag set to allow this status?
|
|
// This checks that ALL flags are set, not just one of them.
|
|
if((status_flags & check_flags) == check_flags)
|
|
return FALSE
|
|
|
|
return TRUE
|
|
|
|
/* STUN */
|
|
/mob/living/proc/IsStun() //If we're stunned
|
|
return has_status_effect(/datum/status_effect/incapacitating/stun)
|
|
|
|
/mob/living/proc/AmountStun() //How many deciseconds remain in our stun
|
|
var/datum/status_effect/incapacitating/stun/S = IsStun()
|
|
if(S)
|
|
return S.duration - world.time
|
|
return 0
|
|
|
|
/mob/living/proc/Stun(amount, ignore_canstun = FALSE) //Can't go below remaining duration
|
|
if(SEND_SIGNAL(src, COMSIG_LIVING_STATUS_STUN, amount, ignore_canstun) & COMPONENT_NO_STUN)
|
|
return
|
|
if(check_stun_immunity(CANSTUN, ignore_canstun))
|
|
return
|
|
var/datum/status_effect/incapacitating/stun/S = IsStun()
|
|
if(S)
|
|
S.duration = max(world.time + amount, S.duration)
|
|
else if(amount > 0)
|
|
S = apply_status_effect(/datum/status_effect/incapacitating/stun, amount)
|
|
return S
|
|
|
|
/mob/living/proc/SetStun(amount, ignore_canstun = FALSE) //Sets remaining duration
|
|
if(SEND_SIGNAL(src, COMSIG_LIVING_STATUS_STUN, amount, ignore_canstun) & COMPONENT_NO_STUN)
|
|
return
|
|
if(check_stun_immunity(CANSTUN, ignore_canstun))
|
|
return
|
|
var/datum/status_effect/incapacitating/stun/S = IsStun()
|
|
if(amount <= 0)
|
|
if(S)
|
|
qdel(S)
|
|
else
|
|
if(S)
|
|
S.duration = world.time + amount
|
|
else
|
|
S = apply_status_effect(/datum/status_effect/incapacitating/stun, amount)
|
|
return S
|
|
|
|
/mob/living/proc/AdjustStun(amount, ignore_canstun = FALSE) //Adds to remaining duration
|
|
if(SEND_SIGNAL(src, COMSIG_LIVING_STATUS_STUN, amount, ignore_canstun) & COMPONENT_NO_STUN)
|
|
return
|
|
if(check_stun_immunity(CANSTUN, ignore_canstun))
|
|
return
|
|
var/datum/status_effect/incapacitating/stun/S = IsStun()
|
|
if(S)
|
|
S.duration += amount
|
|
else if(amount > 0)
|
|
S = apply_status_effect(/datum/status_effect/incapacitating/stun, amount)
|
|
return S
|
|
|
|
/* KNOCKDOWN */
|
|
/mob/living/proc/IsKnockdown() //If we're knocked down
|
|
return has_status_effect(/datum/status_effect/incapacitating/knockdown)
|
|
|
|
/mob/living/proc/AmountKnockdown() //How many deciseconds remain in our knockdown
|
|
var/datum/status_effect/incapacitating/knockdown/K = IsKnockdown()
|
|
if(K)
|
|
return K.duration - world.time
|
|
return 0
|
|
|
|
/mob/living/proc/Knockdown(amount, ignore_canstun = FALSE) //Can't go below remaining duration
|
|
if(SEND_SIGNAL(src, COMSIG_LIVING_STATUS_KNOCKDOWN, amount, ignore_canstun) & COMPONENT_NO_STUN)
|
|
return
|
|
if(check_stun_immunity(CANKNOCKDOWN, ignore_canstun))
|
|
return
|
|
var/datum/status_effect/incapacitating/knockdown/K = IsKnockdown()
|
|
if(K)
|
|
K.duration = max(world.time + amount, K.duration)
|
|
else if(amount > 0)
|
|
K = apply_status_effect(/datum/status_effect/incapacitating/knockdown, amount)
|
|
return K
|
|
|
|
/mob/living/proc/SetKnockdown(amount, ignore_canstun = FALSE) //Sets remaining duration
|
|
if(SEND_SIGNAL(src, COMSIG_LIVING_STATUS_KNOCKDOWN, amount, ignore_canstun) & COMPONENT_NO_STUN)
|
|
return
|
|
if(check_stun_immunity(CANKNOCKDOWN, ignore_canstun))
|
|
return
|
|
var/datum/status_effect/incapacitating/knockdown/K = IsKnockdown()
|
|
if(amount <= 0)
|
|
if(K)
|
|
qdel(K)
|
|
else
|
|
if(K)
|
|
K.duration = world.time + amount
|
|
else
|
|
K = apply_status_effect(/datum/status_effect/incapacitating/knockdown, amount)
|
|
return K
|
|
|
|
/mob/living/proc/AdjustKnockdown(amount, ignore_canstun = FALSE) //Adds to remaining duration
|
|
if(SEND_SIGNAL(src, COMSIG_LIVING_STATUS_KNOCKDOWN, amount, ignore_canstun) & COMPONENT_NO_STUN)
|
|
return
|
|
if(check_stun_immunity(CANKNOCKDOWN, ignore_canstun))
|
|
return
|
|
var/datum/status_effect/incapacitating/knockdown/K = IsKnockdown()
|
|
if(K)
|
|
K.duration += amount
|
|
else if(amount > 0)
|
|
K = apply_status_effect(/datum/status_effect/incapacitating/knockdown, amount)
|
|
return K
|
|
|
|
/* IMMOBILIZED */
|
|
/mob/living/proc/IsImmobilized() //If we're immobilized
|
|
return has_status_effect(/datum/status_effect/incapacitating/immobilized)
|
|
|
|
/mob/living/proc/AmountImmobilized() //How many deciseconds remain in our Immobilized status effect
|
|
var/datum/status_effect/incapacitating/immobilized/I = IsImmobilized()
|
|
if(I)
|
|
return I.duration - world.time
|
|
return 0
|
|
|
|
/mob/living/proc/Immobilize(amount, ignore_canstun = FALSE) //Can't go below remaining duration
|
|
if(SEND_SIGNAL(src, COMSIG_LIVING_STATUS_IMMOBILIZE, amount, ignore_canstun) & COMPONENT_NO_STUN)
|
|
return
|
|
if(check_stun_immunity(CANSTUN, ignore_canstun))
|
|
return
|
|
var/datum/status_effect/incapacitating/immobilized/I = IsImmobilized()
|
|
if(I)
|
|
I.duration = max(world.time + amount, I.duration)
|
|
else if(amount > 0)
|
|
I = apply_status_effect(/datum/status_effect/incapacitating/immobilized, amount)
|
|
return I
|
|
|
|
/mob/living/proc/SetImmobilized(amount, ignore_canstun = FALSE) //Sets remaining duration
|
|
if(SEND_SIGNAL(src, COMSIG_LIVING_STATUS_IMMOBILIZE, amount, ignore_canstun) & COMPONENT_NO_STUN)
|
|
return
|
|
if(check_stun_immunity(CANSTUN, ignore_canstun))
|
|
return
|
|
var/datum/status_effect/incapacitating/immobilized/I = IsImmobilized()
|
|
if(amount <= 0)
|
|
if(I)
|
|
qdel(I)
|
|
else
|
|
if(I)
|
|
I.duration = world.time + amount
|
|
else
|
|
I = apply_status_effect(/datum/status_effect/incapacitating/immobilized, amount)
|
|
return I
|
|
|
|
/mob/living/proc/AdjustImmobilized(amount, ignore_canstun = FALSE) //Adds to remaining duration
|
|
if(SEND_SIGNAL(src, COMSIG_LIVING_STATUS_IMMOBILIZE, amount, ignore_canstun) & COMPONENT_NO_STUN)
|
|
return
|
|
if(check_stun_immunity(CANSTUN, ignore_canstun))
|
|
return
|
|
var/datum/status_effect/incapacitating/immobilized/I = IsImmobilized()
|
|
if(I)
|
|
I.duration += amount
|
|
else if(amount > 0)
|
|
I = apply_status_effect(/datum/status_effect/incapacitating/immobilized, amount)
|
|
return I
|
|
|
|
/* PARALYZED */
|
|
/mob/living/proc/IsParalyzed() //If we're paralyzed
|
|
return has_status_effect(/datum/status_effect/incapacitating/paralyzed)
|
|
|
|
/mob/living/proc/AmountParalyzed() //How many deciseconds remain in our Paralyzed status effect
|
|
var/datum/status_effect/incapacitating/paralyzed/P = IsParalyzed(FALSE)
|
|
if(P)
|
|
return P.duration - world.time
|
|
return 0
|
|
|
|
/mob/living/proc/Paralyze(amount, ignore_canstun = FALSE) //Can't go below remaining duration
|
|
if(SEND_SIGNAL(src, COMSIG_LIVING_STATUS_PARALYZE, amount, ignore_canstun) & COMPONENT_NO_STUN)
|
|
return
|
|
if(check_stun_immunity(CANSTUN|CANKNOCKDOWN, ignore_canstun)) // this requires both can stun and can knockdown
|
|
return
|
|
var/datum/status_effect/incapacitating/paralyzed/P = IsParalyzed(FALSE)
|
|
if(P)
|
|
P.duration = max(world.time + amount, P.duration)
|
|
else if(amount > 0)
|
|
P = apply_status_effect(/datum/status_effect/incapacitating/paralyzed, amount)
|
|
return P
|
|
|
|
/mob/living/proc/SetParalyzed(amount, ignore_canstun = FALSE) //Sets remaining duration
|
|
if(SEND_SIGNAL(src, COMSIG_LIVING_STATUS_PARALYZE, amount, ignore_canstun) & COMPONENT_NO_STUN)
|
|
return
|
|
if(check_stun_immunity(CANSTUN|CANKNOCKDOWN, ignore_canstun))
|
|
return
|
|
var/datum/status_effect/incapacitating/paralyzed/P = IsParalyzed(FALSE)
|
|
if(amount <= 0)
|
|
if(P)
|
|
qdel(P)
|
|
else
|
|
if(P)
|
|
P.duration = world.time + amount
|
|
else
|
|
P = apply_status_effect(/datum/status_effect/incapacitating/paralyzed, amount)
|
|
return P
|
|
|
|
/mob/living/proc/AdjustParalyzed(amount, ignore_canstun = FALSE) //Adds to remaining duration
|
|
if(SEND_SIGNAL(src, COMSIG_LIVING_STATUS_PARALYZE, amount, ignore_canstun) & COMPONENT_NO_STUN)
|
|
return
|
|
if(check_stun_immunity(CANSTUN|CANKNOCKDOWN, ignore_canstun))
|
|
return
|
|
var/datum/status_effect/incapacitating/paralyzed/P = IsParalyzed(FALSE)
|
|
if(P)
|
|
P.duration += amount
|
|
else if(amount > 0)
|
|
P = apply_status_effect(/datum/status_effect/incapacitating/paralyzed, amount)
|
|
return P
|
|
|
|
/* INCAPACITATED */
|
|
|
|
|
|
/// Proc that returns the remaining duration of the status efect in deciseconds.
|
|
/mob/living/proc/amount_incapacitated()
|
|
var/datum/status_effect/incapacitating/incapacitated/incapacitated_status_effect = has_status_effect(/datum/status_effect/incapacitating/incapacitated)
|
|
if (incapacitated_status_effect)
|
|
return incapacitated_status_effect.duration - world.time
|
|
else
|
|
return 0
|
|
|
|
/** Proc that actually applies the status effect.
|
|
* Applies the Incapacitated status effect to a mob/living.
|
|
* * amount - Amount of time the status effect should be applied for, in deciseconds.
|
|
* * ignore_canstun - If TRUE, the mob's resistance to stuns is ignored.
|
|
*/
|
|
/mob/living/proc/incapacitate(amount, ignore_canstun = FALSE)
|
|
if(SEND_SIGNAL(src, COMSIG_LIVING_STATUS_INCAPACITATE, amount, ignore_canstun) & COMPONENT_NO_STUN)
|
|
return
|
|
if(check_stun_immunity(CANSTUN, ignore_canstun))
|
|
return
|
|
var/datum/status_effect/incapacitating/incapacitated/incapacitated_status_effect = has_status_effect(/datum/status_effect/incapacitating/incapacitated)
|
|
if(incapacitated_status_effect)
|
|
incapacitated_status_effect.duration = max(world.time + amount, incapacitated_status_effect.duration)
|
|
else if(amount > 0)
|
|
incapacitated_status_effect = apply_status_effect(/datum/status_effect/incapacitating/incapacitated, amount)
|
|
return incapacitated_status_effect
|
|
|
|
/** Proc that set the incapacitated status effect's remaining duration to a certain time.
|
|
* Checks if the mob has the status effect. If yes, it sets the duration to the amount passed in arguments. If not, applies the status effect
|
|
* and sets the duration to the amount passed in arguments.
|
|
* * amount - Amount of time the status effect should be set to, in deciseconds.
|
|
* * ignore_canstun - If TRUE, the mob's resistance to stuns is ignored.
|
|
*/
|
|
/mob/living/proc/set_incapacitated(amount, ignore_canstun = FALSE)
|
|
if(SEND_SIGNAL(src, COMSIG_LIVING_STATUS_INCAPACITATE, amount, ignore_canstun) & COMPONENT_NO_STUN)
|
|
return
|
|
if(check_stun_immunity(CANSTUN, ignore_canstun))
|
|
return
|
|
var/datum/status_effect/incapacitating/incapacitated/incapacitated_status_effect = has_status_effect(/datum/status_effect/incapacitating/incapacitated)
|
|
if(amount <= 0)
|
|
if(incapacitated_status_effect)
|
|
qdel(incapacitated_status_effect)
|
|
else
|
|
if(incapacitated_status_effect)
|
|
incapacitated_status_effect.duration = world.time + amount
|
|
else
|
|
incapacitated_status_effect = apply_status_effect(/datum/status_effect/incapacitating/incapacitated, amount)
|
|
return incapacitated_status_effect
|
|
|
|
/** Proc that adds duration to an incapacitated status effect.
|
|
* Checks if the mob has the status effect. If yes, it adds the amount passed in arguments to the remaining duration. If not, applies the status effect
|
|
* and sets the duration to the amount passed in arguments.
|
|
* * amount - Amount of time the status effect should be set to, in deciseconds.
|
|
* * ignore_canstun - If TRUE, the mob's resistance to stuns is ignored.
|
|
*/
|
|
/mob/living/proc/adjust_incapacitated(amount, ignore_canstun = FALSE) //Adds to remaining duration
|
|
if(SEND_SIGNAL(src, COMSIG_LIVING_STATUS_INCAPACITATE, amount, ignore_canstun) & COMPONENT_NO_STUN)
|
|
return
|
|
if(check_stun_immunity(CANSTUN, ignore_canstun))
|
|
return
|
|
var/datum/status_effect/incapacitating/incapacitated/incapacitated_status_effect = has_status_effect(/datum/status_effect/incapacitating/incapacitated)
|
|
if(incapacitated_status_effect)
|
|
incapacitated_status_effect.duration += amount
|
|
else if(amount > 0)
|
|
incapacitated_status_effect = apply_status_effect(/datum/status_effect/incapacitating/incapacitated, amount)
|
|
return incapacitated_status_effect
|
|
|
|
//Blanket
|
|
/mob/living/proc/AllImmobility(amount)
|
|
Paralyze(amount)
|
|
Knockdown(amount)
|
|
Stun(amount)
|
|
Immobilize(amount)
|
|
|
|
|
|
/mob/living/proc/SetAllImmobility(amount)
|
|
SetParalyzed(amount)
|
|
SetKnockdown(amount)
|
|
SetStun(amount)
|
|
SetImmobilized(amount)
|
|
|
|
|
|
/mob/living/proc/AdjustAllImmobility(amount)
|
|
AdjustParalyzed(amount)
|
|
AdjustKnockdown(amount)
|
|
AdjustStun(amount)
|
|
AdjustImmobilized(amount)
|
|
|
|
|
|
/* UNCONSCIOUS */
|
|
/mob/living/proc/IsUnconscious() //If we're unconscious
|
|
return has_status_effect(/datum/status_effect/incapacitating/unconscious)
|
|
|
|
/mob/living/proc/AmountUnconscious() //How many deciseconds remain in our unconsciousness
|
|
var/datum/status_effect/incapacitating/unconscious/U = IsUnconscious()
|
|
if(U)
|
|
return U.duration - world.time
|
|
return 0
|
|
|
|
/mob/living/proc/Unconscious(amount, ignore_canstun = FALSE) //Can't go below remaining duration
|
|
if(SEND_SIGNAL(src, COMSIG_LIVING_STATUS_UNCONSCIOUS, amount, ignore_canstun) & COMPONENT_NO_STUN)
|
|
return
|
|
if(check_stun_immunity(CANUNCONSCIOUS, ignore_canstun))
|
|
return
|
|
var/datum/status_effect/incapacitating/unconscious/U = IsUnconscious()
|
|
if(U)
|
|
U.duration = max(world.time + amount, U.duration)
|
|
else if(amount > 0)
|
|
U = apply_status_effect(/datum/status_effect/incapacitating/unconscious, amount)
|
|
return U
|
|
|
|
/mob/living/proc/SetUnconscious(amount, ignore_canstun = FALSE) //Sets remaining duration
|
|
if(SEND_SIGNAL(src, COMSIG_LIVING_STATUS_UNCONSCIOUS, amount, ignore_canstun) & COMPONENT_NO_STUN)
|
|
return
|
|
if(check_stun_immunity(CANUNCONSCIOUS, ignore_canstun))
|
|
return
|
|
var/datum/status_effect/incapacitating/unconscious/U = IsUnconscious()
|
|
if(amount <= 0)
|
|
if(U)
|
|
qdel(U)
|
|
else if(U)
|
|
U.duration = world.time + amount
|
|
else
|
|
U = apply_status_effect(/datum/status_effect/incapacitating/unconscious, amount)
|
|
return U
|
|
|
|
/mob/living/proc/AdjustUnconscious(amount, ignore_canstun = FALSE) //Adds to remaining duration
|
|
if(SEND_SIGNAL(src, COMSIG_LIVING_STATUS_UNCONSCIOUS, amount, ignore_canstun) & COMPONENT_NO_STUN)
|
|
return
|
|
if(check_stun_immunity(CANUNCONSCIOUS, ignore_canstun))
|
|
return
|
|
var/datum/status_effect/incapacitating/unconscious/U = IsUnconscious()
|
|
if(U)
|
|
U.duration += amount
|
|
else if(amount > 0)
|
|
U = apply_status_effect(/datum/status_effect/incapacitating/unconscious, amount)
|
|
return U
|
|
|
|
/* SLEEPING */
|
|
/mob/living/proc/IsSleeping() //If we're asleep
|
|
if(!HAS_TRAIT(src, TRAIT_SLEEPIMMUNE))
|
|
return has_status_effect(/datum/status_effect/incapacitating/sleeping)
|
|
|
|
/mob/living/proc/AmountSleeping() //How many deciseconds remain in our sleep
|
|
var/datum/status_effect/incapacitating/sleeping/S = IsSleeping()
|
|
if(S)
|
|
return S.duration - world.time
|
|
return 0
|
|
|
|
/mob/living/proc/Sleeping(amount) //Can't go below remaining duration
|
|
if(SEND_SIGNAL(src, COMSIG_LIVING_STATUS_SLEEP, amount) & COMPONENT_NO_STUN)
|
|
return
|
|
if(status_flags & GODMODE)
|
|
return
|
|
var/datum/status_effect/incapacitating/sleeping/S = IsSleeping()
|
|
if(S)
|
|
S.duration = max(world.time + amount, S.duration)
|
|
else if(amount > 0)
|
|
S = apply_status_effect(/datum/status_effect/incapacitating/sleeping, amount)
|
|
return S
|
|
|
|
/mob/living/proc/SetSleeping(amount) //Sets remaining duration
|
|
if(SEND_SIGNAL(src, COMSIG_LIVING_STATUS_SLEEP, amount) & COMPONENT_NO_STUN)
|
|
return
|
|
if(status_flags & GODMODE)
|
|
return
|
|
var/datum/status_effect/incapacitating/sleeping/S = IsSleeping()
|
|
if(amount <= 0)
|
|
if(S)
|
|
qdel(S)
|
|
else if(S)
|
|
S.duration = world.time + amount
|
|
else
|
|
S = apply_status_effect(/datum/status_effect/incapacitating/sleeping, amount)
|
|
return S
|
|
|
|
/mob/living/proc/AdjustSleeping(amount) //Adds to remaining duration
|
|
if(SEND_SIGNAL(src, COMSIG_LIVING_STATUS_SLEEP, amount) & COMPONENT_NO_STUN)
|
|
return
|
|
if(status_flags & GODMODE)
|
|
return
|
|
var/datum/status_effect/incapacitating/sleeping/S = IsSleeping()
|
|
if(S)
|
|
S.duration += amount
|
|
else if(amount > 0)
|
|
S = apply_status_effect(/datum/status_effect/incapacitating/sleeping, amount)
|
|
return S
|
|
|
|
///Allows us to set a permanent sleep on a player (use with caution and remember to unset it with SetSleeping() after the effect is over)
|
|
/mob/living/proc/PermaSleeping()
|
|
if(SEND_SIGNAL(src, COMSIG_LIVING_STATUS_SLEEP, -1) & COMPONENT_NO_STUN)
|
|
return
|
|
if(status_flags & GODMODE)
|
|
return
|
|
var/datum/status_effect/incapacitating/sleeping/S = IsSleeping()
|
|
if(S)
|
|
S.duration = -1
|
|
else
|
|
S = apply_status_effect(/datum/status_effect/incapacitating/sleeping, -1)
|
|
return S
|
|
|
|
///////////////////////// CLEAR STATUS /////////////////////////
|
|
|
|
/mob/living/proc/adjust_status_effects_on_shake_up()
|
|
AdjustStun(-60)
|
|
AdjustKnockdown(-60)
|
|
AdjustUnconscious(-60)
|
|
AdjustSleeping(-100)
|
|
AdjustParalyzed(-60)
|
|
AdjustImmobilized(-60)
|
|
|
|
///////////////////////////////// FROZEN /////////////////////////////////////
|
|
|
|
/* FROZEN */
|
|
/mob/living/proc/IsFrozen()
|
|
return has_status_effect(/datum/status_effect/freon)
|
|
|
|
/**
|
|
* Adds the passed quirk to the mob
|
|
*
|
|
* Arguments
|
|
* * quirktype - Quirk typepath to add to the mob
|
|
* If not passed, defaults to this mob's client.
|
|
*
|
|
* Returns TRUE on success, FALSE on failure (already has the quirk, etc)
|
|
*/
|
|
/mob/living/proc/add_quirk(datum/quirk/quirktype, client/override_client)
|
|
if(has_quirk(quirktype))
|
|
return FALSE
|
|
var/qname = initial(quirktype.name)
|
|
if(!SSquirks || !SSquirks.quirks[qname])
|
|
return FALSE
|
|
var/datum/quirk/quirk = new quirktype()
|
|
if(quirk.add_to_holder(new_holder = src, client_source = override_client))
|
|
return TRUE
|
|
qdel(quirk)
|
|
return FALSE
|
|
|
|
/mob/living/proc/remove_quirk(quirktype)
|
|
for(var/datum/quirk/quirk in quirks)
|
|
if(quirk.type == quirktype)
|
|
qdel(quirk)
|
|
return TRUE
|
|
return FALSE
|
|
|
|
/mob/living/proc/has_quirk(quirktype)
|
|
for(var/datum/quirk/quirk in quirks)
|
|
if(quirk.type == quirktype)
|
|
return TRUE
|
|
return FALSE
|
|
|
|
/**
|
|
* Getter function for a mob's quirk
|
|
*
|
|
* Arguments:
|
|
* * quirktype - the type of the quirk to acquire e.g. /datum/quirk/some_quirk
|
|
*
|
|
* Returns the mob's quirk datum if the mob this is called on has the quirk, null on failure
|
|
*/
|
|
/mob/living/proc/get_quirk(quirktype)
|
|
for(var/datum/quirk/quirk in quirks)
|
|
if(quirk.type == quirktype)
|
|
return quirk
|
|
return null
|
|
|
|
/mob/living/proc/cure_husk(source)
|
|
REMOVE_TRAIT(src, TRAIT_HUSK, source)
|
|
if(!HAS_TRAIT(src, TRAIT_HUSK))
|
|
REMOVE_TRAIT(src, TRAIT_DISFIGURED, "husk")
|
|
update_body()
|
|
return TRUE
|
|
|
|
/mob/living/proc/become_husk(source)
|
|
if(!HAS_TRAIT(src, TRAIT_HUSK))
|
|
ADD_TRAIT(src, TRAIT_HUSK, source)
|
|
ADD_TRAIT(src, TRAIT_DISFIGURED, "husk")
|
|
update_body()
|
|
else
|
|
ADD_TRAIT(src, TRAIT_HUSK, source)
|
|
|
|
/mob/living/proc/cure_fakedeath(source)
|
|
remove_traits(list(TRAIT_FAKEDEATH, TRAIT_DEATHCOMA), source)
|
|
if(stat != DEAD)
|
|
tod = null
|
|
|
|
/// Induces fake death on a living mob.
|
|
/mob/living/proc/fakedeath(source, silent = FALSE)
|
|
if(stat != DEAD)
|
|
if(!silent)
|
|
emote("deathgasp")
|
|
tod = station_time_timestamp()
|
|
|
|
add_traits(list(TRAIT_FAKEDEATH, TRAIT_DEATHCOMA), source)
|
|
|
|
///Unignores all slowdowns that lack the IGNORE_NOSLOW flag.
|
|
/mob/living/proc/unignore_slowdown(source)
|
|
REMOVE_TRAIT(src, TRAIT_IGNORESLOWDOWN, source)
|
|
update_movespeed()
|
|
|
|
///Ignores all slowdowns that lack the IGNORE_NOSLOW flag.
|
|
/mob/living/proc/ignore_slowdown(source)
|
|
ADD_TRAIT(src, TRAIT_IGNORESLOWDOWN, source)
|
|
update_movespeed()
|
|
|
|
///Ignores specific slowdowns. Accepts a list of slowdowns.
|
|
/mob/living/proc/add_movespeed_mod_immunities(source, slowdown_type, update = TRUE)
|
|
if(islist(slowdown_type))
|
|
for(var/listed_type in slowdown_type)
|
|
if(ispath(listed_type))
|
|
listed_type = "[listed_type]" //Path2String
|
|
LAZYADDASSOCLIST(movespeed_mod_immunities, listed_type, source)
|
|
else
|
|
if(ispath(slowdown_type))
|
|
slowdown_type = "[slowdown_type]" //Path2String
|
|
LAZYADDASSOCLIST(movespeed_mod_immunities, slowdown_type, source)
|
|
if(update)
|
|
update_movespeed()
|
|
|
|
///Unignores specific slowdowns. Accepts a list of slowdowns.
|
|
/mob/living/proc/remove_movespeed_mod_immunities(source, slowdown_type, update = TRUE)
|
|
if(islist(slowdown_type))
|
|
for(var/listed_type in slowdown_type)
|
|
if(ispath(listed_type))
|
|
listed_type = "[listed_type]" //Path2String
|
|
LAZYREMOVEASSOC(movespeed_mod_immunities, listed_type, source)
|
|
else
|
|
if(ispath(slowdown_type))
|
|
slowdown_type = "[slowdown_type]" //Path2String
|
|
LAZYREMOVEASSOC(movespeed_mod_immunities, slowdown_type, source)
|
|
if(update)
|
|
update_movespeed()
|
|
|
|
/**
|
|
* Adjusts a timed status effect on the mob,taking into account any existing timed status effects.
|
|
* This can be any status effect that takes into account "duration" with their initialize arguments.
|
|
*
|
|
* Positive durations will add deciseconds to the duration of existing status effects
|
|
* or apply a new status effect of that duration to the mob.
|
|
*
|
|
* Negative durations will remove deciseconds from the duration of an existing version of the status effect,
|
|
* removing the status effect entirely if the duration becomes less than zero (less than the current world time).
|
|
*
|
|
* duration - the duration, in deciseconds, to add or remove from the effect
|
|
* effect - the type of status effect being adjusted on the mob
|
|
* max_duration - optional - if set, positive durations will only be added UP TO the passed max duration
|
|
*/
|
|
/mob/living/proc/adjust_timed_status_effect(duration, effect, max_duration)
|
|
if(!isnum(duration))
|
|
CRASH("adjust_timed_status_effect: called with an invalid duration. (Got: [duration])")
|
|
|
|
if(!ispath(effect, /datum/status_effect))
|
|
CRASH("adjust_timed_status_effect: called with an invalid effect type. (Got: [effect])")
|
|
|
|
// If we have a max duration set, we need to check our duration does not exceed it
|
|
if(isnum(max_duration))
|
|
if(max_duration <= 0)
|
|
CRASH("adjust_timed_status_effect: Called with an invalid max_duration. (Got: [max_duration])")
|
|
|
|
if(duration >= max_duration)
|
|
duration = max_duration
|
|
|
|
var/datum/status_effect/existing = has_status_effect(effect)
|
|
if(existing)
|
|
if(isnum(max_duration) && duration > 0)
|
|
// Check the duration remaining on the existing status effect
|
|
// If it's greater than / equal to our passed max duration, we don't need to do anything
|
|
var/remaining_duration = existing.duration - world.time
|
|
if(remaining_duration >= max_duration)
|
|
return
|
|
|
|
// Otherwise, add duration up to the max (max_duration - remaining_duration),
|
|
// or just add duration if it doesn't exceed our max at all
|
|
existing.duration += min(max_duration - remaining_duration, duration)
|
|
|
|
else
|
|
existing.duration += duration
|
|
|
|
// If the duration was decreased and is now less 0 seconds,
|
|
// qdel it / clean up the status effect immediately
|
|
// (rather than waiting for the process tick to handle it)
|
|
if(existing.duration <= world.time)
|
|
qdel(existing)
|
|
|
|
else if(duration > 0)
|
|
apply_status_effect(effect, duration)
|
|
|
|
/**
|
|
* Sets a timed status effect of some kind on a mob to a specific value.
|
|
* If only_if_higher is TRUE, it will only set the value up to the passed duration,
|
|
* so any pre-existing status effects of the same type won't be reduced down
|
|
*
|
|
* duration - the duration, in deciseconds, of the effect. 0 or lower will either remove the current effect or do nothing if none are present
|
|
* effect - the type of status effect given to the mob
|
|
* only_if_higher - if TRUE, we will only set the effect to the new duration if the new duration is longer than any existing duration
|
|
*/
|
|
/mob/living/proc/set_timed_status_effect(duration, effect, only_if_higher = FALSE)
|
|
if(!isnum(duration))
|
|
CRASH("set_timed_status_effect: called with an invalid duration. (Got: [duration])")
|
|
|
|
if(!ispath(effect, /datum/status_effect))
|
|
CRASH("set_timed_status_effect: called with an invalid effect type. (Got: [effect])")
|
|
|
|
var/datum/status_effect/existing = has_status_effect(effect)
|
|
if(existing)
|
|
// set_timed_status_effect to 0 technically acts as a way to clear effects,
|
|
// though remove_status_effect would achieve the same goal more explicitly.
|
|
if(duration <= 0)
|
|
qdel(existing)
|
|
return
|
|
|
|
if(only_if_higher)
|
|
// If the existing status effect has a higher remaining duration
|
|
// than what we aim to set it to, don't downgrade it - do nothing (return)
|
|
var/remaining_duration = existing.duration - world.time
|
|
if(remaining_duration >= duration)
|
|
return
|
|
|
|
// Set the duration accordingly
|
|
existing.duration = world.time + duration
|
|
|
|
else if(duration > 0)
|
|
apply_status_effect(effect, duration)
|
|
|
|
/**
|
|
* Gets how many deciseconds are remaining in
|
|
* the duration of the passed status effect on this mob.
|
|
*
|
|
* If the mob is unaffected by the passed effect, returns 0.
|
|
*/
|
|
/mob/living/proc/get_timed_status_effect_duration(effect)
|
|
if(!ispath(effect, /datum/status_effect))
|
|
CRASH("get_timed_status_effect_duration: called with an invalid effect type. (Got: [effect])")
|
|
|
|
var/datum/status_effect/existing = has_status_effect(effect)
|
|
if(!existing)
|
|
return 0
|
|
// Infinite duration status effects technically are not "timed status effects"
|
|
// by name or nature, but support is included just in case.
|
|
if(existing.duration == -1)
|
|
return INFINITY
|
|
|
|
return existing.duration - world.time
|
|
|
|
/**
|
|
* Adjust the "drunk value" the mob is currently experiencing,
|
|
* or applies a drunk effect if the mob isn't currently drunk (or tipsy)
|
|
*
|
|
* The drunk effect doesn't have a set duration, like dizziness or drugginess,
|
|
* but instead relies on a value that decreases every status effect tick (2 seconds) by:
|
|
* 4% the current drunk_value + 0.01
|
|
*
|
|
* A "drunk value" of 6 is the border between "tipsy" and "drunk".
|
|
*
|
|
* amount - the amount of "drunkness" to apply to the mob.
|
|
* down_to - the lower end of the clamp, when adding the value
|
|
* up_to - the upper end of the clamp, when adding the value
|
|
*/
|
|
/mob/living/proc/adjust_drunk_effect(amount, down_to = 0, up_to = INFINITY)
|
|
if(!isnum(amount))
|
|
CRASH("adjust_drunk_effect: called with an invalid amount. (Got: [amount])")
|
|
|
|
var/datum/status_effect/inebriated/inebriation = has_status_effect(/datum/status_effect/inebriated)
|
|
if(inebriation)
|
|
inebriation.set_drunk_value(clamp(inebriation.drunk_value + amount, down_to, up_to))
|
|
else if(amount > 0)
|
|
apply_status_effect(/datum/status_effect/inebriated/tipsy, amount)
|
|
|
|
|
|
/**
|
|
* Directly sets the "drunk value" the mob is currently experiencing to the passed value,
|
|
* or applies a drunk effect with the passed value if the mob isn't currently drunk
|
|
*
|
|
* set_to - the amount of "drunkness" to set on the mob.
|
|
*/
|
|
/mob/living/proc/set_drunk_effect(set_to)
|
|
if(!isnum(set_to) || set_to < 0)
|
|
CRASH("set_drunk_effect: called with an invalid value. (Got: [set_to])")
|
|
|
|
var/datum/status_effect/inebriated/inebriation = has_status_effect(/datum/status_effect/inebriated)
|
|
if(inebriation)
|
|
inebriation.set_drunk_value(set_to)
|
|
else if(set_to > 0)
|
|
apply_status_effect(/datum/status_effect/inebriated/tipsy, set_to)
|
|
|
|
/// Helper to get the amount of drunkness the mob's currently experiencing.
|
|
/mob/living/proc/get_drunk_amount()
|
|
var/datum/status_effect/inebriated/inebriation = has_status_effect(/datum/status_effect/inebriated)
|
|
return inebriation?.drunk_value || 0
|
|
|
|
/// Helper to check if we seem to be alive or not
|
|
/mob/living/proc/appears_alive()
|
|
return health >= 0 && !HAS_TRAIT(src, TRAIT_FAKEDEATH)
|