diff --git a/code/datums/elements/skittish.dm b/code/datums/elements/skittish.dm
new file mode 100644
index 00000000000..f3706c0e286
--- /dev/null
+++ b/code/datums/elements/skittish.dm
@@ -0,0 +1,61 @@
+/*
+ * An element that makes mobs run into lockers when they bump into them.
+ */
+
+/datum/element/skittish
+ element_flags = ELEMENT_DETACH
+
+/datum/element/skittish/Attach(datum/target)
+ . = ..()
+ if(!isliving(target))
+ return ELEMENT_INCOMPATIBLE
+
+ RegisterSignal(target, COMSIG_MOVABLE_BUMP, .proc/Bump)
+
+/datum/element/skittish/Detach(datum/target)
+ UnregisterSignal(target, COMSIG_MOVABLE_BUMP)
+ . = ..()
+
+/datum/element/skittish/proc/Bump(mob/living/scooby, atom/target)
+ if(scooby.stat != CONSCIOUS || scooby.m_intent != MOVE_INTENT_RUN)
+ return
+
+ if(!istype(target, /obj/structure/closet))
+ return
+
+ var/obj/structure/closet/closet = target
+
+ if(!closet.divable)
+ // Things like secure crates can blow up under certain circumstances
+ return
+
+ var/turf/closet_turf = get_turf(closet)
+
+ if(!closet.opened)
+ if(closet.locked)
+ closet.togglelock(scooby, silent = TRUE)
+ if(!closet.open(scooby))
+ // No message if unable to open, since this is on Bump, spammy potential
+ return
+
+ // If it's a crate, "dive for cover" and start resting so people can jump into crates without slamming the lid on their head
+ if(closet.horizontal)
+ // need to rest before moving, otherwise "can't get crate to close" message will be printed erroneously
+ scooby.set_resting(TRUE, silent = TRUE)
+
+ scooby.forceMove(closet_turf)
+
+ if(!closet.close(scooby))
+ to_chat(scooby, "You can't get [closet] to close!")
+ if(closet.horizontal)
+ scooby.set_resting(FALSE, silent = TRUE)
+ return
+
+ closet.togglelock(scooby, silent = TRUE)
+
+ if(closet.horizontal)
+ scooby.set_resting(FALSE, silent = TRUE)
+
+ closet_turf.visible_message("[scooby] dives into [closet]!")
+ // If you run into a locker, you don't want to run out immediately
+ scooby.Immobilize(0.5 SECONDS)
diff --git a/code/datums/traits/good.dm b/code/datums/traits/good.dm
index 8bd59861af0..c0762bac662 100644
--- a/code/datums/traits/good.dm
+++ b/code/datums/traits/good.dm
@@ -188,7 +188,7 @@
/datum/quirk/skittish
name = "Skittish"
- desc = "You can conceal yourself in danger. Ctrl-shift-click a closed locker to jump into it, as long as you have access."
+ desc = "You're easy to startle, and hide frequently. Run into a closed locker to jump into it, as long as you have access. You can walk to avoid this."
value = 8
mob_trait = TRAIT_SKITTISH
medical_record_text = "Patient demonstrates a high aversion to danger and has described hiding in containers out of fear."
diff --git a/code/game/objects/structures/crates_lockers/closets.dm b/code/game/objects/structures/crates_lockers/closets.dm
index fcbb7a135a5..e4d60c849a4 100644
--- a/code/game/objects/structures/crates_lockers/closets.dm
+++ b/code/game/objects/structures/crates_lockers/closets.dm
@@ -37,6 +37,8 @@
var/delivery_icon = "deliverycloset" //which icon to use when packagewrapped. null to be unwrappable.
var/anchorable = TRUE
var/icon_welded = "welded"
+ /// Whether a skittish person can dive inside this closet. Disable if opening the closet causes "bad things" to happen or that it leads to a logical inconsistency.
+ var/divable = TRUE
/obj/structure/closet/Initialize(mapload)
@@ -102,10 +104,9 @@
. += "The parts are welded together."
else if(secure && !opened)
. += "Alt-click to [locked ? "unlock" : "lock"]."
- if(isliving(user))
- var/mob/living/L = user
- if(HAS_TRAIT(L, TRAIT_SKITTISH))
- . += "Ctrl-Shift-click [src] to jump inside."
+
+ if(HAS_TRAIT(user, TRAIT_SKITTISH) && divable)
+ . += "If you bump into [p_them()] while running, you will jump inside."
/obj/structure/closet/CanAllowThrough(atom/movable/mover, turf/target)
. = ..()
@@ -448,13 +449,6 @@
else
togglelock(user)
-/obj/structure/closet/CtrlShiftClick(mob/living/user)
- if(!HAS_TRAIT(user, TRAIT_SKITTISH))
- return ..()
- if(!user.canUseTopic(src, BE_CLOSE) || !isturf(user.loc))
- return
- dive_into(user)
-
/obj/structure/closet/proc/togglelock(mob/living/user, silent)
if(secure && !broken)
if(allowed(user))
@@ -522,24 +516,3 @@
/obj/structure/closet/return_temperature()
return
-
-/obj/structure/closet/proc/dive_into(mob/living/user)
- var/turf/T1 = get_turf(user)
- var/turf/T2 = get_turf(src)
- if(!opened)
- if(locked)
- togglelock(user, TRUE)
- if(!open(user))
- to_chat(user, "It won't budge!")
- return
- step_towards(user, T2)
- T1 = get_turf(user)
- if(T1 == T2)
- user.set_resting(TRUE) //so people can jump into crates without slamming the lid on their head
- if(!close(user))
- to_chat(user, "You can't get [src] to close!")
- user.set_resting(FALSE)
- return
- user.set_resting(FALSE)
- togglelock(user)
- T1.visible_message("[user] dives into [src]!")
diff --git a/code/game/objects/structures/crates_lockers/crates/large.dm b/code/game/objects/structures/crates_lockers/crates/large.dm
index 4861cc3c5bb..655c42a0826 100644
--- a/code/game/objects/structures/crates_lockers/crates/large.dm
+++ b/code/game/objects/structures/crates_lockers/crates/large.dm
@@ -12,6 +12,9 @@
open_sound_volume = 25
close_sound_volume = 50
+ // Stops people from "diving into" a crate you can't open normally
+ divable = FALSE
+
/obj/structure/closet/crate/large/attack_hand(mob/user)
add_fingerprint(user)
if(manifest)
diff --git a/code/modules/mining/abandoned_crates.dm b/code/modules/mining/abandoned_crates.dm
index 17af647cc64..f86bce4268c 100644
--- a/code/modules/mining/abandoned_crates.dm
+++ b/code/modules/mining/abandoned_crates.dm
@@ -13,6 +13,9 @@
var/spawned_loot = FALSE
tamperproof = 90
+ // Stop people from "diving into" the crate accidentally, and then detonating it.
+ divable = FALSE
+
/obj/structure/closet/crate/secure/loot/Initialize()
. = ..()
var/list/digits = list("1", "2", "3", "4", "5", "6", "7", "8", "9", "0")
@@ -98,17 +101,11 @@
return
return ..()
-/obj/structure/closet/secure/loot/dive_into(mob/living/user)
- if(!locked)
- return ..()
- to_chat(user, "That seems like a stupid idea.")
- return FALSE
-
/obj/structure/closet/crate/secure/loot/emag_act(mob/user)
if(locked)
boom(user)
-/obj/structure/closet/crate/secure/loot/togglelock(mob/user)
+/obj/structure/closet/crate/secure/loot/togglelock(mob/user, silent = FALSE)
if(locked)
boom(user)
else
diff --git a/code/modules/mob/living/init_signals.dm b/code/modules/mob/living/init_signals.dm
index 6eba736084f..08ddbf7a5f7 100644
--- a/code/modules/mob/living/init_signals.dm
+++ b/code/modules/mob/living/init_signals.dm
@@ -41,6 +41,9 @@
RegisterSignal(src, COMSIG_MOVETYPE_FLAG_ENABLED, .proc/on_movement_type_flag_enabled)
RegisterSignal(src, COMSIG_MOVETYPE_FLAG_DISABLED, .proc/on_movement_type_flag_disabled)
+ RegisterSignal(src, SIGNAL_ADDTRAIT(TRAIT_SKITTISH), .proc/on_skittish_trait_gain)
+ RegisterSignal(src, SIGNAL_REMOVETRAIT(TRAIT_SKITTISH), .proc/on_skittish_trait_loss)
+
/// Called when [TRAIT_KNOCKEDOUT] is added to the mob.
/mob/living/proc/on_knockedout_trait_gain(datum/source)
SIGNAL_HANDLER
@@ -192,3 +195,14 @@
/mob/living/proc/on_movement_type_flag_disabled(datum/source, trait)
SIGNAL_HANDLER
update_movespeed(FALSE)
+
+
+/// Called when [TRAIT_SKITTISH] is added to the mob.
+/mob/living/proc/on_skittish_trait_gain(datum/source)
+ SIGNAL_HANDLER
+ AddElement(/datum/element/skittish)
+
+/// Called when [TRAIT_SKITTISH] is removed from the mob.
+/mob/living/proc/on_skittish_trait_loss(datum/source)
+ SIGNAL_HANDLER
+ RemoveElement(/datum/element/skittish)
diff --git a/tgstation.dme b/tgstation.dme
index 811ae45340d..3aa28148237 100644
--- a/tgstation.dme
+++ b/tgstation.dme
@@ -610,6 +610,7 @@
#include "code\datums\elements\rad_insulation.dm"
#include "code\datums\elements\ridable.dm"
#include "code\datums\elements\selfknockback.dm"
+#include "code\datums\elements\skittish.dm"
#include "code\datums\elements\snail_crawl.dm"
#include "code\datums\elements\squashable.dm"
#include "code\datums\elements\squish.dm"