Shadow humanoids are now burned and confused by flashes of light, in lieu of stamina loss when applicable (#92146)

## About The Pull Request

`Flash_act()` no longer stuns Shadow/Nightmare species mobs. It instead
applies confusion and high (-ly spammable) damage. Just to be absolutely
clear, this applies to both the "shadow" halloween species and the
Nightmare antag species.

This applies to most forms of flashes, including welding, flashbangs,
and of course, flashes. I'm going to talk about those seperately:

FLASHES:

Head-on flashes do 16 damage and apply 3 seconds of confusion. This goes
down to 8 damage and 1 second if from the side. If you want to open up a
fight with a Nightmare, you can still flash it like usual. The enemy
will be hurt and confused, but not stunned like previously. You could
continue spamming flashes (assuming you're at the right angle) to keep
doing damage and keep them confused, but they won't be helpless and will
likely start attacking you while you do this.

Not-head-on flashes do half damage and confuse for half as long. It
still works but not as good, just like flashes do in every other case.

Yes, this does include in-hand flash uses, so if you're afraid of
getting jumped by a nightmare, you can keep one in your back pocket and
spam it as you run away for safety.

THE OTHER FLASH_ACT() STUFF:

Other sources of flashes will do full damage regardless of distance or
direction faced. This includes flashbangs (they won't stun) and welding
(your whole body is made of shadow, so you won't be protected by a
welding mask). Seriously. Don't try to operate a welder as a Nightmare.
Just jaunt past the wall. You will die.

OH ALSO:

Shadow species now have a cool sounding scream. They scream when flashed
too.


https://github.com/user-attachments/assets/781f9d2f-d2a9-4be5-ab47-95a4261dfa55

## Why It's Good For The Game

Flashes should not be the remedy to the Nightmare issue. They're
roundstart gear, virtually everywhere, and come as standard gear for
every cyborg. The flashes aren't the issue, it's the effect they have on
Nightmares.

Rather than remove flashes from the equation entirely, they're now a
handy tool for opening up attacks on Nightmares. You can land a good hit
with them to confuse and injure them, then follow up with the baton or
welder or whatever you were carrying around.

Effectively, flashes been bumped down from "two-shot wincon that most of
your adversaries have as default gear" to "controlled equipment that a
player might want when they know they'll have to fight this particular
antag".

As for the rest of the sandbox corners that this affects, I think being
more sensitive to even benign flashes of light makes sense in-character.

And... it adds a little bit more depth to the species. Now all sources
of bright, flashing light are something that must be considered, rather
than just the ones used to kill antagonists.
## Changelog
🆑 Rhials
balance: Nightmares/Shadowpeople are no longer stunned by intense
flashes like flashbangs or handheld flashes.
balance: Nightmares/Shadowpeople are now harmed and confused by ALL
flash sources, including welding or other sources of flash-like
flashing.
sound: Nightmares now have a wretched hiss as their default scream
sound. Spooky!
/🆑
This commit is contained in:
Rhials
2025-07-28 23:31:14 -04:00
committed by Roxy
parent b7a8c21c7b
commit 002099f720
7 changed files with 45 additions and 1 deletions

View File

@@ -417,3 +417,6 @@ BUBBERSTATION CHANGE END */
/// Needs to have support for force overrides and multipliers of 0 (hence why we ternaries are used over 'or's)
#define CALCULATE_FORCE(some_item, atk_mods) \
((((FORCE_OVERRIDE in atk_mods) ? atk_mods[FORCE_OVERRIDE] : some_item.force) + (atk_mods?[FORCE_MODIFIER] || 0)) * ((FORCE_MULTIPLIER in atk_mods) ? atk_mods[FORCE_MULTIPLIER] : 1))
///Do we block carbon-level flash_act() from performing its default stamina damage/knockdown?
#define FLASH_COMPLETED "flash_completed"

View File

@@ -227,6 +227,10 @@
///from living/flash_act(), when a mob is successfully flashed.
#define COMSIG_MOB_FLASHED "mob_flashed"
/// from /obj/item/assembly/flash/flash_carbon, to the mob being flashed
#define COMSIG_MOB_FLASH_OVERRIDE_CHECK "mob_flash_override_check"
/// Has the flash effect been overridden?
#define FLASH_OVERRIDDEN (1<<0)
/// from /obj/item/assembly/flash/flash_carbon, to the mob flashing another carbon
#define COMSIG_MOB_PRE_FLASHED_CARBON "mob_pre_flashed_carbon"
/// Return to override deviation to be full deviation (fail the flash, usually)

View File

@@ -166,7 +166,11 @@
return
if(targeted)
if(flashed.flash_act(1, 1))
var/flash_result = flashed.flash_act(1, 1)
if(flash_result == FLASH_COMPLETED)
return //Behavior was overwritten, so we just skip the flashy stunny part and go with the override behavior instead
if(flash_result)
flashed.set_confusion_if_lower(confusion_duration * CONFUSION_STACK_MAX_MULTIPLIER)
visible_message(span_danger("[user] blinds [flashed] with the flash!"), span_userdanger("[user] blinds you with the flash!"))
//easy way to make sure that you can only long stun someone who is facing in your direction

View File

@@ -487,6 +487,9 @@
return embeds
/mob/living/carbon/flash_act(intensity = 1, override_blindness_check = 0, affect_silicon = 0, visual = 0, type = /atom/movable/screen/fullscreen/flash, length = 25)
if(SEND_SIGNAL(src, COMSIG_MOB_FLASH_OVERRIDE_CHECK, src) & FLASH_OVERRIDDEN) //Check for behavior overrides before doing the act itself. If we have a behavior override, we handle everything there and skip the rest
return FLASH_COMPLETED
var/obj/item/organ/eyes/eyes = get_organ_slot(ORGAN_SLOT_EYES)
if(!eyes) //can't flash what can't see!
return

View File

@@ -32,6 +32,14 @@
BODY_ZONE_CHEST = /obj/item/bodypart/chest/shadow,
)
/datum/species/shadow/on_species_gain(mob/living/carbon/carbon_mob, datum/species/old_species, pref_load, regenerate_icons)
. = ..()
RegisterSignal(carbon_mob, COMSIG_MOB_FLASH_OVERRIDE_CHECK, PROC_REF(on_flashed))
/datum/species/shadow/on_species_loss(mob/living/carbon/human/human, datum/species/new_species, pref_load)
. = ..()
UnregisterSignal(human, COMSIG_MOB_FLASH_OVERRIDE_CHECK)
/datum/species/shadow/check_roundstart_eligible()
if(check_holidays(HALLOWEEN))
return TRUE
@@ -103,3 +111,23 @@
name = "shadowling tumor"
desc = "Something that was once a brain, before being remolded by a shadowling. It has adapted to the dark, irreversibly."
icon = 'icons/obj/medical/organs/shadow_organs.dmi'
/datum/species/shadow/get_scream_sound(mob/living/carbon/human/moth)
return 'sound/mobs/humanoids/shadow/shadow_wail.ogg'
/datum/species/shadow/proc/on_flashed(source, mob/living/carbon/flashed, flash, deviation)
SIGNAL_HANDLER
if(deviation == DEVIATION_FULL) //If no deviation, we can assume it's a non-assembly flash and should do max flash damage.
flashed.apply_damage(16, BURN, attacking_item = flash)
flashed.adjust_confusion_up_to(3 SECONDS, 6 SECONDS)
else //If it's anything less than a full hit, it does less than stellar damage. Bear in mind that this damage is dished out much faster since flashes have a quicker cooldown on clicks.
flashed.apply_damage(8, BURN, attacking_item = flash)
flashed.adjust_confusion_up_to(1 SECONDS, 3 SECONDS)
INVOKE_ASYNC(flashed, TYPE_PROC_REF(/mob, emote), "scream")
flashed.visible_message(span_danger("[flashed] wails in pain as a burst of light singes their flesh!"), \
span_danger("You wail in pain as the sudden burst of light singes your flesh!"), \
span_danger("Something wails in pain! It sounds like a terrifying monster! Good thing you can't see it, or you'd probably be freaking out right now."))
return FLASH_OVERRIDDEN

View File

@@ -234,3 +234,5 @@ sound/effect/plasticflaps.ogg -- door_plastic_tapes.wav by estupe -- https://fre
sound/effects/siren.ogg -- siren.wav by IFartInUrGeneralDirection -- https://freesound.org/s/46092/ -- License: Attribution 4.0
sound/mobs/non-humanoids/stoats/stoat_sound.ogg -- https://suche.tierstimmenarchiv.de/
sounds/mobs/humanoids/shadow/shadow_wail.ogg -- https://freesound.org/people/Robinhood76/sounds/585631/ -- License: Attribution 4.0

Binary file not shown.