diff --git a/code/__defines/dcs/signals.dm b/code/__defines/dcs/signals.dm
index 88ff63af23..8bb95f0d89 100644
--- a/code/__defines/dcs/signals.dm
+++ b/code/__defines/dcs/signals.dm
@@ -468,8 +468,6 @@
#define COMSIG_TOOL_START_USE "tool_start_use"
///from [/obj/item/proc/disableEmbedding]:
#define COMSIG_ITEM_DISABLE_EMBED "item_disable_embed"
-///from [/obj/effect/mine/proc/triggermine]:
-#define COMSIG_MINE_TRIGGERED "minegoboom"
// /obj/item signals for economy
///called when an item is sold by the exports subsystem
diff --git a/code/datums/wires/mines.dm b/code/datums/wires/mines.dm
deleted file mode 100644
index 5e757ad16c..0000000000
--- a/code/datums/wires/mines.dm
+++ /dev/null
@@ -1,84 +0,0 @@
-/datum/wires/mines
- wire_count = 7
- randomize = TRUE
- holder_type = /obj/effect/mine
- proper_name = "Explosive Wires"
-
-/datum/wires/mines/New(atom/_holder)
- wires = list(WIRE_EXPLODE, WIRE_EXPLODE_DELAY, WIRE_DISARM, WIRE_BADDISARM)
- return ..()
-#define WIRE_TRAP 64
-
-/datum/wires/mines/get_status()
- . = ..()
- . += "\[Warning: detonation may occur even with proper equipment.]"
-
-/datum/wires/mines/proc/explode()
- return
-
-/datum/wires/mines/on_cut(wire, mend)
- var/obj/effect/mine/C = holder
-
- switch(wire)
- if(WIRE_EXPLODE)
- C.visible_message("[bicon(C)] *BEEE-*", "[bicon(C)] *BEEE-*")
- C.explode()
-
- if(WIRE_EXPLODE_DELAY)
- C.visible_message("[bicon(C)] *BEEE-*", "[bicon(C)] *BEEE-*")
- C.explode()
-
- if(WIRE_DISARM)
- C.visible_message("[bicon(C)] *click!*", "[bicon(C)] *click!*")
- var/obj/effect/mine/MI = new C.mineitemtype(get_turf(C))
-
- if(C.trap)
- MI.trap = C.trap
- C.trap = null
- MI.trap.forceMove(MI)
-
- spawn(0)
- qdel(C)
-
- if(WIRE_BADDISARM)
- C.visible_message("[bicon(C)] *BEEPBEEPBEEP*", "[bicon(C)] *BEEPBEEPBEEP*")
- spawn(20)
- C.explode()
-
- if(WIRE_TRAP)
- C.visible_message("[bicon(C)] *click!*", "[bicon(C)] *click!*")
-
- if(mend)
- C.visible_message("[bicon(C)] - The mine recalibrates[C.camo_net ? ", revealing \the [C.trap] inside." : "."]")
-
- C.alpha = 255
-
- ..()
-
-/datum/wires/mines/on_pulse(wire)
- var/obj/effect/mine/C = holder
- if(is_cut(wire))
- return
- switch(wire)
- if(WIRE_EXPLODE)
- C.visible_message("[bicon(C)] *beep*", "[bicon(C)] *beep*")
-
- if(WIRE_EXPLODE_DELAY)
- C.visible_message("[bicon(C)] *BEEPBEEPBEEP*", "[bicon(C)] *BEEPBEEPBEEP*")
- spawn(20)
- C.explode()
-
- if(WIRE_DISARM)
- C.visible_message("[bicon(C)] *ping*", "[bicon(C)] *ping*")
-
- if(WIRE_BADDISARM)
- C.visible_message("[bicon(C)] *ping*", "[bicon(C)] *ping*")
-
- if(WIRE_TRAP)
- C.visible_message("[bicon(C)] *ping*", "[bicon(C)] *ping*")
-
- ..()
-
-/datum/wires/mines/interactable(mob/user)
- var/obj/effect/mine/M = holder
- return M.panel_open
diff --git a/code/game/objects/effects/mines.dm b/code/game/objects/effects/mines.dm
deleted file mode 100644
index 52ede9d2e4..0000000000
--- a/code/game/objects/effects/mines.dm
+++ /dev/null
@@ -1,403 +0,0 @@
-/obj/effect/mine
- name = "land mine" //The name and description are deliberately NOT modified, so you can't game the mines you find.
- desc = "A small explosive land mine."
- density = 0
- anchored = 1
- icon = 'icons/obj/weapons.dmi'
- icon_state = "uglymine"
- var/triggered = 0
- var/smoke_strength = 3
- var/obj/item/mine/mineitemtype = /obj/item/mine
- var/panel_open = 0
- var/datum/wires/mines/wires = null
- var/camo_net = FALSE // Will the mine 'cloak' on deployment?
-
- // The trap item will be triggered in some manner when detonating. Default only checks for grenades.
- var/obj/item/trap = null
-
-/obj/effect/mine/Initialize()
- icon_state = "uglyminearmed"
- wires = new(src)
- . = ..()
- if(ispath(trap))
- trap = new trap(src)
- register_dangerous_to_step()
- if(camo_net)
- alpha = 50
-
-/obj/effect/mine/Destroy()
- unregister_dangerous_to_step()
- if(trap)
- QDEL_NULL(trap)
- QDEL_NULL(wires)
- return ..()
-
-/obj/effect/mine/Moved(atom/oldloc)
- . = ..()
- if(.)
- var/turf/old_turf = get_turf(oldloc)
- var/turf/new_turf = get_turf(src)
- if(old_turf != new_turf)
- old_turf.unregister_dangerous_object(src)
- new_turf.register_dangerous_object(src)
-
-/obj/effect/mine/proc/explode(var/mob/living/M)
- var/datum/effect_system/spark_spread/s = new /datum/effect_system/spark_spread()
- triggered = 1
- s.set_up(3, 1, src)
- s.start()
-
- if(trap)
- trigger_trap(M)
- visible_message("\The [src.name] flashes as it is triggered!")
-
- else
- explosion(loc, 0, 2, 3, 4) //land mines are dangerous, folks.
- visible_message("\The [src.name] detonates!")
-
- qdel(s)
- qdel(src)
-
-/obj/effect/mine/proc/trigger_trap(var/mob/living/victim)
- if(istype(trap, /obj/item/grenade))
- var/obj/item/grenade/G = trap
- trap = null
- G.forceMove(get_turf(src))
- if(victim.ckey)
- msg_admin_attack("[key_name_admin(victim)] stepped on \a [src.name], triggering [trap]")
- G.activate()
-
- if(istype(trap, /obj/item/transfer_valve))
- var/obj/item/transfer_valve/TV = trap
- trap = null
- TV.forceMove(get_turf(src))
- TV.toggle_valve()
-
-/obj/effect/mine/bullet_act()
- if(prob(50))
- explode()
-
-/obj/effect/mine/ex_act(severity)
- if(severity <= 2 || prob(50))
- explode()
- ..()
-
-/obj/effect/mine/Crossed(atom/movable/AM as mob|obj)
- if(AM.is_incorporeal())
- return
- Bumped(AM)
-
-/obj/effect/mine/Bumped(mob/M as mob|obj)
-
- if(triggered)
- return
-
- if(istype(M, /obj/mecha))
- explode(M)
-
- if(istype(M, /mob/living/))
- if(!M.hovering)
- explode(M)
-
-/obj/effect/mine/attackby(obj/item/W as obj, mob/living/user as mob)
- if(W.is_screwdriver())
- panel_open = !panel_open
- user.visible_message("[user] very carefully screws the mine's panel [panel_open ? "open" : "closed"].",
- "You very carefully screw the mine's panel [panel_open ? "open" : "closed"].")
- playsound(src, W.usesound, 50, 1)
-
- // Panel open, stay uncloaked, or uncloak if already cloaked. If you don't cloak on place, ignore it and just be normal alpha.
- alpha = camo_net ? (panel_open ? 255 : 50) : 255
-
- else if((W.is_wirecutter() || istype(W, /obj/item/multitool)) && panel_open)
- interact(user)
- else
- ..()
-
-/obj/effect/mine/interact(mob/living/user as mob)
- if(!panel_open || istype(user, /mob/living/silicon/ai))
- return
- user.set_machine(src)
- wires.Interact(user)
-
-/obj/effect/mine/camo
- camo_net = TRUE
-
-/obj/effect/mine/dnascramble
- mineitemtype = /obj/item/mine/dnascramble
-
-/obj/effect/mine/dnascramble/explode(var/mob/living/M)
- var/datum/effect_system/spark_spread/s = new /datum/effect_system/spark_spread()
- triggered = 1
- s.set_up(3, 1, src)
- s.start()
- if(istype(M))
- M.radiation += 50
- randmutb(M)
- domutcheck(M,null)
- visible_message("\The [src.name] flashes violently before disintegrating!")
- spawn(0)
- qdel(s)
- qdel(src)
-
-/obj/effect/mine/stun
- mineitemtype = /obj/item/mine/stun
-
-/obj/effect/mine/stun/explode(var/mob/living/M)
- triggered = 1
- var/datum/effect_system/spark_spread/s = new /datum/effect_system/spark_spread()
- s.set_up(3, 1, src)
- s.start()
- if(istype(M))
- M.Stun(30)
- visible_message("\The [src.name] flashes violently before disintegrating!")
- spawn(0)
- qdel(s)
- qdel(src)
-
-/obj/effect/mine/n2o
- mineitemtype = /obj/item/mine/n2o
-
-/obj/effect/mine/n2o/explode(var/mob/living/M)
- triggered = 1
- for (var/turf/simulated/floor/target in range(1,src))
- if(!target.blocks_air)
- target.assume_gas("nitrous_oxide", 30)
- visible_message("\The [src.name] detonates!")
- spawn(0)
- qdel(src)
-
-/obj/effect/mine/phoron
- mineitemtype = /obj/item/mine/phoron
-
-/obj/effect/mine/phoron/explode(var/mob/living/M)
- triggered = 1
- for (var/turf/simulated/floor/target in range(1,src))
- if(!target.blocks_air)
- target.assume_gas("phoron", 30)
- target.hotspot_expose(1000, CELL_VOLUME)
- visible_message("\The [src.name] detonates!")
- spawn(0)
- qdel(src)
-
-/obj/effect/mine/kick
- mineitemtype = /obj/item/mine/kick
-
-/obj/effect/mine/kick/explode(var/mob/living/M)
- var/datum/effect_system/spark_spread/s = new /datum/effect_system/spark_spread()
- triggered = 1
- s.set_up(3, 1, src)
- s.start()
- if(istype(M, /obj/mecha))
- var/obj/mecha/E = M
- M = E.occupant
- if(istype(M))
- qdel(M.client)
- spawn(0)
- qdel(s)
- qdel(src)
-
-/obj/effect/mine/frag
- mineitemtype = /obj/item/mine/frag
- var/fragment_types = list(/obj/item/projectile/bullet/pellet/fragment)
- var/num_fragments = 20 //total number of fragments produced by the grenade
- //The radius of the circle used to launch projectiles. Lower values mean less projectiles are used but if set too low gaps may appear in the spread pattern
- var/spread_range = 7
-
-/obj/effect/mine/frag/explode(var/mob/living/M)
- var/datum/effect_system/spark_spread/s = new /datum/effect_system/spark_spread()
- triggered = 1
- s.set_up(3, 1, src)
- s.start()
- var/turf/O = get_turf(src)
- if(!O)
- return
- src.fragmentate(O, 20, 7, list(/obj/item/projectile/bullet/pellet/fragment)) //only 20 weak fragments because you're stepping directly on it
- visible_message("\The [src.name] detonates!")
- spawn(0)
- qdel(s)
- qdel(src)
-
-/obj/effect/mine/training //Name and Desc commented out so it's possible to trick people with the training mines
-// name = "training mine"
-// desc = "A mine with its payload removed, for EOD training and demonstrations."
- mineitemtype = /obj/item/mine/training
-
-/obj/effect/mine/training/explode(var/mob/living/M)
- triggered = 1
- visible_message("\The [src.name]'s light flashes rapidly as it 'explodes'.")
- new src.mineitemtype(get_turf(src))
- spawn(0)
- qdel(src)
-
-/obj/effect/mine/emp
- mineitemtype = /obj/item/mine/emp
-
-/obj/effect/mine/emp/explode(var/mob/living/M)
- var/datum/effect_system/spark_spread/s = new /datum/effect_system/spark_spread()
- s.set_up(3, 1, src)
- s.start()
- visible_message("\The [src.name] flashes violently before disintegrating!")
- empulse(loc, 2, 4, 7, 10, 1) // As strong as an EMP grenade
- spawn(0)
- qdel(src)
-
-/obj/effect/mine/emp/camo
- camo_net = TRUE
-
-/obj/effect/mine/incendiary
- mineitemtype = /obj/item/mine/incendiary
-
-/obj/effect/mine/incendiary/explode(var/mob/living/M)
- triggered = 1
- var/datum/effect_system/spark_spread/s = new /datum/effect_system/spark_spread()
- s.set_up(3, 1, src)
- s.start()
- if(istype(M))
- M.adjust_fire_stacks(5)
- M.fire_act()
- visible_message("\The [src.name] bursts into flames!")
- spawn(0)
- qdel(src)
-
-/obj/effect/mine/gadget
- mineitemtype = /obj/item/mine/gadget
-
-/obj/effect/mine/gadget/explode(var/mob/living/M)
- var/datum/effect_system/spark_spread/s = new /datum/effect_system/spark_spread()
- triggered = 1
- s.set_up(3, 1, src)
- s.start()
-
- if(trap)
- trigger_trap(M)
- visible_message("\The [src.name] flashes as it is triggered!")
-
- else
- explosion(loc, 0, 0, 2, 2)
- visible_message("\The [src.name] detonates!")
-
- qdel(s)
- qdel(src)
-
-/////////////////////////////////////////////
-// The held item version of the above mines
-/////////////////////////////////////////////
-/obj/item/mine
- name = "mine"
- desc = "A small explosive mine with 'HE' and a grenade symbol on the side."
- icon = 'icons/obj/weapons.dmi'
- icon_state = "uglymine"
- var/countdown = 10
- var/minetype = /obj/effect/mine //This MUST be an /obj/effect/mine type, or it'll runtime.
-
- var/obj/item/trap = null
-
- var/list/allowed_gadgets = null
-
-/obj/item/mine/attack_self(mob/user as mob) // You do not want to move or throw a land mine while priming it... Explosives + Sudden Movement = Bad Times
- add_fingerprint(user)
- msg_admin_attack("[key_name_admin(user)] primed \a [src]")
- user.visible_message("[user] starts priming \the [src.name].", "You start priming \the [src.name]. Hold still!")
- if(do_after(user, 10 SECONDS))
- playsound(src, 'sound/weapons/armbomb.ogg', 75, 1, -3)
- prime(user)
- else
- visible_message("[user] triggers \the [src.name]!", "You accidentally trigger \the [src.name]!")
- prime(user, TRUE)
- return
-
-/obj/item/mine/attackby(obj/item/W as obj, mob/living/user as mob)
- if(W.is_screwdriver() && trap)
- to_chat(user, "You begin removing \the [trap].")
- if(do_after(user, 10 SECONDS))
- to_chat(user, "You finish disconnecting the mine's trigger.")
- trap.forceMove(get_turf(src))
- trap = null
- return
-
- if(LAZYLEN(allowed_gadgets) && !trap)
- var/allowed = FALSE
-
- for(var/path in allowed_gadgets)
- if(istype(W, path))
- allowed = TRUE
- break
-
- if(allowed)
- user.drop_from_inventory(W)
- W.forceMove(src)
- trap = W
-
- ..()
-
-/obj/item/mine/proc/prime(mob/user as mob, var/explode_now = FALSE)
- visible_message("\The [src.name] beeps as the priming sequence completes.")
- var/obj/effect/mine/R = new minetype(get_turf(src))
- src.transfer_fingerprints_to(R)
- R.add_fingerprint(user)
- if(trap)
- R.trap = trap
- trap = null
- R.trap.forceMove(R)
- if(explode_now)
- R.explode(user)
- spawn(0)
- qdel(src)
-
-/obj/item/mine/dnascramble
- name = "radiation mine"
- desc = "A small explosive mine with a radiation symbol on the side."
- minetype = /obj/effect/mine/dnascramble
-
-/obj/item/mine/phoron
- name = "incendiary mine"
- desc = "A small explosive mine with a fire symbol on the side."
- minetype = /obj/effect/mine/phoron
-
-/obj/item/mine/kick
- name = "kick mine"
- desc = "Concentrated war crimes. Handle with care."
- minetype = /obj/effect/mine/kick
-
-/obj/item/mine/n2o
- name = "nitrous oxide mine"
- desc = "A small explosive mine with three Z's on the side."
- minetype = /obj/effect/mine/n2o
-
-/obj/item/mine/stun
- name = "stun mine"
- desc = "A small explosive mine with a lightning bolt symbol on the side."
- minetype = /obj/effect/mine/stun
-
-/obj/item/mine/frag
- name = "fragmentation mine"
- desc = "A small explosive mine with 'FRAG' and a grenade symbol on the side."
- minetype = /obj/effect/mine/frag
-
-/obj/item/mine/training
- name = "training mine"
- desc = "A mine with its payload removed, for EOD training and demonstrations."
- minetype = /obj/effect/mine/training
-
-/obj/item/mine/emp
- name = "emp mine"
- desc = "A small explosive mine with a lightning bolt symbol on the side."
- minetype = /obj/effect/mine/emp
-
-/obj/item/mine/incendiary
- name = "incendiary mine"
- desc = "A small explosive mine with a fire symbol on the side."
- minetype = /obj/effect/mine/incendiary
-
-/obj/item/mine/gadget
- name = "gadget mine"
- desc = "A small pressure-triggered device. If no component is added, the internal release bolts will detonate in unison when triggered."
-
- allowed_gadgets = list(/obj/item/grenade, /obj/item/transfer_valve)
-
-// This tells AI mobs to not be dumb and step on mines willingly.
-/obj/item/mine/is_safe_to_step(mob/living/L)
- if(!L.hovering)
- return FALSE
- return ..()
diff --git a/code/game/objects/items.dm b/code/game/objects/items.dm
index 5cae51bbb0..f040241e10 100644
--- a/code/game/objects/items.dm
+++ b/code/game/objects/items.dm
@@ -625,8 +625,9 @@ var/global/list/slot_flags_enumeration = list(
generate_blood_overlay()
//Make the blood_overlay have the proper color then apply it.
- blood_overlay.color = blood_color
- add_overlay(blood_overlay)
+ if(blood_overlay)
+ blood_overlay.color = blood_color
+ add_overlay(blood_overlay)
//if this blood isn't already in the list, add it
if(istype(M))
diff --git a/code/game/objects/items/mines/_mine.dm b/code/game/objects/items/mines/_mine.dm
new file mode 100644
index 0000000000..51020e975d
--- /dev/null
+++ b/code/game/objects/items/mines/_mine.dm
@@ -0,0 +1,186 @@
+/obj/item/mine
+ name = "explosive mine"
+ desc = "A small explosive land mine."
+ density = FALSE
+ anchored = FALSE
+ icon = 'icons/obj/mine.dmi'
+ icon_state = "mine"
+
+ var/actual_name
+ var/actual_desc
+ var/actual_icon_state
+ var/hidden_alpha = 255
+
+ var/panel_open = FALSE
+ var/armed = FALSE
+ var/triggering = FALSE
+ var/datum/mine_payload/payload = /datum/mine_payload/explosive
+
+ var/static/list/concealable_turfs = list(
+ /turf/simulated/floor/concrete,
+ /turf/simulated/floor/outdoors
+ )
+
+/obj/item/mine/Initialize()
+ . = ..()
+ if(ispath(payload))
+ payload = new payload
+ register_dangerous_to_step()
+
+ // We store and hide our appearance if we're armed, to avoid people gaming mines via desc.
+ actual_name = name
+ actual_desc = desc
+ actual_icon_state = icon_state
+ update_icon()
+
+/obj/item/mine/Destroy()
+ if(istype(payload))
+ QDEL_NULL(payload)
+ unregister_dangerous_to_step()
+ return ..()
+
+/obj/item/mine/update_icon()
+ . = ..()
+ alpha = initial(alpha)
+ cut_overlays()
+ if(panel_open)
+ add_overlay("[icon_state]_open")
+ else if(armed)
+ add_overlay("[icon_state]_armed")
+ alpha = hidden_alpha
+ else
+ add_overlay("[icon_state]_safe")
+
+/obj/item/mine/attack_self(mob/user) // You do not want to move or throw a land mine while priming it... Explosives + Sudden Movement = Bad Times
+ add_fingerprint(user)
+ msg_admin_attack("[key_name_admin(user)] armed \the [src]")
+ user.visible_message(
+ SPAN_DANGER("\The [user] starts arming \the [src]."),
+ SPAN_DANGER("You start arming \the [src]. Hold still!")
+ )
+ if(do_after(user, 10 SECONDS))
+ playsound(src, 'sound/weapons/armbomb.ogg', 75, 1, -3)
+ prime(user)
+ else
+ visible_message(
+ SPAN_DANGER("\The [user] accidentally triggers \the [src]!"),
+ SPAN_DANGER("You accidentally trigger \the [src]!")
+ )
+ prime(user)
+ trigger_payload(user)
+ return TRUE
+
+// debug proc, replace with proper disarm minigame
+/obj/item/mine/proc/disarm()
+ armed = FALSE
+ triggering = FALSE
+ anchored = FALSE
+ name = actual_name
+ desc = actual_desc
+ icon_state = actual_icon_state
+ hidden_alpha = 255
+ update_icon()
+
+/obj/item/mine/attack_hand(mob/living/user)
+ if(armed)
+ trigger_payload()
+ return TRUE
+ return ..()
+
+/obj/item/mine/attackby(obj/item/W, mob/living/user)
+
+ if(W.is_screwdriver())
+ visible_message(SPAN_NOTICE("\The [user] begins carefully adjusting \the [src]'s casing."))
+ if(do_after(user, 5 SECONDS, src))
+ panel_open = !panel_open
+ visible_message(SPAN_NOTICE("\The [user] carefully [panel_open ? "opens" : "closes"] the casing of \the [src]."))
+ update_icon()
+ else if(armed)
+ to_chat(user, SPAN_DANGER("You set off \the [src]!"))
+ trigger_payload(user)
+ return TRUE
+
+ if(armed)
+ if(panel_open && W.is_wirecutter())
+ visible_message(SPAN_NOTICE("\The [user] begins painstakingly disarming \the [src]..."))
+ if(do_after(user, 10 SECONDS, src))
+ visible_message(SPAN_NOTICE("\The [user] disarms \the [src]!"))
+ disarm()
+ return TRUE
+ if(armed) // checking again in case the do_after() stacks
+ to_chat(user, SPAN_DANGER("You set off \the [src]!"))
+ trigger_payload(user)
+ return TRUE
+
+ return ..()
+
+/obj/item/mine/proc/prime(mob/user)
+
+ if(armed)
+ return
+
+ if(user)
+ visible_message(SPAN_NOTICE("\The [src] beeps as the priming sequence completes."))
+ user.drop_from_inventory(src, get_turf(user))
+ add_fingerprint(user)
+
+ anchored = TRUE
+ armed = TRUE
+
+ if(isturf(loc) && prob(65))
+ for(var/turftype in concealable_turfs)
+ if(istype(loc, turftype))
+ hidden_alpha = pick(50, 90, 120)
+ break
+
+ name = "mine"
+ desc = "A small land mine."
+ icon_state = "mine"
+ update_icon()
+
+/obj/item/mine/Moved(atom/oldloc)
+ . = ..()
+ if(.)
+ var/turf/old_turf = get_turf(oldloc)
+ var/turf/new_turf = get_turf(src)
+ if(old_turf != new_turf)
+ old_turf.unregister_dangerous_object(src)
+ new_turf.register_dangerous_object(src)
+
+/obj/item/mine/proc/trigger_payload(var/mob/living/M)
+ if(!triggering && payload)
+ triggering = TRUE
+ if(ismob(loc))
+ var/mob/holder = loc
+ holder.drop_from_inventory(src)
+ visible_message("\The [src] goes off!")
+ payload.trigger_payload(src, M)
+ disarm() // the mine can be reused if the payload doesn't destroy it.
+ return TRUE
+ return FALSE
+
+/obj/item/mine/bullet_act()
+ if(prob(50))
+ trigger_payload()
+ if(!QDELETED(src))
+ ..()
+
+/obj/item/mine/ex_act(severity)
+ if(severity <= 2 || prob(50))
+ trigger_payload()
+ if(!QDELETED(src))
+ ..()
+
+/obj/item/mine/Crossed(atom/movable/AM)
+ . = ..()
+ if(istype(AM) && !AM.is_incorporeal())
+ Bumped(AM)
+
+/obj/item/mine/Bumped(atom/movable/AM)
+ . = ..()
+ if(!QDELETED(src) && !is_safe_to_step(AM))
+ trigger_payload(AM)
+
+// This tells AI mobs to not be dumb and step on mines willingly.
+/obj/item/mine/is_safe_to_step(mob/living/L)
+ return !istype(L, /obj/mecha) && (!isliving(L) || L.hovering)
diff --git a/code/game/objects/items/mines/_mine_payload.dm b/code/game/objects/items/mines/_mine_payload.dm
new file mode 100644
index 0000000000..0399a53a5b
--- /dev/null
+++ b/code/game/objects/items/mines/_mine_payload.dm
@@ -0,0 +1,22 @@
+/datum/mine_payload
+ var/do_sparks = TRUE
+ var/destroy_self_on_trigger = TRUE
+
+/datum/mine_payload/proc/trigger_payload(var/obj/item/mine/owner, var/atom/trigger)
+ if(do_sparks)
+ var/datum/effect_system/spark_spread/s = new
+ s.set_up(3, 1, owner)
+ s.start()
+ if(destroy_self_on_trigger)
+ if(!QDELETED(owner))
+ QDEL_IN(owner, 1)
+ else
+ owner.disarm() // some mines can be reused
+
+/datum/mine_payload/proc/remove_from_mine()
+ return
+
+/datum/mine_payload/explosive/trigger_payload(var/obj/item/mine/owner, var/atom/trigger)
+ ..()
+ owner.visible_message("\The [owner] detonates!")
+ explosion(owner.loc, 0, 2, 3, 4) //land mines are dangerous, folks.
diff --git a/code/game/objects/items/mines/mine_assembly.dm b/code/game/objects/items/mines/mine_assembly.dm
new file mode 100644
index 0000000000..78849b76fa
--- /dev/null
+++ b/code/game/objects/items/mines/mine_assembly.dm
@@ -0,0 +1,62 @@
+/obj/item/mine/assembly
+ name = "mine assembly"
+ desc = "A small pressure-triggered device. Accepts grenades and tank transfer valves."
+ var/static/list/accepts_items = list(
+ /obj/item/transfer_valve = /datum/mine_payload/assembly/tank_transfer_valve,
+ /obj/item/grenade = /datum/mine_payload/assembly/grenade
+ )
+
+/obj/item/mine/assembly/attackby(obj/item/W, mob/living/user)
+ if(!armed && !triggering)
+ var/datum/mine_payload/assembly/attached_payload = payload
+ if(attached_payload.attached)
+ if(W.is_screwdriver())
+ to_chat(user, "You disconnect \the [src]'s [attached_payload.attached.name] and remove it.")
+ attached_payload.attached.forceMove(get_turf(user))
+ payload.remove_from_mine()
+ QDEL_NULL(payload)
+ else
+ for(var/loadtype in accepts_items)
+ if(istype(W, loadtype))
+ user.drop_from_inventory(W)
+ W.forceMove(src)
+ var/payload_type = accepts_items[loadtype]
+ attached_payload = new payload_type
+ attached_payload.attached = W
+ payload = attached_payload
+ return TRUE
+ return ..()
+
+/datum/mine_payload/assembly
+ var/obj/item/attached
+
+/datum/mine_payload/assembly/New(var/obj/item/_attaching)
+ ..()
+ attached = _attaching
+
+/datum/mine_payload/assembly/Destroy()
+ QDEL_NULL(attached)
+ . = ..()
+
+/datum/mine_payload/assembly/remove_from_mine()
+ attached = null
+
+/datum/mine_payload/assembly/tank_transfer_valve/trigger_payload(var/obj/item/mine/owner, var/atom/trigger)
+ ..()
+ if(istype(attached, /obj/item/transfer_valve))
+ var/obj/item/transfer_valve/ttv = attached
+ ttv.forceMove(get_turf(owner))
+ ttv.toggle_valve()
+ remove_from_mine()
+
+/datum/mine_payload/assembly/grenade/trigger_payload(var/obj/item/mine/owner, var/atom/trigger)
+ ..()
+ if(istype(attached, /obj/item/grenade))
+ var/obj/item/grenade/grenade = attached
+ grenade.forceMove(get_turf(owner))
+ if(ismob(trigger))
+ var/mob/victim = trigger
+ if(victim.ckey)
+ msg_admin_attack("[key_name_admin(victim)] stepped on \a [owner], triggering [grenade]")
+ grenade.activate()
+ remove_from_mine()
diff --git a/code/game/objects/items/mines/mine_dnascamble.dm b/code/game/objects/items/mines/mine_dnascamble.dm
new file mode 100644
index 0000000000..c37bbaf45e
--- /dev/null
+++ b/code/game/objects/items/mines/mine_dnascamble.dm
@@ -0,0 +1,13 @@
+/obj/item/mine/dnascramble
+ name = "radiation mine"
+ desc = "A small explosive mine with a radiation symbol on the side."
+ payload = /datum/mine_payload/dnascramble
+
+/datum/mine_payload/dnascramble/trigger_payload(var/obj/item/mine/owner, var/atom/trigger)
+ ..()
+ if(ismob(trigger))
+ var/mob/M = trigger
+ M.radiation += 50
+ randmutb(M)
+ domutcheck(M,null)
+ owner.visible_message("\The [owner] flashes violently before disintegrating!")
diff --git a/code/game/objects/items/mines/mine_emp.dm b/code/game/objects/items/mines/mine_emp.dm
new file mode 100644
index 0000000000..935b333da9
--- /dev/null
+++ b/code/game/objects/items/mines/mine_emp.dm
@@ -0,0 +1,9 @@
+/obj/item/mine/emp
+ name = "emp mine"
+ desc = "A small explosive mine with a lightning bolt symbol on the side."
+ payload = /datum/mine_payload/emp
+
+/datum/mine_payload/emp/trigger_payload(var/obj/item/mine/owner, var/atom/trigger)
+ ..()
+ owner.visible_message("\The [owner] flashes violently before disintegrating!")
+ empulse(owner.loc, 2, 4, 7, 10, 1) // As strong as an EMP grenade
diff --git a/code/game/objects/items/mines/mine_frag.dm b/code/game/objects/items/mines/mine_frag.dm
new file mode 100644
index 0000000000..c57941065b
--- /dev/null
+++ b/code/game/objects/items/mines/mine_frag.dm
@@ -0,0 +1,17 @@
+/obj/item/mine/frag
+ name = "fragmentation mine"
+ desc = "A small explosive mine with 'FRAG' and a grenade symbol on the side."
+ payload = /datum/mine_payload/frag
+
+/datum/mine_payload/frag
+ var/fragment_types = list(/obj/item/projectile/bullet/pellet/fragment)
+ var/num_fragments = 20 //total number of fragments produced by the grenade
+ //The radius of the circle used to launch projectiles. Lower values mean less projectiles are used but if set too low gaps may appear in the spread pattern
+ var/spread_range = 7
+
+/datum/mine_payload/frag/trigger_payload(var/obj/item/mine/owner, var/atom/trigger)
+ ..()
+ var/turf/O = get_turf(owner)
+ if(O)
+ owner.fragmentate(O, num_fragments, spread_range, fragment_types)
+ owner.visible_message("\The [owner] detonates!")
diff --git a/code/game/objects/items/mines/mine_incendiary.dm b/code/game/objects/items/mines/mine_incendiary.dm
new file mode 100644
index 0000000000..1d2936924a
--- /dev/null
+++ b/code/game/objects/items/mines/mine_incendiary.dm
@@ -0,0 +1,12 @@
+/obj/item/mine/incendiary
+ name = "incendiary mine"
+ desc = "A small explosive mine with a fire symbol on the side."
+ payload = /datum/mine_payload/incendiary
+
+/datum/mine_payload/incendiary/trigger_payload(var/obj/item/mine/owner, var/atom/trigger)
+ ..()
+ for(var/turf/simulated/floor/target in range(1, owner))
+ if(!target.blocks_air)
+ target.assume_gas("phoron", 30)
+ target.hotspot_expose(1000, CELL_VOLUME)
+ owner.visible_message("\The [owner] spews a cloud of flaming gas!")
diff --git a/code/game/objects/items/mines/mine_kick.dm b/code/game/objects/items/mines/mine_kick.dm
new file mode 100644
index 0000000000..564d6c1d1e
--- /dev/null
+++ b/code/game/objects/items/mines/mine_kick.dm
@@ -0,0 +1,13 @@
+/obj/item/mine/kick
+ name = "kick mine"
+ desc = "Concentrated war crimes. Handle with care."
+ payload = /datum/mine_payload/kick
+
+/datum/mine_payload/kick/trigger_payload(var/obj/item/mine/owner, var/atom/trigger)
+ ..()
+ if(istype(trigger, /obj/mecha))
+ var/obj/mecha/E = trigger
+ trigger = E.occupant
+ if(ismob(trigger))
+ var/mob/M = trigger
+ qdel(M.client)
diff --git a/code/game/objects/items/mines/mine_napalm.dm b/code/game/objects/items/mines/mine_napalm.dm
new file mode 100644
index 0000000000..0d6de598e0
--- /dev/null
+++ b/code/game/objects/items/mines/mine_napalm.dm
@@ -0,0 +1,12 @@
+/obj/item/mine/napalm
+ name = "napalm mine"
+ desc = "A small explosive mine with a fire symbol on the side."
+ payload = /datum/mine_payload/napalm
+
+/datum/mine_payload/napalm/trigger_payload(var/obj/item/mine/owner, var/atom/trigger)
+ ..()
+ if(isliving(trigger))
+ var/mob/living/M = trigger
+ M.adjust_fire_stacks(5)
+ M.fire_act()
+ owner.visible_message("\The [owner] bursts into flames!")
diff --git a/code/game/objects/items/mines/mine_sleeping.dm b/code/game/objects/items/mines/mine_sleeping.dm
new file mode 100644
index 0000000000..5e51877b1c
--- /dev/null
+++ b/code/game/objects/items/mines/mine_sleeping.dm
@@ -0,0 +1,11 @@
+/obj/item/mine/sleeping
+ name = "nitrous oxide mine"
+ desc = "A small explosive mine with three Z's on the side."
+ payload = /datum/mine_payload/sleeping
+
+/datum/mine_payload/sleeping/trigger_payload(var/obj/item/mine/owner, var/atom/trigger)
+ ..()
+ for (var/turf/simulated/floor/target in range(1, owner))
+ if(!target.blocks_air)
+ target.assume_gas("nitrous_oxide", 30)
+ owner.visible_message("\The [owner] sprays a cloud of gas!")
diff --git a/code/game/objects/items/mines/mine_stun.dm b/code/game/objects/items/mines/mine_stun.dm
new file mode 100644
index 0000000000..676faa1b48
--- /dev/null
+++ b/code/game/objects/items/mines/mine_stun.dm
@@ -0,0 +1,11 @@
+/obj/item/mine/stun
+ name = "stun mine"
+ desc = "A small explosive mine with a lightning bolt symbol on the side."
+ payload = /datum/mine_payload/stun
+
+/datum/mine_payload/stun/trigger_payload(var/obj/item/mine/owner, var/atom/trigger)
+ ..()
+ if(ismob(trigger))
+ var/mob/M = trigger
+ M.Stun(30)
+ owner.visible_message("\The [owner] flashes violently before disintegrating!")
diff --git a/code/game/objects/items/mines/mine_training.dm b/code/game/objects/items/mines/mine_training.dm
new file mode 100644
index 0000000000..c81ffd5ce1
--- /dev/null
+++ b/code/game/objects/items/mines/mine_training.dm
@@ -0,0 +1,12 @@
+/obj/item/mine/training
+ name = "training mine"
+ desc = "A mine with its payload removed, for EOD training and demonstrations."
+ payload = /datum/mine_payload/training
+
+/datum/mine_payload/training
+ do_sparks = FALSE
+ destroy_self_on_trigger = FALSE
+
+/datum/mine_payload/training/trigger_payload(var/obj/item/mine/owner, var/atom/trigger)
+ ..()
+ owner.visible_message("\The [owner]'s light flashes rapidly as it 'explodes'.")
diff --git a/code/game/objects/random/mapping.dm b/code/game/objects/random/mapping.dm
index 2025d2456f..6319964104 100644
--- a/code/game/objects/random/mapping.dm
+++ b/code/game/objects/random/mapping.dm
@@ -130,18 +130,23 @@
/obj/random/landmine
name = "Random Land Mine"
desc = "This is a random land mine."
- icon = 'icons/obj/weapons.dmi'
- icon_state = "uglymine"
+ icon = 'icons/obj/mine.dmi'
+ icon_state = "mine"
spawn_nothing_percentage = 25
/obj/random/landmine/item_to_spawn()
- return pick(prob(30);/obj/effect/mine,
- prob(25);/obj/effect/mine/frag,
- prob(25);/obj/effect/mine/emp,
- prob(15);/obj/effect/mine/camo,
- prob(15);/obj/effect/mine/emp/camo,
- prob(10);/obj/effect/mine/stun,
- prob(10);/obj/effect/mine/incendiary,)
+ return pick(
+ prob(60);/obj/item/mine,
+ prob(50);/obj/item/mine/emp,
+ prob(25);/obj/item/mine/frag,
+ prob(10);/obj/item/mine/stun,
+ prob(10);/obj/item/mine/incendiary
+ )
+
+/obj/random/landmine/spawn_item()
+ var/obj/item/mine/mine = ..()
+ if(istype(mine))
+ mine.prime()
/obj/random/humanoidremains
name = "Random Humanoid Remains"
diff --git a/icons/obj/mine.dmi b/icons/obj/mine.dmi
new file mode 100644
index 0000000000..1c28f57759
Binary files /dev/null and b/icons/obj/mine.dmi differ
diff --git a/icons/obj/weapons.dmi b/icons/obj/weapons.dmi
index 30c1264169..b662e0e71e 100644
Binary files a/icons/obj/weapons.dmi and b/icons/obj/weapons.dmi differ
diff --git a/maps/submaps/surface_submaps/wilderness/MCamp1.dmm b/maps/submaps/surface_submaps/wilderness/MCamp1.dmm
index 56296e7fac..0a181efc90 100644
--- a/maps/submaps/surface_submaps/wilderness/MCamp1.dmm
+++ b/maps/submaps/surface_submaps/wilderness/MCamp1.dmm
@@ -29,7 +29,7 @@
/turf/simulated/floor/outdoors/dirt,
/area/submap/MilitaryCamp1)
"i" = (
-/obj/effect/mine,
+/obj/random/landmine,
/turf/template_noop,
/area/submap/MilitaryCamp1)
"j" = (
@@ -82,7 +82,6 @@
/turf/simulated/floor/concrete,
/area/submap/MilitaryCamp1)
"u" = (
-/obj/effect/mine,
/obj/random/landmine,
/turf/simulated/floor/concrete,
/area/submap/MilitaryCamp1)
@@ -135,7 +134,7 @@
/area/submap/MilitaryCamp1)
"F" = (
/obj/machinery/door/airlock,
-/obj/effect/mine,
+/obj/random/landmine,
/turf/simulated/floor/concrete,
/area/submap/MilitaryCamp1)
"G" = (
diff --git a/polaris.dme b/polaris.dme
index 3b21aa9d37..cf62d82247 100644
--- a/polaris.dme
+++ b/polaris.dme
@@ -1,6 +1,6 @@
// DM Environment file for baystation12.dme.
// All manual changes should be made outside the BEGIN_ and END_ blocks.
- // New source code should be placed in .dm files: choose File/New --> Code File.
+// New source code should be placed in .dm files: choose File/New --> Code File.
// BEGIN_INTERNALS
// END_INTERNALS
// BEGIN_FILE_DIR
@@ -434,7 +434,6 @@
#include "code\datums\wires\explosive.dm"
#include "code\datums\wires\grid_checker.dm"
#include "code\datums\wires\jukebox.dm"
-#include "code\datums\wires\mines.dm"
#include "code\datums\wires\particle_accelerator.dm"
#include "code\datums\wires\radio.dm"
#include "code\datums\wires\robot.dm"
@@ -900,7 +899,6 @@
#include "code\game\objects\effects\glowshroom.dm"
#include "code\game\objects\effects\item_pickup_ghost.dm"
#include "code\game\objects\effects\landmarks.dm"
-#include "code\game\objects\effects\mines.dm"
#include "code\game\objects\effects\misc.dm"
#include "code\game\objects\effects\overlays.dm"
#include "code\game\objects\effects\portals.dm"
@@ -1012,6 +1010,18 @@
#include "code\game\objects\items\devices\radio\jammer.dm"
#include "code\game\objects\items\devices\radio\radio.dm"
#include "code\game\objects\items\devices\radio\radiopack.dm"
+#include "code\game\objects\items\mines\_mine.dm"
+#include "code\game\objects\items\mines\_mine_payload.dm"
+#include "code\game\objects\items\mines\mine_assembly.dm"
+#include "code\game\objects\items\mines\mine_dnascamble.dm"
+#include "code\game\objects\items\mines\mine_emp.dm"
+#include "code\game\objects\items\mines\mine_frag.dm"
+#include "code\game\objects\items\mines\mine_incendiary.dm"
+#include "code\game\objects\items\mines\mine_kick.dm"
+#include "code\game\objects\items\mines\mine_napalm.dm"
+#include "code\game\objects\items\mines\mine_sleeping.dm"
+#include "code\game\objects\items\mines\mine_stun.dm"
+#include "code\game\objects\items\mines\mine_training.dm"
#include "code\game\objects\items\robot\robot_items.dm"
#include "code\game\objects\items\robot\robot_parts.dm"
#include "code\game\objects\items\robot\robot_upgrades.dm"