Files
Bubberstation/code/modules/unit_tests/stuns.dm
MrMelbert 22799fcb89 Refactors the worst list ever, Stun Absorptions, into status effects + makes status flags more accurate (making certain mobs more vulnerable to incapacitations?) (#76000)
## About The Pull Request

- Refactors the stun absorption list into a status effect

- Does a fair bit of cleanup around stun code

Weird thing involved in this.
Check out this define. 
`IS_STUN_IMMUNE(source, ignore_canstun) ((source.status_flags & GODMODE)
|| (!ignore_canstun && (!(source.status_flags & CANKNOCKDOWN) ||
HAS_TRAIT(source, TRAIT_STUNIMMUNE))))`
Notice anything odd about it?
It only checks for `CANKNOCKDOWN`. 
What does this mean?
Well, *every single* one of the stun procs used this macro for checking
stun immunity. Which means every method of stun checked the
`CANKNOCKDOWN`.
This means that, say you have a mob which has `CANSTUN` but not
`CANKNOCKDOWN`.
Intuitively this means that the mob cannot be knocked down, but can be
stunned.
But instead, this means the mob can't be stunned either. 
This doesn't affect humans, they have all the status flags, but it does
affect some other mobs.
Alien adults (not queens) have `CANUNCONSCIOUS|CANPUSH`. Before, they
didn't have `CANKNOCKDOWN`, so they were fully immune to stuns and
sleeps. But now, they can be knocked unconscious.
However, overall it doesn't change much, as most mobs that flipped off
`CANKNOCKDOWN` flipped off the others too.
For consistency though it makes sense for these flags to work as they
imply.

- `incapacitate` didn't have a signal, now it does

## Why It's Good For The Game

More consistent, better code? I may use this in the future.

## Changelog

🆑 Melbert
refactor: Refactored Stun Absorptions (Bastard Sword, His Grace)
refactor: Refactored Stun Immunity. Note this means that some mobs
which, prior, were immune to all forms of incapacitation are now
vulnerable to some. Notably, adult non-queen xenomorphs are now
vulnerable to falling unconscious.
/🆑
2023-06-16 14:44:25 -06:00

73 lines
3.0 KiB
Plaintext

/// Tests stun and the canstun flag
/datum/unit_test/stun
/datum/unit_test/stun/Run()
var/mob/living/carbon/human/gets_stunned = allocate(/mob/living/carbon/human/consistent)
gets_stunned.Stun(1 SECONDS)
TEST_ASSERT(gets_stunned.IsStun(), "Stun() failed to apply stun")
gets_stunned.SetStun(0 SECONDS)
TEST_ASSERT(!gets_stunned.IsStun(), "SetStun(0) failed to clear stun")
gets_stunned.status_flags &= ~CANSTUN
gets_stunned.Stun(1 SECONDS)
TEST_ASSERT(!gets_stunned.IsStun(), "Stun() stunned despite not having CANSTUN flag")
/// Tests knockdown and the canknockdown flag
/datum/unit_test/knockdown
/datum/unit_test/knockdown/Run()
var/mob/living/carbon/human/gets_knockdown = allocate(/mob/living/carbon/human/consistent)
gets_knockdown.Knockdown(1 SECONDS)
TEST_ASSERT(gets_knockdown.IsKnockdown(), "Knockdown() failed to apply knockdown")
gets_knockdown.SetKnockdown(0 SECONDS)
TEST_ASSERT(!gets_knockdown.IsKnockdown(), "SetKnockdown(0) failed to clear knockdown")
gets_knockdown.status_flags &= ~CANKNOCKDOWN
gets_knockdown.Knockdown(1 SECONDS)
TEST_ASSERT(!gets_knockdown.IsKnockdown(), "Knockdown() knocked over despite not having CANKNOCKDOWN flag")
/// Tests paralyze and stuns that have two flags checked (in this case, canstun and canknockdown)
/datum/unit_test/paralyze
/datum/unit_test/paralyze/Run()
var/mob/living/carbon/human/gets_paralyzed = allocate(/mob/living/carbon/human/consistent)
gets_paralyzed.Paralyze(1 SECONDS)
TEST_ASSERT(gets_paralyzed.IsParalyzed(), "Paralyze() failed to apply paralyze")
gets_paralyzed.SetParalyzed(0 SECONDS)
TEST_ASSERT(!gets_paralyzed.IsParalyzed(), "SetParalyzed(0) failed to clear paralyze")
gets_paralyzed.status_flags &= ~CANSTUN // paralyze needs both CANSTUN and CANKNOCKDOWN to succeed
gets_paralyzed.Paralyze(1 SECONDS)
TEST_ASSERT(!gets_paralyzed.IsParalyzed(), "Paralyze() paralyzed a mob despite not having CANSTUN flag (but still having CANKNOCKDOWN)")
/// Tests unconsciousness and the canunconscious flag
/datum/unit_test/unconsciousness
/datum/unit_test/unconsciousness/Run()
var/mob/living/carbon/human/gets_unconscious = allocate(/mob/living/carbon/human/consistent)
gets_unconscious.Unconscious(1 SECONDS)
TEST_ASSERT(gets_unconscious.IsUnconscious(), "Unconscious() failed to apply unconsciousness")
gets_unconscious.SetUnconscious(0 SECONDS)
TEST_ASSERT(!gets_unconscious.IsUnconscious(), "SetUnconscious(0) failed to clear unconsciousness")
gets_unconscious.status_flags &= ~CANUNCONSCIOUS
gets_unconscious.Unconscious(1 SECONDS)
TEST_ASSERT(!gets_unconscious.IsUnconscious(), "Unconscious() knocked unconscious despite not having CANUNCONSCIOUS flag")
/// Tests for stun absorption
/datum/unit_test/stun_absorb
/datum/unit_test/stun_absorb/Run()
var/mob/living/carbon/human/doesnt_get_stunned = allocate(/mob/living/carbon/human/consistent)
doesnt_get_stunned.add_stun_absorption(source = TRAIT_SOURCE_UNIT_TESTS)
doesnt_get_stunned.Stun(1 SECONDS)
TEST_ASSERT(!doesnt_get_stunned.IsStun(), "Stun() stunned despite having stun absorption")