Files
Alexis 21b4095dfd [MDB IGNORE] [IDB IGNORE] Upstream Sync - 04/17/2026 (#5453)
Upstream 04/17/2026

fixes https://github.com/Bubberstation/Bubberstation/issues/5549

---------

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: tgstation-ci[bot] <179393467+tgstation-ci[bot]@users.noreply.github.com>
Co-authored-by: ArcaneMusic <41715314+ArcaneMusic@users.noreply.github.com>
Co-authored-by: MrMelbert <51863163+MrMelbert@users.noreply.github.com>
Co-authored-by: Rhials <28870487+Rhials@users.noreply.github.com>
Co-authored-by: rageguy505 <54517726+rageguy505@users.noreply.github.com>
Co-authored-by: LemonInTheDark <58055496+LemonInTheDark@users.noreply.github.com>
Co-authored-by: John Willard <53777086+JohnFulpWillard@users.noreply.github.com>
Co-authored-by: Aliceee2ch <160794176+Aliceee2ch@users.noreply.github.com>
Co-authored-by: Time-Green <7501474+Time-Green@users.noreply.github.com>
Co-authored-by: Tsar-Salat <62388554+Tsar-Salat@users.noreply.github.com>
Co-authored-by: SmArtKar <44720187+SmArtKar@users.noreply.github.com>
Co-authored-by: Maxipat <108554989+Maxipat112@users.noreply.github.com>
Co-authored-by: SyncIt21 <110812394+SyncIt21@users.noreply.github.com>
Co-authored-by: deltanedas <39013340+deltanedas@users.noreply.github.com>
Co-authored-by: SimplyLogan <47579821+loganuk@users.noreply.github.com>
Co-authored-by: loganuk <fakeemail123@aol.com>
Co-authored-by: Leland Kemble <70413276+lelandkemble@users.noreply.github.com>
Co-authored-by: FalloutFalcon <86381784+FalloutFalcon@users.noreply.github.com>
Co-authored-by: Roxy <75404941+TealSeer@users.noreply.github.com>
Co-authored-by: Lucy <lucy@absolucy.moe>
Co-authored-by: siliconOpossum <138069572+siliconOpossum@users.noreply.github.com>
Co-authored-by: Isratosh <Isratosh@hotmail.com>
Co-authored-by: TheRyeGuyWhoWillNowDie <70169560+TheRyeGuyWhoWillNowDie@users.noreply.github.com>
Co-authored-by: Neocloudy <88008002+Neocloudy@users.noreply.github.com>
Co-authored-by: Alexander V. <volas@ya.ru>
Co-authored-by: ElGitificador <168473461+ElGitificador@users.noreply.github.com>
Co-authored-by: Twaticus <46540570+Twaticus@users.noreply.github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
Co-authored-by: Bloop <13398309+vinylspiders@users.noreply.github.com>
Co-authored-by: Cameron Lennox <killer65311@gmail.com>
Co-authored-by: Tim <timothymtorres@gmail.com>
Co-authored-by: Iamgoofball <iamgoofball@gmail.com>
Co-authored-by: Layzu666 <121319428+Layzu666@users.noreply.github.com>
Co-authored-by: Arturlang <24881678+Arturlang@users.noreply.github.com>
Co-authored-by: _0Steven <42909981+00-Steven@users.noreply.github.com>
Co-authored-by: mrmanlikesbt <99309552+mrmanlikesbt@users.noreply.github.com>
Co-authored-by: Ben10Omintrix <138636438+Ben10Omintrix@users.noreply.github.com>
Co-authored-by: John F. Kennedy <54908920+MacaroniCritter@users.noreply.github.com>
Co-authored-by: Cursor <102828457+theselfish@users.noreply.github.com>
Co-authored-by: Josh <josh.adam.powell@gmail.com>
Co-authored-by: Josh Powell <josh.powell@softwire.com>
Co-authored-by: Yobrocharlie <Charliemiller5617@gmail.com>
Co-authored-by: Hardly3D <66234359+Hardly3D@users.noreply.github.com>
Co-authored-by: shayoki <96078776+shayoki@users.noreply.github.com>
Co-authored-by: LT3 <83487515+lessthnthree@users.noreply.github.com>
2026-05-16 00:56:00 +02:00

198 lines
7.5 KiB
Plaintext

#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 = CRACK_LENGTH_DEFAULT
/// How many split off cracks are expected?
var/crack_split_count = 2
/// When the crack is finished expanding, will it spawn more cracks?
var/spawns_children = TRUE
/// How many children weakpoints will this crack spawn when it propagates?
var/new_weakpoints = 2
/// 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), 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)
addtimer(CALLBACK(crack_turf, TYPE_PROC_REF(/atom, ex_act), severity, crack_turf), CRACK_PROPAGATION_DELAY * crack_delay)
playsound(source = crack_turf, soundin = SFX_HULL_CREAKING, vol = 35, vary = TRUE, pressure_affected = FALSE, ignore_walls = TRUE)
if(prob(33))
crack_delay++
if(spawns_children)
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)
to_chat(user, span_notice("You begin to strengthen [src]..."))
if(!tool.use_tool(src, user, 4 SECONDS, amount = 1, volume=50))
return ITEM_INTERACT_BLOCKING
to_chat(user, span_notice("\The [src] is fully sealed, eliminating the risk of the weakpoint growing."))
qdel(src)
return ITEM_INTERACT_SUCCESS
/obj/effect/weakpoint/item_interaction(mob/living/user, obj/item/tool, list/modifiers)
if(istype(tool, /obj/item/stack/medical/wrap/sticky_tape))
var/obj/item/stack/medical/wrap/sticky_tape/duct_tape = tool
if(!duct_tape.use(1))
return ITEM_INTERACT_BLOCKING
to_chat(user, span_notice("\The [src] is sealed with a little elbow grease and a mound of [duct_tape]."))
qdel(src)
return ITEM_INTERACT_SUCCESS
return ..()
/obj/effect/weakpoint/add_context(atom/source, list/context, obj/item/held_item, mob/user)
. = ..()
if(held_item?.tool_behaviour == TOOL_WELDER)
context[SCREENTIP_CONTEXT_LMB] = "Repair weakpoint"
return CONTEXTUAL_SCREENTIP_SET
return .
/obj/effect/weakpoint/examine(mob/user)
. = ..()
. += span_notice("\The [src] could be repaired with a welder.")
. += span_warning("A strong enough explosion will cause [src] to expand.")
/**
* Generates a list of turfs from the start location meandering along a randomized set of turns.
* * 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.
*/
/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 = start_location //Start on top of ourselves
var/direction = pick(NORTH, SOUTH, EAST, WEST)
for(var/i in 1 to length)
// Randomly branch or continue
if(prob(CRACK_TURN_CHANCE))
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."
icon_state = "weakpoint"
crack_length = 15
crack_split_count = 6
new_weakpoints = 3
#undef CRACK_PROPAGATION_DELAY
#undef CRACK_TURN_CHANCE
#undef CRACK_DELAY_CHANCE
#undef CRACK_LENGTH_DEFAULT