Files
SmArtKar 7e0fba028f Fixes earthcracker not getting spent on mining z levels (#96533)
## About The Pull Request

Closes #96531

## Changelog
🆑
fix: Fixed earthcracker not getting spent on mining z levels
/🆑
2026-06-17 05:43:59 +02:00

179 lines
6.1 KiB
Plaintext

#define EARTHCRACKER_READY "ready"
#define EARTHCRACKER_ACTIVE "active"
#define EARTHCRACKER_SPENT "spent"
/**
* The E-2 Earthcracker, a traitor device that creates intentional weakpoints on the station after use, which can be triggered via explosions.
* See weakpoint.dm for more specifics on their effects.
*/
/obj/item/earthcracker
name = "E-2 Earthcracker"
desc = "A nasty automated pilebunker can be used to create a massive weakpoint in flooring,\
which can be triggered afterwards by a sufficiently strong enough explosion."
icon = 'icons/obj/devices/tool.dmi'
icon_state = "earthcracker"
base_icon_state = "earthcracker"
/// Is the earthcracker ready to arm, arming, activating, or spent?
var/status = EARTHCRACKER_READY
/// What kind of weakpoint shall you spawn?
var/obj/weakpoint_type = /obj/effect/weakpoint/big
/// The timer for the strike_the_earth activation
var/activation_timer
/obj/item/earthcracker/Initialize(mapload)
. = ..()
if(!weakpoint_type)
CRASH("An earthcracker spawned without a designated weakpoint!")
register_context()
/obj/item/earthcracker/attack_self(mob/user, modifiers)
. = ..()
if(status == EARTHCRACKER_READY)
handle_arming(user)
/obj/item/earthcracker/attack_hand(mob/user, list/modifiers)
. = ..()
if(!anchored)
return NONE
switch(status)
if(EARTHCRACKER_ACTIVE)
if(activation_timer)
return FALSE
var/response = tgui_alert(user, "Activate the earthcracker?", "Activate?", list("Yes", "No")) == "Yes"
if(!response)
return FALSE
if(!user.Adjacent(src))
return FALSE
flick("[base_icon_state]-active", src)
if(is_mining_level(z))
activation_timer = addtimer(CALLBACK(src, PROC_REF(mining_act), user), 1.2 SECONDS)
return TRUE
activation_timer = addtimer(CALLBACK(src, PROC_REF(strike_the_earth)), 1.2 SECONDS)
return TRUE
if(EARTHCRACKER_SPENT)
balloon_alert(user, "used up!")
return FALSE
/obj/item/earthcracker/update_icon_state()
. = ..()
switch(status)
if(EARTHCRACKER_READY)
icon_state = "[base_icon_state]"
if(EARTHCRACKER_ACTIVE)
icon_state = "[base_icon_state]-armed"
if(EARTHCRACKER_SPENT)
icon_state = "[base_icon_state]-spent"
/obj/item/earthcracker/wrench_act(mob/living/user, obj/item/tool)
if(anchored && status == EARTHCRACKER_SPENT)
balloon_alert(user, "it falls apart")
animate(src, 0.6 SECONDS, alpha = 0, easing = CIRCULAR_EASING|EASE_IN)
addtimer(CALLBACK(src, PROC_REF(post_break)), 0.6 SECONDS)
return ITEM_INTERACT_SUCCESS
if(!anchored && status == EARTHCRACKER_READY)
balloon_alert(user, "arm in hands first!")
return ITEM_INTERACT_SUCCESS
if(anchored && status == EARTHCRACKER_ACTIVE)
balloon_alert(user, "unfastening from the floor...")
if(!tool.use_tool(src, user, 8 SECONDS, volume = 50))
return ITEM_INTERACT_FAILURE
anchored = FALSE
status = EARTHCRACKER_READY
update_appearance(UPDATE_ICON)
return NONE
/obj/item/earthcracker/add_context(atom/source, list/context, obj/item/held_item, mob/user)
switch(status)
if(EARTHCRACKER_ACTIVE)
context[SCREENTIP_CONTEXT_LMB] = "Activate device"
if(EARTHCRACKER_SPENT)
if(held_item?.tool_behaviour == TOOL_WRENCH)
context[SCREENTIP_CONTEXT_LMB] = "Disassemble device"
return CONTEXTUAL_SCREENTIP_SET
/obj/item/earthcracker/examine(mob/user)
. = ..()
if(status == EARTHCRACKER_SPENT)
. += span_warning("This device is toast. You could disassemble the remains using a [EXAMINE_HINT("Wrench")].")
else
. += span_info("This device can be unanchored using a [EXAMINE_HINT("Wrench")].")
/obj/item/earthcracker/proc/handle_arming(mob/user)
var/turf/arm_location = get_turf(user)
if(!arm_location)
return FALSE
if(isgroundlessturf(arm_location))
balloon_alert(user, "can't deploy here")
return FALSE
if(status == EARTHCRACKER_SPENT)
balloon_alert(user, "used up!")
return FALSE
balloon_alert(user, "arming...")
if(!do_after(user, 3 SECONDS, src))
balloon_alert(user, "failed to arm")
return FALSE
forceMove(arm_location)
anchored = TRUE
flick("[base_icon_state]-arm", src)
playsound(src, 'sound/items/barcodebeep.ogg', 50, FALSE)
status = EARTHCRACKER_ACTIVE
update_appearance(UPDATE_ICON)
return TRUE
/// The fun part. We spawn a huge weakpoint here.
/obj/item/earthcracker/proc/strike_the_earth()
if(QDELETED(src))
return
playsound(src, 'sound/items/weapons/earthcracker_bang.mp3', 75, FALSE, 3)
var/turf/cracked_hull = drop_location()
new weakpoint_type(cracked_hull)
handle_after_activation(cracked_hull)
/// Cleanup after an earthcracker is activated either for sabotage or mining.
/obj/item/earthcracker/proc/handle_after_activation(turf/cracked_hull)
do_sparks(2, FALSE, src)
cracked_hull?.levelupdate()
status = EARTHCRACKER_SPENT
update_appearance(UPDATE_ICON)
particles = new /particles/smoke/burning/small
activation_timer = null
/// Called after the earthcracker activates.
/obj/item/earthcracker/proc/post_break()
deconstruct(TRUE)
/// When this item is used on a mining Z, we perform an action that breaks all rocks in a radius around us, the same as starting an ore vent wave.
/obj/item/earthcracker/proc/mining_act(mob/user)
for(var/i in 1 to 5)
for(var/turf/rock in oview(i)) // This collects a list of rings of turfs (in a growing radius of i) that we'll applying logic to "drill" below.
if(istype(rock, /turf/closed/mineral))
if(prob(50 + (i * 8)))
continue
var/turf/closed/mineral/drillable = rock
drillable.gets_drilled(user)
if(prob(50))
new /obj/effect/decal/cleanable/rubble(rock)
continue
if(istype(rock, /turf/open/misc/asteroid) && prob(35))
new /obj/effect/decal/cleanable/rubble(rock)
continue
sleep(0.6 SECONDS)
handle_after_activation()
/// Small subtype for shenanigans.
/obj/item/earthcracker/small
name = "E-1 Earthcracker"
desc = "A rusty automated pilebunker can be used to create a weakpoint in flooring,\
which can be triggered afterwards by a sufficiently strong enough explosion.\
You're pretty sure the mining company that used to make these got bought by Nanotrasen ages ago."
weakpoint_type = /obj/effect/weakpoint
#undef EARTHCRACKER_READY
#undef EARTHCRACKER_ACTIVE
#undef EARTHCRACKER_SPENT