diff --git a/code/__DEFINES/inventory.dm b/code/__DEFINES/inventory.dm
index 602dc7f09796..790be39515b0 100644
--- a/code/__DEFINES/inventory.dm
+++ b/code/__DEFINES/inventory.dm
@@ -200,6 +200,33 @@ DEFINE_BITFIELD(no_equip_flags, list(
/// The index of the entry in 'afk_thefts' with the time it happened
#define AFK_THEFT_TIME 3
+/// A list of things that any suit storage can hold
+/// Should consist of ubiquitous, non-specialized items
+/// or items that are meant to be "suit storage agnostic" as
+/// a benefit, which of the time of this commit only applies
+/// to the captain's jetpack, here
+GLOBAL_LIST_INIT(any_suit_storage, typecacheof(list(
+ /obj/item/clipboard,
+ /obj/item/flashlight,
+ /obj/item/tank/internals/emergency_oxygen,
+ /obj/item/tank/internals/plasmaman,
+ /obj/item/lighter,
+ /obj/item/pen,
+ /obj/item/modular_computer/pda,
+ /obj/item/toy,
+ /obj/item/radio,
+ /obj/item/storage/bag/books,
+ /obj/item/storage/fancy/cigarettes,
+ /obj/item/tank/jetpack/oxygen/captain,
+ /obj/item/stack/spacecash,
+ /obj/item/storage/wallet,
+ /obj/item/folder,
+ /obj/item/storage/box/matches,
+ /obj/item/cigarette,
+ /obj/item/storage/belt/holster,
+ /obj/item/storage/pouch,
+)))
+
//Allowed equipment lists for security vests.
GLOBAL_LIST_INIT(detective_vest_allowed, list(
@@ -236,6 +263,7 @@ GLOBAL_LIST_INIT(security_vest_allowed, list(
/obj/item/storage/belt/holster/energy,
/obj/item/gun/ballistic/shotgun/automatic/combat/compact,
/obj/item/pen/red/security,
+ /obj/item/storage/belt/security/webbing,
))
GLOBAL_LIST_INIT(security_wintercoat_allowed, list(
@@ -282,6 +310,8 @@ GLOBAL_LIST_INIT(mining_suit_allowed, list(
/obj/item/pickaxe,
/obj/item/resonator,
/obj/item/spear,
+ /obj/item/storage/belt/mining,
+ /obj/item/storage/belt/chest_pouch,
))
/// List of all "tools" that can fit into belts or work from toolboxes
diff --git a/code/__DEFINES/living.dm b/code/__DEFINES/living.dm
index 76ee12d826a0..d2d9767b0054 100644
--- a/code/__DEFINES/living.dm
+++ b/code/__DEFINES/living.dm
@@ -61,6 +61,9 @@
/// Living mob is being unpinned by some movable (source = the movable doing the unpinning, atom/movable/unpinning)
#define COMSIG_LIVING_UNPINNED_BY "living_unpinned_by"
+/// Sent when a carbon's clothes are examined
+#define COMSIG_CARBON_CLOTHING_EXAMINE "carbon_clothing_examine"
+
/// Various lists of body zones affected by pain.
#define BODY_ZONES_ALL list(BODY_ZONE_HEAD, BODY_ZONE_CHEST, BODY_ZONE_L_ARM, BODY_ZONE_R_ARM, BODY_ZONE_L_LEG, BODY_ZONE_R_LEG)
diff --git a/code/__HELPERS/mobs.dm b/code/__HELPERS/mobs.dm
index 8ce78c6e8382..e21468ef9655 100644
--- a/code/__HELPERS/mobs.dm
+++ b/code/__HELPERS/mobs.dm
@@ -82,9 +82,6 @@
CRASH("No socks to choose from!")
return pick(SSaccessories.socks_list)
-/proc/random_backpack()
- return pick(GLOB.backpacklist)
-
/proc/random_hairstyle(gender)
switch(gender)
if(MALE)
diff --git a/code/_globalvars/lists/flavor_misc.dm b/code/_globalvars/lists/flavor_misc.dm
index b44f0b40ec14..bfbc5a8bfeca 100644
--- a/code/_globalvars/lists/flavor_misc.dm
+++ b/code/_globalvars/lists/flavor_misc.dm
@@ -106,17 +106,7 @@ GLOBAL_LIST_INIT(security_depts_prefs, sort_list(list(
#define GSATCHEL "Grey Satchel"
#define GMESSENGER "Grey Messenger Bag"
#define LSATCHEL "Leather Satchel"
-GLOBAL_LIST_INIT(backpacklist, list(
- DBACKPACK,
- DDUFFELBAG,
- DSATCHEL,
- DMESSENGER,
- GBACKPACK,
- GDUFFELBAG,
- GSATCHEL,
- GMESSENGER,
- LSATCHEL,
-))
+#define BELT_POUCH "Chest Pouches"
//Suit/Skirt
#define PREF_SUIT "Jumpsuit"
diff --git a/code/controllers/subsystem/wardrobe.dm b/code/controllers/subsystem/wardrobe.dm
index d52752402ab5..aaf50d7209a5 100644
--- a/code/controllers/subsystem/wardrobe.dm
+++ b/code/controllers/subsystem/wardrobe.dm
@@ -317,6 +317,10 @@ SUBSYSTEM_DEF(wardrobe)
play_with[WARDROBE_CALLBACK_REMOVE] = CALLBACK(null, TYPE_PROC_REF(/obj/item/storage/box/survival, wardrobe_removal))
initial_callbacks[/obj/item/storage/box/survival] = play_with
+ play_with = new /list(WARDROBE_CALLBACK_REMOVE)
+ play_with[WARDROBE_CALLBACK_REMOVE] = CALLBACK(null, TYPE_PROC_REF(/obj/item/storage/pouch/survival, wardrobe_removal))
+ initial_callbacks[/obj/item/storage/pouch/survival] = play_with
+
/datum/controller/subsystem/wardrobe/proc/load_outfits()
for(var/datum/outfit/to_stock as anything in subtypesof(/datum/outfit))
if(!initial(to_stock.preload)) // Clearly not interested
diff --git a/code/datums/outfit.dm b/code/datums/outfit.dm
index 084e0851723e..38bcb11af18b 100644
--- a/code/datums/outfit.dm
+++ b/code/datums/outfit.dm
@@ -498,3 +498,34 @@
if(!check_rights(NONE))
return
usr.client.open_outfit_editor(src)
+
+/// Replaces the current belt with the passed in belt, without losing whatever was in the current belt slot
+/// Returns TRUE if the replacement was successful, FALSE if it failed
+/datum/outfit/proc/replace_belt_keep_old(obj/item/replaced_belt)
+ if(!belt)
+ belt = replaced_belt
+ return TRUE
+
+ // try to move the existing belt to the backpack
+ if(l_hand && r_hand && belt::w_class <= WEIGHT_CLASS_NORMAL)
+ LAZYADD(backpack_contents, belt)
+ belt = replaced_belt
+ return TRUE
+
+ // try to carry the existing belt in a hand
+ if(!l_hand)
+ l_hand = belt
+ belt = replaced_belt
+ return TRUE
+
+ if(!r_hand)
+ r_hand = belt
+ belt = replaced_belt
+ return TRUE
+
+ // failed to equip the new belt, try to add it to the backpack instead
+ if(replaced_belt::w_class <= WEIGHT_CLASS_NORMAL)
+ LAZYADD(backpack_contents, replaced_belt)
+ return TRUE
+
+ return FALSE
diff --git a/code/datums/storage/storage.dm b/code/datums/storage/storage.dm
index b4bb2c6445d3..3232f3099567 100644
--- a/code/datums/storage/storage.dm
+++ b/code/datums/storage/storage.dm
@@ -439,7 +439,7 @@ GLOBAL_LIST_EMPTY(cached_storage_typecaches)
if(!can_insert(to_insert, user, messages = messages, force = force))
return FALSE
- SEND_SIGNAL(parent, COMSIG_STORAGE_STORED_ITEM, to_insert, user, force)
+ SEND_SIGNAL(parent, COMSIG_ATOM_STORED_ITEM, to_insert, user, force)
SEND_SIGNAL(src, COMSIG_STORAGE_STORED_ITEM, to_insert, user, force)
to_insert.forceMove(real_location)
item_insertion_feedback(user, to_insert, override)
@@ -512,7 +512,7 @@ GLOBAL_LIST_EMPTY(cached_storage_typecaches)
*/
/datum/storage/proc/item_insertion_feedback(mob/user, obj/item/thing, override = FALSE)
if(animated)
- animate_parent()
+ animate_storage()
if(override)
return
@@ -557,7 +557,7 @@ GLOBAL_LIST_EMPTY(cached_storage_typecaches)
thing.moveToNullspace()
if(animated)
- animate_parent()
+ animate_storage()
refresh_views()
parent.update_appearance()
@@ -836,10 +836,11 @@ GLOBAL_LIST_EMPTY(cached_storage_typecaches)
user.active_storage.hide_contents(user)
hide_contents(user)
return COMPONENT_CANCEL_ATTACK_CHAIN
- if(ishuman(user))
- var/mob/living/carbon/human/hum = user
- if(hum.l_store == parent || hum.r_store == parent)
- return
+ // Non-module change: Commented out because it messes with pocket pouches
+ // if(ishuman(user))
+ // var/mob/living/carbon/human/hum = user
+ // if(hum.l_store == parent || hum.r_store == parent)
+ // return
if(parent.loc == user)
INVOKE_ASYNC(src, PROC_REF(open_storage), user)
return COMPONENT_CANCEL_ATTACK_CHAIN
@@ -915,7 +916,7 @@ GLOBAL_LIST_EMPTY(cached_storage_typecaches)
return FALSE
if(animated)
- animate_parent()
+ animate_storage()
if(rustle_sound)
play_storage_sound() // NON-MODULE CHANGE
@@ -1107,9 +1108,9 @@ GLOBAL_LIST_EMPTY(cached_storage_typecaches)
parent.balloon_alert(user, "will now pick up one at a time")
/// Gives a spiffy animation to our parent to represent opening and closing.
-/datum/storage/proc/animate_parent()
- var/matrix/old_matrix = parent.transform
- animate(parent, time = 1.5, loop = 0, transform = parent.transform.Scale(1.07, 0.9))
+/datum/storage/proc/animate_storage(atom/animate = parent)
+ var/matrix/old_matrix = animate.transform
+ animate(animate, time = 1.5, loop = 0, transform = animate.transform.Scale(1.07, 0.9))
animate(time = 2, transform = old_matrix)
/// Signal proc for [COMSIG_ATOM_CONTENTS_WEIGHT_CLASS_CHANGED] to drop items out of our storage if they're suddenly too heavy.
diff --git a/code/game/objects/items.dm b/code/game/objects/items.dm
index 30239d8269a4..97270853d271 100644
--- a/code/game/objects/items.dm
+++ b/code/game/objects/items.dm
@@ -25,6 +25,8 @@
///Icon file for mob worn overlays.
var/icon/worn_icon
+ ///Icon file used in occasional cases where the item must be mirrored
+ var/mirror_icon
///Icon state for mob worn overlays, if null the normal icon_state will be used.
var/worn_icon_state
///Icon state for the belt overlay, if null the normal icon_state will be used.
diff --git a/code/game/objects/items/devices/laserpointer.dm b/code/game/objects/items/devices/laserpointer.dm
index 67576eba5617..cd3832bbd5c5 100644
--- a/code/game/objects/items/devices/laserpointer.dm
+++ b/code/game/objects/items/devices/laserpointer.dm
@@ -9,7 +9,7 @@
item_flags = NOBLUDGEON
slot_flags = ITEM_SLOT_BELT
custom_materials = list(/datum/material/iron = SMALL_MATERIAL_AMOUNT * 5, /datum/material/glass = SMALL_MATERIAL_AMOUNT * 5)
- w_class = WEIGHT_CLASS_SMALL
+ w_class = WEIGHT_CLASS_TINY
///Currently stored blulespace crystal, if any. Required to use the pointer through walls
var/obj/item/stack/ore/bluespace_crystal/crystal_lens
///Currently stored micro-laser diode
diff --git a/code/game/objects/items/devices/scanners/health_analyzer.dm b/code/game/objects/items/devices/scanners/health_analyzer.dm
index d8011959f446..41970133135d 100644
--- a/code/game/objects/items/devices/scanners/health_analyzer.dm
+++ b/code/game/objects/items/devices/scanners/health_analyzer.dm
@@ -11,7 +11,7 @@
item_flags = NOBLUDGEON
slot_flags = ITEM_SLOT_BELT
throwforce = 3
- w_class = WEIGHT_CLASS_TINY
+ w_class = WEIGHT_CLASS_SMALL
throw_speed = 3
throw_range = 7
custom_materials = list(/datum/material/iron=SMALL_MATERIAL_AMOUNT *2)
@@ -625,6 +625,7 @@
desc = "A helpful, child-proofed, and most importantly, extremely cheap MeLo-Tech medical scanner used to diagnose injuries and recommend treatment for serious wounds. While it might not sound very informative for it to be able to tell you if you have a gaping hole in your body or not, it applies a temporary holoimage near the wound with information that is guaranteed to double the efficacy and speed of treatment."
mode = SCANNER_NO_MODE
give_wound_treatment_bonus = TRUE
+ w_class = WEIGHT_CLASS_TINY
/// Cooldown for when the analyzer will allow you to ask it for encouragement. Don't get greedy!
var/next_encouragement
diff --git a/code/game/objects/items/devices/scanners/sequence_scanner.dm b/code/game/objects/items/devices/scanners/sequence_scanner.dm
index 6598a7b802d5..08b0bd0d0dc3 100644
--- a/code/game/objects/items/devices/scanners/sequence_scanner.dm
+++ b/code/game/objects/items/devices/scanners/sequence_scanner.dm
@@ -11,7 +11,7 @@
item_flags = NOBLUDGEON
slot_flags = ITEM_SLOT_BELT
throwforce = 3
- w_class = WEIGHT_CLASS_TINY
+ w_class = WEIGHT_CLASS_SMALL
throw_speed = 3
throw_range = 7
custom_materials = list(/datum/material/iron=SMALL_MATERIAL_AMOUNT*2)
diff --git a/code/game/objects/items/food/bait.dm b/code/game/objects/items/food/bait.dm
index 9ba9ffe26587..2c23d5030676 100644
--- a/code/game/objects/items/food/bait.dm
+++ b/code/game/objects/items/food/bait.dm
@@ -39,6 +39,7 @@
lefthand_file = 'icons/mob/inhands/items_lefthand.dmi'
righthand_file = 'icons/mob/inhands/items_righthand.dmi'
inhand_icon_state = "pen"
+ w_class = WEIGHT_CLASS_TINY
bait_quality = TRAIT_GREAT_QUALITY_BAIT //this is only here for autowiki purposes, it's removed on init.
food_reagents = list(/datum/reagent/drug/kronkaine = 2) //The kronkaine is the thing that makes this a great bait.
tastes = list("hypocrisy" = 1)
@@ -89,4 +90,3 @@
/obj/item/food/bait/doughball/synthetic/unconsumable/Initialize(mapload)
. = ..()
ADD_TRAIT(src, TRAIT_BAIT_UNCONSUMABLE, INNATE_TRAIT)
-
diff --git a/code/game/objects/items/storage/backpack.dm b/code/game/objects/items/storage/backpack.dm
index 925e71f2f2c0..429526e1e5f3 100644
--- a/code/game/objects/items/storage/backpack.dm
+++ b/code/game/objects/items/storage/backpack.dm
@@ -298,6 +298,16 @@
desc = "A trendy looking satchel."
icon_state = "satchel-norm"
inhand_icon_state = "satchel-norm"
+ slot_flags = ITEM_SLOT_BACK|ITEM_SLOT_BELT
+
+/obj/item/storage/backpack/satchel/equipped(mob/user, slot, initial)
+ if(slot & ITEM_SLOT_BELT)
+ AddComponent(/datum/component/slows_with_backpack)
+ return ..()
+
+/obj/item/storage/backpack/satchel/dropped(mob/user, silent)
+ . = ..()
+ qdel(GetComponent(/datum/component/slows_with_backpack))
/obj/item/storage/backpack/satchel/leather
name = "leather satchel"
diff --git a/code/game/objects/items/storage/bags.dm b/code/game/objects/items/storage/bags.dm
index a74e37ad06a7..054cd3b3967e 100644
--- a/code/game/objects/items/storage/bags.dm
+++ b/code/game/objects/items/storage/bags.dm
@@ -500,6 +500,7 @@
/obj/item/reagent_containers/cup/tube,
/obj/item/reagent_containers/hypospray/medipen,
/obj/item/reagent_containers/syringe,
+ /obj/item/food/meat/slab,
))
/*
@@ -560,6 +561,7 @@
/obj/item/stack/ore/bluespace_crystal,
/obj/item/stock_parts,
/obj/item/wallframe/camera,
+ /obj/item/stack/sheet,
))
/obj/item/storage/bag/harpoon_quiver
diff --git a/code/game/objects/items/storage/belt.dm b/code/game/objects/items/storage/belt.dm
index 1dcbe597ccee..ed834a21b3e6 100644
--- a/code/game/objects/items/storage/belt.dm
+++ b/code/game/objects/items/storage/belt.dm
@@ -865,3 +865,17 @@
/obj/item/seeds,
/obj/item/shovel/spade,
))
+
+/obj/item/storage/belt/chest_pouch
+ name = "chest pouches"
+ desc = "A bunch of pouches worn across the chest."
+ gender = PLURAL
+ icon_state = "explorer2"
+ inhand_icon_state = "explorer2"
+ worn_icon_state = "explorer2"
+ storage_type = /datum/storage/backpack
+ mirror_icon = 'icons/mob/clothing/belt.dmi'
+
+/obj/item/storage/belt/chest_pouch/Initialize(mapload)
+ . = ..()
+ AddComponent(/datum/component/slows_with_backpack)
diff --git a/code/game/objects/items/storage/medkit.dm b/code/game/objects/items/storage/medkit.dm
index f9b3ec327606..794eb6c236e5 100644
--- a/code/game/objects/items/storage/medkit.dm
+++ b/code/game/objects/items/storage/medkit.dm
@@ -466,6 +466,7 @@
/obj/item/storage/pill_bottle/Initialize(mapload)
. = ..()
atom_storage.allow_quick_gather = TRUE
+ atom_storage.max_specific_storage = WEIGHT_CLASS_TINY
atom_storage.set_holdable(list(
/obj/item/reagent_containers/pill,
/obj/item/food/bait/natural,
@@ -802,7 +803,7 @@
inhand_icon_state = "contsolid"
lefthand_file = 'icons/mob/inhands/equipment/medical_lefthand.dmi'
righthand_file = 'icons/mob/inhands/equipment/medical_righthand.dmi'
- w_class = WEIGHT_CLASS_SMALL
+ w_class = WEIGHT_CLASS_NORMAL
/obj/item/storage/test_tube_rack/Initialize(mapload)
. = ..()
diff --git a/code/game/objects/items/storage/toolbox.dm b/code/game/objects/items/storage/toolbox.dm
index 8c59ec39b50d..bed22491b5bb 100644
--- a/code/game/objects/items/storage/toolbox.dm
+++ b/code/game/objects/items/storage/toolbox.dm
@@ -81,7 +81,7 @@
if (!user.put_in_inactive_hand(picked_item))
return ITEM_INTERACT_BLOCKING
- atom_storage.animate_parent()
+ atom_storage.animate_storage()
if (istype(picked_item, /obj/item/weldingtool))
var/obj/item/weldingtool/welder = picked_item
if (!welder.welding)
diff --git a/code/modules/antagonists/clown_ops/outfits.dm b/code/modules/antagonists/clown_ops/outfits.dm
index 7dc84b56d856..a689330d0a24 100644
--- a/code/modules/antagonists/clown_ops/outfits.dm
+++ b/code/modules/antagonists/clown_ops/outfits.dm
@@ -16,7 +16,7 @@
/obj/item/reagent_containers/spray/waterflower/lube = 1,
/obj/item/mod/skin_applier/honkerative = 1,
)
- box = /obj/item/storage/box/survival/syndie
+ box = /obj/item/storage/pouch/survival/syndie
implants = list(/obj/item/implant/sad_trombone)
uplink_type = /obj/item/uplink/clownop
diff --git a/code/modules/antagonists/nukeop/outfits.dm b/code/modules/antagonists/nukeop/outfits.dm
index 9aa08dcdbaa6..c58f5d33bd48 100644
--- a/code/modules/antagonists/nukeop/outfits.dm
+++ b/code/modules/antagonists/nukeop/outfits.dm
@@ -12,7 +12,7 @@
belt = /obj/item/gun/ballistic/automatic/pistol/clandestine
skillchips = list(/obj/item/skillchip/disk_verifier)
- box = /obj/item/storage/box/survival/syndie
+ box = /obj/item/storage/pouch/survival/syndie
/// Amount of TC to automatically store in this outfit's uplink.
var/tc = 25
/// Enables big voice on this outfit's headset, used for nukie leaders.
diff --git a/code/modules/antagonists/traitor/contractor/contract_teammate.dm b/code/modules/antagonists/traitor/contractor/contract_teammate.dm
index c62e8aee7942..5bccc5722070 100644
--- a/code/modules/antagonists/traitor/contractor/contract_teammate.dm
+++ b/code/modules/antagonists/traitor/contractor/contract_teammate.dm
@@ -32,7 +32,7 @@
id_trim = /datum/id_trim/chameleon/operative
backpack_contents = list(
- /obj/item/storage/box/survival,
+ /obj/item/storage/pouch/survival,
/obj/item/implanter/uplink,
/obj/item/clothing/mask/chameleon,
/obj/item/storage/fancy/cigarettes/cigpack_syndicate,
diff --git a/code/modules/bitrunning/server/obj_generation.dm b/code/modules/bitrunning/server/obj_generation.dm
index 54c265f8e33a..6d994ec21256 100644
--- a/code/modules/bitrunning/server/obj_generation.dm
+++ b/code/modules/bitrunning/server/obj_generation.dm
@@ -75,7 +75,7 @@
QDEL_LIST(bag.contents)
bag.contents += list(
- new /obj/item/storage/box/survival,
+ new /obj/item/storage/pouch/survival,
new /obj/item/storage/medkit/regular,
new /obj/item/flashlight,
)
diff --git a/code/modules/client/preferences/clothing.dm b/code/modules/client/preferences/clothing.dm
index 4199b0e39416..a38756ed6578 100644
--- a/code/modules/client/preferences/clothing.dm
+++ b/code/modules/client/preferences/clothing.dm
@@ -31,6 +31,7 @@
DSATCHEL,
DDUFFELBAG,
DMESSENGER,
+ BELT_POUCH,
)
/datum/preference/choiced/backpack/create_default_value()
@@ -48,6 +49,8 @@
return /obj/item/storage/backpack/duffelbag
if (GMESSENGER)
return /obj/item/storage/backpack/messenger
+ if (BELT_POUCH)
+ return /obj/item/storage/belt/chest_pouch
// In a perfect world, these would be your department's backpack.
// However, this doesn't factor in assistants, or no high slot, and would
diff --git a/code/modules/clothing/ears/_ears.dm b/code/modules/clothing/ears/_ears.dm
index 33e977e90f1e..60ee0f99c653 100644
--- a/code/modules/clothing/ears/_ears.dm
+++ b/code/modules/clothing/ears/_ears.dm
@@ -24,6 +24,7 @@
resistance_flags = FLAMMABLE
custom_price = PAYCHECK_COMMAND * 1.5
flags_cover = EARS_COVERED
+ w_class = WEIGHT_CLASS_SMALL
/obj/item/clothing/ears/earmuffs/Initialize(mapload)
. = ..()
diff --git a/code/modules/clothing/outfits/ert.dm b/code/modules/clothing/outfits/ert.dm
index cfc810290d42..5ae52292963e 100644
--- a/code/modules/clothing/outfits/ert.dm
+++ b/code/modules/clothing/outfits/ert.dm
@@ -41,7 +41,7 @@
id = /obj/item/card/id/advanced/centcom/ert
back = /obj/item/mod/control/pre_equipped/responsory/commander
l_hand = /obj/item/gun/energy/e_gun
- box = /obj/item/storage/box/survival/centcom
+ box = /obj/item/storage/pouch/survival/centcom
backpack_contents = list(
/obj/item/melee/baton/security/loaded = 1,
)
@@ -68,7 +68,7 @@
id = /obj/item/card/id/advanced/centcom/ert/security
back = /obj/item/mod/control/pre_equipped/responsory/security
l_hand = /obj/item/gun/energy/e_gun/stun
- box = /obj/item/storage/box/survival/centcom
+ box = /obj/item/storage/pouch/survival/centcom
backpack_contents = list(
/obj/item/melee/baton/security/loaded = 1,
/obj/item/storage/box/handcuffs = 1,
@@ -92,7 +92,7 @@
id = /obj/item/card/id/advanced/centcom/ert/medical
back = /obj/item/mod/control/pre_equipped/responsory/medic
- box = /obj/item/storage/box/survival/centcom
+ box = /obj/item/storage/pouch/survival/centcom
backpack_contents = list(
/obj/item/gun/medbeam = 1,
/obj/item/melee/baton/security/loaded = 1,
@@ -124,7 +124,7 @@
id = /obj/item/card/id/advanced/centcom/ert/engineer
back = /obj/item/mod/control/pre_equipped/responsory/engineer
l_hand = /obj/item/gun/energy/e_gun
- box = /obj/item/storage/box/survival/centcom
+ box = /obj/item/storage/pouch/survival/centcom
backpack_contents = list(
/obj/item/construction/rcd/loaded/upgraded = 1,
/obj/item/melee/baton/security/loaded = 1,
@@ -152,7 +152,7 @@
id_trim = /datum/id_trim/centcom/official
uniform = /obj/item/clothing/under/rank/centcom/official
back = /obj/item/storage/backpack/satchel
- box = /obj/item/storage/box/survival
+ box = /obj/item/storage/pouch/survival
backpack_contents = list(
/obj/item/stamp/centcom = 1,
)
@@ -214,7 +214,7 @@
l_hand = /obj/item/gun/energy/e_gun
belt = /obj/item/storage/belt/soulstone
glasses = /obj/item/clothing/glasses/hud/health
- box = /obj/item/storage/box/survival/centcom
+ box = /obj/item/storage/pouch/survival/centcom
backpack_contents = list(
/obj/item/nullrod = 1,
)
@@ -235,7 +235,7 @@
id = /obj/item/card/id/advanced/centcom/ert/janitor
back = /obj/item/mod/control/pre_equipped/responsory/janitor
- box = /obj/item/storage/box/survival/centcom
+ box = /obj/item/storage/pouch/survival/centcom
backpack_contents = list(
/obj/item/grenade/clusterbuster/cleaner = 1,
/obj/item/melee/baton/security/loaded = 1,
@@ -265,7 +265,7 @@
id = /obj/item/card/id/advanced/centcom/ert/clown
back = /obj/item/mod/control/pre_equipped/responsory/clown
- box = /obj/item/storage/box/survival/centcom
+ box = /obj/item/storage/pouch/survival/centcom
backpack_contents = list(
/obj/item/gun/ballistic/revolver/reverse = 1,
/obj/item/melee/energy/sword/bananium = 1,
@@ -295,7 +295,7 @@
id_trim = /datum/id_trim/centcom/intern
uniform = /obj/item/clothing/under/rank/centcom/intern
back = /obj/item/storage/backpack/satchel
- box = /obj/item/storage/box/survival
+ box = /obj/item/storage/pouch/survival
belt = /obj/item/melee/baton
ears = /obj/item/radio/headset/headset_cent
glasses = /obj/item/clothing/glasses/sunglasses
@@ -429,7 +429,7 @@
id_trim = /datum/id_trim/centcom/deathsquad
uniform = /obj/item/clothing/under/rank/centcom/commander
back = /obj/item/mod/control/pre_equipped/apocryphal
- box = /obj/item/storage/box/survival/centcom
+ box = /obj/item/storage/pouch/survival/centcom
backpack_contents = list(
/obj/item/ammo_box/a357 = 1,
/obj/item/flashlight = 1,
@@ -548,7 +548,7 @@
shoes = /obj/item/clothing/shoes/cowboy
gloves = /obj/item/clothing/gloves/combat
back = /obj/item/storage/backpack/satchel/leather
- box = /obj/item/storage/box/survival
+ box = /obj/item/storage/pouch/survival
l_pocket = /obj/item/switchblade
r_pocket = /obj/item/reagent_containers/hypospray/medipen/salacid
ears = /obj/item/radio/headset
diff --git a/code/modules/clothing/outfits/event.dm b/code/modules/clothing/outfits/event.dm
index 43857f5f3cb3..3d98d4dcf5ef 100644
--- a/code/modules/clothing/outfits/event.dm
+++ b/code/modules/clothing/outfits/event.dm
@@ -12,7 +12,7 @@
shoes = /obj/item/clothing/shoes/sneakers/red
r_pocket = /obj/item/flashlight
- box = /obj/item/storage/box/survival/engineer
+ box = /obj/item/storage/pouch/survival/engineer
/datum/outfit/santa/post_equip(mob/living/carbon/human/user, visualsOnly = FALSE)
if(visualsOnly)
diff --git a/code/modules/clothing/outfits/standard.dm b/code/modules/clothing/outfits/standard.dm
index cb94519f8727..40619f8e7989 100644
--- a/code/modules/clothing/outfits/standard.dm
+++ b/code/modules/clothing/outfits/standard.dm
@@ -296,7 +296,7 @@
backpack_contents = list(
/obj/item/spellbook = 1,
)
- box = /obj/item/storage/box/survival
+ box = /obj/item/storage/pouch/survival
ears = /obj/item/radio/headset
head = /obj/item/clothing/head/wizard
shoes = /obj/item/clothing/shoes/sandal/magic
diff --git a/code/modules/clothing/outfits/vr.dm b/code/modules/clothing/outfits/vr.dm
index fb618cd831b6..f1012822f223 100644
--- a/code/modules/clothing/outfits/vr.dm
+++ b/code/modules/clothing/outfits/vr.dm
@@ -17,7 +17,7 @@
id_trim = /datum/id_trim/vr/operative
uniform = /obj/item/clothing/under/syndicate
back = /obj/item/storage/backpack
- box = /obj/item/storage/box/survival/syndie
+ box = /obj/item/storage/pouch/survival/syndie
belt = /obj/item/gun/ballistic/automatic/pistol/clandestine
gloves = /obj/item/clothing/gloves/combat
shoes = /obj/item/clothing/shoes/combat
diff --git a/code/modules/clothing/suits/jacket.dm b/code/modules/clothing/suits/jacket.dm
index c2534d798cd9..c220b1442ff2 100644
--- a/code/modules/clothing/suits/jacket.dm
+++ b/code/modules/clothing/suits/jacket.dm
@@ -15,10 +15,12 @@
body_parts_covered = CHEST|GROIN|ARMS
min_cold_protection_temperature = FIRE_SUIT_MIN_TEMP_PROTECT
species_exception = list(/datum/species/golem)
+ var/pocket_slots = 2
/obj/item/clothing/suit/jacket/Initialize(mapload)
. = ..()
AddElement(/datum/element/pat_out_fire)
+ create_storage(storage_type = /datum/storage/coatpocket, max_slots = pocket_slots)
/obj/item/clothing/suit/toggle/jacket
icon = 'icons/obj/clothing/suits/jacket.dmi'
@@ -61,6 +63,7 @@
flags_1 = IS_PLAYER_COLORABLE_1
blood_overlay_type = "coat"
flags_inv = HIDEBELT
+ pocket_slots = 4
/obj/item/clothing/suit/jacket/blazer
name = "blazer jacket"
@@ -83,6 +86,7 @@
greyscale_config_worn = /datum/greyscale_config/jacket_oversized/worn
greyscale_colors = "#414344"
flags_1 = IS_PLAYER_COLORABLE_1
+ pocket_slots = 4
/obj/item/clothing/suit/jacket/fancy
name = "fancy fur coat"
diff --git a/code/modules/clothing/suits/jobs.dm b/code/modules/clothing/suits/jobs.dm
index 9acbbd749ae5..f25f260a4f80 100644
--- a/code/modules/clothing/suits/jobs.dm
+++ b/code/modules/clothing/suits/jobs.dm
@@ -31,6 +31,10 @@
species_exception = list(/datum/species/golem)
armor_type = /datum/armor/suit_apron
+/obj/item/clothing/suit/apron/Initialize(mapload)
+ . = ..()
+ create_storage(storage_type = /datum/storage/coatpocket)
+
/datum/armor/suit_apron
bio = 50
@@ -63,6 +67,7 @@
/obj/item/clothing/suit/apron/overalls/grey
greyscale_colors = COLOR_JOB_DEFAULT
icon_state = "/obj/item/clothing/suit/apron/overalls/grey"
+
//Captain
/obj/item/clothing/suit/jacket/capjacket
name = "captain's parade jacket"
@@ -78,6 +83,7 @@
strip_delay = 60
equip_delay_other = 40
max_integrity = 250
+ pocket_slots = 3
/obj/item/clothing/suit/jacket/capjacket/Initialize(mapload)
. = ..()
@@ -100,6 +106,7 @@
)
toggle_noun = "sleeves"
species_exception = list(/datum/species/golem)
+ pocket_slots = 3
//Cook
/datum/armor/toggle_chef
@@ -189,6 +196,7 @@
/obj/item/tank/internals/plasmaman,
/obj/item/t_scanner,
/obj/item/gun/ballistic/rifle/boltaction/pipegun/prime,
+ /obj/item/storage/belt/chest_pouch,
)
resistance_flags = NONE
species_exception = list(/datum/species/golem)
@@ -433,6 +441,10 @@
/obj/item/extinguisher,
)
+/obj/item/clothing/suit/atmos_overalls/Initialize(mapload)
+ . = ..()
+ create_storage(storage_type = /datum/storage/coatpocket)
+
/datum/armor/atmos_overalls
fire = 100
acid = 50
diff --git a/code/modules/clothing/suits/toggles.dm b/code/modules/clothing/suits/toggles.dm
index 12ba36c89eb7..c15830e5db14 100644
--- a/code/modules/clothing/suits/toggles.dm
+++ b/code/modules/clothing/suits/toggles.dm
@@ -61,10 +61,13 @@
abstract_type = /obj/item/clothing/suit/toggle
/// The noun that is displayed to the user on toggle. EX: "Toggles the suit's [buttons]".
var/toggle_noun = "buttons"
+ /// Number of pocket slots it has
+ var/pocket_slots = 2
/obj/item/clothing/suit/toggle/Initialize(mapload)
. = ..()
AddComponent(/datum/component/toggle_icon, toggle_noun)
+ create_storage(storage_type = /datum/storage/coatpocket, max_slots = pocket_slots)
/obj/item/clothing/head/hooded
abstract_type = /obj/item/clothing/head/hooded
diff --git a/code/modules/clothing/suits/wintercoats.dm b/code/modules/clothing/suits/wintercoats.dm
index 38a3c2561dd9..eb348e0a8390 100644
--- a/code/modules/clothing/suits/wintercoats.dm
+++ b/code/modules/clothing/suits/wintercoats.dm
@@ -12,13 +12,17 @@
armor_type = /datum/armor/hooded_wintercoat
hood_down_overlay_suffix = "_hood"
/// How snug are we?
- var/zipped = FALSE
+ var/zipped = TRUE
+ /// Hoods are stored in contents, so we have to have a second dummy object that our coat pockets point to to hide that
+ var/obj/effect/abstract/abstract_storage/coat_pockets/storage_pocket_holder
/datum/armor/hooded_wintercoat
bio = 10
/obj/item/clothing/suit/hooded/wintercoat/Initialize(mapload)
. = ..()
+ update_appearance(UPDATE_ICON_STATE)
+ register_context()
AddElement(/datum/element/pat_out_fire)
allowed += list(
/obj/item/flashlight,
@@ -31,31 +35,54 @@
/obj/item/tank/internals/plasmaman,
/obj/item/toy,
)
+ storage_pocket_holder = new(src)
+ storage_pocket_holder.name = "pockets"
+ create_storage(storage_type = /datum/storage/coatpocket) // melbert todo : contents moment
+ atom_storage.set_real_location(storage_pocket_holder)
-/obj/item/clothing/suit/hooded/wintercoat/on_hood_up(obj/item/clothing/head/hooded/hood)
+/obj/item/clothing/suit/hooded/wintercoat/Destroy()
+ QDEL_NULL(storage_pocket_holder)
+ return ..()
+
+/obj/item/clothing/suit/hooded/wintercoat/Exited(atom/movable/gone, direction)
. = ..()
- zipped = TRUE
+ if(gone == storage_pocket_holder)
+ storage_pocket_holder = null
+ if(!QDELING(gone)) // where the hell do you think you're doing
+ qdel(gone)
+
+/obj/item/clothing/suit/hooded/wintercoat/atom_deconstruct(disassembled)
+ storage_pocket_holder?.deconstruct(disassembled) // propagate deconstruction so storage items dump out
+ return ..()
+
+// /obj/item/clothing/suit/hooded/wintercoat/on_hood_up(obj/item/clothing/head/hooded/hood)
+// . = ..()
+// zipped = TRUE
+
+// /obj/item/clothing/suit/hooded/wintercoat/on_hood_down(obj/item/clothing/head/hooded/hood)
+// . = ..()
+// zipped = FALSE
+
-/// Called when the hood is hidden
-/obj/item/clothing/suit/hooded/wintercoat/on_hood_down(obj/item/clothing/head/hooded/hood)
+/obj/item/clothing/suit/hooded/wintercoat/add_context(atom/source, list/context, obj/item/held_item, mob/user)
. = ..()
- zipped = FALSE
+ context[SCREENTIP_CONTEXT_ALT_RMB] = zipped ? "Unzip" : "Zip"
+ return CONTEXTUAL_SCREENTIP_SET
/obj/item/clothing/suit/hooded/wintercoat/examine(mob/user)
. = ..()
+ . += span_notice("Alt-Right-click to [zipped ? "un" : ""]zip.")
- . += span_notice("Alt-click to [zipped ? "un" : ""]zip.")
-
+/obj/item/clothing/suit/hooded/wintercoat/update_icon_state()
+ . = ..()
+ worn_icon_state = "[initial(post_init_icon_state) || initial(icon_state)][zipped ? "_t" : ""]"
-/obj/item/clothing/suit/hooded/wintercoat/click_alt(mob/user)
+/obj/item/clothing/suit/hooded/wintercoat/click_alt_secondary(mob/user)
zipped = !zipped
playsound(src, 'sound/items/zip_up.ogg', 30, TRUE, -3)
- worn_icon_state = "[initial(post_init_icon_state) || initial(icon_state)][zipped ? "_t" : ""]"
balloon_alert(user, "[zipped ? "" : "un"]zipped")
-
- if(ishuman(loc))
- var/mob/living/carbon/human/wearer = loc
- wearer.update_worn_oversuit()
+ update_appearance(UPDATE_ICON_STATE)
+ update_slot_icon()
return CLICK_ACTION_SUCCESS
/obj/item/clothing/head/hooded/winterhood
diff --git a/code/modules/clothing/under/_under.dm b/code/modules/clothing/under/_under.dm
index 21d70112bb3e..08923ea59370 100644
--- a/code/modules/clothing/under/_under.dm
+++ b/code/modules/clothing/under/_under.dm
@@ -105,16 +105,16 @@
if(accessory_overlay)
. += accessory_overlay
-/obj/item/clothing/under/attackby(obj/item/attacking_item, mob/user, params)
- if(has_sensor == BROKEN_SENSORS && istype(attacking_item, /obj/item/stack/cable_coil))
- var/obj/item/stack/cable_coil/cabling = attacking_item
+/obj/item/clothing/under/item_interaction(mob/living/user, obj/item/tool, list/modifiers)
+ if(has_sensor == BROKEN_SENSORS && istype(tool, /obj/item/stack/cable_coil))
+ var/obj/item/stack/cable_coil/cabling = tool
to_chat(user, span_notice("You repair the suit sensors on [src] with [cabling]."))
cabling.use(1)
has_sensor = HAS_SENSORS
- return TRUE
+ return ITEM_INTERACT_SUCCESS
- if(istype(attacking_item, /obj/item/clothing/accessory))
- return attach_accessory(attacking_item, user)
+ if(istype(tool, /obj/item/clothing/accessory))
+ return attach_accessory(tool, user) ? ITEM_INTERACT_SUCCESS : ITEM_INTERACT_BLOCKING
return ..()
diff --git a/code/modules/clothing/under/accessories/badges.dm b/code/modules/clothing/under/accessories/badges.dm
index c9400ccfc573..34c0ec9a1b58 100644
--- a/code/modules/clothing/under/accessories/badges.dm
+++ b/code/modules/clothing/under/accessories/badges.dm
@@ -3,6 +3,7 @@
name = "attorney's badge"
desc = "Fills you with the conviction of JUSTICE. Lawyers tend to want to show it to everyone they meet."
icon_state = "lawyerbadge"
+ w_class = WEIGHT_CLASS_TINY
/obj/item/clothing/accessory/lawyers_badge/interact(mob/user)
. = ..()
@@ -28,6 +29,7 @@
name = "\improper Clown Pin"
desc = "A pin to show off your appreciation for clowns and clowning!"
icon_state = "clown_enjoyer_pin"
+ w_class = WEIGHT_CLASS_TINY
/obj/item/clothing/accessory/clown_enjoyer_pin/can_attach_accessory(obj/item/clothing/under/attach_to, mob/living/user)
. = ..()
@@ -56,6 +58,7 @@
name = "\improper Mime Pin"
desc = "A pin to show off your appreciation for mimes and miming!"
icon_state = "mime_fan_pin"
+ w_class = WEIGHT_CLASS_TINY
/obj/item/clothing/accessory/mime_fan_pin/can_attach_accessory(obj/item/clothing/under/attach_to, mob/living/user)
. = ..()
@@ -198,18 +201,21 @@
name = "deaf personnel pin"
desc = "Indicates that the wearer is deaf."
icon_state = "deaf_pin"
+ w_class = WEIGHT_CLASS_TINY
///Awarded for being dutiful and extinguishing the debt from the "Indebted" quirk.
/obj/item/clothing/accessory/debt_payer_pin
name = "debt payer pin"
desc = "I've paid my debt and all I've got was this pin."
icon_state = "debt_payer_pin"
+ w_class = WEIGHT_CLASS_TINY
/// Self-identify as a dangerous subversive
/obj/item/clothing/accessory/anti_sec_pin
name = "subversive pin"
desc = "A badge which loudly and proudly proclaims your hostility to the Nanotrasen Security Team, and authority in general."
icon_state = "anti_sec"
+ w_class = WEIGHT_CLASS_TINY
/obj/item/clothing/accessory/anti_sec_pin/Initialize(mapload)
. = ..()
@@ -244,6 +250,7 @@
desc_controls = "Click person with it to show them it"
icon_state = "press_badge"
attachment_slot = NONE // actually NECK but that doesn't make sense
+ w_class = WEIGHT_CLASS_TINY
/// The name of the person in the badge
var/journalist_name
/// The name of the press person is working for
diff --git a/code/modules/clothing/under/accessories/medals.dm b/code/modules/clothing/under/accessories/medals.dm
index d5a6e559f8e1..c18793a7ede5 100644
--- a/code/modules/clothing/under/accessories/medals.dm
+++ b/code/modules/clothing/under/accessories/medals.dm
@@ -4,6 +4,7 @@
icon_state = "bronze"
custom_materials = list(/datum/material/iron = HALF_SHEET_MATERIAL_AMOUNT)
resistance_flags = FIRE_PROOF
+ w_class = WEIGHT_CLASS_TINY
/// Sprite used for medalbox
var/medaltype = "medal"
/// Has this been use for a commendation?
diff --git a/code/modules/clothing/under/accessories/tribal.dm b/code/modules/clothing/under/accessories/tribal.dm
index ad55b26fa89f..d3efb11d5cf2 100644
--- a/code/modules/clothing/under/accessories/tribal.dm
+++ b/code/modules/clothing/under/accessories/tribal.dm
@@ -10,6 +10,7 @@
desc = "A skull shaped ornament, intended to protect the important things in life."
icon_state = "skull"
attachment_slot = GROIN
+ w_class = WEIGHT_CLASS_NORMAL
/obj/item/clothing/accessory/skilt
name = "Sinew Skirt"
@@ -17,3 +18,4 @@
icon_state = "skilt"
minimize_when_attached = FALSE
attachment_slot = GROIN
+ w_class = WEIGHT_CLASS_NORMAL
diff --git a/code/modules/clothing/under/accessories/vests.dm b/code/modules/clothing/under/accessories/vests.dm
index d3b5c5642f06..ee7c2ab69e34 100644
--- a/code/modules/clothing/under/accessories/vests.dm
+++ b/code/modules/clothing/under/accessories/vests.dm
@@ -14,6 +14,7 @@
greyscale_config_worn = /datum/greyscale_config/waistcoat/worn
greyscale_colors = "#414344"
flags_1 = IS_PLAYER_COLORABLE_1
+ w_class = WEIGHT_CLASS_NORMAL
/obj/item/clothing/accessory/vest_sheriff
name = "sheriff vest"
@@ -24,6 +25,7 @@
inhand_icon_state = "vest_sheriff"
minimize_when_attached = TRUE
attachment_slot = NONE
+ w_class = WEIGHT_CLASS_NORMAL
/obj/item/clothing/accessory/maidcorset
name = "maid corset"
@@ -34,6 +36,7 @@
righthand_file = 'icons/mob/inhands/clothing/suits_righthand.dmi'
minimize_when_attached = FALSE
attachment_slot = NONE
+ w_class = WEIGHT_CLASS_NORMAL
/obj/item/clothing/accessory/maidapron
name = "maid apron"
@@ -44,3 +47,4 @@
righthand_file = 'icons/mob/inhands/clothing/suits_righthand.dmi'
minimize_when_attached = FALSE
attachment_slot = NONE
+ w_class = WEIGHT_CLASS_NORMAL
diff --git a/code/modules/food_and_drinks/machinery/smartfridge.dm b/code/modules/food_and_drinks/machinery/smartfridge.dm
index d5c1c7a23a29..b0af64c4e269 100644
--- a/code/modules/food_and_drinks/machinery/smartfridge.dm
+++ b/code/modules/food_and_drinks/machinery/smartfridge.dm
@@ -678,7 +678,7 @@
var/repair_rate = 0
/obj/machinery/smartfridge/organ/accept_check(obj/item/O)
- return (isorgan(O) || isbodypart(O))
+ return (isorgan(O) || isbodypart(O) || istype(O, /obj/item/food/meat/slab))
/obj/machinery/smartfridge/organ/load(obj/item/item, mob/user)
. = ..()
diff --git a/code/modules/instruments/piano_synth.dm b/code/modules/instruments/piano_synth.dm
index 8e107d494c77..44b9c8601af4 100644
--- a/code/modules/instruments/piano_synth.dm
+++ b/code/modules/instruments/piano_synth.dm
@@ -55,6 +55,7 @@
strip_delay = 100 //air pods don't fall out
instrument_range = 0 //you're paying for quality here
custom_premium_price = PAYCHECK_CREW * 36 //Save up 5 shifts worth of pay just to lose it down a drainpipe on the sidewalk
+ w_class = WEIGHT_CLASS_TINY
/obj/item/circuit_component/synth
display_name = "Synthesizer"
diff --git a/code/modules/jobs/job_types/_job.dm b/code/modules/jobs/job_types/_job.dm
index 0fd1e1f27fcc..567c2c12f467 100644
--- a/code/modules/jobs/job_types/_job.dm
+++ b/code/modules/jobs/job_types/_job.dm
@@ -379,7 +379,7 @@
belt = /obj/item/modular_computer/pda
back = /obj/item/storage/backpack
shoes = /obj/item/clothing/shoes/sneakers/black
- box = /obj/item/storage/box/survival
+ box = /obj/item/storage/pouch/survival
preload = TRUE // These are used by the prefs ui, and also just kinda could use the extra help at roundstart
@@ -409,6 +409,10 @@
back = duffelbag //Department duffel bag
if(DMESSENGER)
back = messenger //Department messenger bag
+ if(BELT_POUCH)
+ if(replace_belt_keep_old(/obj/item/storage/belt/chest_pouch))
+ back = null // Replaces the backpack with belt pouch
+
else
back = backpack //Department backpack
diff --git a/code/modules/jobs/job_types/atmospheric_technician.dm b/code/modules/jobs/job_types/atmospheric_technician.dm
index 6a174ab39e60..29ac02a7e9c8 100644
--- a/code/modules/jobs/job_types/atmospheric_technician.dm
+++ b/code/modules/jobs/job_types/atmospheric_technician.dm
@@ -66,7 +66,7 @@
duffelbag = /obj/item/storage/backpack/duffelbag/engineering
messenger = /obj/item/storage/backpack/messenger/eng
- box = /obj/item/storage/box/survival/engineer
+ box = /obj/item/storage/pouch/survival/engineer
pda_slot = ITEM_SLOT_LPOCKET
/datum/outfit/job/atmos/mod
diff --git a/code/modules/jobs/job_types/chemist.dm b/code/modules/jobs/job_types/chemist.dm
index 01c7f5f8ab59..182616a691f4 100644
--- a/code/modules/jobs/job_types/chemist.dm
+++ b/code/modules/jobs/job_types/chemist.dm
@@ -70,5 +70,5 @@
duffelbag = /obj/item/storage/backpack/duffelbag/chemistry
messenger = /obj/item/storage/backpack/messenger/chem
- box = /obj/item/storage/box/survival/medical
+ box = /obj/item/storage/pouch/survival/medical
chameleon_extras = /obj/item/gun/syringe
diff --git a/code/modules/jobs/job_types/chief_engineer.dm b/code/modules/jobs/job_types/chief_engineer.dm
index e4a5318fb974..19f102c8694d 100644
--- a/code/modules/jobs/job_types/chief_engineer.dm
+++ b/code/modules/jobs/job_types/chief_engineer.dm
@@ -94,7 +94,7 @@
duffelbag = /obj/item/storage/backpack/duffelbag/engineering
messenger = /obj/item/storage/backpack/messenger/eng
- box = /obj/item/storage/box/survival/engineer
+ box = /obj/item/storage/pouch/survival/engineer
chameleon_extras = /obj/item/stamp/head/ce
// skillchips = list(/obj/item/skillchip/job/engineer)
pda_slot = ITEM_SLOT_LPOCKET
diff --git a/code/modules/jobs/job_types/chief_medical_officer.dm b/code/modules/jobs/job_types/chief_medical_officer.dm
index fe8ded260468..69c644dbd9aa 100644
--- a/code/modules/jobs/job_types/chief_medical_officer.dm
+++ b/code/modules/jobs/job_types/chief_medical_officer.dm
@@ -94,7 +94,7 @@
duffelbag = /obj/item/storage/backpack/duffelbag/med
messenger = /obj/item/storage/backpack/messenger/med
- box = /obj/item/storage/box/survival/medical
+ box = /obj/item/storage/pouch/survival/medical
chameleon_extras = list(
/obj/item/gun/syringe,
/obj/item/stamp/head/cmo,
diff --git a/code/modules/jobs/job_types/coroner.dm b/code/modules/jobs/job_types/coroner.dm
index de2113ac8989..e6c949e127a9 100644
--- a/code/modules/jobs/job_types/coroner.dm
+++ b/code/modules/jobs/job_types/coroner.dm
@@ -56,7 +56,7 @@
jobtype = /datum/job/coroner
id_trim = /datum/id_trim/job/coroner
- box = /obj/item/storage/box/survival/medical
+ box = /obj/item/storage/pouch/survival/medical
backpack_contents = list(
/obj/item/storage/box/bodybags = 1,
/obj/item/autopsy_scanner = 1,
diff --git a/code/modules/jobs/job_types/head_of_security.dm b/code/modules/jobs/job_types/head_of_security.dm
index 27270d229a02..6f04a9c572fe 100644
--- a/code/modules/jobs/job_types/head_of_security.dm
+++ b/code/modules/jobs/job_types/head_of_security.dm
@@ -80,7 +80,7 @@
duffelbag = /obj/item/storage/backpack/duffelbag/sec
messenger = /obj/item/storage/backpack/messenger/sec
- box = /obj/item/storage/box/survival/security
+ box = /obj/item/storage/pouch/survival/security
chameleon_extras = list(
/obj/item/gun/energy/e_gun/hos,
/obj/item/stamp/head/hos,
diff --git a/code/modules/jobs/job_types/medical_doctor.dm b/code/modules/jobs/job_types/medical_doctor.dm
index 8fe1230a9180..e27f275b1142 100644
--- a/code/modules/jobs/job_types/medical_doctor.dm
+++ b/code/modules/jobs/job_types/medical_doctor.dm
@@ -78,7 +78,7 @@
duffelbag = /obj/item/storage/backpack/duffelbag/med
messenger = /obj/item/storage/backpack/messenger/med
- box = /obj/item/storage/box/survival/medical
+ box = /obj/item/storage/pouch/survival/medical
chameleon_extras = /obj/item/gun/syringe
// skillchips = list(/obj/item/skillchip/entrails_reader)
diff --git a/code/modules/jobs/job_types/paramedic.dm b/code/modules/jobs/job_types/paramedic.dm
index 22917ad2061a..538814565d74 100644
--- a/code/modules/jobs/job_types/paramedic.dm
+++ b/code/modules/jobs/job_types/paramedic.dm
@@ -75,6 +75,6 @@
duffelbag = /obj/item/storage/backpack/duffelbag/med
messenger = /obj/item/storage/backpack/messenger/med
- box = /obj/item/storage/box/survival/medical
+ box = /obj/item/storage/pouch/survival/medical
chameleon_extras = /obj/item/gun/syringe
pda_slot = ITEM_SLOT_LPOCKET
diff --git a/code/modules/jobs/job_types/security_officer.dm b/code/modules/jobs/job_types/security_officer.dm
index a506c1485f58..95a5152210fb 100644
--- a/code/modules/jobs/job_types/security_officer.dm
+++ b/code/modules/jobs/job_types/security_officer.dm
@@ -241,7 +241,7 @@ GLOBAL_LIST_EMPTY(security_officer_distribution)
duffelbag = /obj/item/storage/backpack/duffelbag/sec
messenger = /obj/item/storage/backpack/messenger/sec
- box = /obj/item/storage/box/survival/security
+ box = /obj/item/storage/pouch/survival/security
chameleon_extras = list(
/obj/item/clothing/glasses/hud/security/sunglasses,
/obj/item/clothing/head/helmet,
diff --git a/code/modules/jobs/job_types/shaft_miner.dm b/code/modules/jobs/job_types/shaft_miner.dm
index d4c3b38d29c2..73e7906ed968 100644
--- a/code/modules/jobs/job_types/shaft_miner.dm
+++ b/code/modules/jobs/job_types/shaft_miner.dm
@@ -64,7 +64,7 @@
duffelbag = /obj/item/storage/backpack/duffelbag/explorer
messenger = /obj/item/storage/backpack/messenger/explorer
- box = /obj/item/storage/box/survival/mining
+ box = /obj/item/storage/pouch/survival/mining
chameleon_extras = /obj/item/gun/energy/recharge/kinetic_accelerator
/datum/outfit/job/miner/equipped
@@ -101,7 +101,7 @@
/obj/item/kinetic_crusher/compact = 1,
/obj/item/resonator/upgraded = 1,
)
- box = /obj/item/storage/box/survival/mining/bonus
+ box = /obj/item/storage/pouch/survival/mining/bonus
l_pocket = /obj/item/modular_computer/pda/shaftminer
r_pocket = /obj/item/extinguisher/mini
belt = /obj/item/storage/belt/mining/healing
diff --git a/code/modules/jobs/job_types/station_engineer.dm b/code/modules/jobs/job_types/station_engineer.dm
index 1ce8f9bbd0fc..d9cc7d765422 100644
--- a/code/modules/jobs/job_types/station_engineer.dm
+++ b/code/modules/jobs/job_types/station_engineer.dm
@@ -79,7 +79,7 @@
/obj/item/construction/rcd/loaded,
)
- box = /obj/item/storage/box/survival/engineer
+ box = /obj/item/storage/pouch/survival/engineer
pda_slot = ITEM_SLOT_LPOCKET
// skillchips = list(/obj/item/skillchip/job/engineer)
diff --git a/code/modules/jobs/job_types/virologist.dm b/code/modules/jobs/job_types/virologist.dm
index 61fda519626d..32cd2f949c4a 100644
--- a/code/modules/jobs/job_types/virologist.dm
+++ b/code/modules/jobs/job_types/virologist.dm
@@ -69,4 +69,4 @@
duffelbag = /obj/item/storage/backpack/duffelbag/virology
messenger = /obj/item/storage/backpack/messenger/vir
- box = /obj/item/storage/box/survival/medical
+ box = /obj/item/storage/pouch/survival/medical
diff --git a/code/modules/jobs/job_types/warden.dm b/code/modules/jobs/job_types/warden.dm
index 5699fcd6bbb0..367cc16ccd4b 100644
--- a/code/modules/jobs/job_types/warden.dm
+++ b/code/modules/jobs/job_types/warden.dm
@@ -75,5 +75,5 @@
duffelbag = /obj/item/storage/backpack/duffelbag/sec
messenger = /obj/item/storage/backpack/messenger/sec
- box = /obj/item/storage/box/survival/security
+ box = /obj/item/storage/pouch/survival/security
implants = list(/obj/item/implant/mindshield)
diff --git a/code/modules/library/skill_learning/skillchip.dm b/code/modules/library/skill_learning/skillchip.dm
index 944480a64c78..2e041541495c 100644
--- a/code/modules/library/skill_learning/skillchip.dm
+++ b/code/modules/library/skill_learning/skillchip.dm
@@ -5,7 +5,7 @@
icon = 'icons/obj/devices/circuitry_n_data.dmi'
icon_state = "skillchip"
custom_price = PAYCHECK_CREW * 3
- w_class = WEIGHT_CLASS_SMALL
+ w_class = WEIGHT_CLASS_TINY
/// Traits automatically granted by this chip, optional. Lazylist.
var/list/auto_traits
diff --git a/code/modules/mining/equipment/marker_beacons.dm b/code/modules/mining/equipment/marker_beacons.dm
index c33181dd8068..80923301a2a0 100644
--- a/code/modules/mining/equipment/marker_beacons.dm
+++ b/code/modules/mining/equipment/marker_beacons.dm
@@ -25,6 +25,7 @@ GLOBAL_LIST_INIT(marker_beacon_colors, sort_list(list(
novariants = TRUE
cost = 1
source = /datum/robot_energy_storage/beacon
+ w_class = WEIGHT_CLASS_SMALL
var/picked_color = "Random"
/obj/item/stack/marker_beacon/ten //miners start with 10 of these
diff --git a/code/modules/mob/living/carbon/examine.dm b/code/modules/mob/living/carbon/examine.dm
index b023caf8aeae..d2337b248299 100644
--- a/code/modules/mob/living/carbon/examine.dm
+++ b/code/modules/mob/living/carbon/examine.dm
@@ -21,8 +21,7 @@
. = list()
var/list/clothes_info = get_clothing_examine_info(user)
- for(var/slot in clothes_info)
- var/slot_text = clothes_info[slot]
+ for(var/slot, slot_text in clothes_info)
if(slot_text)
. += slot_text
@@ -443,6 +442,8 @@
if(ears && !(obscured_slots & HIDEEARS) && !HAS_TRAIT(ears, TRAIT_EXAMINE_SKIP))
clothes[CLOTHING_SLOT(EARS)] = "[t_He] [t_has] [ears.examine_title(user, href = TRUE)] on [t_his] ears."
+ SEND_SIGNAL(src, COMSIG_CARBON_CLOTHING_EXAMINE, user, clothes)
+
return clothes
/mob/living/carbon/human/get_clothing_examine_info(mob/living/user)
diff --git a/code/modules/mob/living/carbon/human/_species.dm b/code/modules/mob/living/carbon/human/_species.dm
index 3da1d6a6f0d7..7118e7e7079c 100644
--- a/code/modules/mob/living/carbon/human/_species.dm
+++ b/code/modules/mob/living/carbon/human/_species.dm
@@ -660,15 +660,14 @@ GLOBAL_LIST_EMPTY(features_by_species)
if(!disable_warning)
to_chat(H, span_warning("You need a suit before you can attach this [I.name]!"))
return FALSE
- if(!H.wear_suit.allowed)
- if(!disable_warning)
- to_chat(H, span_warning("You somehow have a suit with no defined allowed items for suit storage, stop that."))
- return FALSE
+ var/any_suit_storage = (is_type_in_typecache(I, GLOB.any_suit_storage) || I.w_class == WEIGHT_CLASS_TINY)
+ if(any_suit_storage)
+ return TRUE
if(I.w_class > WEIGHT_CLASS_BULKY)
if(!disable_warning)
to_chat(H, span_warning("The [I.name] is too big to attach!")) //should be src?
return FALSE
- if( istype(I, /obj/item/modular_computer/pda) || istype(I, /obj/item/pen) || is_type_in_list(I, H.wear_suit.allowed) )
+ if( is_type_in_list(I, H.wear_suit.allowed) )
return TRUE
return FALSE
if(ITEM_SLOT_HANDCUFFED)
@@ -684,8 +683,9 @@ GLOBAL_LIST_EMPTY(features_by_species)
return FALSE
return TRUE
if(ITEM_SLOT_BACKPACK)
- if(H.back && H.back.atom_storage?.can_insert(I, H, messages = TRUE, force = indirect_action ? STORAGE_SOFT_LOCKED : STORAGE_NOT_LOCKED))
- return TRUE
+ for(var/obj/item/thing in list(H.get_item_by_slot(ITEM_SLOT_BACK), H.get_item_by_slot(ITEM_SLOT_BELT)))
+ if(thing.atom_storage?.can_insert(I, H, messages = !disable_warning && !indirect_action, force = indirect_action ? STORAGE_SOFT_LOCKED : STORAGE_NOT_LOCKED))
+ return TRUE
return FALSE
return FALSE //Unsupported slot
diff --git a/code/modules/mob/living/carbon/human/human_update_icons.dm b/code/modules/mob/living/carbon/human/human_update_icons.dm
index 43247682c152..fe6ad2e01bd2 100644
--- a/code/modules/mob/living/carbon/human/human_update_icons.dm
+++ b/code/modules/mob/living/carbon/human/human_update_icons.dm
@@ -354,7 +354,7 @@ There are several things that need to be remembered:
if(HAS_TRAIT(worn_item, TRAIT_NO_WORN_ICON) || (obscured_slots & HIDESUITSTORAGE))
return
- var/mutable_appearance/s_store_overlay = worn_item.build_worn_icon(default_layer = SUIT_STORE_LAYER, default_icon_file = 'icons/mob/clothing/belt_mirror.dmi')
+ var/mutable_appearance/s_store_overlay = worn_item.build_worn_icon(default_layer = SUIT_STORE_LAYER, default_icon_file = worn_item.mirror_icon || 'icons/mob/clothing/belt_mirror.dmi')
var/obj/item/bodypart/chest/my_chest = get_bodypart(BODY_ZONE_CHEST)
my_chest?.worn_suit_storage_offset?.apply_offset(s_store_overlay)
overlays_standing[SUIT_STORE_LAYER] = s_store_overlay
diff --git a/code/modules/mob/living/carbon/inventory.dm b/code/modules/mob/living/carbon/inventory.dm
index dfb82d056647..f746ba458b19 100644
--- a/code/modules/mob/living/carbon/inventory.dm
+++ b/code/modules/mob/living/carbon/inventory.dm
@@ -139,8 +139,11 @@
put_in_hands(equipping)
update_held_items()
if(ITEM_SLOT_BACKPACK)
- if(!back || !back.atom_storage?.attempt_insert(equipping, src, override = TRUE, force = indirect_action ? STORAGE_SOFT_LOCKED : STORAGE_NOT_LOCKED))
- not_handled = TRUE
+ not_handled = TRUE
+ for(var/obj/item/thing in list(get_item_by_slot(ITEM_SLOT_BACK), get_item_by_slot(ITEM_SLOT_BELT)))
+ if(thing.atom_storage?.attempt_insert(equipping, src, override = TRUE, force = indirect_action ? STORAGE_SOFT_LOCKED : STORAGE_NOT_LOCKED, messages = !initial && !indirect_action))
+ not_handled = FALSE
+ break
else
not_handled = TRUE
diff --git a/code/modules/mob_spawn/ghost_roles/space_roles.dm b/code/modules/mob_spawn/ghost_roles/space_roles.dm
index 79d028bdbcb2..374d3c0d4a10 100644
--- a/code/modules/mob_spawn/ghost_roles/space_roles.dm
+++ b/code/modules/mob_spawn/ghost_roles/space_roles.dm
@@ -138,7 +138,7 @@
l_pocket = /obj/item/gun/ballistic/automatic/pistol/clandestine
r_pocket = /obj/item/knife/combat/survival
- box = /obj/item/storage/box/survival/syndie
+ box = /obj/item/storage/pouch/survival/syndie
/obj/effect/mob_spawn/ghost_role/human/syndicate/battlecruiser/assault
name = "Syndicate Battlecruiser Assault Operative"
diff --git a/code/modules/projectiles/boxes_magazines/external/grenade.dm b/code/modules/projectiles/boxes_magazines/external/grenade.dm
index 4ba7d43efae4..c8106d3e1577 100644
--- a/code/modules/projectiles/boxes_magazines/external/grenade.dm
+++ b/code/modules/projectiles/boxes_magazines/external/grenade.dm
@@ -5,4 +5,4 @@
caliber = CALIBER_75
multiple_sprites = AMMO_BOX_FULL_EMPTY
max_ammo = 8
-
+ w_class = WEIGHT_CLASS_SMALL
diff --git a/code/modules/projectiles/boxes_magazines/external/lmg.dm b/code/modules/projectiles/boxes_magazines/external/lmg.dm
index 5af59b037770..769810e177bf 100644
--- a/code/modules/projectiles/boxes_magazines/external/lmg.dm
+++ b/code/modules/projectiles/boxes_magazines/external/lmg.dm
@@ -4,6 +4,7 @@
ammo_type = /obj/item/ammo_casing/m7mm
caliber = CALIBER_A7MM
max_ammo = 50
+ w_class = WEIGHT_CLASS_SMALL
/obj/item/ammo_box/magazine/m7mm/hollow
name = "box magazine (Hollow-Point 7mm)"
diff --git a/code/modules/projectiles/boxes_magazines/external/toy.dm b/code/modules/projectiles/boxes_magazines/external/toy.dm
index 79911ec47866..0c66cc7d55e1 100644
--- a/code/modules/projectiles/boxes_magazines/external/toy.dm
+++ b/code/modules/projectiles/boxes_magazines/external/toy.dm
@@ -49,6 +49,7 @@
base_icon_state = "a7mm"
ammo_type = /obj/item/ammo_casing/foam_dart
max_ammo = 50
+ w_class = WEIGHT_CLASS_SMALL
/obj/item/ammo_box/magazine/toy/m762/update_icon_state()
. = ..()
diff --git a/code/modules/surgery/bodyparts/parts.dm b/code/modules/surgery/bodyparts/parts.dm
index b9d33a1f7d1c..5316485196f5 100644
--- a/code/modules/surgery/bodyparts/parts.dm
+++ b/code/modules/surgery/bodyparts/parts.dm
@@ -12,6 +12,7 @@
px_y = 0
grind_results = null
wound_resistance = 10
+ w_class = WEIGHT_CLASS_BULKY
bodypart_trait_source = CHEST_TRAIT
///The bodyshape(s) allowed to attach to this chest.
var/acceptable_bodyshape = BODYSHAPE_HUMANOID
diff --git a/code/modules/surgery/surgery_tools.dm b/code/modules/surgery/surgery_tools.dm
index 67fb90ba8b41..aedcc6f4bdc0 100644
--- a/code/modules/surgery/surgery_tools.dm
+++ b/code/modules/surgery/surgery_tools.dm
@@ -9,7 +9,7 @@
custom_materials = list(/datum/material/iron = SHEET_MATERIAL_AMOUNT*3, /datum/material/glass =SHEET_MATERIAL_AMOUNT * 1.5)
obj_flags = CONDUCTS_ELECTRICITY
item_flags = SURGICAL_TOOL
- w_class = WEIGHT_CLASS_TINY
+ w_class = WEIGHT_CLASS_SMALL
tool_behaviour = TOOL_RETRACTOR
toolspeed = 1
drop_sound = 'maplestation_modules/sound/items/drop/knife3.ogg'
@@ -40,7 +40,7 @@
custom_materials = list(/datum/material/iron = SHEET_MATERIAL_AMOUNT * 2.5, /datum/material/glass = SHEET_MATERIAL_AMOUNT * 1.25)
obj_flags = CONDUCTS_ELECTRICITY
item_flags = SURGICAL_TOOL
- w_class = WEIGHT_CLASS_TINY
+ w_class = WEIGHT_CLASS_SMALL
attack_verb_continuous = list("attacks", "pinches")
attack_verb_simple = list("attack", "pinch")
tool_behaviour = TOOL_HEMOSTAT
@@ -82,7 +82,7 @@
custom_materials = list(/datum/material/iron = SHEET_MATERIAL_AMOUNT*1.25, /datum/material/glass = SMALL_MATERIAL_AMOUNT*7.5)
obj_flags = CONDUCTS_ELECTRICITY
item_flags = SURGICAL_TOOL
- w_class = WEIGHT_CLASS_TINY
+ w_class = WEIGHT_CLASS_SMALL
attack_verb_continuous = list("burns")
attack_verb_simple = list("burn")
tool_behaviour = TOOL_CAUTERY
@@ -222,7 +222,7 @@
item_flags = SURGICAL_TOOL
force = 10
demolition_mod = 0.25
- w_class = WEIGHT_CLASS_TINY
+ w_class = WEIGHT_CLASS_SMALL
throwforce = 5
throw_speed = 3
throw_range = 5
@@ -333,7 +333,7 @@
lefthand_file = 'icons/mob/inhands/equipment/medical_lefthand.dmi'
righthand_file = 'icons/mob/inhands/equipment/medical_righthand.dmi'
inhand_icon_state = "drapes"
- w_class = WEIGHT_CLASS_TINY
+ w_class = WEIGHT_CLASS_SMALL
attack_verb_continuous = list("slaps")
attack_verb_simple = list("slap")
drop_sound = 'maplestation_modules/sound/items/drop/generic2.ogg'
diff --git a/code/modules/vehicles/vehicle_key.dm b/code/modules/vehicles/vehicle_key.dm
index d5d9b5b774cb..73cbe7268e38 100644
--- a/code/modules/vehicles/vehicle_key.dm
+++ b/code/modules/vehicles/vehicle_key.dm
@@ -94,3 +94,4 @@
attack_verb_simple = list("flog", "whip", "lash", "discipline")
hitsound = 'sound/weapons/whip.ogg'
slot_flags = ITEM_SLOT_BELT
+ w_class = WEIGHT_CLASS_SMALL
diff --git a/maplestation.dme b/maplestation.dme
index 4fe727a5440f..b8c234f24b37 100644
--- a/maplestation.dme
+++ b/maplestation.dme
@@ -6313,6 +6313,7 @@
#include "maplestation_modules\code\datums\components\knockoff_move.dm"
#include "maplestation_modules\code\datums\components\limbless_aid.dm"
#include "maplestation_modules\code\datums\components\make_item_slow.dm"
+#include "maplestation_modules\code\datums\components\slows_with_backpack.dm"
#include "maplestation_modules\code\datums\components\stackable_item.dm"
#include "maplestation_modules\code\datums\components\crafting\recipes.dm"
#include "maplestation_modules\code\datums\diseases\disease_resistance.dm"
@@ -6397,9 +6398,12 @@
#include "maplestation_modules\code\game\objects\items\other_loadout_items\loadout_inhand_items.dm"
#include "maplestation_modules\code\game\objects\items\storage\belt.dm"
#include "maplestation_modules\code\game\objects\items\storage\boxes.dm"
+#include "maplestation_modules\code\game\objects\items\storage\coatpocket.dm"
#include "maplestation_modules\code\game\objects\items\storage\garment.dm"
#include "maplestation_modules\code\game\objects\items\storage\medkit.dm"
+#include "maplestation_modules\code\game\objects\items\storage\pouch.dm"
#include "maplestation_modules\code\game\objects\items\storage\storage.dm"
+#include "maplestation_modules\code\game\objects\items\storage\uniformpocket.dm"
#include "maplestation_modules\code\game\objects\items\tcg\tdatet.dm"
#include "maplestation_modules\code\game\objects\spawners\cycle_helper.dm"
#include "maplestation_modules\code\game\objects\spawners\random\contraband.dm"
diff --git a/maplestation_modules/code/datums/components/slows_with_backpack.dm b/maplestation_modules/code/datums/components/slows_with_backpack.dm
new file mode 100644
index 000000000000..c31b1e7c0aef
--- /dev/null
+++ b/maplestation_modules/code/datums/components/slows_with_backpack.dm
@@ -0,0 +1,63 @@
+/// Add to an item to cause it to slow the wearer if worn simultaneously with a backpack.
+/datum/component/slows_with_backpack
+
+/datum/component/slows_with_backpack/Initialize(...)
+ if(!isitem(parent))
+ return COMPONENT_INCOMPATIBLE
+
+ RegisterSignal(parent, COMSIG_ITEM_EQUIPPED, PROC_REF(on_equipped))
+ RegisterSignal(parent, COMSIG_ITEM_DROPPED, PROC_REF(on_unequipped))
+ RegisterSignal(parent, COMSIG_ATOM_EXAMINE, PROC_REF(on_examine))
+
+/datum/component/slows_with_backpack/Destroy()
+ var/obj/item/item_parent = parent
+ if(ismob(item_parent.loc))
+ UnregisterSignal(item_parent.loc, COMSIG_MOB_EQUIPPED_ITEM)
+ UnregisterSignal(item_parent.loc, COMSIG_MOB_UNEQUIPPED_ITEM)
+
+ qdel(parent.GetComponent(/datum/component/make_item_slow))
+ UnregisterSignal(parent, COMSIG_ITEM_EQUIPPED)
+ UnregisterSignal(parent, COMSIG_ITEM_DROPPED)
+ UnregisterSignal(parent, COMSIG_ATOM_EXAMINE)
+ return ..()
+
+/datum/component/slows_with_backpack/proc/on_examine(obj/item/source, mob/examiner, list/examine_list)
+ SIGNAL_HANDLER
+ examine_list += span_info("Wearing both a backpack and [source] simultaneously will encumber you.")
+
+/datum/component/slows_with_backpack/proc/on_equipped(obj/item/source, mob/user, slot)
+ SIGNAL_HANDLER
+
+ if(!(slot & (source.slot_flags|ITEM_SLOT_SUITSTORE)))
+ return
+
+ RegisterSignal(user, COMSIG_MOB_EQUIPPED_ITEM, PROC_REF(check_for_backpack))
+ RegisterSignal(user, COMSIG_MOB_UNEQUIPPED_ITEM, PROC_REF(uncheck_for_backpack))
+ var/obj/item/storage/backpack/backpack = user.get_item_by_slot(ITEM_SLOT_BACK)
+ if(isnull(backpack))
+ return
+
+ source.AddComponent(/datum/component/make_item_slow, 0.75)
+ to_chat(user, span_warning("Wearing [source] and [backpack] at the same time encumbers you a bit."))
+
+/datum/component/slows_with_backpack/proc/on_unequipped(obj/item/source, mob/user, ...)
+ SIGNAL_HANDLER
+ UnregisterSignal(user, COMSIG_MOB_EQUIPPED_ITEM)
+ UnregisterSignal(user, COMSIG_MOB_UNEQUIPPED_ITEM)
+ qdel(source.GetComponent(/datum/component/make_item_slow))
+
+/datum/component/slows_with_backpack/proc/check_for_backpack(mob/living/user, obj/item/equipped, slot)
+ SIGNAL_HANDLER
+
+ if((slot & ITEM_SLOT_BACK) && (equipped.slot_flags & ITEM_SLOT_BACK) && istype(equipped, /obj/item/storage/backpack))
+ parent.AddComponent(/datum/component/make_item_slow, 0.75)
+ to_chat(user, span_warning("Wearing [parent] and [equipped] at the same time encumbers you a bit."))
+
+/datum/component/slows_with_backpack/proc/uncheck_for_backpack(mob/living/user, obj/item/unequipped, ...)
+ SIGNAL_HANDLER
+
+ if(!istype(unequipped, /obj/item/storage/backpack))
+ return
+ if(!(unequipped.slot_flags & ITEM_SLOT_BACK))
+ return
+ qdel(parent.GetComponent(/datum/component/make_item_slow))
diff --git a/maplestation_modules/code/game/objects/items/storage/coatpocket.dm b/maplestation_modules/code/game/objects/items/storage/coatpocket.dm
new file mode 100644
index 000000000000..f07df82f357a
--- /dev/null
+++ b/maplestation_modules/code/game/objects/items/storage/coatpocket.dm
@@ -0,0 +1,13 @@
+/datum/storage/coatpocket
+ max_slots = 3
+ max_specific_storage = POCKET_WEIGHT_CLASS
+
+/datum/storage/coatpocket/can_insert(obj/item/to_insert, mob/user, messages, force)
+ . = ..()
+ if(!.)
+ return FALSE
+ if(to_insert.atom_storage && to_insert.w_class >= max_specific_storage)
+ if(messages && user)
+ parent.balloon_alert(user, "too big!")
+ return FALSE
+ return TRUE
diff --git a/maplestation_modules/code/game/objects/items/storage/pouch.dm b/maplestation_modules/code/game/objects/items/storage/pouch.dm
new file mode 100644
index 000000000000..06061c297498
--- /dev/null
+++ b/maplestation_modules/code/game/objects/items/storage/pouch.dm
@@ -0,0 +1,373 @@
+/datum/storage/pouch
+ max_specific_storage = WEIGHT_CLASS_SMALL
+ max_slots = 5
+ max_total_storage = 10
+ storage_sound = 'maplestation_modules/sound/items/storage/briefcase.ogg'
+ allow_big_nesting = TRUE
+
+// Commented out because people will probably hate this
+// /datum/storage/pouch/can_insert(obj/item/to_insert, mob/user, messages, force)
+// . = ..()
+// if(!.)
+// return FALSE
+// if(parent.loc?.atom_storage && !force)
+// if(messages && user)
+// parent.balloon_alert(user, "[LOWER_TEXT(parent.loc)] is in the way!")
+// return FALSE
+// return TRUE
+
+/datum/storage/pouch/survival
+ max_specific_storage = WEIGHT_CLASS_TINY
+ max_slots = 5
+ max_total_storage = 9
+
+/datum/storage/pouch/survival/New(atom/parent, max_slots, max_specific_storage, max_total_storage)
+ . = ..()
+ var/static/list/survival_typecache = typecacheof(list(
+ /obj/item/analyzer,
+ /obj/item/assembly/flash,
+ /obj/item/chameleon,
+ /obj/item/climbing_hook/emergency,
+ /obj/item/clipboard,
+ /obj/item/clockwork_slab,
+ /obj/item/clothing/accessory/medal,
+ /obj/item/clothing/glasses,
+ /obj/item/clothing/gloves,
+ /obj/item/clothing/mask/breath,
+ /obj/item/clothing/mask/gas/explorer,
+ /obj/item/clothing/mask/gas/sechailer,
+ /obj/item/clothing/mask/gas/syndicate,
+ /obj/item/clothing/mask/muzzle,
+ /obj/item/clothing/neck/eldritch_amulet,
+ /obj/item/clothing/neck/fake_heretic_amulet,
+ /obj/item/clothing/neck/heretic_focus,
+ /obj/item/codex_cicatrix,
+ /obj/item/crowbar, // ehhhhhh
+ /obj/item/desynchronizer,
+ /obj/item/extinguisher/mini,
+ /obj/item/flashlight,
+ /obj/item/folder,
+ /obj/item/food/donkpocket,
+ /obj/item/geiger_counter,
+ /obj/item/gps,
+ /obj/item/grenade,
+ /obj/item/hand_tele,
+ /obj/item/implanter,
+ /obj/item/instrument/harmonica,
+ /obj/item/instrument/piano_synth/headphones,
+ /obj/item/knife,
+ /obj/item/laser_pointer,
+ /obj/item/melee/baton/telescopic,
+ /obj/item/melee/cultblade/advanced_dagger,
+ /obj/item/melee/cultblade/dagger,
+ /obj/item/melee/energy,
+ /obj/item/melee/rune_carver,
+ /obj/item/mining_scanner,
+ /obj/item/modular_computer/pda,
+ /obj/item/multitool,
+ /obj/item/pinpointer,
+ /obj/item/radio,
+ /obj/item/restraints/handcuffs,
+ /obj/item/stack/cable_coil,
+ /obj/item/stack/medical,
+ /obj/item/stock_parts/power_store/cell,
+ /obj/item/storage/pill_bottle,
+ /obj/item/storage/wallet,
+ /obj/item/swapper,
+ /obj/item/syndicate_teleporter,
+ /obj/item/t_scanner,
+ /obj/item/tank/internals/emergency_oxygen,
+ /obj/item/tank/internals/plasmaman/belt,
+ /obj/item/teleportation_scroll,
+ /obj/item/tome,
+ /obj/item/toy/clockwork_watch,
+ ))
+
+ exception_hold = survival_typecache
+
+/datum/storage/pouch/survival/can_insert(obj/item/to_insert, mob/user, messages = TRUE, force = STORAGE_NOT_LOCKED)
+ . = ..()
+ if(!.)
+ return FALSE
+ // items in the exception list are still limited
+ if(to_insert.w_class >= WEIGHT_CLASS_NORMAL)
+ if(messages && user)
+ to_insert.balloon_alert(user, "too big!")
+ return FALSE
+ return TRUE
+
+/obj/item/storage/pouch
+ name = "pouch"
+ desc = "A pocket sized pouch."
+ icon = 'maplestation_modules/icons/obj/storage/pouch.dmi'
+ worn_icon = 'maplestation_modules/icons/mob/storage/pouch.dmi'
+ mirror_icon = 'maplestation_modules/icons/mob/storage/pouch_mirror.dmi'
+ icon_state = "pouch"
+ base_icon_state = "pouch"
+ inhand_icon_state = "syringe_kit"
+ lefthand_file = 'icons/mob/inhands/equipment/medical_lefthand.dmi'
+ righthand_file = 'icons/mob/inhands/equipment/medical_righthand.dmi'
+ resistance_flags = FLAMMABLE
+ drop_sound = 'maplestation_modules/sound/items/drop/generic2.ogg'
+ pickup_sound = 'maplestation_modules/sound/items/pickup/generic3.ogg'
+ w_class = POCKET_WEIGHT_CLASS
+ storage_type = /datum/storage/pouch
+ slot_flags = ITEM_SLOT_BELT
+ custom_price = PAYCHECK_COMMAND
+ custom_premium_price = PAYCHECK_COMMAND
+ /// Overlay to apply to the pouch
+ var/overlay_state = ""
+ /// Changes the icon state if an item was recently added or removed to storage
+ VAR_PRIVATE/recently_opened = FALSE
+
+/obj/item/storage/pouch/Initialize(mapload)
+ . = ..()
+ update_appearance()
+ RegisterSignals(src, list(COMSIG_ATOM_STORED_ITEM, COMSIG_ATOM_REMOVED_ITEM), PROC_REF(animate_icon))
+
+/obj/item/storage/pouch/update_overlays()
+ . = ..()
+ if(overlay_state)
+ . += overlay_state
+
+/obj/item/storage/pouch/update_icon_state()
+ . = ..()
+ icon_state = "[base_icon_state][recently_opened ? "_open" : ""]"
+
+/obj/item/storage/pouch/proc/animate_icon(...)
+ SIGNAL_HANDLER
+ recently_opened = TRUE
+ update_appearance(UPDATE_ICON_STATE)
+ addtimer(CALLBACK(src, PROC_REF(reset_recently_opened)), 2 SECONDS, TIMER_UNIQUE|TIMER_OVERRIDE)
+
+/obj/item/storage/pouch/proc/reset_recently_opened()
+ recently_opened = FALSE
+ update_appearance(UPDATE_ICON_STATE)
+
+/obj/item/storage/pouch/equipped(mob/user, slot, initial)
+ . = ..()
+ if(slot & (ITEM_SLOT_LPOCKET|ITEM_SLOT_RPOCKET))
+ RegisterSignal(user, COMSIG_CARBON_CLOTHING_EXAMINE, PROC_REF(on_examine))
+ else
+ UnregisterSignal(user, COMSIG_CARBON_CLOTHING_EXAMINE)
+
+/obj/item/storage/pouch/dropped(mob/user, silent)
+ . = ..()
+ UnregisterSignal(user, COMSIG_CARBON_CLOTHING_EXAMINE)
+
+/obj/item/storage/pouch/proc/on_examine(mob/source, mob/examiner, list/examine_list)
+ SIGNAL_HANDLER
+ if(HAS_TRAIT(src, TRAIT_EXAMINE_SKIP))
+ return
+ examine_list[type] = "[source.p_They()] [source.p_have()] [examine_title(examiner, href = TRUE)] \
+ clipped to [source.p_their()] [source.get_slot_by_item(src) == ITEM_SLOT_LPOCKET ? "left" : "right"] pocket."
+
+/obj/item/storage/pouch/tools
+ name = "tool pouch"
+ desc = "A pocket sized pouch, perfectly capable of holding a few tools."
+ overlay_state = "wrench"
+
+/obj/item/storage/pouch/pills
+ name = "pill pouch"
+ desc = "A pocket sized pouch, perfect for holding a few pills or small bottles."
+ overlay_state = "writing"
+
+/obj/item/storage/pouch/sharps
+ name = "sharps pouch"
+ desc = "A pocket sized pouch, perfect for holding a few syringes or small tools."
+ icon_state = "sharps"
+ overlay_state = "syringe"
+
+/obj/item/storage/pouch/handcuffs
+ name = "handcuff pouch"
+ desc = "A pocket sized pouch, capable of holding an extra pair of handcuffs or a flash."
+ overlay_state = "handcuffs"
+
+/obj/item/storage/pouch/flare
+ name = "flare pouch"
+ desc = "A pocket sized pouch, made to hold a few flares for an emergency."
+ overlay_state = "flare"
+
+/obj/item/storage/pouch/flare/PopulateContents()
+ . = ..()
+ for(var/i in 1 to 5)
+ new /obj/item/flashlight/flare(src)
+
+/obj/item/storage/pouch/botany
+ name = "botany pouch"
+ desc = "A pocket sized pouch, perfect for holding a few seeds, bottles, or small tools."
+ // overlay_state = "botany"
+
+/obj/item/storage/pouch/mining
+ name = "mining pouch"
+ desc = "A pocket sized pouch, made to hold mining supplies."
+ overlay_state = "mining"
+
+// Commented out because they fit already I think
+// /obj/item/storage/pouch/mining/Initialize(mapload)
+// . = ..()
+// atom_storage.set_holdable(list(
+// /obj/item/key/lasso,
+// /obj/item/mining_stabilizer,
+// /obj/item/organ/monster_core,
+// /obj/item/resonator,
+// /obj/item/skeleton_key,
+// /obj/item/stack/marker_beacon,
+// /obj/item/stack/sheet/animalhide,
+// /obj/item/stack/sheet/bone,
+// /obj/item/stack/sheet/sinew,
+// /obj/item/wormhole_jaunter,
+// ))
+
+/obj/item/storage/pouch/survival
+ name = "surival pouch"
+ desc = "A pocket sized pouch, assigned to members of the crew to use in emergencies."
+ icon_state = "pouch_em"
+ base_icon_state = "pouch_em"
+ overlay_state = "emergencytank"
+ storage_type = /datum/storage/pouch/survival
+ /// What type of mask are we going to use for this box?
+ var/mask_type = /obj/item/clothing/mask/breath
+ /// Which internals tank are we going to use for this box?
+ var/internal_type = /obj/item/tank/internals/emergency_oxygen
+ /// What medipen should be present in this box?
+ var/medipen_type = /obj/item/reagent_containers/hypospray/medipen
+ /// Whether or not this pouch should contain a radio
+ var/radio = FALSE
+
+/obj/item/storage/pouch/survival/Initialize(mapload)
+ if(isplasmaman(loc))
+ internal_type = /obj/item/tank/internals/plasmaman/belt
+ . = ..()
+
+ var/extra_slots_needed = length(contents) - atom_storage.max_slots
+ if(extra_slots_needed > 0)
+ atom_storage.max_slots += extra_slots_needed
+ atom_storage.max_total_storage += extra_slots_needed * 2
+ if(HAS_TRAIT(SSstation, STATION_TRAIT_PREMIUM_INTERNALS))
+ atom_storage.max_slots += 2
+ atom_storage.max_total_storage += 4
+ name = "large [name]"
+ transform = transform.Scale(1.25, 1)
+
+/obj/item/storage/pouch/survival/proc/wardrobe_removal()
+ if(!isplasmaman(loc)) //We need to specially fill the box with plasmaman gear, since it's intended for one
+ return
+ var/obj/item/mask = locate(mask_type) in src
+ var/obj/item/internals = locate(internal_type) in src
+ new /obj/item/tank/internals/plasmaman/belt(src)
+ qdel(mask) // Get rid of the items that shouldn't be
+ qdel(internals)
+
+/obj/item/storage/pouch/survival/PopulateContents()
+ if(!isnull(mask_type))
+ new mask_type(src)
+
+ if(!isnull(internal_type))
+ new internal_type(src)
+
+ if(!isnull(medipen_type))
+ new medipen_type(src)
+
+ if(HAS_TRAIT(SSstation, STATION_TRAIT_PREMIUM_INTERNALS))
+ new /obj/item/flashlight/flare(src)
+ if(radio || HAS_TRAIT(SSstation, STATION_TRAIT_PREMIUM_INTERNALS))
+ new /obj/item/radio/off(src)
+
+ if(HAS_TRAIT(SSstation, STATION_TRAIT_RADIOACTIVE_NEBULA))
+ new /obj/item/storage/pill_bottle/potassiodide(src)
+
+ if(SSmapping.is_planetary() && LAZYLEN(SSmapping.multiz_levels))
+ new /obj/item/climbing_hook/emergency(src)
+
+/obj/item/storage/pouch/survival/engineer
+ internal_type = /obj/item/tank/internals/emergency_oxygen/engi
+ radio = TRUE
+
+/obj/item/storage/pouch/survival/mining
+ mask_type = /obj/item/clothing/mask/gas/explorer/folded
+
+/obj/item/storage/pouch/survival/mining/bonus
+ mask_type = null
+ internal_type = /obj/item/tank/internals/emergency_oxygen/double
+
+/obj/item/storage/pouch/survival/mining/bonus/PopulateContents()
+ . = ..()
+ new /obj/item/gps/mining(src)
+ new /obj/item/t_scanner/adv_mining_scanner(src)
+
+/obj/item/storage/pouch/survival/medical
+ mask_type = /obj/item/clothing/mask/breath/medical
+
+/obj/item/storage/pouch/survival/security
+ mask_type = /obj/item/clothing/mask/gas/sechailer
+ radio = TRUE
+
+/obj/item/storage/pouch/survival/syndie
+ // icon_state = "syndiebox"
+ mask_type = /obj/item/clothing/mask/gas/syndicate
+ internal_type = /obj/item/tank/internals/emergency_oxygen/engi
+ medipen_type = /obj/item/reagent_containers/hypospray/medipen/atropine
+ radio = TRUE
+
+/obj/item/storage/pouch/survival/syndie/PopulateContents()
+ . = ..()
+ new /obj/item/crowbar/red(src)
+ new /obj/item/screwdriver/red(src)
+ new /obj/item/weldingtool/mini(src)
+ new /obj/item/paper/fluff/operative(src)
+
+/obj/item/storage/pouch/survival/centcom
+ internal_type = /obj/item/tank/internals/emergency_oxygen/double
+ radio = TRUE
+
+/obj/item/storage/pouch/survival/centcom/PopulateContents()
+ . = ..()
+ new /obj/item/crowbar(src)
+
+/obj/structure/closet/secure_closet/engineering_personal/PopulateContents()
+ . = ..()
+ new /obj/item/storage/pouch/tools(src)
+
+/obj/machinery/vending/tool
+ added_premium = list(
+ /obj/item/storage/pouch/tools = 3,
+ )
+
+/obj/machinery/vending/engivend
+ added_premium = list(
+ /obj/item/storage/pouch/tools = 5,
+ )
+
+/obj/machinery/vending/wardrobe/medi_wardrobe
+ added_premium = list(
+ /obj/item/storage/pouch/sharps = 4,
+ /obj/item/storage/pouch/pills = 4,
+ )
+
+/obj/machinery/vending/wardrobe/chem_wardrobe
+ added_premium = list(
+ /obj/item/storage/pouch/sharps = 2,
+ /obj/item/storage/pouch/pills = 2,
+ )
+
+/obj/machinery/vending/wardrobe/sec_wardrobe
+ added_premium = list(
+ /obj/item/storage/pouch/handcuffs = 5,
+ )
+
+/obj/structure/closet/wardrobe/miner/PopulateContents()
+ . = ..()
+ new /obj/item/storage/pouch/mining(src)
+ new /obj/item/storage/pouch/mining(src)
+
+/obj/machinery/vending/wardrobe/hydro_wardrobe
+ added_premium = list(
+ /obj/item/storage/pouch/botany = 4,
+ )
+
+/obj/machinery/vending/wardrobe/cargo_wardrobe
+ added_premium = list(
+ /obj/item/storage/pouch = 4,
+ /obj/item/storage/pouch/tools = 2,
+ )
diff --git a/maplestation_modules/code/game/objects/items/storage/uniformpocket.dm b/maplestation_modules/code/game/objects/items/storage/uniformpocket.dm
new file mode 100644
index 000000000000..25ca62c26dd6
--- /dev/null
+++ b/maplestation_modules/code/game/objects/items/storage/uniformpocket.dm
@@ -0,0 +1,266 @@
+/obj/item/clothing/under
+ /// The "pockets" attached to this uniform
+ var/obj/effect/abstract/abstract_storage/uniform_pockets/pockets
+
+/obj/item/clothing/under/Initialize(mapload)
+ . = ..()
+ RegisterSignal(src, COMSIG_ITEM_POST_UNEQUIP, PROC_REF(take_pockets_comsig))
+
+/obj/item/clothing/under/Destroy()
+ QDEL_NULL(pockets)
+ return ..()
+
+/obj/item/clothing/under/add_context(atom/source, list/context, obj/item/held_item, mob/living/user)
+ . = ..()
+ if(!isnull(held_item) && can_slip_in_pockets(user, held_item))
+ context[SCREENTIP_CONTEXT_RMB] = "Add to pockets"
+ . = CONTEXTUAL_SCREENTIP_SET
+
+/obj/item/clothing/under/examine(mob/user)
+ . = ..()
+ if(!pockets)
+ return
+ if(pockets.id)
+ . += ("• " + span_notice("It's got [pockets.id] attached to [p_they()]."))
+ if(pockets.l_pocket && pockets.r_pocket && pockets.l_pocket.w_class == WEIGHT_CLASS_TINY && pockets.r_pocket.w_class == WEIGHT_CLASS_TINY)
+ . += ("• " + span_notice("You can see something in both of [p_their()] pockets."))
+ else if(pockets.l_pocket)
+ . += ("• " + span_notice("You can see [pockets.l_pocket.w_class == WEIGHT_CLASS_TINY ? "something" : "\a [pockets.l_pocket]"] in [p_their()] left pocket."))
+ else if(pockets.r_pocket)
+ . += ("• " + span_notice("You can see [pockets.r_pocket.w_class == WEIGHT_CLASS_TINY ? "something" : "\a [pockets.r_pocket]"] in [p_their()] right pocket."))
+
+/obj/item/clothing/under/proc/can_slip_in_pockets(mob/living/user, obj/item/tool)
+ if(tool.w_class > POCKET_WEIGHT_CLASS)
+ return FALSE
+ if(src == user.get_item_by_slot(slot_flags))
+ return FALSE
+
+ return TRUE
+
+/obj/item/clothing/under/item_interaction_secondary(mob/living/user, obj/item/tool, list/modifiers)
+ if(!can_slip_in_pockets(user, tool))
+ return NONE
+
+ if(isnull(pockets))
+ init_pockets()
+
+ else if(tool.slot_flags & ITEM_SLOT_ID)
+ if(pockets.id)
+ to_chat(user, span_warning("[src] already has an ID attached to [p_them()]."))
+ return ITEM_INTERACT_BLOCKING
+
+ else if(pockets.l_pocket && pockets.r_pocket)
+ to_chat(user, span_warning("[src] already has something in both of [p_their()] pockets."))
+ return ITEM_INTERACT_BLOCKING
+
+ if(!pockets.atom_storage.can_insert(tool))
+ balloon_alert(user, "can't fit!")
+ QDEL_NULL(pockets)
+ return ITEM_INTERACT_BLOCKING
+
+ user.visible_message(
+ span_notice("[user] slips something in [src]'s pockets."),
+ span_notice("You slip [tool] in [src]'s pockets."),
+ vision_distance = COMBAT_MESSAGE_RANGE,
+ )
+ if(!do_after(user, 2 SECONDS, src) \
+ || !pockets.atom_storage.can_insert(tool) \
+ || !user.temporarilyRemoveItemFromInventory(tool))
+ QDEL_NULL(pockets)
+ return ITEM_INTERACT_BLOCKING
+
+ if(tool.slot_flags & ITEM_SLOT_ID)
+ if(!pockets.id)
+ pockets.id = tool
+ tool.forceMove(pockets)
+ return ITEM_INTERACT_SUCCESS
+ if(!pockets.l_pocket)
+ pockets.l_pocket = tool
+ tool.forceMove(pockets)
+ return ITEM_INTERACT_SUCCESS
+ if(!pockets.r_pocket)
+ pockets.r_pocket = tool
+ tool.forceMove(pockets)
+ return ITEM_INTERACT_SUCCESS
+
+ // need to do this incase someone else added pocket items while we were waiting
+ balloon_alert(user, "can't fit!")
+ user.put_in_active_hand(tool)
+ return ITEM_INTERACT_BLOCKING
+
+/obj/item/clothing/under/equipped(mob/living/user, slot)
+ . = ..()
+ if(isnull(pockets))
+ return
+ if(!(slot & slot_flags))
+ return
+
+ // do not allow storage interaction while worn
+ pockets.unregister_storage_signals()
+ pockets.atom_storage?.close_all()
+ // put pocket items back to relevant slots
+ for(var/equip_thing, equip_slot in pockets.get_items())
+ user.equip_to_slot_if_possible(equip_thing, equip_slot, disable_warning = TRUE)
+ // anything that maybe left behind for whatever reason
+ dump_pockets(user.drop_location())
+
+/obj/item/clothing/under/throw_impact(atom/hit_atom, datum/thrownthing/throwingdatum)
+ . = ..()
+ if(.)
+ return
+ // always dump on toss
+ dump_pockets()
+
+/obj/item/clothing/under/dropped(mob/living/user)
+ . = ..()
+ if(isnull(pockets))
+ return
+
+ // ensure you can interact with pockets after unequipping
+ pockets.register_storage_signals()
+ // drop pocket items if putting the uniform on the ground, otherwise keep
+ if(!ismob(loc) && should_dump_on_drop())
+ dump_pockets()
+
+/obj/item/clothing/under/atom_deconstruct(disassembled)
+ pockets?.deconstruct(disassembled)
+ return ..()
+
+/// Checks if we should dump pocket contents on drop
+/obj/item/clothing/under/proc/should_dump_on_drop()
+ for(var/atom/movable/thing in loc)
+ if(GLOB.typecache_elevated_structures[thing.type])
+ return FALSE
+ return TRUE
+
+/// Dumps pocket contents to the given location
+/obj/item/clothing/under/proc/dump_pockets(atom/drop_loc = drop_location())
+ pockets?.atom_storage?.remove_all(drop_loc)
+
+/obj/item/clothing/under/proc/take_pockets_comsig(datum/source, force, newloc, no_move, invdrop, silent)
+ SIGNAL_HANDLER
+
+ if(!invdrop || QDELING(src))
+ return
+
+ var/mob/living/carbon/human/wearer = loc
+ if(!istype(wearer))
+ return
+ if(!wearer.wear_id && !wearer.l_store && !wearer.r_store)
+ return
+
+ take_pockets(wearer)
+
+/obj/item/clothing/under/Exited(atom/movable/gone, direction)
+ . = ..()
+ if(gone == pockets)
+ pockets = null
+ if(!QDELING(gone))
+ qdel(gone)
+
+/// Init pockets if necessary
+/obj/item/clothing/under/proc/init_pockets()
+ pockets ||= new(src)
+
+/// Take our pockets and IDs and places them in relevant slots
+/obj/item/clothing/under/proc/take_pockets(mob/living/carbon/human/from_who)
+ init_pockets()
+
+ var/obj/item/who_id = from_who.wear_id
+ if(who_id && !pockets.id && pockets.atom_storage.can_insert(who_id) && from_who.temporarilyRemoveItemFromInventory(who_id))
+ pockets.id = who_id
+ who_id.forceMove(pockets)
+
+ var/obj/item/who_l_pocket = from_who.l_store
+ if(who_l_pocket && !pockets.l_pocket && pockets.atom_storage.can_insert(who_l_pocket) && from_who.temporarilyRemoveItemFromInventory(who_l_pocket))
+ pockets.l_pocket = who_l_pocket
+ who_l_pocket.forceMove(pockets)
+
+ var/obj/item/who_r_pocket = from_who.r_store
+ if(who_r_pocket && !pockets.r_pocket && pockets.atom_storage.can_insert(who_r_pocket) && from_who.temporarilyRemoveItemFromInventory(who_r_pocket))
+ pockets.r_pocket = who_r_pocket
+ who_r_pocket.forceMove(pockets)
+
+// Storage just for uniform fake pockets
+/datum/storage/uniform_pocket
+
+/datum/storage/uniform_pocket/attempt_insert(obj/item/to_insert, mob/user, override, force, messages)
+ return FALSE // Don't let anyone inser things normally AT ALL thank you. We'll forceMove if we must
+
+/datum/storage/uniform_pocket/animate_storage(atom/animate)
+ animate = parent.loc
+ return ..() // Redirects animations to the uniform itself (parent.loc)
+
+/**
+ * Abstract object intended for either:
+ * - Holding a storage datum for an atom that might get another storage datum from another source
+ * - Holding an item's contents that might have other non-storage contents
+ */
+/obj/effect/abstract/abstract_storage
+ density = FALSE
+ invisibility = INVISIBILITY_ABSTRACT
+ anchored = TRUE
+ mouse_opacity = MOUSE_OPACITY_TRANSPARENT
+ // hack to get around the fact that we fail canreach if our loc doesn't have a storage of itself
+ // probably fine if we just rename this flag to be more accurate (CAN_ALWAYS_REACH_1 or something)
+ flags_1 = IS_ONTOP_1
+ /// What type of storage do we use
+ var/storage_type = /datum/storage
+
+/obj/effect/abstract/abstract_storage/Initialize(mapload)
+ . = ..()
+ if(!isnull(storage_type))
+ create_storage(storage_type = storage_type)
+
+// Used for uniforms (to circumvent accessories)
+/obj/effect/abstract/abstract_storage/uniform_pockets
+ name = "pockets"
+ storage_type = /datum/storage/uniform_pocket
+ /// What was in our left pocket?
+ var/obj/item/l_pocket
+ /// What was in our right pocket?
+ var/obj/item/r_pocket
+ /// What was in our ID slot?
+ var/obj/item/id
+
+/obj/effect/abstract/abstract_storage/uniform_pockets/Initialize(mapload)
+ . = ..()
+ atom_storage.max_specific_storage = POCKET_WEIGHT_CLASS
+ atom_storage.max_slots = 3
+ atom_storage.max_total_storage = atom_storage.max_specific_storage * atom_storage.max_slots
+ if(isnull(loc))
+ return
+
+ name = "[loc.name]'s pockets"
+ register_storage_signals()
+
+/obj/effect/abstract/abstract_storage/uniform_pockets/proc/register_storage_signals()
+ atom_storage.RegisterSignal(loc, COMSIG_MOUSEDROP_ONTO, TYPE_PROC_REF(/datum/storage, on_mousedrop_onto), TRUE)
+ atom_storage.RegisterSignals(loc, list(COMSIG_CLICK_ALT, COMSIG_ATOM_ATTACK_GHOST, COMSIG_ATOM_ATTACK_HAND_SECONDARY), TYPE_PROC_REF(/datum/storage, open_storage_on_signal), TRUE)
+
+/obj/effect/abstract/abstract_storage/uniform_pockets/proc/unregister_storage_signals()
+ atom_storage.UnregisterSignal(loc, COMSIG_MOUSEDROP_ONTO)
+ atom_storage.UnregisterSignal(loc, list(COMSIG_CLICK_ALT, COMSIG_ATOM_ATTACK_GHOST, COMSIG_ATOM_ATTACK_HAND_SECONDARY))
+
+/obj/effect/abstract/abstract_storage/uniform_pockets/Exited(atom/movable/gone, direction)
+ . = ..()
+ if(gone == id)
+ id = null
+ if(gone == l_pocket)
+ l_pocket = null
+ if(gone == r_pocket)
+ r_pocket = null
+
+/obj/effect/abstract/abstract_storage/uniform_pockets/proc/get_items()
+ . = list()
+ if(id)
+ .[id] = ITEM_SLOT_ID
+ if(l_pocket)
+ .[l_pocket] = ITEM_SLOT_LPOCKET
+ if(r_pocket)
+ .[r_pocket] = ITEM_SLOT_RPOCKET
+
+// Used for winter coats because they store the hood in the coat's contents
+/obj/effect/abstract/abstract_storage/coat_pockets
+ name = "coat pockets"
+ storage_type = null
diff --git a/maplestation_modules/code/modules/clothing/suits/armor.dm b/maplestation_modules/code/modules/clothing/suits/armor.dm
index 58c42bf8fa0b..80a4116de8d9 100644
--- a/maplestation_modules/code/modules/clothing/suits/armor.dm
+++ b/maplestation_modules/code/modules/clothing/suits/armor.dm
@@ -115,3 +115,4 @@
/obj/item/clothing/suit/greyscale_parade/Initialize(mapload)
. = ..()
AddComponent(/datum/component/toggle_icon/greyscale, "buttons", /datum/greyscale_config/parade_formal_open, /datum/greyscale_config/parade_formal_open_worn)
+ create_storage(storage_type = /datum/storage/coatpocket)
diff --git a/maplestation_modules/code/modules/jobs/job_types/asset_protection.dm b/maplestation_modules/code/modules/jobs/job_types/asset_protection.dm
index ebb816e2be6b..80a7f1ade807 100644
--- a/maplestation_modules/code/modules/jobs/job_types/asset_protection.dm
+++ b/maplestation_modules/code/modules/jobs/job_types/asset_protection.dm
@@ -75,7 +75,7 @@
suit = /obj/item/clothing/suit/armor/vest/asset_protection
suit_store = /obj/item/gun/energy/disabler/phaser
id_trim = /datum/id_trim/job/asset_protection
- box = /obj/item/storage/box/survival/security
+ box = /obj/item/storage/pouch/survival/security
implants = list(/obj/item/implant/mindshield)
diff --git a/maplestation_modules/code/modules/jobs/job_types/bridge_officer.dm b/maplestation_modules/code/modules/jobs/job_types/bridge_officer.dm
index 4695a1b59e39..caf176cf295b 100644
--- a/maplestation_modules/code/modules/jobs/job_types/bridge_officer.dm
+++ b/maplestation_modules/code/modules/jobs/job_types/bridge_officer.dm
@@ -81,7 +81,7 @@
shoes = /obj/item/clothing/shoes/laceup
head = /obj/item/clothing/head/beret/black/bridge_officer
id_trim = /datum/id_trim/job/bridge_officer
- box = /obj/item/storage/box/survival
+ box = /obj/item/storage/pouch/survival
backpack_contents = list(/obj/item/melee/baton/telescopic = 1, /obj/item/gun/energy/disabler = 1)
diff --git a/maplestation_modules/code/modules/jobs/job_types/noble_ambassador.dm b/maplestation_modules/code/modules/jobs/job_types/noble_ambassador.dm
index b4cb012f2e84..ecd714ad5ce1 100644
--- a/maplestation_modules/code/modules/jobs/job_types/noble_ambassador.dm
+++ b/maplestation_modules/code/modules/jobs/job_types/noble_ambassador.dm
@@ -64,7 +64,7 @@
suit = /obj/item/clothing/suit/toggle/noble
shoes = /obj/item/clothing/shoes/noble
id_trim = /datum/id_trim/job/noble_ambassador
- box = /obj/item/storage/box/survival
+ box = /obj/item/storage/pouch/survival
backpack_contents = list(/obj/item/melee/baton/telescopic = 1)
diff --git a/maplestation_modules/code/modules/loadouts/loadout_items/loadout_datum_belts.dm b/maplestation_modules/code/modules/loadouts/loadout_items/loadout_datum_belts.dm
index 663e37e7797c..30d2d7ebbf3f 100644
--- a/maplestation_modules/code/modules/loadouts/loadout_items/loadout_datum_belts.dm
+++ b/maplestation_modules/code/modules/loadouts/loadout_items/loadout_datum_belts.dm
@@ -10,29 +10,8 @@
abstract_type = /datum/loadout_item/belts
/datum/loadout_item/belts/insert_path_into_outfit(datum/outfit/outfit, list/item_details, mob/living/carbon/human/equipper, visuals_only, job_equipping_step)
- if(!outfit.belt)
- outfit.belt = item_path
- return
- // try to move the existing belt to the backpack
- var/obj/item/move_belt = outfit.belt
- if(outfit.l_hand && outfit.r_hand && initial(move_belt.w_class) <= WEIGHT_CLASS_NORMAL)
- LAZYADD(outfit.backpack_contents, outfit.belt)
- outfit.belt = item_path
- return
- // try to carry the existing belt in a hand
- if(!outfit.l_hand)
- outfit.l_hand = outfit.belt
- outfit.belt = item_path
- return
- if(!outfit.r_hand)
- outfit.r_hand = outfit.belt
- outfit.belt = item_path
- return
- // failed to put it on, put it in the backpack
- if(initial(item_path.w_class) <= WEIGHT_CLASS_NORMAL)
- LAZYADD(outfit.backpack_contents, item_path)
- return
- to_chat(equipper, span_notice("Your loadout belt was not equipped to preserve your job's equipment."))
+ if(!outfit.replace_belt_keep_old(item_path))
+ to_chat(equipper, span_notice("Your loadout belt was not equipped to preserve your job's equipment."))
/datum/loadout_item/belts/fanny_pack_black
name = "Fannypack (Black)"
diff --git a/maplestation_modules/code/modules/vending/clothesmate.dm b/maplestation_modules/code/modules/vending/clothesmate.dm
index 546b3127b824..dab78bca7999 100644
--- a/maplestation_modules/code/modules/vending/clothesmate.dm
+++ b/maplestation_modules/code/modules/vending/clothesmate.dm
@@ -44,6 +44,17 @@
/obj/item/clothing/shoes/heels = 3,
),
),
+
+ list(
+ "name" = "Storage",
+ "products" = list(
+ /obj/item/storage/backpack/messenger = 2,
+ /obj/item/storage/backpack/satchel = 2,
+ /obj/item/storage/backpack/satchel/leather = 2,
+ /obj/item/storage/belt/chest_pouch = 4,
+ /obj/item/storage/pouch = 6,
+ ),
+ ),
)
added_premium = list(
/obj/item/clothing/shoes/heels/fancy = 2,
diff --git a/maplestation_modules/icons/mob/storage/pouch.dmi b/maplestation_modules/icons/mob/storage/pouch.dmi
new file mode 100644
index 000000000000..38a7b26cb5f6
Binary files /dev/null and b/maplestation_modules/icons/mob/storage/pouch.dmi differ
diff --git a/maplestation_modules/icons/mob/storage/pouch_mirror.dmi b/maplestation_modules/icons/mob/storage/pouch_mirror.dmi
new file mode 100644
index 000000000000..7cfe7676c4ac
Binary files /dev/null and b/maplestation_modules/icons/mob/storage/pouch_mirror.dmi differ
diff --git a/maplestation_modules/icons/obj/storage/pouch.dmi b/maplestation_modules/icons/obj/storage/pouch.dmi
new file mode 100644
index 000000000000..e96e4eddc13c
Binary files /dev/null and b/maplestation_modules/icons/obj/storage/pouch.dmi differ