Fixes and improvements to weakpoints. (#95641)

## About The Pull Request

Weakpoints have a few things adjusted on them to result in more expected
behavior.

* They now have infinite move resistance to avoid being thrown by
explosions, as well as being thrown into space.
* The function for spawning and propagating a crack has been adjusted to
avoid propagating over space tiles.
* Weakpoints now animate their spawning in, in order to look more
natural when observed.
* Weakpoints now start on a lower layer to avoid being above cables,
pipes, etc.

## Why It's Good For The Game

It bugged me that weakpoints could spawn onto/be moved onto space tiles
and I made this as an attempt to prevent that from happening as much as
possible.

Also tweaks a few of the functional/visual aspects of the cracks to be
both more obvious as well as look more pleasing when you see one spawn
in.

## Changelog

🆑
fix: Weakpoints have more safeguards to prevent them from spawning onto
space.
image: Weakpoints now have an animation to spawn in with.
/🆑
This commit is contained in:
ArcaneMusic
2026-04-11 13:53:22 -04:00
committed by GitHub
parent a38a7d1531
commit a5ca784dd9
@@ -2,17 +2,22 @@
#define CRACK_PROPAGATION_DELAY 0.1 SECONDS
#define CRACK_TURN_CHANCE 50
#define CRACK_DELAY_CHANCE 33
#define CRACK_LENGTH_DEFAULT 8
/obj/effect/weakpoint
name = "weakpoint crack"
desc = "A suspicious crack runs along the ground."
icon = 'icons/effects/effects.dmi'
icon_state = "weakpoint"
base_icon_state = "weakpoint"
layer = ABOVE_NORMAL_TURF_LAYER
move_resist = INFINITY
alpha = 0
/// The required strength of explosion for a weakpoint to propogate
var/required_strength = EXPLODE_LIGHT
//How many turfs should this weakpoint crack when triggered? Crack length splits by default and doesn't recurse
var/crack_length = 8
var/crack_length = CRACK_LENGTH_DEFAULT
/// How many split off cracks are expected?
var/crack_split_count = 2
@@ -20,25 +25,33 @@
var/spawns_children = TRUE
/// How many children weakpoints will this crack spawn when it propagates?
var/new_weakpoints = 2
/obj/effect/weakpoint/Initialize(mapload)
. = ..()
AddElement(/datum/element/undertile, TRAIT_T_RAY_VISIBLE, INVISIBILITY_OBSERVER, use_anchor = TRUE)
register_context()
/obj/effect/weakpoint/ex_act(severity, target)
. = ..()
/// These turfs are things we don't want to spawn new cracks onto.
var/static/list/skip_turfs = typecacheof(list(
/turf/open/space,
/turf/open/misc/asteroid,
/turf/open/misc/snow,
))
/obj/effect/weakpoint/Initialize(mapload)
. = ..()
AddElement(/datum/element/undertile, TRAIT_T_RAY_VISIBLE, INVISIBILITY_OBSERVER, use_anchor = TRUE)
RegisterSignal(src, COMSIG_TURF_CHANGE, PROC_REF(turf_changed))
register_context()
animate(src, alpha = 255, time = 0.3 SECONDS)
/obj/effect/weakpoint/ex_act(severity, target)
. = ..()
if(severity < required_strength)
balloon_alert_to_hearers("*crack*")
playsound(source = src, soundin = SFX_HULL_CREAKING, vol = 50, vary = TRUE, pressure_affected = FALSE, ignore_walls = TRUE)
return //return ominous sounds when we're under the threshold.
var/list/chain_turfs = get_crack_chain(get_turf(src), 8, TRUE, skip_turfs) // Get a nice chain of turfs
var/list/chain_turfs = get_crack_chain(get_turf(src), crack_length, TRUE, skip_turfs) // Get a nice chain of turfs
for(var/atom/along_length in chain_turfs)
for(var/extra_turfs in get_adjacent_turfs(chain_turfs[along_length])) //use get_adjacent turfs to help add extra turfs.
if(chain_turfs[extra_turfs])
continue
chain_turfs += extra_turfs
var/crack_delay = 0
for(var/turf/crack_turf in chain_turfs)
@@ -48,14 +61,7 @@
crack_delay++
if(spawns_children)
chain_turfs = typecache_filter_list_reverse(chain_turfs, skip_turfs) //Filter out things that we don't want to spawn new weakpoints onto.
for(var/i in 1 to new_weakpoints)
var/obj/effect/weakpoint/newpoint = new(pick(chain_turfs))
//inherit parent var values in case of var-editing.
newpoint.new_weakpoints = new_weakpoints
newpoint.crack_length = crack_length
newpoint.crack_split_count = crack_split_count
addtimer(CALLBACK(loc, TYPE_PROC_REF(/turf, create_new_cracks), chain_turfs, new_weakpoints, skip_turfs, crack_length, crack_split_count), CRACK_PROPAGATION_DELAY * crack_delay)
qdel(src)
/obj/effect/weakpoint/welder_act(mob/living/user, obj/item/tool)
@@ -93,39 +99,90 @@
* * start_location: The turf to begin the chain of turfs from.
* * length: How many lengths this chain needs to be.
* * add_splits: Should this crack chain apply additional instances of get_crack_chain while recursively cracking even further.
* * turfs_to_skip: a typecache of turfs that we block spreading to when getting a chain.
*/
/obj/effect/weakpoint/proc/get_crack_chain(start_location, length, add_splits = TRUE, turfs_to_skip = list())
/obj/effect/weakpoint/proc/get_crack_chain(start_location, length, add_splits = TRUE)
if(!length)
CRASH("Weakpoint spawned with no length value!")
if(!start_location)
CRASH("No start location for crack specified!")
var/list/turf/cracked_turfs = list()
var/turf/current = loc //Start on top of ourselves
var/turf/current = start_location //Start on top of ourselves
var/direction = pick(NORTH, SOUTH, EAST, WEST)
for(var/i in 1 to length)
if(length(turfs_to_skip) && is_type_in_typecache(current, turfs_to_skip))
direction = turn(direction, pick(90, 135, 180, 225, 270)) //We'll either turn or reverse the direction of the crack if we can't get around our obstacle.
current = get_turf(get_step(current, direction))
continue
cracked_turfs += current
// Randomly branch or continue
if(prob(CRACK_TURN_CHANCE))
direction = turn(direction, pick(-90, -45, 45, 90))
direction = turn(direction, pick(90, 135, 180, 225, 270))
current = get_turf(get_step(current, direction))
if(!isturf(current))
break
if(length(skip_turfs) && is_type_in_typecache(current, skip_turfs))
continue
cracked_turfs += current
if(add_splits)
for(var/subcrack in 1 to crack_split_count)
cracked_turfs += get_crack_chain(pick(cracked_turfs), max(round(length/2 ), 1), FALSE) //Stop recursion here
message_admins("Station weakpoint triggered, affecting [length(cracked_turfs)] turfs in [loc_name(start_location)].")
log_game("Station weakpoint triggered, affecting [length(cracked_turfs)] turfs in [loc_name(start_location)].")
return cracked_turfs
/// If this turf becomes something we can't spawn a crack on, we should try and shift the crack or otherwise qdel.
/obj/effect/weakpoint/proc/turf_changed(turf/source)
SIGNAL_HANDLER
var/turf/option
var/list/turf/choices = get_adjacent_open_turfs(src)
while(!option && length(choices))
option = pick_n_take(get_adjacent_open_turfs(src))
if(locate(/obj/effect/weakpoint) in option)
continue
if(is_type_in_typecache(option, skip_turfs))
continue
if(!option)
qdel(src)
return
forceMove(option)
/**
* Used by weakpoint cracks to spawn new cracks after the crack is finished propagating.
* * chain_turfs: The list of turfs that we're going to pull from in order to generate a new weakpoint. Generated by ex_act on the parent weakpoint.
*/
/turf/proc/create_new_cracks(list/chain_turfs, new_weakpoints = 1, skip_turfs = list(), crack_length = 2, crack_split_count = 1)
if(!chain_turfs || !length(chain_turfs))
chain_turfs = list(src)
chain_turfs += get_adjacent_turfs(src)
if(skip_turfs)
chain_turfs = typecache_filter_list_reverse(chain_turfs, skip_turfs) //Filter out things that we don't want to spawn new weakpoints onto.
var/active_count = 0
var/list/new_cracks = list()
while(active_count < new_weakpoints)
if(!length(chain_turfs))
return
var/turf/spawn_location = pick_n_take(chain_turfs)
if(locate(/obj/effect/weakpoint) in spawn_location)
continue
if(skip_turfs)
if(is_type_in_typecache(spawn_location, skip_turfs))
continue
var/obj/effect/weakpoint/newpoint = new(spawn_location)
//inherit parent var values in case of var-editing.
newpoint.new_weakpoints = new_weakpoints
newpoint.crack_length = crack_length
newpoint.crack_split_count = crack_split_count
new_cracks += newpoint
spawn_location.levelupdate()
active_count++
notify_ghosts(
"A new crack has been spawned in [get_area(src)].",
source = pick(new_cracks),
header = "Weakpoint created",
ghost_sound = 'sound/effects/hit_kick.ogg',
)
/obj/effect/weakpoint/big
name = "dangerous weakpoint"
desc = "A suspicious crack runs along the ground. This one makes you feel particuarly uneasy."
@@ -137,3 +194,4 @@
#undef CRACK_PROPAGATION_DELAY
#undef CRACK_TURN_CHANCE
#undef CRACK_DELAY_CHANCE
#undef CRACK_LENGTH_DEFAULT