Files
Bubberstation/code/datums/components/torn_wall.dm
paganiy 33ea581933 Changeling's last resort breaks near obstacles (#93109)
## About The Pull Request

- **fixes** a runtime error that occurred when removing antag info
button from the ling's old body (which became null) after transforming
into a worm.
- **fixes** a bug that caused a worm to appear in the debug room when
spamming the "yes" button in the TGUI alert window
- **changes** the blind range of last resort from 2 to 4, because it has
a short animation now

**Added** the ability for the changeling's "Last Resort" to break
through walls and other objects accompanied by blood, gore, and
disgusting sounds😊


https://github.com/user-attachments/assets/a2f263ec-a809-404f-a001-8d3643ba887b
## Why It's Good For The Game
currently, the explosion from "last resort" feels generic, similar to a
grenade or bomb. As a bioweapon, the changeling's ability should reflect
its biological nature — as if the ling is rapidly expanding its cells,
bursting its own body to rupture the surrounding environment and
explode.

regarding the ability to break walls: the current design allows for a
counter-play strategy of quickly building walls around a ling (it takes
like 10 seconds or less) who is in stasis or accumulating reagents for
last resort. While containing a ling in proper cell is valid roleplay
(like for science), this "fortnite-style" walling tactic feels cheap.
The intended design of the ability is to force the destruction of the
ling's body, not to allow them to be permanently walled in with no
option other than ghosting.

Yeah, i know that players will just build a cell that's 2 walls thick or
even bigger, but i think that's fiiine.
## Changelog
🆑
add: changeling's last resort ability now can rupture surrounding them
walls and other objects
add: last resort now has a short animation
balance: increased last resort's blind range from 2 to 4 tiles
fix: fixed several runtimes related to changeling's last resort ability
sound: added a gore sound effect to last resort explosion
/🆑
2025-10-11 14:56:34 -07:00

107 lines
3.6 KiB
Plaintext

#define TORN_WALL_RUINED 2
#define TORN_WALL_DAMAGED 1
#define TORN_WALL_INITIAL 0
/**
* Component applied to a wall to progressively destroy it.
* If component is applied to something which already has it, stage increases.
* Wall is destroyed on third application.
* Can be fixed using a welder
*/
/datum/component/torn_wall
dupe_mode = COMPONENT_DUPE_UNIQUE_PASSARGS
var/current_stage = TORN_WALL_INITIAL
/datum/component/torn_wall/Initialize(current_stage)
. = ..()
if (!isclosedturf(parent) || isindestructiblewall(parent))
return COMPONENT_INCOMPATIBLE
src.current_stage = current_stage || src.current_stage
/datum/component/torn_wall/RegisterWithParent()
RegisterSignal(parent, COMSIG_ATOM_EXAMINE, PROC_REF(on_examined))
RegisterSignal(parent, COMSIG_ATOM_TOOL_ACT(TOOL_WELDER), PROC_REF(on_welded))
RegisterSignal(parent, COMSIG_ATOM_UPDATE_OVERLAYS, PROC_REF(on_update_overlays))
RegisterSignal(parent, COMSIG_TURF_CHANGE, PROC_REF(on_turf_changed))
apply_visuals()
/datum/component/torn_wall/UnregisterFromParent()
var/atom/atom_parent = parent
UnregisterSignal(parent, list(
COMSIG_ATOM_EXAMINE,
COMSIG_ATOM_TOOL_ACT(TOOL_WELDER),
COMSIG_ATOM_UPDATE_OVERLAYS,
COMSIG_TURF_CHANGE,
))
atom_parent.update_appearance(UPDATE_ICON)
/datum/component/torn_wall/InheritComponent(datum/component/C, i_am_original)
increase_stage()
/// Play a fun animation and make our wall look damaged
/datum/component/torn_wall/proc/apply_visuals()
var/atom/atom_parent = parent
playsound(atom_parent, 'sound/effects/bang.ogg', 50, vary = TRUE)
atom_parent.update_appearance(UPDATE_ICON)
atom_parent.Shake(shake_interval = 0.1 SECONDS, duration = 0.5 SECONDS)
/// Make the effect more dramatic
/datum/component/torn_wall/proc/increase_stage()
current_stage++
if (current_stage != TORN_WALL_RUINED)
apply_visuals()
return
var/turf/closed/wall/attached_wall = parent
playsound(attached_wall, 'sound/effects/meteorimpact.ogg', 100, vary = TRUE)
if(ismineralturf(attached_wall))
var/turf/closed/mineral/mineral_turf = attached_wall
mineral_turf.gets_drilled()
return
attached_wall.dismantle_wall(devastated = TRUE)
/// Fix it up on weld
/datum/component/torn_wall/proc/on_welded(atom/source, mob/user, obj/item/tool)
SIGNAL_HANDLER
INVOKE_ASYNC(src, PROC_REF(try_repair), source, user, tool)
return ITEM_INTERACT_BLOCKING
/// Fix us up
/datum/component/torn_wall/proc/try_repair(atom/source, mob/user, obj/item/tool)
source.balloon_alert(user, "repairing...")
if(!tool.use_tool(source, user, 5 SECONDS, amount = 2, volume = 50))
source.balloon_alert(user, "interrupted!")
return
current_stage--
if (current_stage < TORN_WALL_INITIAL)
qdel(src)
return
source.update_appearance(UPDATE_ICON)
try_repair(source, user, tool) // Keep going
/// Give them a hint
/datum/component/torn_wall/proc/on_examined(atom/source, mob/user, list/examine_list)
SIGNAL_HANDLER
var/intensity = (current_stage == TORN_WALL_INITIAL) ? "slightly" : "badly"
examine_list += span_notice("It looks [intensity] damaged.")
examine_list += span_info("You may be able to repair it using a welding tool.")
/// Show a little crack on here
/datum/component/torn_wall/proc/on_update_overlays(turf/source, list/overlays)
SIGNAL_HANDLER
var/mutable_appearance/crack = mutable_appearance('icons/turf/overlays.dmi', "explodable", source.layer + 0.1)
if (current_stage == TORN_WALL_INITIAL)
crack.alpha *= 0.5
overlays += crack
/// If the wall becomes any other turf, delete us. Transforming into a different works fine as a fix.
/datum/component/torn_wall/proc/on_turf_changed()
SIGNAL_HANDLER
qdel(src)
#undef TORN_WALL_RUINED
#undef TORN_WALL_DAMAGED
#undef TORN_WALL_INITIAL