diff --git a/code/datums/uplink_items/uplink_traitor.dm b/code/datums/uplink_items/uplink_traitor.dm
index 545ec96e3bc..ff2cdec2b6d 100644
--- a/code/datums/uplink_items/uplink_traitor.dm
+++ b/code/datums/uplink_items/uplink_traitor.dm
@@ -77,6 +77,7 @@
cost = 25 //A chef can get a knife that sharp easily, though it won't block. While you can get endless boomerang, they are less deadly than a stech, and slower / more predictable.
job = list("Mime", "Chef")
+// Shaft miner
/datum/uplink_item/jobspecific/pressure_mod
name = "Kinetic Accelerator Pressure Mod"
desc = "A modification kit which allows Kinetic Accelerators to do greatly increased damage while indoors. Occupies 35% mod capacity."
@@ -86,6 +87,15 @@
job = list("Shaft Miner")
surplus = 0 // Requires a KA to even be used.
+/datum/uplink_item/jobspecific/mining_charge_hacker
+ name = "Mining Charge Hacker"
+ desc = "Looks and functions like an advanced mining scanner, but allows mining charges to be placed anywhere and destroy more than rocks. \
+ Use it on a mining charge to override its safeties. Reduces explosive power of mining charges due to the modification of their internals."
+ reference = "MCH"
+ item = /obj/item/t_scanner/adv_mining_scanner/syndicate
+ cost = 25
+ job = list("Shaft Miner")
+
//Chef
/datum/uplink_item/jobspecific/specialsauce
name = "Chef Excellence's Special Sauce"
diff --git a/code/game/objects/items/weapons/explosives.dm b/code/game/objects/items/weapons/explosives.dm
index ab458dc8c36..dd5df9c4122 100644
--- a/code/game/objects/items/weapons/explosives.dm
+++ b/code/game/objects/items/weapons/explosives.dm
@@ -12,6 +12,7 @@
var/image_overlay = null
var/obj/item/assembly/nadeassembly = null
var/assemblyattacher
+ var/notify_admins = TRUE
/obj/item/grenade/plastic/Initialize(mapload)
. = ..()
@@ -79,8 +80,9 @@
target = AM
loc = null
- message_admins("[key_name_admin(user)]([ADMIN_QUE(user,"?")]) ([ADMIN_FLW(user,"FLW")]) planted [src.name] on [target.name] at ([target.x],[target.y],[target.z] - JMP) with [det_time] second fuse",0,1)
- log_game("[key_name(user)] planted [name] on [target.name] at ([target.x],[target.y],[target.z]) with [det_time] second fuse")
+ if(notify_admins)
+ message_admins("[ADMIN_LOOKUPFLW(user)] planted [src.name] on [target.name] at ([target.x],[target.y],[target.z] - JMP) with [det_time] second fuse", 0, 1)
+ log_game("[key_name(user)] planted [name] on [target.name] at ([target.x],[target.y],[target.z]) with [det_time] second fuse")
AddComponent(/datum/component/persistent_overlay, image_overlay, target)
if(!nadeassembly)
diff --git a/code/modules/mining/equipment/mining_charges.dm b/code/modules/mining/equipment/mining_charges.dm
new file mode 100644
index 00000000000..25c7e0252a3
--- /dev/null
+++ b/code/modules/mining/equipment/mining_charges.dm
@@ -0,0 +1,215 @@
+/obj/item/grenade/plastic/miningcharge
+ name = "industrial mining charge"
+ desc = "Used to make big holes in rocks. Only works on rocks!"
+ icon = 'icons/obj/mining.dmi'
+ icon_state = "mining-charge-2"
+ item_state = "charge_indust"
+ det_time = 5
+ notify_admins = FALSE // no need to make adminlogs on lavaland, while they are "safe" to use
+ /// When TRUE, charges won't detonate on it's own. Used for mining detonator
+ var/timer_off = FALSE
+ var/installed = FALSE
+ var/smoke_amount = 3
+ /// list of sizes for explosion. Third number is used for actual rock explosion size, second number is radius for Weaken() effects, first is used for hacked charges
+ var/boom_sizes = list(2, 3, 5)
+ var/hacked = FALSE
+
+/obj/item/grenade/plastic/miningcharge/Initialize()
+ . = ..()
+ image_overlay = mutable_appearance(icon, "[icon_state]_active", ON_EDGED_TURF_LAYER)
+
+/obj/item/grenade/plastic/miningcharge/examine(mob/user)
+ . = ..()
+ if(hacked)
+ . += "Its wiring is haphazardly changed."
+ if(timer_off)
+ . += "The mining charge is connected to a detonator."
+
+/obj/item/grenade/plastic/miningcharge/attack_self(mob/user)
+ if(nadeassembly)
+ nadeassembly.attack_self(user)
+
+/obj/item/grenade/plastic/miningcharge/afterattack(atom/movable/AM, mob/user, flag)
+ if(!ismineralturf(AM) && !hacked)
+ return
+ if(is_ancient_rock(AM) && !hacked)
+ to_chat(user, "This rock appears to be resistant to all mining tools except pickaxes!")
+ return
+ if(!timer_off) //override original proc for plastic explosions
+ return ..()
+ if(!flag)
+ return
+ if(iscarbon(AM))
+ return
+ to_chat(user, "You start planting [src].")
+ if(!do_after(user, (2.5 SECONDS) * toolspeed, target = AM))
+ return
+ if(!user.unEquip(src))
+ return
+ target = AM
+ forceMove(AM)
+ if(hacked)
+ message_admins("[ADMIN_LOOKUPFLW(user)] planted [name] on [target.name] at [ADMIN_COORDJMP(target)]")
+ log_game("planted [name] on [target.name] at [COORD(target)]", user)
+ installed = TRUE
+ target.overlays += image_overlay
+
+/obj/item/grenade/plastic/miningcharge/attackby(obj/item/I, mob/user, params)
+ if(!istype(I, /obj/item/detonator))
+ return
+ var/obj/item/detonator/detonator = I
+ if((src in detonator.bombs) || timer_off)
+ to_chat(user, "[src] was already synchronized to a existing detonator!")
+ return
+ detonator.bombs += src
+ timer_off = TRUE
+ to_chat(user, "You synchronize [src] to [I].")
+ playsound(src, 'sound/machines/twobeep.ogg', 50)
+ detonator.update_icon()
+
+/obj/item/grenade/plastic/miningcharge/proc/detonate()
+ addtimer(CALLBACK(src, PROC_REF(prime)), 3 SECONDS)
+
+/obj/item/grenade/plastic/miningcharge/prime()
+ if(hacked) //try not to blow your fingers off
+ explode()
+ return
+ var/turf/simulated/mineral/location = get_turf(target)
+ var/datum/effect_system/smoke_spread/S = new
+ S.set_up(smoke_amount, 0, location, null)
+ S.start()
+ for(var/turf/simulated/mineral/rock in circlerangeturfs(location, boom_sizes[3]))
+ var/distance = get_dist_euclidian(location, rock)
+ if(distance <= boom_sizes[3])
+ rock.mineralAmt += 3 // if rock is going to get drilled, add bonus mineral amount
+ rock.gets_drilled()
+ for(var/mob/living/carbon/C in circlerange(location, boom_sizes[3]))
+ var/distance = get_dist_euclidian(location, C)
+ C.flash_eyes()
+ C.Weaken((boom_sizes[2] - distance) * 1 SECONDS) //1 second for how close you are to center if you're in range
+ C.AdjustDeaf((boom_sizes[3] - distance) * 5 SECONDS) //guaranteed deafness
+ var/obj/item/organ/internal/ears/ears = C.get_int_organ(/obj/item/organ/internal/ears)
+ if(istype(ears) && C.check_ear_prot() < HEARING_PROTECTION_MINOR) //headsets should be enough to avoid taking damage
+ ears.receive_damage((boom_sizes[3] - distance) * 2) //something like that i guess. Mega charge makes 12 damage to ears if nearby
+ to_chat(C, "You are knocked down by the power of the mining charge!")
+ qdel(src)
+
+/obj/item/grenade/plastic/miningcharge/proc/explode()
+ var/turf/location
+ if(target)
+ if(!QDELETED(target))
+ if(isturf(target))
+ location = get_turf(target)
+ else
+ location = get_atom_on_turf(target)
+ target.overlays -= image_overlay
+ else
+ location = get_atom_on_turf(src)
+ if(location)
+ explosion(location, boom_sizes[1], boom_sizes[2], boom_sizes[3], cause = src)
+ location.ex_act(2, target)
+ qdel(src)
+
+/obj/item/grenade/plastic/miningcharge/proc/override_safety()
+ hacked = TRUE
+ notify_admins = TRUE
+ boom_sizes[1] = round(boom_sizes[1] / 3) //lesser - 0, normal - 0, mega - 1; c4 - 0
+ boom_sizes[2] = round(boom_sizes[2] / 3) //lesser - 0, normal - 1, mega - 2; c4 - 0
+ boom_sizes[3] = round(boom_sizes[3] / 1.5) //lesser - 2, normal - 3, mega - 5; c4 - 3
+
+/// Overriding to avoid the chargers from exploding because of received damage
+/obj/item/grenade/plastic/miningcharge/deconstruct(disassembled = TRUE)
+ if(!QDELETED(src))
+ qdel(src)
+
+/obj/item/grenade/plastic/miningcharge/lesser
+ name = "mining charge"
+ desc = "A mining charge. This one seems less powerful than industrial. Only works on rocks!"
+ icon_state = "mining-charge-1"
+ item_state = "charge_lesser"
+ smoke_amount = 1
+ boom_sizes = list(1, 2, 3)
+
+/obj/item/grenade/plastic/miningcharge/mega
+ name = "experimental mining charge"
+ desc = "A mining charge. This one seems much more powerful than normal!"
+ icon_state = "mining-charge-3"
+ item_state = "charge_mega"
+ smoke_amount = 5
+ boom_sizes = list(4, 6, 8)
+
+/obj/item/storage/backpack/duffel/miningcharges/populate_contents()
+ for(var/i in 1 to 5)
+ new /obj/item/grenade/plastic/miningcharge/lesser(src)
+ for(var/i in 1 to 3)
+ new /obj/item/grenade/plastic/miningcharge(src)
+ new /obj/item/detonator(src)
+
+//MINING CHARGE HACKER
+
+/obj/item/t_scanner/adv_mining_scanner/syndicate
+ var/charges = 6
+
+/obj/item/t_scanner/adv_mining_scanner/syndicate/examine(mob/user)
+ . = ..()
+ . += "This scanner has an extra port for overriding mining charge safeties."
+
+/obj/item/t_scanner/adv_mining_scanner/syndicate/afterattack(atom/target, mob/user, proximity_flag, click_parameters)
+ if(!istype(target, /obj/item/grenade/plastic/miningcharge))
+ return
+ var/obj/item/grenade/plastic/miningcharge/charge = target
+ if(charge.hacked)
+ to_chat(user, "[src] is already overridden!")
+ return
+ if(charges <= 0)
+ to_chat(user, "Its overriding function is depleted.")
+ return
+ charge.override_safety()
+ visible_message("Sparks fly out of [src]!")
+ playsound(src, "sparks", 50, TRUE)
+ charges--
+ if(charges <= 0)
+ to_chat(user, "[src]'s internal battery for overriding mining charges has run dry!")
+
+// MINING CHARGES DETONATOR
+
+/obj/item/detonator
+ name = "mining charge detonator"
+ desc = "A specialized mining device designed for controlled demolition operations using mining explosives."
+ w_class = WEIGHT_CLASS_SMALL
+ icon = 'icons/obj/mining.dmi'
+ icon_state = "Detonator-0"
+
+ /// list of all bombs connected to a detonator for a moment
+ var/list/bombs = list()
+
+/obj/item/detonator/examine(mob/user)
+ . = ..()
+ if(length(bombs))
+ . += "List of synched bombs:"
+ for(var/obj/item/grenade/plastic/miningcharge/charge in bombs)
+ . += "[bicon(charge)] [charge]. Current status: [charge.installed ? "ready to detonate" : "ready to deploy"]."
+
+/obj/item/detonator/update_icon()
+ . = ..()
+ if(length(bombs))
+ icon_state = "Detonator-1"
+ else
+ icon_state = initial(icon_state)
+
+/obj/item/detonator/attack_self(mob/user)
+ playsound(src, 'sound/items/detonator.ogg', 40)
+ if(length(bombs))
+ to_chat(user, "Activating explosives...")
+ for(var/obj/item/grenade/plastic/miningcharge/charge in bombs)
+ if(QDELETED(charge))
+ bombs -= charge
+ update_icon() //if the last bomb was qdeleted, detonator icon should change after activating
+ continue
+ if(charge.installed)
+ bombs -= charge
+ charge.detonate()
+ update_icon()
+ else
+ to_chat(user, "There are no charges linked to a detonator!")
+ return ..()
diff --git a/code/modules/mining/machine_vending.dm b/code/modules/mining/machine_vending.dm
index 80e0b252ade..ba69109c473 100644
--- a/code/modules/mining/machine_vending.dm
+++ b/code/modules/mining/machine_vending.dm
@@ -42,6 +42,7 @@
EQUIPMENT("Mining MODsuit", /obj/item/mod/control/pre_equipped/mining/vendor, 3500),
EQUIPMENT("Asteroid MODsuit Skin", /obj/item/mod/skin_applier/asteroid, 1000),
EQUIPMENT("Tracking Bio-chip Kit", /obj/item/storage/box/minertracker, 600),
+ EQUIPMENT("Mining Charge Detonator", /obj/item/detonator, 150)
)
prize_list["Consumables"] = list(
EQUIPMENT("10 Marker Beacons", /obj/item/stack/marker_beacon/ten, 100),
@@ -50,6 +51,8 @@
EQUIPMENT("Jaunter", /obj/item/wormhole_jaunter, 750),
EQUIPMENT("Chasm Jaunter Recovery Grenade", /obj/item/grenade/jaunter_grenade, 1500),
EQUIPMENT("Lazarus Injector", /obj/item/lazarus_injector, 1000),
+ EQUIPMENT("Mining Charge", /obj/item/grenade/plastic/miningcharge/lesser, 150),
+ EQUIPMENT("Industrial Mining Charge", /obj/item/grenade/plastic/miningcharge, 500),
EQUIPMENT("Point Transfer Card", /obj/item/card/mining_point_card, 500),
EQUIPMENT("Shelter Capsule", /obj/item/survivalcapsule, 400),
EQUIPMENT("Stabilizing Serum", /obj/item/hivelordstabilizer, 400),
@@ -248,7 +251,7 @@
* * redeemer - The person holding it
*/
/obj/machinery/mineral/equipment_vendor/proc/redeem_voucher(obj/item/mining_voucher/voucher, mob/redeemer)
- var/items = list("Survival Capsule and Explorer's Webbing", "Resonator Kit", "Minebot Kit", "Extraction and Rescue Kit", "Crusher Kit", "Plasma Cutter", "Jaunter Kit", "Mining Conscription Kit")
+ var/items = list("Survival Capsule and Explorer's Webbing", "Resonator Kit", "Minebot Kit", "Extraction and Rescue Kit", "Crusher Kit", "Plasma Cutter", "Mining Explosives Kit", "Jaunter Kit", "Mining Conscription Kit")
var/selection = tgui_input_list(redeemer, "Pick your equipment", "Mining Voucher Redemption", items)
if(!selection || !Adjacent(redeemer) || QDELETED(voucher) || voucher.loc != redeemer)
@@ -274,6 +277,8 @@
new /obj/item/kinetic_crusher(drop_location)
if("Plasma Cutter")
new /obj/item/gun/energy/plasmacutter(drop_location)
+ if("Mining Explosives Kit")
+ new /obj/item/storage/backpack/duffel/miningcharges(drop_location)
if("Jaunter Kit")
new /obj/item/wormhole_jaunter(drop_location)
new /obj/item/stack/medical/bruise_pack/advanced(drop_location)
diff --git a/code/modules/research/designs/mining_designs.dm b/code/modules/research/designs/mining_designs.dm
index 3b4e5a1c1cb..831092befaa 100644
--- a/code/modules/research/designs/mining_designs.dm
+++ b/code/modules/research/designs/mining_designs.dm
@@ -111,6 +111,16 @@
build_path = /obj/item/borg/upgrade/modkit/aoe/turfs
category = list("Mining", "Cyborg Upgrade Modules")
+/datum/design/mining_charges
+ name = "Experimental Mining Charge"
+ desc = "An experimental mining charge used to make big holes in rocks."
+ id = "megacharge"
+ req_tech = list("materials" = 5, "engineering" = 5, "plasmatech" = 6)
+ build_type = PROTOLATHE
+ materials = list(MAT_METAL = 4000, MAT_PLASMA = 6000, MAT_URANIUM = 1000)
+ build_path = /obj/item/grenade/plastic/miningcharge/mega
+ category = list("Mining")
+
/datum/design/lavarods
name = "Lava-Resistant Iron Rods"
desc = "Treated, specialized iron rods. When exposed to the vacuum of space their coating breaks off, but they can hold up against the extreme heat of molten liquids."
diff --git a/icons/mob/inhands/items_lefthand.dmi b/icons/mob/inhands/items_lefthand.dmi
index 33942e4a03c..556989be5d2 100644
Binary files a/icons/mob/inhands/items_lefthand.dmi and b/icons/mob/inhands/items_lefthand.dmi differ
diff --git a/icons/mob/inhands/items_righthand.dmi b/icons/mob/inhands/items_righthand.dmi
index 01cee2e989d..5350e346160 100644
Binary files a/icons/mob/inhands/items_righthand.dmi and b/icons/mob/inhands/items_righthand.dmi differ
diff --git a/icons/obj/mining.dmi b/icons/obj/mining.dmi
index 4a74f194c51..4ca486bcfb7 100644
Binary files a/icons/obj/mining.dmi and b/icons/obj/mining.dmi differ
diff --git a/paradise.dme b/paradise.dme
index 522424f7148..9c97b387faa 100644
--- a/paradise.dme
+++ b/paradise.dme
@@ -2053,6 +2053,7 @@
#include "code\modules\mining\equipment\lazarus_injector.dm"
#include "code\modules\mining\equipment\marker_beacons.dm"
#include "code\modules\mining\equipment\mineral_scanner.dm"
+#include "code\modules\mining\equipment\mining_charges.dm"
#include "code\modules\mining\equipment\mining_tools.dm"
#include "code\modules\mining\equipment\regenerative_core.dm"
#include "code\modules\mining\equipment\resonator.dm"
diff --git a/sound/items/detonator.ogg b/sound/items/detonator.ogg
new file mode 100644
index 00000000000..b607bdc3607
Binary files /dev/null and b/sound/items/detonator.ogg differ