diff --git a/code/game/objects/items/devices/earthcracker.dm b/code/game/objects/items/devices/earthcracker.dm new file mode 100644 index 00000000000..455be3168f2 --- /dev/null +++ b/code/game/objects/items/devices/earthcracker.dm @@ -0,0 +1,178 @@ +#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 diff --git a/code/modules/cargo/markets/market_items/weapons.dm b/code/modules/cargo/markets/market_items/weapons.dm index c9326807cc5..ce2c16735fe 100644 --- a/code/modules/cargo/markets/market_items/weapons.dm +++ b/code/modules/cargo/markets/market_items/weapons.dm @@ -153,3 +153,13 @@ price_max = CARGO_CRATE_VALUE * 5 stock_max = 2 availability_prob = 80 + +/datum/market_item/weapon/earthcracker + name = "E-1 Earthcracker" + desc = "Surplus mining equipment from one of the many, nameless asteroid mining companies bought out by Nanotrasen in this sector.\ + While they were decent enough at mining asteroids, these things really shine at leaving large cracks on station-class hulls when deployed these days." + item = /obj/item/earthcracker/small + price_min = CARGO_CRATE_VALUE + price_max = CARGO_CRATE_VALUE * 3 + stock_max = 1 + availability_prob = 30 diff --git a/code/modules/uplink/uplink_items/explosive.dm b/code/modules/uplink/uplink_items/explosive.dm index 89d0d9d23ea..c42dc2a0a39 100644 --- a/code/modules/uplink/uplink_items/explosive.dm +++ b/code/modules/uplink/uplink_items/explosive.dm @@ -121,6 +121,15 @@ purchasable_from = ~UPLINK_ALL_SYNDIE_OPS /// Ops get their own version. limited_discount_stock = 4 +/datum/uplink_item/explosives/earthcracker + name = "E-2 Earthcracker" + desc = "The E-2 Earthcracker makes for a great partner to any conventional explosive. Set the device up on any station hull, arm, and activate.\ + What remains is a conventionally dangerous weakpoint, that will crack open a random pattern of floors upon being hit with an explosive force.\ + That pattern of cracks will in-turn also create additional cracks, ad-finimum if not repaired. It can also be used for mining out rock, though that's less advised." + item = /obj/item/earthcracker + cost = 2 + limited_discount_stock = 2 + /datum/uplink_item/explosives/syndicate_bomb/New() . = ..() desc = replacetext(desc, "%MIN_BOMB_TIMER", SYNDIEBOMB_MIN_TIMER_SECONDS) diff --git a/icons/mob/inhands/equipment/tools_lefthand.dmi b/icons/mob/inhands/equipment/tools_lefthand.dmi index c8936fde8da..adaedb6483f 100644 Binary files a/icons/mob/inhands/equipment/tools_lefthand.dmi and b/icons/mob/inhands/equipment/tools_lefthand.dmi differ diff --git a/icons/mob/inhands/equipment/tools_righthand.dmi b/icons/mob/inhands/equipment/tools_righthand.dmi index 192413a739f..454a225c82a 100644 Binary files a/icons/mob/inhands/equipment/tools_righthand.dmi and b/icons/mob/inhands/equipment/tools_righthand.dmi differ diff --git a/icons/obj/devices/tool.dmi b/icons/obj/devices/tool.dmi index 9075c0d2063..5a4f58b0de3 100644 Binary files a/icons/obj/devices/tool.dmi and b/icons/obj/devices/tool.dmi differ diff --git a/sound/attributions.txt b/sound/attributions.txt index ade4c8fe7e7..3e315731646 100644 --- a/sound/attributions.txt +++ b/sound/attributions.txt @@ -246,5 +246,7 @@ sound/effect/droplet.ogg -- "Drop - Water" By mattfinarelli -- https://freesound sound/effects/swapper/swap_A.ogg and swap_B.ogg by ArcaneMusic, License: Creative Commons 0, man-made mouth noises, slight cleanup in audacity. +sound/items/weapons/earthcracker_bang.mp3 by Jean Filho -- https://freesound.org/people/Jean_Filho/sounds/807381/ -- License: Creative Commons 0 + sound/machines/data_transmission.ogg -- Elements from Tim Verberne -- https://freesound.org/people/Tim_Verberne/sounds/558942/ -- License: Creative Commons 0 and samples from Ping.ogg from throughout the codebase. diff --git a/sound/items/weapons/earthcracker_bang.mp3 b/sound/items/weapons/earthcracker_bang.mp3 new file mode 100644 index 00000000000..7baaf2ac0ba Binary files /dev/null and b/sound/items/weapons/earthcracker_bang.mp3 differ diff --git a/tgstation.dme b/tgstation.dme index d198f3df04f..36f5422e607 100644 --- a/tgstation.dme +++ b/tgstation.dme @@ -2672,6 +2672,7 @@ #include "code\game\objects\items\devices\chameleonproj.dm" #include "code\game\objects\items\devices\destabilizing_crystal.dm" #include "code\game\objects\items\devices\desynchronizer.dm" +#include "code\game\objects\items\devices\earthcracker.dm" #include "code\game\objects\items\devices\electroadaptive_pseudocircuit.dm" #include "code\game\objects\items\devices\flashlight.dm" #include "code\game\objects\items\devices\forcefieldprojector.dm"