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"