diff --git a/code/__defines/misc.dm b/code/__defines/misc.dm
index f9a1624f8f..a7b3bd86f8 100644
--- a/code/__defines/misc.dm
+++ b/code/__defines/misc.dm
@@ -157,6 +157,8 @@
#define MAT_GRAPHITE "graphite"
#define MAT_LEATHER "leather"
#define MAT_CHITIN "chitin"
+#define MAT_CLOTH "cloth"
+#define MAT_SYNCLOTH "syncloth"
#define SHARD_SHARD "shard"
#define SHARD_SHRAPNEL "shrapnel"
diff --git a/code/datums/autolathe/devices.dm b/code/datums/autolathe/devices.dm
index 9c6ab5bb97..eed4839159 100644
--- a/code/datums/autolathe/devices.dm
+++ b/code/datums/autolathe/devices.dm
@@ -26,6 +26,12 @@
name = "mechanical trap"
path =/obj/item/weapon/beartrap
+/datum/category_item/autolathe/devices/barbedwire
+ name = "barbed wire"
+ path = /obj/item/weapon/material/barbedwire
+ hidden = 1
+ resources = list(DEFAULT_WALL_MATERIAL = 10000)
+
/datum/category_item/autolathe/devices/electropack
name = "electropack"
path =/obj/item/device/radio/electropack
diff --git a/code/datums/autolathe/tools.dm b/code/datums/autolathe/tools.dm
index 9e9a87ea71..9b88a496fa 100644
--- a/code/datums/autolathe/tools.dm
+++ b/code/datums/autolathe/tools.dm
@@ -48,6 +48,11 @@
path = /obj/item/weapon/reagent_containers/spray
resources = list(MAT_PLASTIC = 2000)
+/datum/category_item/autolathe/devices/slowwire
+ name = "snare wire"
+ path = /obj/item/weapon/material/barbedwire/plastic
+ resources = list(MAT_PLASTIC = 10000)
+
/datum/category_item/autolathe/tools/spraynozzle
name = "spray nozzle"
path = /obj/item/weapon/reagent_containers/spray
diff --git a/code/datums/uplink/tools.dm b/code/datums/uplink/tools.dm
index 51d7ec7cd2..eee41e9699 100644
--- a/code/datums/uplink/tools.dm
+++ b/code/datums/uplink/tools.dm
@@ -92,6 +92,12 @@
desc = "A device which is capable of disrupting subspace communications, preventing the use of headsets, PDAs, and communicators within \
a radius of seven meters. It runs off weapon cells, which can be replaced as needed. One cell will last for approximately ten minutes."
+/datum/uplink_item/item/tools/wall_elecrtifier
+ name = "Wall Electrifier"
+ item_cost = 10
+ path = /obj/item/weapon/cell/spike
+ desc = "A modified powercell which will electrify walls and reinforced floors in a 3x3 tile range around it. Always active."
+
/datum/uplink_item/item/tools/emag
name = "Cryptographic Sequencer"
item_cost = 30
diff --git a/code/datums/wires/mines.dm b/code/datums/wires/mines.dm
index 209fcc4c30..5e757ad16c 100644
--- a/code/datums/wires/mines.dm
+++ b/code/datums/wires/mines.dm
@@ -1,5 +1,5 @@
/datum/wires/mines
- wire_count = 6
+ wire_count = 7
randomize = TRUE
holder_type = /obj/effect/mine
proper_name = "Explosive Wires"
@@ -7,6 +7,7 @@
/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()
. = ..()
@@ -29,7 +30,13 @@
if(WIRE_DISARM)
C.visible_message("[bicon(C)] *click!*", "[bicon(C)] *click!*")
- new C.mineitemtype(get_turf(C))
+ 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)
@@ -37,6 +44,15 @@
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)
@@ -57,6 +73,10 @@
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)
diff --git a/code/game/machinery/deployable.dm b/code/game/machinery/deployable.dm
index db27559796..64a3cc1fc7 100644
--- a/code/game/machinery/deployable.dm
+++ b/code/game/machinery/deployable.dm
@@ -1,111 +1,8 @@
/*
CONTAINS:
Deployable items
-Barricades
*/
-//Barricades!
-/obj/structure/barricade
- name = "barricade"
- desc = "This space is blocked off by a barricade."
- icon = 'icons/obj/structures.dmi'
- icon_state = "barricade"
- anchored = 1.0
- density = 1.0
- var/health = 100
- var/maxhealth = 100
- var/datum/material/material
-
-/obj/structure/barricade/New(var/newloc, var/material_name)
- ..(newloc)
- if(!material_name)
- material_name = "wood"
- material = get_material_by_name("[material_name]")
- if(!material)
- qdel(src)
- return
- name = "[material.display_name] barricade"
- desc = "This space is blocked off by a barricade made of [material.display_name]."
- color = material.icon_colour
- maxhealth = material.integrity
- health = maxhealth
-
-/obj/structure/barricade/get_material()
- return material
-
-/obj/structure/barricade/attackby(obj/item/W as obj, mob/user as mob)
- user.setClickCooldown(user.get_attack_speed(W))
- if(istype(W, /obj/item/stack))
- var/obj/item/stack/D = W
- if(D.get_material_name() != material.name)
- return //hitting things with the wrong type of stack usually doesn't produce messages, and probably doesn't need to.
- if(health < maxhealth)
- if(D.get_amount() < 1)
- to_chat(user, "You need one sheet of [material.display_name] to repair \the [src].")
- return
- visible_message("[user] begins to repair \the [src].")
- if(do_after(user,20) && health < maxhealth)
- if(D.use(1))
- health = maxhealth
- visible_message("[user] repairs \the [src].")
- return
- return
- else
- switch(W.damtype)
- if("fire")
- health -= W.force * 1
- if("brute")
- health -= W.force * 0.75
- if(material == (get_material_by_name(MAT_WOOD) || get_material_by_name(MAT_SIFWOOD)))
- playsound(src, 'sound/effects/woodcutting.ogg', 100, 1)
- else
- playsound(src, 'sound/weapons/smash.ogg', 50, 1)
- CheckHealth()
- ..()
-
-/obj/structure/barricade/proc/CheckHealth()
- if(health <= 0)
- dismantle()
- return
-
-/obj/structure/barricade/take_damage(var/damage)
- health -= damage
- CheckHealth()
- return
-
-/obj/structure/barricade/attack_generic(var/mob/user, var/damage, var/attack_verb)
- visible_message("[user] [attack_verb] the [src]!")
- if(material == get_material_by_name("resin"))
- playsound(src, 'sound/effects/attackblob.ogg', 100, 1)
- else if(material == (get_material_by_name(MAT_WOOD) || get_material_by_name(MAT_SIFWOOD)))
- playsound(src, 'sound/effects/woodcutting.ogg', 100, 1)
- else
- playsound(src, 'sound/weapons/smash.ogg', 50, 1)
- user.do_attack_animation(src)
- health -= damage
- CheckHealth()
- return
-
-/obj/structure/barricade/proc/dismantle()
- material.place_dismantled_product(get_turf(src))
- visible_message("\The [src] falls apart!")
- qdel(src)
- return
-
-/obj/structure/barricade/ex_act(severity)
- switch(severity)
- if(1.0)
- dismantle()
- if(2.0)
- health -= 25
- CheckHealth()
-
-/obj/structure/barricade/CanPass(atom/movable/mover, turf/target)//So bullets will fly over and stuff.
- if(istype(mover) && mover.checkpass(PASSTABLE))
- return TRUE
- return FALSE
-
-//Actual Deployable machinery stuff
/obj/machinery/deployable
name = "deployable"
desc = "deployable"
diff --git a/code/game/objects/effects/mines.dm b/code/game/objects/effects/mines.dm
index c522b4300e..c5e1f26c61 100644
--- a/code/game/objects/effects/mines.dm
+++ b/code/game/objects/effects/mines.dm
@@ -7,16 +7,32 @@
icon_state = "uglymine"
var/triggered = 0
var/smoke_strength = 3
- var/mineitemtype = /obj/item/weapon/mine
+ var/obj/item/weapon/mine/mineitemtype = /obj/item/weapon/mine
var/panel_open = 0
var/datum/wires/mines/wires = null
register_as_dangerous_object = TRUE
+ 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/New()
icon_state = "uglyminearmed"
wires = new(src)
+ if(ispath(trap))
+ trap = new trap(src)
+
+/obj/effect/mine/Initialize()
+ ..()
+
+ if(camo_net)
+ alpha = 50
+
/obj/effect/mine/Destroy()
+ if(trap)
+ QDEL_NULL(trap)
qdel_null(wires)
return ..()
@@ -25,11 +41,33 @@
triggered = 1
s.set_up(3, 1, src)
s.start()
- explosion(loc, 0, 2, 3, 4) //land mines are dangerous, folks.
- visible_message("\The [src.name] detonates!")
+
+ 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/weapon/grenade))
+ var/obj/item/weapon/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/device/transfer_valve))
+ var/obj/item/device/transfer_valve/TV = trap
+ trap = null
+ TV.forceMove(get_turf(src))
+ TV.toggle_valve()
+
/obj/effect/mine/bullet_act()
if(prob(50))
explode()
@@ -63,6 +101,9 @@
"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/device/multitool)) && panel_open)
interact(user)
else
@@ -74,6 +115,9 @@
user.set_machine(src)
wires.Interact(user)
+/obj/effect/mine/camo
+ camo_net = TRUE
+
/obj/effect/mine/dnascramble
mineitemtype = /obj/item/weapon/mine/dnascramble
@@ -193,6 +237,9 @@
spawn(0)
qdel(src)
+/obj/effect/mine/emp/camo
+ camo_net = TRUE
+
/obj/effect/mine/incendiary
mineitemtype = /obj/item/weapon/mine/incendiary
@@ -208,6 +255,26 @@
spawn(0)
qdel(src)
+/obj/effect/mine/gadget
+ mineitemtype = /obj/item/weapon/mine/gadget
+
+/obj/effect/mine/gadget/explode(var/mob/living/M)
+ var/datum/effect/effect/system/spark_spread/s = new /datum/effect/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
/////////////////////////////////////////////
@@ -219,6 +286,10 @@
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/weapon/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]")
@@ -231,11 +302,39 @@
prime(user, TRUE)
return
+/obj/item/weapon/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/weapon/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)
@@ -286,8 +385,14 @@
desc = "A small explosive mine with a fire symbol on the side."
minetype = /obj/effect/mine/incendiary
+/obj/item/weapon/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/weapon/grenade, /obj/item/device/transfer_valve)
+
// This tells AI mobs to not be dumb and step on mines willingly.
/obj/item/weapon/mine/is_safe_to_step(mob/living/L)
if(!L.hovering)
return FALSE
- return ..()
\ No newline at end of file
+ return ..()
diff --git a/code/game/objects/items/devices/spy_bug.dm b/code/game/objects/items/devices/spy_bug.dm
index 03d0bdd60c..60ca5cc1a2 100644
--- a/code/game/objects/items/devices/spy_bug.dm
+++ b/code/game/objects/items/devices/spy_bug.dm
@@ -88,6 +88,14 @@
if(get_dist(user, src) == 0)
. += "It has a tiny camera inside. Needs to be both configured and brought in contact with monitor device to be fully functional."
+/obj/item/device/camerabug/update_icon()
+ ..()
+
+ if(anchored) // Standard versions are relatively obvious if not hidden in a container. Anchoring them is advised, to disguise them.
+ alpha = 50
+ else
+ alpha = 255
+
/obj/item/device/camerabug/attackby(obj/item/W as obj, mob/living/user as mob)
if(istype(W, /obj/item/device/bug_monitor))
var/obj/item/device/bug_monitor/SM = W
@@ -101,6 +109,15 @@
linkedmonitor = null
else
to_chat(user, "Error: The device is linked to another monitor.")
+
+ else if(W.is_wrench() && user.a_intent != I_HURT)
+ if(isturf(loc))
+ anchored = !anchored
+
+ to_chat(user, "You [anchored ? "" : "un"]secure \the [src].")
+
+ update_icon()
+ return
else
if(W.force >= 5)
visible_message("\The [src] lens shatters!")
diff --git a/code/game/objects/items/stacks/matter_synth.dm b/code/game/objects/items/stacks/matter_synth.dm
index d92cd5f8dd..02c6518374 100644
--- a/code/game/objects/items/stacks/matter_synth.dm
+++ b/code/game/objects/items/stacks/matter_synth.dm
@@ -56,3 +56,6 @@
name = "Bandage Synthesizer"
max_energy = 10
recharge_rate = 1
+
+/datum/matter_synth/cloth
+ name = "Cloth Synthesizer"
diff --git a/code/game/objects/items/stacks/sandbags.dm b/code/game/objects/items/stacks/sandbags.dm
new file mode 100644
index 0000000000..c4e755c485
--- /dev/null
+++ b/code/game/objects/items/stacks/sandbags.dm
@@ -0,0 +1,158 @@
+/obj/item/stack/sandbags
+ name = "sandbag"
+ desc = "Filled sandbags. Fortunately pre-filled."
+ singular_name = "sandbag"
+ icon = 'icons/obj/sandbags.dmi'
+ icon_state = "sandbag"
+ w_class = ITEMSIZE_LARGE
+ force = 10.0
+ throwforce = 20.0
+ throw_speed = 5
+ throw_range = 3
+ drop_sound = 'sound/items/drop/clothing.ogg'
+ pickup_sound = 'sound/items/pickup/clothing.ogg'
+ matter = list(MAT_CLOTH = SHEET_MATERIAL_AMOUNT * 2)
+ max_amount = 30
+ attack_verb = list("hit", "bludgeoned", "pillowed")
+ no_variants = TRUE
+ stacktype = /obj/item/stack/sandbags
+
+ pass_color = TRUE
+
+ var/bag_material = "cloth"
+
+/obj/item/stack/sandbags/cyborg
+ name = "sandbag synthesizer"
+ desc = "A device that makes filled sandbags. Don't ask how."
+ gender = NEUTER
+ matter = null
+ uses_charge = 1
+ charge_costs = list(500)
+ stacktype = /obj/item/stack/sandbags
+
+ bag_material = MAT_SYNCLOTH
+
+/obj/item/stack/sandbags/New(var/newloc, var/amt, var/bag_mat)
+ ..()
+ recipes = sandbag_recipes
+ update_icon()
+
+ if(bag_mat)
+ bag_material = bag_mat
+
+ var/datum/material/M = get_material_by_name("[bag_material]")
+ if(!M)
+ qdel(src)
+ return
+
+ color = M.icon_colour
+
+/obj/item/stack/sandbags/update_icon()
+ var/amount = get_amount()
+
+ slowdown = round(amount / 10, 0.1)
+
+var/global/list/datum/stack_recipe/sandbag_recipes = list( \
+ new/datum/stack_recipe("barricade", /obj/structure/barricade/sandbag, 3, time = 5 SECONDS, one_per_turf = 1, on_floor = 1, pass_stack_color = TRUE))
+
+/obj/item/stack/sandbags/produce_recipe(datum/stack_recipe/recipe, var/quantity, mob/user)
+ var/required = quantity*recipe.req_amount
+ var/produced = min(quantity*recipe.res_amount, recipe.max_res_amount)
+
+ if (!can_use(required))
+ if (produced>1)
+ to_chat(user, "You haven't got enough [src] to build \the [produced] [recipe.title]\s!")
+ else
+ to_chat(user, "You haven't got enough [src] to build \the [recipe.title]!")
+ return
+
+ if (recipe.one_per_turf && (locate(recipe.result_type) in user.loc))
+ to_chat(user, "There is another [recipe.title] here!")
+ return
+
+ if (recipe.on_floor && !isfloor(user.loc))
+ to_chat(user, "\The [recipe.title] must be constructed on the floor!")
+ return
+
+ if (recipe.time)
+ to_chat(user, "Building [recipe.title] ...")
+ if (!do_after(user, recipe.time))
+ return
+
+ if (use(required))
+ var/atom/O = new recipe.result_type(user.loc, bag_material)
+
+ if(istype(O, /obj))
+ var/obj/Ob = O
+
+ if(LAZYLEN(Ob.matter)) // Law of equivalent exchange.
+ Ob.matter.Cut()
+
+ else
+ Ob.matter = list()
+
+ var/mattermult = istype(Ob, /obj/item) ? min(2000, 400 * Ob.w_class) : 2000
+
+ Ob.matter[recipe.use_material] = mattermult / produced * required
+
+ O.set_dir(user.dir)
+ O.add_fingerprint(user)
+
+ if (istype(O, /obj/item/stack))
+ var/obj/item/stack/S = O
+ S.amount = produced
+ S.add_to_stacks(user)
+
+ if (istype(O, /obj/item/weapon/storage)) //BubbleWrap - so newly formed boxes are empty
+ for (var/obj/item/I in O)
+ qdel(I)
+
+ if ((pass_color || recipe.pass_color))
+ if(!color)
+ if(recipe.use_material)
+ var/datum/material/MAT = get_material_by_name(recipe.use_material)
+ if(MAT.icon_colour)
+ O.color = MAT.icon_colour
+ else
+ return
+ else
+ O.color = color
+
+// Empty bags. Yes, you need to fill them.
+
+/obj/item/stack/emptysandbag
+ name = "sandbag"
+ desc = "Empty sandbags. You know what must be done."
+ singular_name = "sandbag"
+ icon = 'icons/obj/sandbags.dmi'
+ icon_state = "sandbag_e"
+ w_class = ITEMSIZE_LARGE
+
+ strict_color_stacking = TRUE
+ max_amount = 30
+ stacktype = /obj/item/stack/emptysandbag
+
+ pass_color = TRUE
+
+ var/bag_material = "cloth"
+
+/obj/item/stack/emptysandbag/New(var/newloc, var/amt, var/bag_mat)
+ ..(newloc, amt)
+
+ if(bag_mat)
+ bag_material = bag_mat
+
+ var/datum/material/M = get_material_by_name("[bag_material]")
+ if(!M)
+ qdel(src)
+ return
+
+ color = M.icon_colour
+
+/obj/item/stack/emptysandbag/attack_self(var/mob/user)
+ while(do_after(user, 1 SECOND) && can_use(1) && istype(get_turf(src), /turf/simulated/floor/outdoors))
+ use(1)
+ var/obj/item/stack/sandbags/SB = new (get_turf(src), 1, bag_material)
+ SB.color = color
+ if(user)
+ to_chat(user, "You fill a sandbag.")
diff --git a/code/game/objects/items/weapons/material/material_weapons.dm b/code/game/objects/items/weapons/material/material_weapons.dm
index 23c04f2a81..5563b71689 100644
--- a/code/game/objects/items/weapons/material/material_weapons.dm
+++ b/code/game/objects/items/weapons/material/material_weapons.dm
@@ -97,6 +97,8 @@
/obj/item/weapon/material/proc/check_health(var/consumed)
if(health<=0)
+ health = 0
+
if(fragile)
shatter(consumed)
else if(!dulled && can_dull)
diff --git a/code/game/objects/items/weapons/traps.dm b/code/game/objects/items/weapons/traps.dm
index 0ec9bc7af3..c583ce1eef 100644
--- a/code/game/objects/items/weapons/traps.dm
+++ b/code/game/objects/items/weapons/traps.dm
@@ -1,3 +1,9 @@
+
+/*
+ * Beartraps.
+ * Buckles crossing individuals, doing moderate brute damage.
+ */
+
/obj/item/weapon/beartrap
name = "mechanical trap"
throw_speed = 2
@@ -158,3 +164,238 @@
color = "#C9DCE1"
origin_tech = list(TECH_MATERIAL = 4, TECH_BLUESPACE = 3, TECH_MAGNET = 4, TECH_PHORON = 2, TECH_ARCANE = 1)
+
+/*
+ * Barbed-Wire.
+ * Slows individuals crossing it. Barefoot individuals will be cut. Can be electrified by placing over a cable node.
+ */
+
+/obj/item/weapon/material/barbedwire
+ name = "barbed wire"
+ desc = "A coil of wire."
+ icon = 'icons/obj/trap.dmi'
+ icon_state = "barbedwire"
+ anchored = FALSE
+ layer = TABLE_LAYER
+ w_class = ITEMSIZE_LARGE
+ explosion_resistance = 1
+ can_dull = TRUE
+ fragile = TRUE
+ force_divisor = 0.20
+ thrown_force_divisor = 0.25
+
+ sharp = TRUE
+
+/obj/item/weapon/material/barbedwire/set_material(var/new_material)
+ ..()
+
+ if(!QDELETED(src))
+ health = round(material.integrity / 3)
+ name = (material.get_edge_damage() * force_divisor > 15) ? "[material.display_name] razor wire" : "[material.display_name] [initial(name)]"
+
+/obj/item/weapon/material/barbedwire/proc/can_use(mob/user)
+ return (user.IsAdvancedToolUser() && !issilicon(user) && !user.stat && !user.restrained())
+
+/obj/item/weapon/material/barbedwire/attack_hand(mob/user as mob)
+ if(anchored && can_use(user))
+ user.visible_message(
+ "[user] starts to collect \the [src].",
+ "You begin collecting \the [src]!",
+ "You hear the sound of rustling [material.name]."
+ )
+ playsound(src, 'sound/machines/click.ogg', 50, 1)
+
+ if(do_after(user, health))
+ user.visible_message(
+ "[user] has collected \the [src].",
+ "You have collected \the [src]!"
+ )
+ anchored = 0
+ update_icon()
+ else
+ ..()
+
+/obj/item/weapon/material/barbedwire/attack_self(mob/user as mob)
+ ..()
+ if(!anchored && can_use(user))
+ user.visible_message(
+ "[user] starts to deploy \the [src].",
+ "You begin deploying \the [src]!",
+ "You hear the rustling of [material.name]."
+ )
+
+ if (do_after(user, 60))
+ user.visible_message(
+ "[user] has deployed \the [src].",
+ "You have deployed \the [src]!",
+ "You hear the rustling of [material.name]."
+ )
+ playsound(src, 'sound/items/Wirecutter.ogg',70, 1)
+ spawn(2)
+ playsound(src, 'sound/items/Wirecutter.ogg',40, 1)
+ user.drop_from_inventory(src)
+ forceMove(get_turf(src))
+ anchored = 1
+ update_icon()
+
+/obj/item/weapon/material/barbedwire/attackby(obj/item/W as obj, mob/user as mob)
+ if(!istype(W))
+ return
+
+ if((W.flags & NOCONDUCT) || !shock(user, 70, pick(BP_L_HAND, BP_R_HAND)))
+ user.setClickCooldown(user.get_attack_speed(W))
+ user.do_attack_animation(src)
+ playsound(src, 'sound/effects/grillehit.ogg', 40, 1)
+
+ var/inc_damage = W.force
+
+ if(W.is_wirecutter())
+ if(!shock(user, 100, pick(BP_L_HAND, BP_R_HAND)))
+ playsound(src, W.usesound, 100, 1)
+ inc_damage *= 3
+
+ if(W.damtype != BRUTE)
+ inc_damage *= 0.3
+
+ health -= inc_damage
+
+ check_health()
+
+ ..()
+
+/obj/item/weapon/material/barbedwire/update_icon()
+ ..()
+
+ if(anchored)
+ icon_state = "[initial(icon_state)]-out"
+ else
+ icon_state = "[initial(icon_state)]"
+
+/obj/item/weapon/material/barbedwire/Crossed(atom/movable/AM as mob|obj)
+ if(AM.is_incorporeal())
+ return
+ if(anchored && isliving(AM))
+ var/mob/living/L = AM
+ if(L.m_intent == "run")
+ L.visible_message(
+ "[L] steps in \the [src].",
+ "You step in \the [src]!",
+ "You hear a sharp rustling!"
+ )
+ attack_mob(L)
+ update_icon()
+ ..()
+
+/obj/item/weapon/material/barbedwire/proc/shock(mob/user as mob, prb, var/target_zone = BP_TORSO)
+ if(!anchored || health == 0) // anchored/destroyed grilles are never connected
+ return 0
+ if(material.conductivity <= 0)
+ return 0
+ if(!prob(prb))
+ return 0
+ if(!in_range(src, user))//To prevent TK and mech users from getting shocked
+ return 0
+ var/turf/T = get_turf(src)
+ var/obj/structure/cable/C = T.get_cable_node()
+ if(C)
+ if(C.powernet)
+ var/datum/powernet/PN = C.powernet
+
+ if(PN)
+ PN.trigger_warning()
+
+ var/PN_damage = PN.get_electrocute_damage() * (material.conductivity / 50)
+
+ var/drained_energy = PN_damage * 10 / CELLRATE
+
+ PN.draw_power(drained_energy)
+
+ if(ishuman(user))
+ var/mob/living/carbon/human/H = user
+
+ var/obj/item/organ/external/affected = H.get_organ(check_zone(target_zone))
+
+ H.electrocute_act(PN_damage, src, H.get_siemens_coefficient_organ(affected))
+
+ else
+ if(isliving(user))
+ var/mob/living/L = user
+ L.electrocute_act(PN_damage, src, 0.8)
+
+ var/datum/effect/effect/system/spark_spread/s = new /datum/effect/effect/system/spark_spread
+ s.set_up(3, 1, src)
+ s.start()
+ if(user.stunned)
+ return 1
+ else
+ return 0
+ return 0
+
+/obj/item/weapon/material/barbedwire/proc/attack_mob(mob/living/L)
+ var/target_zone
+ if(L.lying)
+ target_zone = ran_zone()
+ else
+ target_zone = pick("l_foot", "r_foot", "l_leg", "r_leg")
+
+ //armour
+ var/blocked = L.run_armor_check(target_zone, "melee")
+ var/soaked = L.get_armor_soak(target_zone, "melee")
+
+ if(blocked >= 100)
+ return
+
+ if(soaked >= 30)
+ return
+
+ if(L.buckled) //wheelchairs, office chairs, rollerbeds
+ return
+
+ shock(L, 100, target_zone)
+
+ L.add_modifier(/datum/modifier/entangled, 3 SECONDS)
+
+ if(!L.apply_damage(force * (issilicon(L) ? 0.25 : 1), BRUTE, target_zone, blocked, soaked, src, sharp, edge))
+ return
+
+ playsound(src, 'sound/effects/glass_step.ogg', 50, 1) // not sure how to handle metal shards with sounds
+ if(ishuman(L))
+ var/mob/living/carbon/human/H = L
+
+ if(H.species.siemens_coefficient<0.5) //Thick skin.
+ return
+
+ if( H.shoes || ( H.wear_suit && (H.wear_suit.body_parts_covered & FEET) ) )
+ return
+
+ if(H.species.flags & NO_MINOR_CUT)
+ return
+
+ to_chat(H, "You step directly on \the [src]!")
+
+ var/list/check = list("l_foot", "r_foot")
+ while(check.len)
+ var/picked = pick(check)
+ var/obj/item/organ/external/affecting = H.get_organ(picked)
+ if(affecting)
+ if(affecting.robotic >= ORGAN_ROBOT)
+ return
+ if(affecting.take_damage(force, 0))
+ H.UpdateDamageIcon()
+ H.updatehealth()
+ if(affecting.organ_can_feel_pain())
+ H.Weaken(3)
+ return
+ check -= picked
+
+ if(material.is_brittle() && prob(material.hardness))
+ health = 0
+ else if(!prob(material.hardness))
+ health--
+ check_health()
+
+ return
+
+/obj/item/weapon/material/barbedwire/plastic
+ name = "snare wire"
+ default_material = MAT_PLASTIC
diff --git a/code/game/objects/random/mapping.dm b/code/game/objects/random/mapping.dm
index 16be9dff94..4d40578c1e 100644
--- a/code/game/objects/random/mapping.dm
+++ b/code/game/objects/random/mapping.dm
@@ -92,6 +92,8 @@
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,)
diff --git a/code/game/objects/structures/barricades.dm b/code/game/objects/structures/barricades.dm
new file mode 100644
index 0000000000..34ab6025c7
--- /dev/null
+++ b/code/game/objects/structures/barricades.dm
@@ -0,0 +1,185 @@
+//Barricades!
+/obj/structure/barricade
+ name = "barricade"
+ desc = "This space is blocked off by a barricade."
+ icon = 'icons/obj/structures.dmi'
+ icon_state = "barricade"
+ anchored = 1.0
+ density = 1.0
+ var/health = 100
+ var/maxhealth = 100
+ var/datum/material/material
+
+/obj/structure/barricade/New(var/newloc, var/material_name)
+ ..(newloc)
+ if(!material_name)
+ material_name = "wood"
+ material = get_material_by_name("[material_name]")
+ if(!material)
+ qdel(src)
+ return
+ name = "[material.display_name] barricade"
+ desc = "This space is blocked off by a barricade made of [material.display_name]."
+ color = material.icon_colour
+ maxhealth = material.integrity
+ health = maxhealth
+
+/obj/structure/barricade/get_material()
+ return material
+
+/obj/structure/barricade/attackby(obj/item/W as obj, mob/user as mob)
+ user.setClickCooldown(user.get_attack_speed(W))
+ if(istype(W, /obj/item/stack))
+ var/obj/item/stack/D = W
+ if(D.get_material_name() != material.name)
+ return //hitting things with the wrong type of stack usually doesn't produce messages, and probably doesn't need to.
+ if(health < maxhealth)
+ if(D.get_amount() < 1)
+ to_chat(user, "You need one sheet of [material.display_name] to repair \the [src].")
+ return
+ visible_message("[user] begins to repair \the [src].")
+ if(do_after(user,20) && health < maxhealth)
+ if(D.use(1))
+ health = maxhealth
+ visible_message("[user] repairs \the [src].")
+ return
+ return
+ else
+ switch(W.damtype)
+ if("fire")
+ health -= W.force * 1
+ if("brute")
+ health -= W.force * 0.75
+ if(material == (get_material_by_name(MAT_WOOD) || get_material_by_name(MAT_SIFWOOD)))
+ playsound(src, 'sound/effects/woodcutting.ogg', 100, 1)
+ else
+ playsound(src, 'sound/weapons/smash.ogg', 50, 1)
+ CheckHealth()
+ ..()
+
+/obj/structure/barricade/proc/CheckHealth()
+ if(health <= 0)
+ dismantle()
+
+ health = min(health, maxhealth)
+
+ return
+
+/obj/structure/barricade/take_damage(var/damage)
+ health -= damage
+ CheckHealth()
+ return
+
+/obj/structure/barricade/attack_generic(var/mob/user, var/damage, var/attack_verb)
+ visible_message("[user] [attack_verb] the [src]!")
+ if(material == get_material_by_name("resin"))
+ playsound(src, 'sound/effects/attackblob.ogg', 100, 1)
+ else if(material == (get_material_by_name(MAT_CLOTH) || get_material_by_name(MAT_SYNCLOTH)))
+ playsound(src, 'sound/items/drop/clothing.ogg', 100, 1)
+ else if(material == (get_material_by_name(MAT_WOOD) || get_material_by_name(MAT_SIFWOOD)))
+ playsound(src, 'sound/effects/woodcutting.ogg', 100, 1)
+ else
+ playsound(src, 'sound/weapons/smash.ogg', 50, 1)
+ user.do_attack_animation(src)
+ health -= damage
+ CheckHealth()
+ return
+
+/obj/structure/barricade/proc/dismantle()
+ material.place_dismantled_product(get_turf(src))
+ visible_message("\The [src] falls apart!")
+ qdel(src)
+ return
+
+/obj/structure/barricade/ex_act(severity)
+ switch(severity)
+ if(1.0)
+ dismantle()
+ if(2.0)
+ health -= 25
+ CheckHealth()
+
+/obj/structure/barricade/CanPass(atom/movable/mover, turf/target)//So bullets will fly over and stuff.
+ if(istype(mover) && mover.checkpass(PASSTABLE))
+ return TRUE
+ return FALSE
+
+/obj/structure/barricade/sandbag
+ name = "sandbags"
+ desc = "Bags. Bags of sand. It's rough and coarse and somehow stays in the bag."
+ icon = 'icons/obj/sandbags.dmi'
+ icon_state = "blank"
+
+/obj/structure/barricade/sandbag/New(var/newloc, var/material_name)
+ if(!material_name)
+ material_name = "cloth"
+ ..(newloc, material_name)
+ material = get_material_by_name("[material_name]")
+ if(!material)
+ qdel(src)
+ return
+ name = "[material.display_name] [initial(name)]"
+ desc = "This space is blocked off by a barricade made of [material.display_name]."
+ color = null
+ maxhealth = material.integrity * 2 // These things are, commonly, used to stop bullets where possible.
+ health = maxhealth
+ update_connections(1)
+
+/obj/structure/barricade/sandbag/Destroy()
+ update_connections(1, src)
+ ..()
+
+/obj/structure/barricade/sandbag/dismantle()
+ update_connections(1, src)
+ material.place_dismantled_product(get_turf(src))
+ visible_message("\The [src] falls apart!")
+ qdel(src)
+ return
+
+/obj/structure/barricade/sandbag/update_icon()
+ if(!material)
+ return
+
+ cut_overlays()
+ var/image/I
+
+ for(var/i = 1 to 4)
+ I = image('icons/obj/sandbags.dmi', "sandbags[connections[i]]", dir = 1<<(i-1))
+ I.color = material.icon_colour
+ add_overlay(I)
+
+ return
+
+/obj/structure/barricade/sandbag/update_connections(propagate = 0, var/obj/structure/barricade/sandbag/ignore = null)
+ if(!material)
+ return
+ var/list/dirs = list()
+ for(var/obj/structure/barricade/sandbag/S in orange(src, 1))
+ if(!S.material)
+ continue
+ if(S == ignore)
+ continue
+ if(propagate >= 1)
+ S.update_connections(propagate - 1, ignore)
+ if(can_join_with(S))
+ dirs += get_dir(src, S)
+
+ connections = dirs_to_corner_states(dirs)
+
+ update_icon()
+
+/obj/structure/barricade/sandbag/proc/can_join_with(var/obj/structure/barricade/sandbag/S)
+ if(material == S.material)
+ return 1
+ return 0
+
+/obj/structure/barricade/sandbag/CanPass(atom/movable/mover, turf/target)
+ . = ..()
+
+ if(.)
+ if(istype(mover, /obj/item/projectile))
+ var/obj/item/projectile/P = mover
+
+ if(P.firer && get_dist(P.firer, src) > 1) // If you're firing from adjacent turfs, you are unobstructed.
+ if(P.armor_penetration < (material.protectiveness + material.hardness) || prob(33))
+ return FALSE
diff --git a/code/modules/materials/material_recipes.dm b/code/modules/materials/material_recipes.dm
index 6e4b7c741f..a33d1f8e68 100644
--- a/code/modules/materials/material_recipes.dm
+++ b/code/modules/materials/material_recipes.dm
@@ -28,6 +28,7 @@
recipes += new/datum/stack_recipe("[display_name] fork", /obj/item/weapon/material/kitchen/utensil/fork/plastic, 1, on_floor = 1, supplied_material = "[name]", pass_stack_color = TRUE)
recipes += new/datum/stack_recipe("[display_name] knife", /obj/item/weapon/material/knife/plastic, 1, on_floor = 1, supplied_material = "[name]", pass_stack_color = TRUE)
recipes += new/datum/stack_recipe("[display_name] blade", /obj/item/weapon/material/butterflyblade, 6, time = 20, one_per_turf = 0, on_floor = 1, supplied_material = "[name]", pass_stack_color = TRUE)
+ recipes += new/datum/stack_recipe("[display_name] defense wire", /obj/item/weapon/material/barbedwire, 10, time = 1 MINUTE, one_per_turf = 0, on_floor = 1, supplied_material = "[name]", pass_stack_color = TRUE)
/datum/material/steel/generate_recipes()
..()
@@ -222,6 +223,7 @@
/datum/material/cloth/generate_recipes()
recipes = list()
+<<<<<<< HEAD
recipes += new/datum/stack_recipe("woven net", /obj/item/weapon/material/fishing_net, 10, time = 30 SECONDS, pass_stack_color = TRUE)
recipes += new/datum/stack_recipe("bedsheet", /obj/item/weapon/bedsheet, 10, time = 30 SECONDS, pass_stack_color = TRUE)
recipes += new/datum/stack_recipe("uniform", /obj/item/clothing/under/color/white, 8, time = 15 SECONDS, pass_stack_color = TRUE)
@@ -237,6 +239,24 @@
recipes += new/datum/stack_recipe("baggy pants", /obj/item/clothing/under/pants/baggy/white, 8, time = 10 SECONDS, pass_stack_color = TRUE)
recipes += new/datum/stack_recipe("belt pouch", /obj/item/weapon/storage/belt/fannypack/white, 25, time = 1 MINUTE, pass_stack_color = TRUE)
recipes += new/datum/stack_recipe("crude bandage", /obj/item/stack/medical/crude_pack, 1, time = 2 SECONDS, pass_stack_color = TRUE)
+=======
+ recipes += new/datum/stack_recipe("woven net", /obj/item/weapon/material/fishing_net, 10, time = 30 SECONDS, pass_stack_color = TRUE, supplied_material = "[name]")
+ recipes += new/datum/stack_recipe("bedsheet", /obj/item/weapon/bedsheet, 10, time = 30 SECONDS, pass_stack_color = TRUE, recycle_material = "[name]")
+ recipes += new/datum/stack_recipe("uniform", /obj/item/clothing/under/color/white, 8, time = 15 SECONDS, pass_stack_color = TRUE, recycle_material = "[name]")
+ recipes += new/datum/stack_recipe("foot wraps", /obj/item/clothing/shoes/footwraps, 2, time = 5 SECONDS, pass_stack_color = TRUE, recycle_material = "[name]")
+ recipes += new/datum/stack_recipe("gloves", /obj/item/clothing/gloves/white, 2, time = 5 SECONDS, pass_stack_color = TRUE, recycle_material = "[name]")
+ recipes += new/datum/stack_recipe("wig", /obj/item/clothing/head/powdered_wig, 4, time = 10 SECONDS, pass_stack_color = TRUE, recycle_material = "[name]")
+ recipes += new/datum/stack_recipe("philosopher's wig", /obj/item/clothing/head/philosopher_wig, 50, time = 2 MINUTES, pass_stack_color = TRUE, recycle_material = "[name]")
+ recipes += new/datum/stack_recipe("taqiyah", /obj/item/clothing/head/taqiyah, 3, time = 6 SECONDS, pass_stack_color = TRUE, recycle_material = "[name]")
+ recipes += new/datum/stack_recipe("turban", /obj/item/clothing/head/turban, 3, time = 6 SECONDS, pass_stack_color = TRUE, recycle_material = "[name]")
+ recipes += new/datum/stack_recipe("hijab", /obj/item/clothing/head/hijab, 3, time = 6 SECONDS, pass_stack_color = TRUE, recycle_material = "[name]")
+ recipes += new/datum/stack_recipe("kippa", /obj/item/clothing/head/kippa, 3, time = 6 SECONDS, pass_stack_color = TRUE, recycle_material = "[name]")
+ recipes += new/datum/stack_recipe("scarf", /obj/item/clothing/accessory/scarf/white, 4, time = 5 SECONDS, pass_stack_color = TRUE, recycle_material = "[name]")
+ recipes += new/datum/stack_recipe("baggy pants", /obj/item/clothing/under/pants/baggy/white, 8, time = 10 SECONDS, pass_stack_color = TRUE, recycle_material = "[name]")
+ recipes += new/datum/stack_recipe("belt pouch", /obj/item/weapon/storage/belt/fannypack/white, 25, time = 1 MINUTE, pass_stack_color = TRUE, recycle_material = "[name]")
+ recipes += new/datum/stack_recipe("crude bandage", /obj/item/stack/medical/crude_pack, 1, time = 2 SECONDS, pass_stack_color = TRUE, recycle_material = "[name]")
+ recipes += new/datum/stack_recipe("empty sandbag", /obj/item/stack/emptysandbag, 2, time = 2 SECONDS, pass_stack_color = TRUE, supplied_material = "[name]")
+>>>>>>> bd9f63a... Gadgets & Gizmos (#7786)
/datum/material/resin/generate_recipes()
recipes = list()
@@ -269,4 +289,5 @@
recipes += new/datum/stack_recipe("[display_name] ring", /obj/item/clothing/gloves/ring/material, 1, on_floor = 1, supplied_material = "[name]", pass_stack_color = TRUE)
recipes += new/datum/stack_recipe("[display_name] bracelet", /obj/item/clothing/accessory/bracelet/material, 1, on_floor = 1, supplied_material = "[name]", pass_stack_color = TRUE)
recipes += new/datum/stack_recipe("[display_name] armor plate", /obj/item/weapon/material/armor_plating, 1, time = 20, on_floor = 1, supplied_material = "[name]", pass_stack_color = TRUE)
+ recipes += new/datum/stack_recipe("empty sandbag", /obj/item/stack/emptysandbag, 2, time = 2 SECONDS, pass_stack_color = TRUE, supplied_material = "[name]")
recipes += new/datum/stack_recipe("whip", /obj/item/weapon/material/whip, 5, time = 15 SECONDS, pass_stack_color = TRUE, supplied_material = "[name]")
diff --git a/code/modules/materials/materials.dm b/code/modules/materials/materials.dm
index 068a745cbb..572438107d 100644
--- a/code/modules/materials/materials.dm
+++ b/code/modules/materials/materials.dm
@@ -1010,6 +1010,19 @@ var/list/name_to_material
pass_stack_colors = TRUE
supply_conversion_value = 2
+/datum/material/cloth/syncloth
+ name = "syncloth"
+ stack_origin_tech = list(TECH_MATERIAL = 3, TECH_BIO = 2)
+ door_icon_base = "wood"
+ ignition_point = T0C+532
+ melting_point = T0C+600
+ integrity = 200
+ protectiveness = 15 // 4%
+ flags = MATERIAL_PADDING
+ conductive = 0
+ pass_stack_colors = TRUE
+ supply_conversion_value = 3
+
/datum/material/cult
name = "cult"
display_name = "disturbing stone"
diff --git a/code/modules/mob/_modifiers/modifiers_misc.dm b/code/modules/mob/_modifiers/modifiers_misc.dm
index 3b9663d855..fee761cf30 100644
--- a/code/modules/mob/_modifiers/modifiers_misc.dm
+++ b/code/modules/mob/_modifiers/modifiers_misc.dm
@@ -426,4 +426,14 @@ the artifact triggers the rage.
heat_protection = -0.5
cold_protection = -0.5
- siemens_coefficient = 1.5
\ No newline at end of file
+ siemens_coefficient = 1.5
+
+/datum/modifier/entangled
+ name = "entangled"
+ desc = "Its hard to move."
+
+ on_created_text = "You're caught in something! It's hard to move."
+ on_expired_text = "Your movement is freed."
+ stacks = MODIFIER_STACK_EXTEND
+
+ slowdown = 2
diff --git a/code/modules/mob/living/silicon/robot/robot_modules/syndicate.dm b/code/modules/mob/living/silicon/robot/robot_modules/syndicate.dm
index 7c6f22d6b9..fe39040432 100644
--- a/code/modules/mob/living/silicon/robot/robot_modules/syndicate.dm
+++ b/code/modules/mob/living/silicon/robot/robot_modules/syndicate.dm
@@ -37,6 +37,12 @@
src.modules += new /obj/item/weapon/pinpointer/shuttle/merc(src)
src.modules += new /obj/item/weapon/melee/energy/sword(src)
+ var/datum/matter_synth/cloth = new /datum/matter_synth/cloth(40000)
+ synths += cloth
+
+ var/obj/item/stack/sandbags/cyborg/SB = new /obj/item/stack/sandbags/cyborg(src)
+ SB.synths += list(cloth)
+
var/jetpack = new/obj/item/weapon/tank/jetpack/carbondioxide(src)
src.modules += jetpack
R.internals = jetpack
diff --git a/code/modules/power/cells/esoteric_cells.dm b/code/modules/power/cells/esoteric_cells.dm
new file mode 100644
index 0000000000..b45c19a783
--- /dev/null
+++ b/code/modules/power/cells/esoteric_cells.dm
@@ -0,0 +1,74 @@
+
+/obj/item/weapon/cell/spike
+ name = "modified power cell"
+ desc = "A modified power cell sitting in a highly conductive chassis."
+ origin_tech = list(TECH_POWER = 2)
+ icon_state = "spikecell"
+ maxcharge = 10000
+ matter = list(DEFAULT_WALL_MATERIAL = 1000, MAT_GLASS = 80, MAT_SILVER = 100)
+ self_recharge = TRUE
+ charge_amount = 150
+
+/obj/item/weapon/cell/spike/process()
+ ..()
+
+ var/turf/Center = get_turf(src)
+
+ var/shock_count = 0
+ for(var/turf/T in range(Center, 1))
+
+ if(prob(round(charge / 250)) && charge >= (maxcharge / 4))
+
+ if(locate(/obj/effect/temporary_effect/pulse/staticshock) in T)
+ continue
+
+ var/conductive = FALSE
+
+ if(istype(T, /turf/simulated/wall))
+ var/turf/simulated/wall/WT = T
+
+ if(WT.material.conductive)
+ conductive = TRUE
+ else if(WT.girder_material.conductive)
+ conductive = TRUE
+ else if(WT.reinf_material && WT.reinf_material.conductive)
+ conductive = TRUE
+
+ if(istype(T, /turf/simulated/floor))
+ var/turf/simulated/floor/F = T
+ if(istype(F.flooring, /decl/flooring/reinforced))
+ conductive = TRUE
+
+ if(conductive)
+ shock_count += 1
+ new /obj/effect/temporary_effect/pulse/staticshock(T)
+
+ if(shock_count)
+ while(shock_count)
+ use(200)
+ shock_count--
+
+/obj/effect/temporary_effect/pulse/staticshock
+ name = "electric field"
+ desc = "Caution: Do not touch."
+ pulses_remaining = 10
+ pulse_delay = 2 SECONDS
+ icon_state = "blue_static"
+
+/obj/effect/temporary_effect/pulse/staticshock/on_pulse()
+ ..()
+
+ for(var/mob/living/L in view(1, src))
+ if(!issilicon(L) && prob(L.mob_size))
+ var/obj/item/projectile/beam/shock/weak/P = new (get_turf(src))
+ P.launch_projectile_from_turf(L, BP_TORSO)
+
+ var/obj/item/weapon/plastique/C4 = locate() in get_turf(src)
+
+ if(C4)
+ C4.visible_message("The current fries \the [C4]!")
+
+ if(prob(10))
+ C4.explode(get_turf(src))
+ else
+ qdel(C4)
diff --git a/code/modules/projectiles/projectile/beams.dm b/code/modules/projectiles/projectile/beams.dm
index 41430bea38..8c888fee3e 100644
--- a/code/modules/projectiles/projectile/beams.dm
+++ b/code/modules/projectiles/projectile/beams.dm
@@ -261,3 +261,7 @@
agony = 15
eyeblur = 2
hitsound = 'sound/weapons/zapbang.ogg'
+
+/obj/item/projectile/beam/shock/weak
+ damage = 5
+ agony = 10
diff --git a/icons/effects/effects.dmi b/icons/effects/effects.dmi
index e8905467f6..f578e1f9ac 100644
Binary files a/icons/effects/effects.dmi and b/icons/effects/effects.dmi differ
diff --git a/icons/obj/power.dmi b/icons/obj/power.dmi
index 732bb44e00..c806ec99be 100644
Binary files a/icons/obj/power.dmi and b/icons/obj/power.dmi differ
diff --git a/icons/obj/sandbags.dmi b/icons/obj/sandbags.dmi
new file mode 100644
index 0000000000..0a5c24598a
Binary files /dev/null and b/icons/obj/sandbags.dmi differ
diff --git a/icons/obj/trap.dmi b/icons/obj/trap.dmi
new file mode 100644
index 0000000000..108bc46726
Binary files /dev/null and b/icons/obj/trap.dmi differ
diff --git a/vorestation.dme b/vorestation.dme
index 5d1aabd37b..a9ecbfab29 100644
--- a/vorestation.dme
+++ b/vorestation.dme
@@ -1194,6 +1194,7 @@
#include "code\game\objects\items\stacks\nanopaste.dm"
#include "code\game\objects\items\stacks\nanopaste_vr.dm"
#include "code\game\objects\items\stacks\rods.dm"
+#include "code\game\objects\items\stacks\sandbags.dm"
#include "code\game\objects\items\stacks\stack.dm"
#include "code\game\objects\items\stacks\telecrystal.dm"
#include "code\game\objects\items\stacks\tickets.dm"
@@ -1385,6 +1386,7 @@
#include "code\game\objects\random\mob_vr.dm"
#include "code\game\objects\random\spacesuits.dm"
#include "code\game\objects\random\unidentified\medicine.dm"
+#include "code\game\objects\structures\barricades.dm"
#include "code\game\objects\structures\barsign.dm"
#include "code\game\objects\structures\bedsheet_bin.dm"
#include "code\game\objects\structures\bedsheet_bin_vr.dm"
@@ -3184,7 +3186,11 @@
#include "code\modules\power\antimatter\control.dm"
#include "code\modules\power\antimatter\shielding.dm"
#include "code\modules\power\cells\device_cells.dm"
+<<<<<<< HEAD:vorestation.dme
#include "code\modules\power\cells\device_cells_vr.dm"
+=======
+#include "code\modules\power\cells\esoteric_cells.dm"
+>>>>>>> bd9f63a... Gadgets & Gizmos (#7786):polaris.dme
#include "code\modules\power\cells\power_cells.dm"
#include "code\modules\power\fusion\_setup.dm"
#include "code\modules\power\fusion\fusion_circuits.dm"