Files
ArcaneMusic 283fdd5290 Adds the E-2 Earthcracker, a traitor tool for premeditated sabotage. (#95731)
## About The Pull Request

Adds a new traitor item, the E-2 Earthcracker. The Earthcracker is a
handheld sabotage device that you can deploy onto the ground in order to
deliberately create a weakpoint on that location.

As a recap, weakpoints can be exploited with a sufficiently large enough
explosive in order to create a chain of cracked turfs from it's
location, randomly breaking floors and walls, as well as attempting to
create new weakpoints that will allow for more of the hull to break
down. Weakpoints, if discovered, can be welded to taped up to repair
them using sticky tape.

The earthcracker creates a longer, and larger weakpoint than the kind
that spawn naturally. However, to use this subtly, you'll need to hide
the weakpoint created, as well as clear away the spent earthcracker by
using a wrench.

Practical use is: Get the earthcracker, use in hand to arm/anchor onto a
turf (Can be unwrenched at this point), activate with an empty hand to
begin the cracking process, then wrench away, and you have a well
hidden, high power sabotage device.

Two variants are available in-game: The E-2 Earthcracker which can be
obtained from the traitor uplink at 2TC each, and the E-1 Earthcracker
which can be purchased on the black market. The E-1 variant spawns
normal run-of-the-mill weakpoints as opposed to the E-2, with a 30%
availability from the back market, at a cost of 200-600 credits.


![earthcraking](https://github.com/user-attachments/assets/0ab3a5af-f6c3-4096-b59a-7a1b44a01700)


## Why It's Good For The Game

I'll be frank, I don't think we necessarily need *more* tools to cause
havoc, but I wanted to expand the weakpoint framework a bit and this
idea came to mind. The Earthcracker fits in the same category as C4, but
without a signifigant amount of the control that comes from C4 and
absolutely from X4. This stands to cause more damage across the hull,
with the ability to keep expanding the crack. For that reason, I think I
may have underpriced this in terms of TC, but I'm up for discussion on
if it needs to go up to a 3-5 range.

In an ideal world, this could be used for making booby traps, such as
planting an earthcracker in an area like escape or a larger department,
and then triggering the weakpoint when the right people are around, even
through something like a detomatrix or a trigger on a grenade.

As an added reminder, weakpoints have a dedicated method to repair them
if discovered, that being welding them or hitting them with sticky tape
to repair them quickly, offering some counterplay.

I also added a lighter variant onto the black market as a fun, dubious
thing to have on the black market.

## Changelog
🆑
add: Adds the E-2 Earthcracker device as a purchasable traitor item for
2 TC. Use it to create potentially devastating weakpoints onto the
station!
/🆑
2026-05-07 06:13:55 +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