diff --git a/aurora.dme b/aurora.dme
index 97e737de..1e11d8f1 100644
--- a/aurora.dme
+++ b/aurora.dme
@@ -39,6 +39,7 @@
#define FILE_DIR "icons/obj/clothing/species/tajaran"
#define FILE_DIR "icons/obj/clothing/species/unathi"
#define FILE_DIR "icons/obj/custom_items"
+#define FILE_DIR "icons/obj/door_braces"
#define FILE_DIR "icons/obj/doors"
#define FILE_DIR "icons/obj/flora"
#define FILE_DIR "icons/obj/machines"
@@ -567,6 +568,7 @@
#include "code\game\objects\items\devices\binoculars.dm"
#include "code\game\objects\items\devices\chameleonproj.dm"
#include "code\game\objects\items\devices\debugger.dm"
+#include "code\game\objects\items\devices\door_bracer.dm"
#include "code\game\objects\items\devices\flash.dm"
#include "code\game\objects\items\devices\flashlight.dm"
#include "code\game\objects\items\devices\isocube.dm"
diff --git a/code/datums/supplypacks.dm b/code/datums/supplypacks.dm
index 696fb288..6da7f62f 100644
--- a/code/datums/supplypacks.dm
+++ b/code/datums/supplypacks.dm
@@ -1345,3 +1345,23 @@ var/list/all_supply_groups = list("Operations","Security","Hospitality","Enginee
containername = "Pill Bottle Kit"
access = access_medical
group = "Medical / Science"
+
+/datum/supply_packs/doorbracers_engineering
+ name = "Engineering Doorbracer Crate"
+ contains = list(/obj/item/device/doorbrace/engineering,
+ /obj/item/device/doorbrace/engineering,
+ /obj/item/device/doorbrace/engineering)
+ cost = 30
+ containertype = /obj/structure/closet/crate
+ containername = "engineering doorbracers"
+ group = "Engineering"
+
+/datum/supply_packs/doorbracers_security
+ name = "Security Doorbracer Crate"
+ contains = list(/obj/item/device/doorbrace/security,
+ /obj/item/device/doorbrace/security,
+ /obj/item/device/doorbrace/security)
+ cost = 30
+ containertype = /obj/structure/closet/crate
+ containername = "security doorbracers"
+ group = "Security"
diff --git a/code/game/machinery/doors/airlock.dm b/code/game/machinery/doors/airlock.dm
index 8b49259e..4712c727 100644
--- a/code/game/machinery/doors/airlock.dm
+++ b/code/game/machinery/doors/airlock.dm
@@ -51,6 +51,7 @@
var/door_sound='sound/machines/airlock.ogg'
var/door_sound_distance=30
autoclose = 1
+ var/obj/item/device/doorbrace/bracer = null
/obj/machinery/door/airlock/command
name = "Airlock"
@@ -717,6 +718,15 @@ About the new airlock wires panel:
set_frequency(ST.change_freq(frequency))
return
+ if (istype(C, /obj/item/device/doorbrace))
+ if (bracer)
+ user << "There is already a [bracer] on [src]!"
+ return
+
+ var/obj/item/device/doorbrace/newbracer = C
+ newbracer.attachto(src, user)
+ return
+
src.add_fingerprint(user)
if((istype(C, /obj/item/weapon/weldingtool) && !( src.operating > 0 ) && src.density))
var/obj/item/weapon/weldingtool/W = C
@@ -824,7 +834,10 @@ About the new airlock wires panel:
playsound(src.loc, door_sound, door_sound_distance, 1)
/obj/machinery/door/airlock/open(var/forced=0)
- if( operating || welded || locked )
+ if( operating || welded || locked)
+ return 0
+ if (bracer)
+ visible_message("[src]'s actuators whirr, but the door does not open.")
return 0
if(!forced)
if( !arePowerSystemsOn() || isWireCut(AIRLOCK_WIRE_OPEN_DOOR) )
@@ -915,7 +928,9 @@ About the new airlock wires panel:
break
/obj/machinery/door/airlock/proc/prison_open()
+ if (bracer)
+ return
src.unlock()
src.open()
src.lock()
- return
\ No newline at end of file
+ return
diff --git a/code/game/objects/items/devices/door_bracer.dm b/code/game/objects/items/devices/door_bracer.dm
new file mode 100644
index 00000000..8c45f2cf
--- /dev/null
+++ b/code/game/objects/items/devices/door_bracer.dm
@@ -0,0 +1,289 @@
+#define STATUS_INACTIVE 0
+#define STATUS_ACTIVE 1
+#define STATUS_BROKEN 2
+
+#define LAYER_ATTACHED 3.2
+#define LAYER_NORMAL 3
+
+/obj/item/device/doorbrace
+ name = "magnetic door lock"
+ desc = "A large, ID locked device used for completely locking down airlocks."
+ icon = 'icons/obj/door_braces/centcom.dmi'
+ icon_state = "inactive"
+ w_class = 3
+ req_access = list(103)
+ health = 90
+
+ var/department = "CENTCOM"
+ var/status = 0
+ var/constructionstate = 0
+ var/obj/machinery/door/airlock/target = null
+
+/obj/item/device/doorbrace/security
+ icon = 'icons/obj/door_braces/security.dmi'
+ department = "Security"
+ req_access = list(1)
+
+/obj/item/device/doorbrace/engineering
+ icon = 'icons/obj/door_braces/engineering.dmi'
+ department = "Engineering"
+ req_access = null
+ req_one_access = list(11, 24)
+
+/obj/item/device/doorbrace/examine()
+ ..()
+
+ if (status == STATUS_BROKEN)
+ usr << "It looks broken!"
+ else
+ usr << "\blue This device has [department] department markings on it."
+
+/obj/item/device/doorbrace/attack_hand(var/mob/user)
+ if (status == STATUS_ACTIVE)
+ ui_interact(user)
+ else
+ ..()
+
+/obj/item/device/doorbrace/bullet_act(var/obj/item/projectile/Proj)
+ takedamage(Proj.damage)
+ ..()
+
+/obj/item/device/doorbrace/attackby(var/obj/item/I, var/mob/user)
+ if (status == STATUS_BROKEN)
+ user << "[src] is broken beyond repair!"
+ return
+
+ if (istype(I, /obj/item/weapon) && user.a_intent == "hurt")
+ if (I.force >= 8)
+ user.visible_message("[user] bashes [src] with [I]!", "You strike [src] with [I], damaging it!")
+ takedamage(I.force)
+ return
+ else
+ user.visible_message("[user] hits [src] with [I] to no visible effect.", "You hit [src] with [I], but it appears to have no effect.")
+ return
+
+ switch (constructionstate)
+ if (0)
+ if (istype(I, /obj/item/weapon/card/emag))
+ var/obj/item/weapon/card/emag/emagcard = I
+ emagcard.uses--
+ visible_message("[src] sparks and falls off the door!", "You emag [src], frying its circuitry[status == STATUS_ACTIVE ? " and making it drop onto the floor" : ""]!")
+
+ setstatus(STATUS_BROKEN)
+ return
+
+ if (status == STATUS_ACTIVE && istype(I, /obj/item/weapon/card/id))
+ if (check_access(I) && !constructionstate)
+ user << "You swipe your [I] through [src], making it drop onto the floor with a thud."
+ setstatus(STATUS_INACTIVE)
+ return
+ else if (constructionstate)
+ user << "You cannot swipe your [I] through [src] with it partially dismantled!"
+ return
+ else
+ user << "A red light flashes on [src] as you swipe your [I] through it."
+ flick("deny",src)
+ return
+
+ if (istype(I, /obj/item/weapon/screwdriver))
+ user << "You unfasten and remove the plastic cover from [src], revealing a thick metal shell."
+ playsound(loc, 'sound/items/Screwdriver.ogg', 50, 1)
+ setconstructionstate(1)
+ return
+
+ if (1)
+ if (istype(I, /obj/item/weapon/screwdriver))
+ user << "You put the metal cover of back onto [src], and screw it tight."
+ playsound(loc, 'sound/items/Screwdriver.ogg', 50, 1)
+ setconstructionstate(0)
+ return
+ if (istype(I, /obj/item/weapon/weldingtool))
+ var/obj/item/weapon/weldingtool/WT = I
+ if (WT.remove_fuel(1, user))
+ user.visible_message("[user] starts welding through the metal shell of [src].", "You start welding through the metal covering of [src]")
+ playsound(loc, 'sound/items/Welder.ogg', 50, 1)
+ if (do_after(user, 25))
+ user << "You are able to weld through the metal shell of [src]."
+ setconstructionstate(2)
+ return
+ if (2)
+ if (istype(I, /obj/item/weapon/crowbar))
+ user << "You pry off the metal covering from [src]."
+ playsound(loc, 'sound/items/Crowbar.ogg', 50, 1)
+ setconstructionstate(3)
+ return
+ if (3)
+ if (istype(I, /obj/item/weapon/wirecutters))
+ user << "You cut the wires connecting the [src]'s magnets to their powersupply, [target ? "making the device fall off [target] and rendering it unusable." : "rendering the device unusable."]"
+ playsound(loc, 'sound/items/Wirecutter.ogg', 50, 1)
+ setconstructionstate(4)
+ return
+
+/obj/item/device/doorbrace/proc/attachto(var/obj/machinery/door/airlock/newtarget, var/mob/user as mob)
+ if (status == STATUS_BROKEN)
+ user << "[src] is damaged beyond repair! It cannot be used!"
+ return
+
+ if (!newtarget.density || newtarget.operating)
+ user << "[newtarget] must be closed before you can attach [src] to it!"
+ return
+
+ if (newtarget.p_open)
+ user << "You must close [newtarget]'s maintenance panel before attaching [src] to it!"
+ return
+
+ user.visible_message("[user] starts mounting [src] onto [newtarget].", "You begin mounting [src] onto [newtarget].")
+ if (do_after(user, 35, 1))
+ if (status == STATUS_BROKEN)
+ user << "[src] is damaged beyond repair! It cannot be used!"
+ return
+
+ if (!newtarget.density)
+ user << "[newtarget] must be closed before you can attach [src] to it!"
+ return
+
+ if (newtarget.p_open)
+ user << "You must close [newtarget]'s maintenance panel before attaching [src] to it!"
+ return
+
+ user.visible_message("[user] attached [src] onto [newtarget] and flicks it on. The magnetic lock now seals [newtarget].", "You attached [src] onto [newtarget] and switched on the magnetic lock.")
+ user.drop_item()
+
+ setstatus(STATUS_ACTIVE, newtarget)
+ return
+
+/obj/item/device/doorbrace/proc/setstatus(var/newstatus, var/obj/machinery/door/airlock/newtarget as obj)
+ switch (newstatus)
+ if (STATUS_INACTIVE)
+ if (status != STATUS_ACTIVE)
+ return
+ if (!target)
+ return
+
+ detach()
+ icon_state = "inactive"
+ status = newstatus
+
+ if (STATUS_ACTIVE)
+ if (status != STATUS_INACTIVE)
+ return
+ if (!newtarget)
+ return
+
+ attach(newtarget)
+ icon_state = "active"
+ status = newstatus
+
+ if (STATUS_BROKEN)
+ spark()
+
+ if (target)
+ var/playflick = 1
+ if (constructionstate)
+ playflick = 0
+
+ detach(playflick)
+
+ icon_state = "broken"
+ status = newstatus
+
+/obj/item/device/doorbrace/proc/setconstructionstate(var/newstate)
+ constructionstate = newstate
+ if (newstate == 0)
+ if (status == STATUS_ACTIVE)
+ icon_state = "active"
+ else
+ icon_state = "inactive"
+ else if (newstate == 2)
+ flick("deconstruct_2_anim", src)
+ else if (newstate == 4)
+ setstatus(STATUS_BROKEN)
+ else
+ icon_state = "deconstruct_[constructionstate]"
+
+/obj/item/device/doorbrace/proc/detach(var/playflick = 1)
+ if (target)
+
+ if (playflick)
+ spawn(-15) flick("release", src)
+
+ adjustsprite(null)
+ layer = LAYER_NORMAL
+
+ target.bracer = null
+
+ anchored = 0
+
+/obj/item/device/doorbrace/proc/attach(var/obj/machinery/door/airlock/newtarget as obj)
+ adjustsprite(newtarget)
+ layer = LAYER_ATTACHED
+ flick("deploy", src)
+
+ newtarget.bracer = src
+ target = newtarget
+
+ anchored = 1
+
+/obj/item/device/doorbrace/proc/adjustsprite(var/obj/target as obj)
+ if (target)
+ switch (get_dir(src, target))
+ if (NORTH)
+ pixel_x = 0
+ pixel_y = 32
+ if (NORTHEAST)
+ pixel_x = 32
+ pixel_y = 32
+ if (EAST)
+ pixel_x = 32
+ pixel_y = 0
+ if (SOUTHEAST)
+ pixel_x = 32
+ pixel_y = -32
+ if (SOUTH)
+ pixel_x = 0
+ pixel_y = -32
+ if (SOUTHWEST)
+ pixel_x = -32
+ pixel_y = -32
+ if (WEST)
+ pixel_x = -32
+ pixel_y = 0
+ if (NORTHWEST)
+ pixel_x = -32
+ pixel_y = 32
+ else
+ pixel_x = 0
+ pixel_y = 0
+
+/obj/item/device/doorbrace/proc/takedamage(var/damage)
+ health -= damage
+
+ if (damage >= 40 && prob(50))
+ health = 0
+
+ if (health <= 0)
+ visible_message("[src] sparks[target ? " and falls off of \the [target]!" : "!"] It is now completely unusable!")
+ setstatus(STATUS_BROKEN)
+ return
+
+ if (prob(50))
+ spark()
+
+/obj/item/device/doorbrace/proc/spark()
+ var/datum/effect/effect/system/spark_spread/s = new /datum/effect/effect/system/spark_spread
+
+ if (target)
+ s.set_up(5, 1, target)
+ else
+ s.set_up(5, 1, src)
+
+ s.start()
+ spawn(5)
+ del(s)
+
+#undef STATUS_INACTIVE
+#undef STATUS_ACTIVE
+#undef STATUS_BROKEN
+
+#undef LAYER_ATTACHED
+#undef LAYER_NORMAL
diff --git a/icons/obj/door_braces/centcom.dmi b/icons/obj/door_braces/centcom.dmi
new file mode 100644
index 00000000..97a97794
Binary files /dev/null and b/icons/obj/door_braces/centcom.dmi differ
diff --git a/icons/obj/door_braces/engineering.dmi b/icons/obj/door_braces/engineering.dmi
new file mode 100644
index 00000000..49323f4a
Binary files /dev/null and b/icons/obj/door_braces/engineering.dmi differ
diff --git a/icons/obj/door_braces/security.dmi b/icons/obj/door_braces/security.dmi
new file mode 100644
index 00000000..00a820fb
Binary files /dev/null and b/icons/obj/door_braces/security.dmi differ
diff --git a/maps/tgstation2.dmm b/maps/tgstation2.dmm
index af54753e..a954fa60 100644
--- a/maps/tgstation2.dmm
+++ b/maps/tgstation2.dmm
@@ -638,7 +638,7 @@
"amn" = (/obj/structure/rack,/obj/item/clothing/mask/gas{pixel_x = 3; pixel_y = 3},/obj/item/clothing/mask/gas{pixel_x = 3; pixel_y = 3},/obj/item/clothing/mask/gas,/obj/item/clothing/mask/gas,/obj/item/clothing/mask/gas{pixel_x = -3; pixel_y = -3},/obj/item/clothing/mask/gas{pixel_x = -3; pixel_y = -3},/obj/structure/window/reinforced{dir = 4},/obj/item/device/binoculars,/obj/item/device/binoculars,/turf/simulated/floor{icon_state = "bot"; dir = 1},/area/security/armoury)
"amo" = (/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers,/turf/simulated/floor{dir = 1; icon_state = "warning"},/area/security/armoury)
"amp" = (/obj/structure/cable{d1 = 1; d2 = 2; icon_state = "1-2"},/obj/machinery/atmospherics/pipe/simple/hidden/supply,/turf/simulated/floor{dir = 1; icon_state = "warning"},/area/security/armoury)
-"amq" = (/obj/machinery/light_switch{pixel_y = 28},/obj/machinery/atmospherics/pipe/simple/hidden/supply{dir = 6},/turf/simulated/floor,/area/security/armoury)
+"amq" = (/obj/machinery/light_switch{pixel_y = 28},/obj/machinery/atmospherics/pipe/simple/hidden/supply{dir = 6},/obj/structure/rack,/obj/item/device/doorbrace/security{pixel_x = 5; pixel_y = -5},/obj/item/device/doorbrace/security,/obj/item/device/doorbrace/security{pixel_x = -5; pixel_y = 5},/turf/simulated/floor,/area/security/armoury)
"amr" = (/obj/structure/dispenser{plasmatanks = 0},/obj/machinery/alarm{locked = 1; pixel_y = 23},/obj/machinery/atmospherics/unary/vent_pump/on{tag = "icon-map_vent_out (WEST)"; icon_state = "map_vent_out"; dir = 8},/obj/machinery/camera{dir = 8},/turf/simulated/floor{icon_state = "bot"},/area/security/armoury)
"ams" = (/obj/structure/cable{d1 = 1; d2 = 4; icon_state = "1-4"},/obj/structure/cable{d1 = 2; d2 = 4; icon_state = "2-4"},/turf/simulated/floor/plating/airless,/area/solar/auxport)
"amt" = (/obj/structure/cable{d1 = 4; d2 = 8; icon_state = "4-8"; pixel_x = 0},/obj/structure/cable{d1 = 1; d2 = 4; icon_state = "1-4"},/obj/structure/cable{d1 = 2; d2 = 4; icon_state = "2-4"},/turf/simulated/floor/plating/airless,/area/solar/auxport)
@@ -6605,7 +6605,7 @@
"cxa" = (/obj/structure/stool,/obj/machinery/light/small{dir = 4},/turf/simulated/floor/plating,/area/maintenance/aft)
"cxb" = (/obj/structure/grille,/obj/structure/window/reinforced{dir = 1},/obj/structure/window/reinforced{dir = 4},/obj/structure/window/reinforced,/turf/simulated/floor/plating,/area/maintenance/aft)
"cxc" = (/turf/simulated/wall/r_wall,/area/engine/storage_hard)
-"cxd" = (/obj/machinery/power/apc{dir = 8; name = "Engineering Storage APC"; pixel_x = -26; pixel_y = 3},/obj/structure/cable{icon_state = "0-4"; d2 = 4},/turf/simulated/floor,/area/engine/storage)
+"cxd" = (/obj/machinery/power/apc{dir = 8; name = "Engineering Storage APC"; pixel_x = -26; pixel_y = 3},/obj/structure/cable{icon_state = "0-4"; d2 = 4},/obj/structure/table/reinforced{icon_state = "table"},/obj/item/device/doorbrace/engineering{pixel_x = 5; pixel_y = -5},/obj/item/device/doorbrace/engineering,/obj/item/device/doorbrace/engineering{pixel_x = -5; pixel_y = 5},/turf/simulated/floor,/area/engine/storage)
"cxe" = (/obj/structure/cable{d1 = 1; d2 = 2; icon_state = "1-2"},/obj/structure/cable{d1 = 1; d2 = 8; icon_state = "1-8"},/obj/machinery/atmospherics/pipe/simple/hidden/supply,/obj/machinery/atmospherics/pipe/manifold/hidden/scrubbers{tag = "icon-map-scrubbers (WEST)"; icon_state = "map-scrubbers"; dir = 8},/turf/simulated/floor,/area/engine/storage)
"cxf" = (/obj/structure/disposalpipe/segment,/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{tag = "icon-intact-scrubbers (EAST)"; icon_state = "intact-scrubbers"; dir = 4},/turf/simulated/floor,/area/engine/storage)
"cxg" = (/obj/structure/table,/obj/item/weapon/airlock_electronics,/obj/item/weapon/airlock_electronics,/obj/item/weapon/cable_coil,/obj/item/weapon/cable_coil,/obj/item/clothing/glasses/welding,/obj/item/weapon/book/manual/supermatter_engine,/obj/structure/disposalpipe/segment{dir = 1; icon_state = "pipe-c"},/obj/machinery/atmospherics/unary/vent_scrubber/on{tag = "icon-map_scrubber_on (WEST)"; icon_state = "map_scrubber_on"; dir = 8},/turf/simulated/floor,/area/engine/storage)