diff --git a/code/__DEFINES/components.dm b/code/__DEFINES/components.dm
index 3338fc1cda..dbe8cfbb62 100644
--- a/code/__DEFINES/components.dm
+++ b/code/__DEFINES/components.dm
@@ -142,8 +142,9 @@
#define COMSIG_CARBON_SOUNDBANG "carbon_soundbang" //from base of mob/living/carbon/soundbang_act(): (list(intensity))
// /obj signals
-#define COMSIG_OBJ_DECONSTRUCT "obj_deconstruct" //from base of obj/deconstruct(): (disassembled)
-#define COMSIG_OBJ_SETANCHORED "obj_setanchored" //called in /obj/structure/setAnchored(): (value)
+#define COMSIG_OBJ_DECONSTRUCT "obj_deconstruct" //from base of obj/deconstruct(): (disassembled)
+#define COMSIG_OBJ_BREAK "obj_break" //from base of /obj/obj_break(): (damage_flag)
+#define COMSIG_OBJ_SETANCHORED "obj_setanchored" //called in /obj/structure/setAnchored(): (value)
// /obj/item signals
#define COMSIG_ITEM_ATTACK "item_attack" //from base of obj/item/attack(): (/mob/living/target, /mob/living/user)
diff --git a/code/datums/components/storage/concrete/_concrete.dm b/code/datums/components/storage/concrete/_concrete.dm
index 4d7e8bddc5..0b78605869 100644
--- a/code/datums/components/storage/concrete/_concrete.dm
+++ b/code/datums/components/storage/concrete/_concrete.dm
@@ -6,6 +6,8 @@
/datum/component/storage/concrete
var/drop_all_on_deconstruct = TRUE
var/drop_all_on_destroy = FALSE
+ var/drop_all_on_break = FALSE
+ var/unlock_on_break = FALSE
var/transfer_contents_on_component_transfer = FALSE
var/list/datum/component/storage/slaves = list()
@@ -16,6 +18,7 @@
. = ..()
RegisterSignal(parent, COMSIG_ATOM_CONTENTS_DEL, .proc/on_contents_del)
RegisterSignal(parent, COMSIG_OBJ_DECONSTRUCT, .proc/on_deconstruct)
+ RegisterSignal(parent, COMSIG_OBJ_BREAK, .proc/on_break)
/datum/component/storage/concrete/Destroy()
var/atom/real_location = real_location()
@@ -100,6 +103,12 @@
if(drop_all_on_deconstruct)
do_quick_empty()
+/datum/component/storage/concrete/proc/on_break(datum/source, damage_flag)
+ if(drop_all_on_break)
+ do_quick_empty()
+ if(unlock_on_break)
+ set_locked(source, FALSE)
+
/datum/component/storage/concrete/can_see_contents()
. = ..()
for(var/i in slaves)
diff --git a/code/datums/components/storage/concrete/emergency.dm b/code/datums/components/storage/concrete/emergency.dm
new file mode 100644
index 0000000000..e5f9d83a17
--- /dev/null
+++ b/code/datums/components/storage/concrete/emergency.dm
@@ -0,0 +1,22 @@
+/datum/component/storage/concrete/emergency
+ drop_all_on_break = TRUE
+ unlock_on_break = TRUE
+ locked = TRUE
+
+/datum/component/storage/concrete/emergency/Initialize()
+ . = ..()
+ RegisterSignal(parent, COMSIG_ATOM_EMAG_ACT, .proc/unlock_me)
+
+/datum/component/storage/concrete/emergency/signal_insertion_attempt(datum/source, obj/item/I, mob/M, silent = FALSE, force = FALSE)
+ if(!silent && istype(I, /obj/item/card/emag))
+ silent = TRUE // suppresses the message
+ return ..()
+
+/datum/component/storage/concrete/check_locked(datum/source, mob/user, message = FALSE)
+ . = locked && GLOB.security_level < SEC_LEVEL_RED
+ if(message && . && user)
+ to_chat(user, "The storage unit will only unlock during a Red or Delta security alert.")
+
+/datum/component/storage/concrete/emergency/proc/unlock_me(datum/source)
+ if(locked)
+ set_locked(source, FALSE)
diff --git a/code/datums/components/storage/storage.dm b/code/datums/components/storage/storage.dm
index dc25729e37..869fe59ae9 100644
--- a/code/datums/components/storage/storage.dm
+++ b/code/datums/components/storage/storage.dm
@@ -156,8 +156,7 @@
next += slave.parent
/datum/component/storage/proc/attack_self(datum/source, mob/M)
- if(locked)
- to_chat(M, "[parent] seems to be locked!")
+ if(check_locked(source, M, TRUE))
return FALSE
if((M.get_active_held_item() == parent) && allow_quick_empty)
quick_empty(M)
@@ -166,8 +165,7 @@
if(!isitem(O) || !click_gather || SEND_SIGNAL(O, COMSIG_CONTAINS_STORAGE))
return FALSE
. = COMPONENT_NO_ATTACK
- if(locked)
- to_chat(M, "[parent] seems to be locked!")
+ if(check_locked(source, M, TRUE))
return FALSE
var/atom/A = parent
var/obj/item/I = O
@@ -238,8 +236,7 @@
var/atom/A = parent
if((!ishuman(M) && (A.loc != M)) || (M.stat != CONSCIOUS) || M.restrained() || !M.canmove)
return
- if(locked)
- to_chat(M, "[parent] seems to be locked!")
+ if(check_locked(null, M, TRUE))
return FALSE
A.add_fingerprint(M)
to_chat(M, "You start dumping out [parent].")
@@ -281,7 +278,7 @@
/datum/component/storage/proc/set_locked(datum/source, new_state)
locked = new_state
- if(locked)
+ if(check_locked())
close_all()
/datum/component/storage/proc/_process_numerical_display()
@@ -456,8 +453,7 @@
var/atom/A = parent
var/atom/dump_destination = dest_object.get_dumping_location()
if(A.Adjacent(M) && dump_destination && M.Adjacent(dump_destination))
- if(locked)
- to_chat(M, "[parent] seems to be locked!")
+ if(check_locked(null, M, TRUE))
return FALSE
if(dump_destination.storage_contents_dump_act(src, M))
playsound(A, "rustle", 50, 1, -5)
@@ -563,10 +559,9 @@
var/atom/host = parent
if(real_location == I.loc)
return FALSE //Means the item is already in the storage item
- if(locked)
+ if(check_locked(null, M, !stop_messages))
if(M && !stop_messages)
host.add_fingerprint(M)
- to_chat(M, "[host] seems to be locked!")
return FALSE
if(real_location.contents.len >= max_items)
if(!stop_messages)
@@ -659,8 +654,10 @@
/datum/component/storage/proc/on_check()
return TRUE
-/datum/component/storage/proc/check_locked()
- return locked
+/datum/component/storage/proc/check_locked(datum/source, mob/user, message = FALSE)
+ . = locked
+ if(message && . && user)
+ to_chat(user, "[parent] seems to be locked!")
/datum/component/storage/proc/signal_take_type(datum/source, type, atom/destination, amount = INFINITY, check_adjacent = FALSE, force = FALSE, mob/user, list/inserted)
if(!force)
@@ -720,9 +717,7 @@
if(A.loc == user)
. = COMPONENT_NO_ATTACK_HAND
- if(locked)
- to_chat(user, "[parent] seems to be locked!")
- else
+ if(!check_locked(source, user, TRUE))
show_to(user)
A.do_jiggle()
@@ -747,8 +742,7 @@
/datum/component/storage/proc/on_alt_click(datum/source, mob/user)
if(!isliving(user) || !user.CanReach(parent))
return
- if(locked)
- to_chat(user, "[parent] seems to be locked!")
+ if(check_locked(source, user, TRUE))
return
var/atom/A = parent
diff --git a/code/game/objects/items/cards_ids.dm b/code/game/objects/items/cards_ids.dm
index 30b1ca3399..96bbe759ca 100644
--- a/code/game/objects/items/cards_ids.dm
+++ b/code/game/objects/items/cards_ids.dm
@@ -105,7 +105,7 @@
if(isturf(A))
return
- if(istype(A,/obj/item/storage/lockbox))
+ if(istype(A,/obj/item/storage/lockbox) || istype(A, /obj/item/storage/pod))
A.emag_act(user)
uses = max(uses - 1, 0)
if(!uses)
diff --git a/code/game/objects/obj_defense.dm b/code/game/objects/obj_defense.dm
index 6221416db8..2db2cd08d8 100644
--- a/code/game/objects/obj_defense.dm
+++ b/code/game/objects/obj_defense.dm
@@ -241,6 +241,7 @@ GLOBAL_DATUM_INIT(acid_overlay, /mutable_appearance, mutable_appearance('icons/e
//what happens when the obj's health is below integrity_failure level.
/obj/proc/obj_break(damage_flag)
+ SEND_SIGNAL(src, COMSIG_OBJ_BREAK, damage_flag)
return
//what happens when the obj's integrity reaches zero.
diff --git a/code/modules/shuttle/emergency.dm b/code/modules/shuttle/emergency.dm
index 9af4194049..d41fd6a79b 100644
--- a/code/modules/shuttle/emergency.dm
+++ b/code/modules/shuttle/emergency.dm
@@ -516,10 +516,10 @@
name = "emergency space suits"
desc = "A wall mounted safe containing space suits. Will only open in emergencies."
anchored = TRUE
- density = FALSE
icon = 'icons/obj/storage.dmi'
icon_state = "safe"
- var/unlocked = FALSE
+ integrity_failure = 100
+ component_type = /datum/component/storage/concrete/emergency
/obj/item/storage/pod/PopulateContents()
new /obj/item/clothing/head/helmet/space/orange(src)
@@ -535,26 +535,6 @@
new /obj/item/survivalcapsule(src)
new /obj/item/storage/toolbox/emergency(src)
-/obj/item/storage/pod/attackby(obj/item/W, mob/user, params)
- if (can_interact(user))
- return ..()
-
-/obj/item/storage/pod/attack_hand(mob/user)
- if (can_interact(user))
- SEND_SIGNAL(src, COMSIG_TRY_STORAGE_SHOW, user)
- return TRUE
-
-/obj/item/storage/pod/MouseDrop(over_object, src_location, over_location)
- if(can_interact(usr))
- return ..()
-
-/obj/item/storage/pod/can_interact(mob/user)
- if(!..())
- return FALSE
- if(GLOB.security_level == SEC_LEVEL_RED || GLOB.security_level == SEC_LEVEL_DELTA || unlocked)
- return TRUE
- to_chat(user, "The storage unit will only unlock during a Red or Delta security alert.")
-
/obj/docking_port/mobile/emergency/backup
name = "backup shuttle"
id = "backup"
diff --git a/code/modules/shuttle/on_move.dm b/code/modules/shuttle/on_move.dm
index 9942446868..a6904c28cc 100644
--- a/code/modules/shuttle/on_move.dm
+++ b/code/modules/shuttle/on_move.dm
@@ -290,7 +290,8 @@ All ShuttleMove procs go here
// ignores the movement of the shuttle from the staging area on CentCom to
// the station as it is loaded in.
if (oldT && !is_centcom_level(oldT.z))
- unlocked = TRUE
+ GET_COMPONENT(STR, /datum/component/storage/concrete/emergency)
+ STR?.unlock_me()
/************************************Mob move procs************************************/
diff --git a/tgstation.dme b/tgstation.dme
index c9098249b0..cbbec7f02d 100755
--- a/tgstation.dme
+++ b/tgstation.dme
@@ -380,6 +380,7 @@
#include "code\datums\components\storage\concrete\_concrete.dm"
#include "code\datums\components\storage\concrete\bag_of_holding.dm"
#include "code\datums\components\storage\concrete\bluespace.dm"
+#include "code\datums\components\storage\concrete\emergency.dm"
#include "code\datums\components\storage\concrete\implant.dm"
#include "code\datums\components\storage\concrete\pockets.dm"
#include "code\datums\components\storage\concrete\rped.dm"