Files
SmArtKarandGitHub c37d65b3d4 Makes decals unhittable in combat mode, reduces vent debris spawns (#96859)
## About The Pull Request
Cleanable decals, such as rubble, trash, glass shards, etc, can no
longer be hit (not interacted with, but just offensively hit) in combat
mode.
Ore vents now more consistently clear rocks around them, and spawn
noticeably less debris.

## Why It's Good For The Game

Suggested under my necropolis tile PR, some larger decals may steal your
clicks in combat which I do not think offers any positive gameplay
value.
Ore vents just spawn too much debris, and as it only has one sprite, it
just looks really bad.

## Changelog
🆑
qol: Ore vents spawn less rubble and are more consistent at excavating
the surrounding area
balance: Cleanable decals can no longer be hit (not cleaned, just hit)
if the user has combat mode on.
/🆑
2026-07-09 17:43:15 +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((i * 15) - 25))
continue
var/turf/closed/mineral/drillable = rock
drillable.gets_drilled(user)
if(prob(15))
new /obj/effect/decal/cleanable/rubble(rock)
continue
if(istype(rock, /turf/open/misc/asteroid) && prob(10))
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