From 7d0f393f5d3cb4ebe7ca5427628e4d1e9a8d2303 Mon Sep 17 00:00:00 2001
From: magatsuchi <88991542+magatsuchi@users.noreply.github.com>
Date: Fri, 8 Jul 2022 20:13:18 -0500
Subject: [PATCH] Tsu's Brand Spanking New Storage: or, How I Learned To Pass
Github Copilot As My Own Code (#67478)
Currently, storage works as a subtype of /datum/component, utilizing GetComponent() and signals to operate. While this is a pretty good idea in theory, the execution was pretty trash, and we end up with alot of GetComponent() snowflake code (something that shouldn't even need to be used frankly), and a heaping load of scattered procs that lead into one another, and procs that don't get utilized properly.
Instead, this PR adds atom_storage and proc/create_storage(. . .) to every atom, allowing for the possibility of storage on quite frankly anything. Not only does this entirely remove the need for signals, but it heavily squashes down the number of needed procs in total (removing snowflake signal procs that just lead to one another), reducing overall proc overhead and improving performance.
---
code/__DEFINES/dcs/signals/signals_storage.dm | 32 -
code/__DEFINES/flags.dm | 2 +
code/__DEFINES/inventory.dm | 10 +-
code/__HELPERS/atoms.dm | 6 +-
code/_globalvars/bitfields.dm | 1 +
code/_onclick/click.dm | 13 +-
code/_onclick/hud/screen_objects.dm | 6 +-
code/datums/components/crafting/crafting.dm | 2 +-
code/datums/components/explodable.dm | 12 +-
code/datums/components/food/decomposition.dm | 8 +-
.../components/{storage => }/food_storage.dm | 0
code/datums/components/holderloving.dm | 8 +-
.../components/storage/concrete/_concrete.dm | 204 ----
.../storage/concrete/bag_of_holding.dm | 27 -
.../components/storage/concrete/bluespace.dm | 22 -
.../storage/concrete/extract_inventory.dm | 37 -
.../components/storage/concrete/fish_case.dm | 4 -
.../components/storage/concrete/implant.dm | 18 -
.../components/storage/concrete/rped.dm | 33 -
.../components/storage/concrete/stack.dm | 68 --
.../storage/concrete/trading_cards.dm | 49 -
.../components/storage/concrete/wallet.dm | 13 -
code/datums/components/storage/storage.dm | 960 ---------------
code/datums/elements/item_scaling.dm | 14 +-
code/datums/quirks/_quirk.dm | 2 +-
code/datums/storage/storage.dm | 1063 +++++++++++++++++
.../datums/storage/subtypes/bag_of_holding.dm | 34 +
code/datums/storage/subtypes/cards.dm | 66 +
.../storage/subtypes/extract_inventory.dm | 43 +
code/datums/storage/subtypes/implant.dm | 10 +
.../concrete => storage/subtypes}/pockets.dm | 87 +-
code/game/atoms.dm | 63 +-
code/game/atoms_movable.dm | 16 +-
code/game/machinery/_machinery.dm | 4 +-
code/game/machinery/constructable_frame.dm | 2 +-
code/game/machinery/launch_pad.dm | 2 +-
code/game/objects/items.dm | 23 +-
code/game/objects/items/crayons.dm | 6 +-
.../items/devices/portable_chem_mixer.dm | 33 +-
code/game/objects/items/dice.dm | 6 +-
.../objects/items/implants/implant_storage.dm | 21 +-
code/game/objects/items/mail.dm | 13 +-
code/game/objects/items/melee/misc.dm | 8 +-
code/game/objects/items/religion.dm | 3 +-
code/game/objects/items/stacks/stack.dm | 1 +
code/game/objects/items/storage/backpack.dm | 67 +-
code/game/objects/items/storage/bags.dm | 191 ++-
code/game/objects/items/storage/basket.dm | 7 +-
code/game/objects/items/storage/belt.dm | 149 +--
code/game/objects/items/storage/book.dm | 5 +-
code/game/objects/items/storage/boxes.dm | 59 +-
code/game/objects/items/storage/briefcase.dm | 7 +-
code/game/objects/items/storage/fancy.dm | 99 +-
code/game/objects/items/storage/garment.dm | 15 +-
code/game/objects/items/storage/holsters.dm | 50 +-
code/game/objects/items/storage/lockbox.dm | 46 +-
code/game/objects/items/storage/medkit.dm | 35 +-
code/game/objects/items/storage/secure.dm | 33 +-
code/game/objects/items/storage/sixpack.dm | 11 +-
code/game/objects/items/storage/storage.dm | 14 +-
code/game/objects/items/storage/toolbox.dm | 33 +-
.../game/objects/items/storage/uplink_kits.dm | 12 +-
code/game/objects/items/storage/wallets.dm | 8 +-
code/game/objects/items/tcg/tcg.dm | 11 +-
.../structures/crates_lockers/closets.dm | 2 +-
.../structures/crates_lockers/crates/bins.dm | 2 +-
code/game/objects/structures/tables_racks.dm | 2 +-
code/game/turfs/turf.dm | 19 +-
.../antagonists/clown_ops/clown_weapons.dm | 10 +-
code/modules/antagonists/cult/cult.dm | 2 +-
.../heretic/items/heretic_armor.dm | 6 +-
code/modules/clothing/chameleon.dm | 9 +-
code/modules/clothing/clothing.dm | 15 +-
code/modules/clothing/head/fedora.dm | 6 +-
code/modules/clothing/head/helmet.dm | 6 +-
code/modules/clothing/head/jobs.dm | 10 +-
code/modules/clothing/head/religious.dm | 12 +-
code/modules/clothing/outfits/standard.dm | 10 +-
code/modules/clothing/outfits/vv_outfit.dm | 4 +-
code/modules/clothing/shoes/boots.dm | 30 +-
code/modules/clothing/shoes/clown.dm | 3 +-
code/modules/clothing/shoes/costume.dm | 6 +-
code/modules/clothing/shoes/cowboy.dm | 4 +-
code/modules/clothing/shoes/gunboots.dm | 4 +-
code/modules/clothing/shoes/jumpboots.dm | 6 +-
code/modules/clothing/suits/moth.dm | 6 +-
code/modules/clothing/under/accessories.dm | 33 +-
code/modules/detectivework/evidence.dm | 6 +-
code/modules/events/wizard/rpgloot.dm | 6 +-
code/modules/explorer_drone/exodrone.dm | 9 +-
code/modules/fishing/aquarium/aquarium_kit.dm | 6 +-
code/modules/fishing/fishing_equipment.dm | 5 +-
.../kitchen_machinery/deep_fryer.dm | 2 +-
.../kitchen_machinery/microwave.dm | 2 +-
.../kitchen_machinery/processor.dm | 2 +-
.../kitchen_machinery/smartfridge.dm | 4 +-
code/modules/holiday/easter.dm | 3 +-
code/modules/hydroponics/biogenerator.dm | 2 +-
code/modules/hydroponics/hydroponics.dm | 2 +-
code/modules/hydroponics/seed_extractor.dm | 5 +-
code/modules/library/bookcase.dm | 5 +-
code/modules/mining/fulton.dm | 2 +-
code/modules/mining/lavaland/tendril_loot.dm | 18 +-
code/modules/mining/money_bag.dm | 8 +-
code/modules/mining/satchel_ore_boxdm.dm | 4 +-
code/modules/mob/inventory.dm | 8 +-
.../mob/living/carbon/human/inventory.dm | 6 +-
.../mob/living/carbon/human/species.dm | 2 +-
code/modules/mob/living/carbon/inventory.dm | 2 +-
code/modules/mob/living/living.dm | 6 +-
.../mob/living/silicon/robot/inventory.dm | 2 +-
.../friendly/drone/drone_tools.dm | 15 +-
.../mob/living/simple_animal/slime/slime.dm | 2 +-
code/modules/mob/mob_defines.dm | 2 +-
code/modules/mod/modules/modules_antag.dm | 4 +-
code/modules/mod/modules/modules_general.dm | 31 +-
code/modules/paperwork/handlabeler.dm | 2 +-
code/modules/photography/photos/album.dm | 9 +-
code/modules/power/cell.dm | 2 +-
.../modules/projectiles/guns/ballistic/bow.dm | 9 +-
.../projectiles/guns/energy/dueling.dm | 11 +-
.../chemistry/machinery/chem_master.dm | 9 +-
.../chemistry/machinery/reagentgrinder.dm | 2 +-
.../chemistry/reagents/food_reagents.dm | 2 +-
code/modules/recycling/disposal/bin.dm | 12 +-
code/modules/research/stock_parts.dm | 17 +-
.../xenobiology/crossbreeding/reproductive.dm | 24 +-
.../research/xenobiology/xenobiology.dm | 2 +-
code/modules/shuttle/emergency.dm | 2 +-
code/modules/unit_tests/serving_tray.dm | 2 +-
code/modules/vending/_vending.dm | 2 +-
config/admins.txt | 1 +
tgstation.dme | 21 +-
133 files changed, 2056 insertions(+), 2358 deletions(-)
delete mode 100644 code/__DEFINES/dcs/signals/signals_storage.dm
rename code/datums/components/{storage => }/food_storage.dm (100%)
delete mode 100644 code/datums/components/storage/concrete/_concrete.dm
delete mode 100644 code/datums/components/storage/concrete/bag_of_holding.dm
delete mode 100644 code/datums/components/storage/concrete/bluespace.dm
delete mode 100644 code/datums/components/storage/concrete/extract_inventory.dm
delete mode 100644 code/datums/components/storage/concrete/fish_case.dm
delete mode 100644 code/datums/components/storage/concrete/implant.dm
delete mode 100644 code/datums/components/storage/concrete/rped.dm
delete mode 100644 code/datums/components/storage/concrete/stack.dm
delete mode 100644 code/datums/components/storage/concrete/trading_cards.dm
delete mode 100644 code/datums/components/storage/concrete/wallet.dm
delete mode 100644 code/datums/components/storage/storage.dm
create mode 100644 code/datums/storage/storage.dm
create mode 100644 code/datums/storage/subtypes/bag_of_holding.dm
create mode 100644 code/datums/storage/subtypes/cards.dm
create mode 100644 code/datums/storage/subtypes/extract_inventory.dm
create mode 100644 code/datums/storage/subtypes/implant.dm
rename code/datums/{components/storage/concrete => storage/subtypes}/pockets.dm (63%)
diff --git a/code/__DEFINES/dcs/signals/signals_storage.dm b/code/__DEFINES/dcs/signals/signals_storage.dm
deleted file mode 100644
index 72bddfba280..00000000000
--- a/code/__DEFINES/dcs/signals/signals_storage.dm
+++ /dev/null
@@ -1,32 +0,0 @@
-// /datum/component/storage signals
-///() - returns bool.
-#define COMSIG_CONTAINS_STORAGE "is_storage"
-///(obj/item/inserting, mob/user, silent, force) - returns bool
-#define COMSIG_TRY_STORAGE_INSERT "storage_try_insert"
-///(mob/show_to, force) - returns bool.
-#define COMSIG_TRY_STORAGE_SHOW "storage_show_to"
-///(mob/hide_from) - returns bool
-#define COMSIG_TRY_STORAGE_HIDE_FROM "storage_hide_from"
-///returns bool
-#define COMSIG_TRY_STORAGE_HIDE_ALL "storage_hide_all"
-///(newstate)
-#define COMSIG_TRY_STORAGE_SET_LOCKSTATE "storage_lock_set_state"
-///() - returns bool. MUST CHECK IF STORAGE IS THERE FIRST!
-#define COMSIG_IS_STORAGE_LOCKED "storage_get_lockstate"
-///(type, atom/destination, amount = INFINITY, check_adjacent, force, mob/user, list/inserted) - returns bool - type can be a list of types.
-#define COMSIG_TRY_STORAGE_TAKE_TYPE "storage_take_type"
-///(type, amount = INFINITY, force = FALSE). Force will ignore max_items, and amount is normally clamped to max_items.
-#define COMSIG_TRY_STORAGE_FILL_TYPE "storage_fill_type"
-///(obj, new_loc, force = FALSE) - returns bool
-#define COMSIG_TRY_STORAGE_TAKE "storage_take_obj"
-///(loc) - returns bool - if loc is null it will dump at parent location.
-#define COMSIG_TRY_STORAGE_QUICK_EMPTY "storage_quick_empty"
-///(list/list_to_inject_results_into, recursively_search_inside_storages = TRUE)
-#define COMSIG_TRY_STORAGE_RETURN_INVENTORY "storage_return_inventory"
-///(obj/item/insertion_candidate, mob/user, silent) - returns bool
-#define COMSIG_TRY_STORAGE_CAN_INSERT "storage_can_equip"
-
-//from base of atom/movable/on_enter_storage(): (datum/component/storage/concrete/master_storage)
-#define COMSIG_STORAGE_ENTERED "storage_entered"
-//from base of atom/movable/on_exit_storage(): (datum/component/storage/concrete/master_storage)
-#define COMSIG_STORAGE_EXITED "storage_exited"
diff --git a/code/__DEFINES/flags.dm b/code/__DEFINES/flags.dm
index fa4c59612d3..c596b9bb5c5 100644
--- a/code/__DEFINES/flags.dm
+++ b/code/__DEFINES/flags.dm
@@ -58,6 +58,8 @@ GLOBAL_LIST_INIT(bitflags, list(1, 2, 4, 8, 16, 32, 64, 128, 256, 512, 1024, 204
#define IS_PLAYER_COLORABLE_1 (1<<21)
/// Whether or not this atom has contextual screentips when hovered OVER
#define HAS_CONTEXTUAL_SCREENTIPS_1 (1<<22)
+// Whether or not this atom is storing contents for a disassociated storage object
+#define HAS_DISASSOCIATED_STORAGE_1 (1<<23)
// Update flags for [/atom/proc/update_appearance]
/// Update the atom's name
diff --git a/code/__DEFINES/inventory.dm b/code/__DEFINES/inventory.dm
index 7ad02ab4525..a18ac4fb395 100644
--- a/code/__DEFINES/inventory.dm
+++ b/code/__DEFINES/inventory.dm
@@ -2,15 +2,15 @@
//ITEM INVENTORY WEIGHT, FOR w_class
/// Usually items smaller then a human hand, (e.g. playing cards, lighter, scalpel, coins/holochips)
-#define WEIGHT_CLASS_TINY 1
+#define WEIGHT_CLASS_TINY 1
/// Pockets can hold small and tiny items, (e.g. flashlight, multitool, grenades, GPS device)
-#define WEIGHT_CLASS_SMALL 2
+#define WEIGHT_CLASS_SMALL 2
/// Standard backpacks can carry tiny, small & normal items, (e.g. fire extinguisher, stun baton, gas mask, metal sheets)
-#define WEIGHT_CLASS_NORMAL 3
+#define WEIGHT_CLASS_NORMAL 3
/// Items that can be weilded or equipped but not stored in an inventory, (e.g. defibrillator, backpack, space suits)
-#define WEIGHT_CLASS_BULKY 4
+#define WEIGHT_CLASS_BULKY 4
/// Usually represents objects that require two hands to operate, (e.g. shotgun, two-handed melee weapons)
-#define WEIGHT_CLASS_HUGE 5
+#define WEIGHT_CLASS_HUGE 5
/// Essentially means it cannot be picked up or placed in an inventory, (e.g. mech parts, safe)
#define WEIGHT_CLASS_GIGANTIC 6
diff --git a/code/__HELPERS/atoms.dm b/code/__HELPERS/atoms.dm
index ebb704678b8..861f9475208 100644
--- a/code/__HELPERS/atoms.dm
+++ b/code/__HELPERS/atoms.dm
@@ -319,11 +319,7 @@ rough example of the "cone" made by the 3 dirs checked
. = list()
if(!istype(target) || !(target.item_flags & IN_STORAGE))
return
- var/datum/component/storage/concrete/storage_datum = target.loc.GetComponent(/datum/component/storage/concrete)
+ var/datum/storage/storage_datum = target.loc.atom_storage
if(!storage_datum)
return
. += storage_datum.parent
- for(var/datum/component/storage/slave as anything in storage_datum.slaves)
- if(!isatom(slave.parent))
- continue
- . += slave.parent
diff --git a/code/_globalvars/bitfields.dm b/code/_globalvars/bitfields.dm
index 79067e9666d..80d8b5bb631 100644
--- a/code/_globalvars/bitfields.dm
+++ b/code/_globalvars/bitfields.dm
@@ -116,6 +116,7 @@ DEFINE_BITFIELD(flags_1, list(
"CAN_BE_DIRTY_1" = CAN_BE_DIRTY_1,
"CONDUCT_1" = CONDUCT_1,
"HAS_CONTEXTUAL_SCREENTIPS_1" = HAS_CONTEXTUAL_SCREENTIPS_1,
+ "HAS_DISASSOCIATED_STORAGE_1" = HAS_DISASSOCIATED_STORAGE_1,
"HOLOGRAM_1" = HOLOGRAM_1,
"INITIALIZED_1" = INITIALIZED_1,
"IS_ONTOP_1" = IS_ONTOP_1,
diff --git a/code/_onclick/click.dm b/code/_onclick/click.dm
index 5c8ca3cd6cb..6accd544551 100644
--- a/code/_onclick/click.dm
+++ b/code/_onclick/click.dm
@@ -153,6 +153,12 @@
if(!loc.AllowClick())
return
+ // In a storage item with a disassociated storage parent
+ var/obj/item/item_atom = A
+ if(istype(item_atom))
+ if((item_atom.item_flags & IN_STORAGE) && (item_atom.loc.flags_1 & HAS_DISASSOCIATED_STORAGE_1))
+ UnarmedAttack(item_atom, TRUE, modifiers)
+
//Standard reach turf to turf or reaching inside storage
if(CanReach(A,W))
if(W)
@@ -206,6 +212,7 @@
var/list/closed = list()
var/list/checking = list(ultimate_target)
+
while (checking.len && depth > 0)
var/list/next = list()
--depth
@@ -214,7 +221,7 @@
if(closed[target] || isarea(target)) // avoid infinity situations
continue
- if(isturf(target) || isturf(target.loc) || (target in direct_access) || (ismovable(target) && target.flags_1 & IS_ONTOP_1)) //Directly accessible atoms
+ if(isturf(target) || isturf(target.loc) || (target in direct_access) || (ismovable(target) && target.flags_1 & IS_ONTOP_1) || target.loc.atom_storage) //Directly accessible atoms
if(Adjacent(target) || (tool && CheckToolReach(src, target, tool.reach))) //Adjacent or reaching attacks
return TRUE
@@ -223,8 +230,7 @@
if (!target.loc)
continue
- //Storage and things with reachable internal atoms need add to next here. Or return COMPONENT_ALLOW_REACH.
- if(SEND_SIGNAL(target.loc, COMSIG_ATOM_CANREACH, next) & COMPONENT_ALLOW_REACH)
+ if(target.loc.atom_storage)
next += target.loc
checking = next
@@ -285,6 +291,7 @@
* modifiers is a lazy list of click modifiers this attack had,
* used for figuring out different properties of the click, mostly right vs left and such.
*/
+
/mob/proc/UnarmedAttack(atom/A, proximity_flag, list/modifiers)
if(ismob(A))
changeNext_move(CLICK_CD_MELEE)
diff --git a/code/_onclick/hud/screen_objects.dm b/code/_onclick/hud/screen_objects.dm
index c39f4d28836..85755575b7b 100644
--- a/code/_onclick/hud/screen_objects.dm
+++ b/code/_onclick/hud/screen_objects.dm
@@ -247,8 +247,8 @@
master = new_master
/atom/movable/screen/close/Click()
- var/datum/component/storage/S = master
- S.hide_from(usr)
+ var/datum/storage/storage = master
+ storage.hide_contents(usr)
return TRUE
/atom/movable/screen/drop
@@ -453,7 +453,7 @@
return TRUE
if(usr.incapacitated())
return TRUE
- if (ismecha(usr.loc)) // stops inventory actions in a mech
+ if(ismecha(usr.loc)) // stops inventory actions in a mech
return TRUE
if(master)
var/obj/item/I = usr.get_active_held_item()
diff --git a/code/datums/components/crafting/crafting.dm b/code/datums/components/crafting/crafting.dm
index 58b65127f1d..39cb6dd1cdd 100644
--- a/code/datums/components/crafting/crafting.dm
+++ b/code/datums/components/crafting/crafting.dm
@@ -161,7 +161,7 @@
var/list/present_qualities = list()
for(var/obj/item/contained_item in source.contents)
- if(contained_item.GetComponent(/datum/component/storage))
+ if(contained_item.atom_storage)
for(var/obj/item/subcontained_item in contained_item.contents)
available_tools[subcontained_item.type] = TRUE
if(subcontained_item.tool_behaviour)
diff --git a/code/datums/components/explodable.dm b/code/datums/components/explodable.dm
index 5059eb3ebd1..a91f849846c 100644
--- a/code/datums/components/explodable.dm
+++ b/code/datums/components/explodable.dm
@@ -34,8 +34,10 @@
if(isclothing(parent))
RegisterSignal(parent, COMSIG_ITEM_EQUIPPED, .proc/on_equip)
RegisterSignal(parent, COMSIG_ITEM_DROPPED, .proc/on_drop)
- if(SEND_SIGNAL(parent, COMSIG_CONTAINS_STORAGE))
- RegisterSignal(parent, COMSIG_TRY_STORAGE_INSERT, .proc/explodable_insert_item)
+
+ var/atom/atom_parent = parent
+ if(atom_parent.atom_storage)
+ RegisterSignal(parent, COMSIG_ATOM_ENTERED, .proc/explodable_insert_item)
if (devastation_range)
src.devastation_range = devastation_range
@@ -51,9 +53,11 @@
src.delete_after = delete_after
/// Explode if our parent is a storage place and something with high heat is inserted in.
-/datum/component/explodable/proc/explodable_insert_item(datum/source, obj/item/I, mob/M, silent = FALSE, force = FALSE)
+/datum/component/explodable/proc/explodable_insert_item(datum/source, obj/item/I)
SIGNAL_HANDLER
-
+ if(!(I.item_flags & IN_STORAGE))
+ return
+
check_if_detonate(I)
/datum/component/explodable/proc/explodable_impact(datum/source, atom/hit_atom, datum/thrownthing/throwingdatum)
diff --git a/code/datums/components/food/decomposition.dm b/code/datums/components/food/decomposition.dm
index 3ee6d6191fc..8a233cfb86b 100644
--- a/code/datums/components/food/decomposition.dm
+++ b/code/datums/components/food/decomposition.dm
@@ -36,11 +36,11 @@
RegisterSignal(parent, COMSIG_MOVABLE_MOVED, .proc/handle_movement)
RegisterSignal(parent, list(
COMSIG_ITEM_PICKUP, //person picks up an item
- COMSIG_STORAGE_ENTERED), //Object enters a storage object (boxes, etc.)
+ COMSIG_ATOM_ENTERED), //Object enters a storage object (boxes, etc.)
.proc/picked_up)
RegisterSignal(parent, list(
COMSIG_ITEM_DROPPED, //Object is dropped anywhere
- COMSIG_STORAGE_EXITED), //Object exits a storage object (boxes, etc)
+ COMSIG_ATOM_EXITED), //Object exits a storage object (boxes, etc)
.proc/dropped)
RegisterSignal(parent, COMSIG_PARENT_EXAMINE, .proc/examine)
@@ -59,10 +59,10 @@
/datum/component/decomposition/UnregisterFromParent()
UnregisterSignal(parent, list(
COMSIG_ITEM_PICKUP,
- COMSIG_STORAGE_ENTERED,
+ COMSIG_ATOM_ENTERED,
COMSIG_MOVABLE_MOVED,
COMSIG_ITEM_DROPPED,
- COMSIG_STORAGE_EXITED,
+ COMSIG_ATOM_EXITED,
COMSIG_PARENT_EXAMINE))
/datum/component/decomposition/proc/handle_movement()
diff --git a/code/datums/components/storage/food_storage.dm b/code/datums/components/food_storage.dm
similarity index 100%
rename from code/datums/components/storage/food_storage.dm
rename to code/datums/components/food_storage.dm
diff --git a/code/datums/components/holderloving.dm b/code/datums/components/holderloving.dm
index 03dcb1da2d9..e5e25dbb34f 100644
--- a/code/datums/components/holderloving.dm
+++ b/code/datums/components/holderloving.dm
@@ -35,8 +35,8 @@
RegisterSignal(parent, list(
COMSIG_ITEM_DROPPED,
COMSIG_ITEM_EQUIPPED,
- COMSIG_STORAGE_ENTERED,
- COMSIG_STORAGE_EXITED,
+ COMSIG_ATOM_ENTERED,
+ COMSIG_ATOM_EXITED,
), .proc/check_my_loc)
/datum/component/holderloving/UnregisterFromParent()
@@ -44,8 +44,8 @@
UnregisterSignal(parent, list(
COMSIG_ITEM_DROPPED,
COMSIG_ITEM_EQUIPPED,
- COMSIG_STORAGE_ENTERED,
- COMSIG_STORAGE_EXITED,
+ COMSIG_ATOM_ENTERED,
+ COMSIG_ATOM_EXITED,
))
/datum/component/holderloving/PostTransfer()
diff --git a/code/datums/components/storage/concrete/_concrete.dm b/code/datums/components/storage/concrete/_concrete.dm
deleted file mode 100644
index b78bebba07c..00000000000
--- a/code/datums/components/storage/concrete/_concrete.dm
+++ /dev/null
@@ -1,204 +0,0 @@
-
-// External storage-related logic:
-// /mob/proc/ClickOn() in /_onclick/click.dm - clicking items in storages
-// /mob/living/Move() in /modules/mob/living/living.dm - hiding storage boxes on mob movement
-
-/datum/component/storage/concrete
- can_transfer = TRUE
- var/drop_all_on_deconstruct = TRUE
- var/drop_all_on_destroy = FALSE
- var/transfer_contents_on_component_transfer = FALSE
- var/list/datum/component/storage/slaves = list()
-
- var/list/_contents_limbo // Where objects go to live mid transfer
- var/list/_user_limbo // The last users before the component started moving
-
-/datum/component/storage/concrete/Initialize()
- . = ..()
- RegisterSignal(parent, COMSIG_ATOM_CONTENTS_DEL, .proc/on_contents_del)
- RegisterSignal(parent, COMSIG_OBJ_DECONSTRUCT, .proc/on_deconstruct)
-
-/datum/component/storage/concrete/Destroy()
- var/atom/real_location = real_location()
- for(var/atom/_A in real_location)
- _A.mouse_opacity = initial(_A.mouse_opacity)
- if(drop_all_on_destroy)
- do_quick_empty()
- for(var/i in slaves)
- var/datum/component/storage/slave = i
- slave.change_master(null)
- QDEL_LIST(_contents_limbo)
- _user_limbo = null
- return ..()
-
-/datum/component/storage/concrete/master()
- return src
-
-/datum/component/storage/concrete/real_location()
- return parent
-
-/datum/component/storage/concrete/PreTransfer()
- if(is_using)
- _user_limbo = is_using.Copy()
- close_all()
- if(transfer_contents_on_component_transfer)
- _contents_limbo = list()
- for(var/atom/movable/AM in parent)
- _contents_limbo += AM
- AM.moveToNullspace()
-
-/datum/component/storage/concrete/PostTransfer()
- if(!isatom(parent))
- return COMPONENT_INCOMPATIBLE
- if(transfer_contents_on_component_transfer)
- for(var/i in _contents_limbo)
- var/atom/movable/AM = i
- AM.forceMove(parent)
- _contents_limbo = null
- if(_user_limbo)
- for(var/i in _user_limbo)
- show_to(i)
- _user_limbo = null
-
-/datum/component/storage/concrete/_insert_physical_item(obj/item/I, override = FALSE)
- . = TRUE
- var/atom/real_location = real_location()
- if(I.loc != real_location)
- I.forceMove(real_location)
- refresh_mob_views()
-
-/datum/component/storage/concrete/refresh_mob_views()
- . = ..()
- for(var/i in slaves)
- var/datum/component/storage/slave = i
- slave.refresh_mob_views()
-
-/datum/component/storage/concrete/emp_act(datum/source, severity)
- if(emp_shielded)
- return
- var/atom/real_location = real_location()
- for(var/i in real_location)
- var/atom/A = i
- A.emp_act(severity)
-
-/datum/component/storage/concrete/proc/on_slave_link(datum/component/storage/S)
- if(S == src)
- return FALSE
- slaves += S
- return TRUE
-
-/datum/component/storage/concrete/proc/on_slave_unlink(datum/component/storage/S)
- slaves -= S
- return FALSE
-
-/datum/component/storage/concrete/proc/on_contents_del(datum/source, atom/A)
- SIGNAL_HANDLER
- var/atom/real_location = parent
- if(A in real_location)
- usr = null
- remove_from_storage(A, null)
-
-/datum/component/storage/concrete/proc/on_deconstruct(datum/source, disassembled)
- SIGNAL_HANDLER
- if(drop_all_on_deconstruct)
- do_quick_empty()
-
-/datum/component/storage/concrete/can_see_contents()
- . = ..()
- for(var/i in slaves)
- var/datum/component/storage/slave = i
- . |= slave.can_see_contents()
-
-//Resets screen loc and other vars of something being removed from storage.
-/datum/component/storage/concrete/_removal_reset(atom/movable/thing)
- thing.layer = initial(thing.layer)
- thing.plane = initial(thing.plane)
- thing.mouse_opacity = initial(thing.mouse_opacity)
- if(thing.maptext)
- thing.maptext = ""
-
-/datum/component/storage/concrete/remove_from_storage(atom/movable/AM, atom/new_location)
- //Cache this as it should be reusable down the bottom, will not apply if anyone adds a sleep to dropped
- //or moving objects, things that should never happen
- var/atom/parent = src.parent
- var/list/seeing_mobs = can_see_contents()
- for(var/mob/M in seeing_mobs)
- M.client.screen -= AM
- if(isitem(AM))
- var/obj/item/removed_item = AM
- removed_item.item_flags &= ~IN_STORAGE
- if(ismob(parent.loc))
- var/mob/carrying_mob = parent.loc
- removed_item.dropped(carrying_mob, TRUE)
- if(new_location)
- //Reset the items values
- _removal_reset(AM)
- AM.forceMove(new_location)
- //We don't want to call this if the item is being destroyed
- AM.on_exit_storage(src)
- else
- //Being destroyed, just move to nullspace now (so it's not in contents for the icon update)
- AM.moveToNullspace()
- refresh_mob_views()
- if(isobj(parent))
- var/obj/O = parent
- O.update_appearance()
- return TRUE
-
-/datum/component/storage/concrete/proc/slave_can_insert_object(datum/component/storage/slave, obj/item/I, stop_messages = FALSE, mob/M)
- return TRUE
-
-/datum/component/storage/concrete/proc/handle_item_insertion_from_slave(datum/component/storage/slave, obj/item/I, prevent_warning = FALSE, M)
- . = handle_item_insertion(I, prevent_warning, M, slave)
- if(. && !prevent_warning)
- slave.mob_item_insertion_feedback(usr, M, I)
-
-/datum/component/storage/concrete/handle_item_insertion(obj/item/I, prevent_warning = FALSE, mob/M, datum/component/storage/remote) //Remote is null or the slave datum
- var/datum/component/storage/concrete/master = master()
- var/atom/parent = src.parent
- var/moved = FALSE
- if(!istype(I))
- return FALSE
- if(M)
- if(!M.temporarilyRemoveItemFromInventory(I))
- return FALSE
- else
- moved = TRUE //At this point if the proc fails we need to manually move the object back to the turf/mob/whatever.
- if(I.pulledby)
- I.pulledby.stop_pulling()
- if(silent)
- prevent_warning = TRUE
- if(!_insert_physical_item(I))
- if(moved)
- if(M)
- if(!M.put_in_active_hand(I))
- I.forceMove(parent.drop_location())
- else
- I.forceMove(parent.drop_location())
- return FALSE
- I.on_enter_storage(master)
- I.item_flags |= IN_STORAGE
- refresh_mob_views()
- I.mouse_opacity = MOUSE_OPACITY_OPAQUE //So you can click on the area around the item to equip it, instead of having to pixel hunt
- if(M)
- if(M.client && M.active_storage != src)
- M.client.screen -= I
- if(M.observers && M.observers.len)
- for(var/i in M.observers)
- var/mob/dead/observe = i
- if(observe.client && observe.active_storage != src)
- observe.client.screen -= I
- if(!remote)
- parent.add_fingerprint(M)
- if(!prevent_warning)
- mob_item_insertion_feedback(usr, M, I)
- update_icon()
- return TRUE
-
-/datum/component/storage/concrete/update_icon()
- if(isobj(parent))
- var/obj/O = parent
- O.update_appearance()
- for(var/i in slaves)
- var/datum/component/storage/slave = i
- slave.update_icon()
diff --git a/code/datums/components/storage/concrete/bag_of_holding.dm b/code/datums/components/storage/concrete/bag_of_holding.dm
deleted file mode 100644
index 0b63707d3ad..00000000000
--- a/code/datums/components/storage/concrete/bag_of_holding.dm
+++ /dev/null
@@ -1,27 +0,0 @@
-/datum/component/storage/concrete/bluespace/bag_of_holding/handle_item_insertion(obj/item/W, prevent_warning = FALSE, mob/living/user)
- var/atom/A = parent
- if(A == W) //don't put yourself into yourself.
- return
- var/list/obj/item/storage/backpack/holding/matching = typecache_filter_list(W.get_all_contents(), typecacheof(/obj/item/storage/backpack/holding))
- matching -= A
- if(istype(W, /obj/item/storage/backpack/holding) || matching.len)
- INVOKE_ASYNC(src, .proc/recursive_insertion, W, user)
- return
- . = ..()
-
-/datum/component/storage/concrete/bluespace/bag_of_holding/proc/recursive_insertion(obj/item/W, mob/living/user)
- var/atom/A = parent
- var/safety = tgui_alert(user, "Doing this will have extremely dire consequences for the station and its crew. Be sure you know what you're doing.", "Put in [A.name]?", list("Proceed", "Abort"))
- if(safety != "Proceed" || QDELETED(A) || QDELETED(W) || QDELETED(user) || !user.canUseTopic(A, BE_CLOSE, iscarbon(user)))
- return
- var/turf/loccheck = get_turf(A)
- to_chat(user, span_danger("The Bluespace interfaces of the two devices catastrophically malfunction!"))
- qdel(W)
- playsound(loccheck,'sound/effects/supermatter.ogg', 200, TRUE)
-
- message_admins("[ADMIN_LOOKUPFLW(user)] detonated a bag of holding at [ADMIN_VERBOSEJMP(loccheck)].")
- log_game("[key_name(user)] detonated a bag of holding at [loc_name(loccheck)].")
-
- user.gib(TRUE, TRUE, TRUE)
- new/obj/boh_tear(loccheck)
- qdel(A)
diff --git a/code/datums/components/storage/concrete/bluespace.dm b/code/datums/components/storage/concrete/bluespace.dm
deleted file mode 100644
index 5c5b4f86d0f..00000000000
--- a/code/datums/components/storage/concrete/bluespace.dm
+++ /dev/null
@@ -1,22 +0,0 @@
-/datum/component/storage/concrete/bluespace
- var/dumping_range = 8
- var/dumping_sound = 'sound/items/pshoom.ogg'
- var/alt_sound = 'sound/items/pshoom_2.ogg'
-
-/datum/component/storage/concrete/bluespace/dump_content_at(atom/dest, mob/M)
- var/atom/A = parent
- if(A.Adjacent(M))
- var/atom/dumping_location = dest.get_dumping_location()
- var/turf/bagT = get_turf(parent)
- var/turf/destT = get_turf(dumping_location)
- if(destT && bagT && bagT.z == destT.z && get_dist(M, dumping_location) < dumping_range)
- if(dumping_location.storage_contents_dump_act(src, M))
- if(alt_sound && prob(1))
- playsound(src, alt_sound, 40, TRUE)
- else
- playsound(src, dumping_sound, 40, TRUE)
- M.Beam(dumping_location, icon_state="rped_upgrade", time=5)
- return TRUE
- to_chat(M, span_hear("The [A.name] buzzes."))
- playsound(src, 'sound/machines/buzz-sigh.ogg', 50, FALSE)
- return FALSE
diff --git a/code/datums/components/storage/concrete/extract_inventory.dm b/code/datums/components/storage/concrete/extract_inventory.dm
deleted file mode 100644
index ece6c638a48..00000000000
--- a/code/datums/components/storage/concrete/extract_inventory.dm
+++ /dev/null
@@ -1,37 +0,0 @@
-/datum/component/storage/concrete/extract_inventory
- max_combined_w_class = WEIGHT_CLASS_TINY * 3
- max_items = 3
- insert_preposition = "in"
-//These need to be false in order for the extract's food to be unextractable
-//from the inventory
- attack_hand_interact = FALSE
- quickdraw = FALSE
- can_transfer = FALSE
- drop_all_on_deconstruct = FALSE
- locked = TRUE //True in order to prevent messing with the inventory in any way other than the specified ways on reproductive.dm
- rustle_sound = FALSE
- silent = TRUE
- var/obj/item/slimecross/reproductive/parentSlimeExtract
-
-
-/datum/component/storage/concrete/extract_inventory/Initialize()
- . = ..()
- set_holdable(/obj/item/food/monkeycube)
- if(!istype(parent, /obj/item/slimecross/reproductive))
- return COMPONENT_INCOMPATIBLE
- parentSlimeExtract = parent
-
-
-/datum/component/storage/concrete/extract_inventory/proc/processCubes(obj/item/slimecross/reproductive/parentSlimeExtract, mob/user)
-
- if(length(parentSlimeExtract.contents) >= max_items)
- QDEL_LIST(parentSlimeExtract.contents)
- createExtracts(parentSlimeExtract,user)
-
-/datum/component/storage/concrete/extract_inventory/proc/createExtracts(obj/item/slimecross/reproductive/parentSlimeExtract, mob/user)
- var/cores = rand(1,4)
- playsound(parentSlimeExtract, 'sound/effects/splat.ogg', 40, TRUE)
- parentSlimeExtract.last_produce = world.time
- to_chat(user, span_notice("[parentSlimeExtract] briefly swells to a massive size, and expels [cores] extract[cores > 1 ? "s":""]!"))
- for(var/i in 1 to cores)
- new parentSlimeExtract.extract_type(parentSlimeExtract.drop_location())
diff --git a/code/datums/components/storage/concrete/fish_case.dm b/code/datums/components/storage/concrete/fish_case.dm
deleted file mode 100644
index 398956c77b4..00000000000
--- a/code/datums/components/storage/concrete/fish_case.dm
+++ /dev/null
@@ -1,4 +0,0 @@
-/datum/component/storage/concrete/fish_case
- max_items = 1
- can_hold_trait = TRAIT_FISH_CASE_COMPATIBILE
- can_hold_description = "fish and aquarium equipment"
diff --git a/code/datums/components/storage/concrete/implant.dm b/code/datums/components/storage/concrete/implant.dm
deleted file mode 100644
index 405b3098fe5..00000000000
--- a/code/datums/components/storage/concrete/implant.dm
+++ /dev/null
@@ -1,18 +0,0 @@
-/datum/component/storage/concrete/implant
- max_w_class = WEIGHT_CLASS_NORMAL
- max_combined_w_class = 6
- max_items = 2
- drop_all_on_destroy = TRUE
- drop_all_on_deconstruct = TRUE
- silent = TRUE
- allow_big_nesting = TRUE
-
-/datum/component/storage/concrete/implant/Initialize()
- . = ..()
- set_holdable(null, list(/obj/item/disk/nuclear))
-
-/datum/component/storage/concrete/implant/InheritComponent(datum/component/storage/concrete/implant/I, original)
- if(!istype(I))
- return ..()
- max_combined_w_class += I.max_combined_w_class
- max_items += I.max_items
diff --git a/code/datums/components/storage/concrete/rped.dm b/code/datums/components/storage/concrete/rped.dm
deleted file mode 100644
index a6ffb79e93a..00000000000
--- a/code/datums/components/storage/concrete/rped.dm
+++ /dev/null
@@ -1,33 +0,0 @@
-/datum/component/storage/concrete/rped
- collection_mode = COLLECT_EVERYTHING
- allow_quick_gather = TRUE
- allow_quick_empty = TRUE
- click_gather = TRUE
- max_w_class = WEIGHT_CLASS_NORMAL
- max_combined_w_class = 100
- max_items = 50
- display_numerical_stacking = TRUE
-
-/datum/component/storage/concrete/rped/can_be_inserted(obj/item/I, stop_messages, mob/M)
- . = ..()
- if(!I.get_part_rating())
- if (!stop_messages)
- to_chat(M, span_warning("[parent] only accepts machine parts!"))
- return FALSE
-
-/datum/component/storage/concrete/bluespace/rped
- collection_mode = COLLECT_EVERYTHING
- allow_quick_gather = TRUE
- allow_quick_empty = TRUE
- click_gather = TRUE
- max_w_class = WEIGHT_CLASS_BULKY // can fit vending refills
- max_combined_w_class = 800
- max_items = 400
- display_numerical_stacking = TRUE
-
-/datum/component/storage/concrete/bluespace/rped/can_be_inserted(obj/item/I, stop_messages, mob/M)
- . = ..()
- if(!I.get_part_rating())
- if (!stop_messages)
- to_chat(M, span_warning("[parent] only accepts machine parts!"))
- return FALSE
diff --git a/code/datums/components/storage/concrete/stack.dm b/code/datums/components/storage/concrete/stack.dm
deleted file mode 100644
index 1b09c7f53c7..00000000000
--- a/code/datums/components/storage/concrete/stack.dm
+++ /dev/null
@@ -1,68 +0,0 @@
-//Stack-only storage.
-/datum/component/storage/concrete/stack
- display_numerical_stacking = TRUE
- var/max_combined_stack_amount = 300
- max_w_class = WEIGHT_CLASS_NORMAL
- max_combined_w_class = WEIGHT_CLASS_NORMAL * 14
-
-/datum/component/storage/concrete/stack/proc/total_stack_amount()
- . = 0
- var/atom/real_location = real_location()
- for(var/i in real_location)
- var/obj/item/stack/S = i
- if(!istype(S))
- continue
- . += S.amount
-
-/datum/component/storage/concrete/stack/proc/remaining_space()
- return max(0, max_combined_stack_amount - total_stack_amount())
-
-//emptying procs do not need modification as stacks automatically merge.
-
-/datum/component/storage/concrete/stack/_insert_physical_item(obj/item/I, override = FALSE)
- if(!istype(I, /obj/item/stack))
- if(override)
- return ..()
- return FALSE
- var/atom/real_location = real_location()
- var/obj/item/stack/S = I
- var/can_insert = min(S.amount, remaining_space())
- if(!can_insert)
- return FALSE
- for(var/i in real_location) //combine.
- if(QDELETED(I))
- return
- var/obj/item/stack/_S = i
- if(!istype(_S))
- continue
- if(_S.merge_type == S.merge_type)
- _S.add(can_insert)
- S.use(can_insert, TRUE)
- return TRUE
- I = S.split_stack(null, can_insert)
- return ..()
-
-/datum/component/storage/concrete/stack/remove_from_storage(obj/item/I, atom/new_location)
- var/atom/real_location = real_location()
- var/obj/item/stack/S = I
- if(!istype(S))
- return ..()
- if(S.amount > S.max_amount)
- var/overrun = S.amount - S.max_amount
- S.amount = S.max_amount
- var/obj/item/stack/temp = new S.type(real_location, overrun)
- handle_item_insertion(temp)
- return ..(S, new_location)
-
-/datum/component/storage/concrete/stack/_process_numerical_display()
- var/atom/real_location = real_location()
- . = list()
- for(var/i in real_location)
- var/obj/item/stack/I = i
- if(!istype(I) || QDELETED(I)) //We're specialized stack storage, just ignore non stacks.
- continue
- if(!.[I.merge_type])
- .[I.merge_type] = new /datum/numbered_display(I, I.amount)
- else
- var/datum/numbered_display/ND = .[I.merge_type]
- ND.number += I.amount
diff --git a/code/datums/components/storage/concrete/trading_cards.dm b/code/datums/components/storage/concrete/trading_cards.dm
deleted file mode 100644
index 4c68685068c..00000000000
--- a/code/datums/components/storage/concrete/trading_cards.dm
+++ /dev/null
@@ -1,49 +0,0 @@
-/**
- *A storage component to be used on card piles, for use as hands/decks/discard piles. Don't use on something that's not a card pile!
- */
-/datum/component/storage/concrete/tcg
- display_numerical_stacking = FALSE
- max_w_class = WEIGHT_CLASS_TINY
- max_items = 30
- max_combined_w_class = WEIGHT_CLASS_TINY * 30
- ///The deck that the card pile is using for FAIR PLAY.
-
-/datum/component/storage/concrete/tcg/Initialize()
- . = ..()
- set_holdable(list(/obj/item/tcgcard))
-
-/datum/component/storage/concrete/tcg/PostTransfer()
- . = ..()
- handle_empty_deck()
-
-/datum/component/storage/concrete/tcg/remove_from_storage(atom/movable/AM, atom/new_location)
- . = ..()
- handle_empty_deck()
-
-/datum/component/storage/concrete/tcg/show_to(mob/M)
- . = ..()
- M.visible_message(span_notice("[M] starts to look through the contents of \the [parent]!"), \
- span_notice("You begin looking into the contents of \the [parent]!"))
-
-/datum/component/storage/concrete/tcg/close(mob/M)
- . = ..()
- var/list/card_contents = contents()
- var/obj/temp_parent = parent
- temp_parent.visible_message(span_notice("\the [parent] is shuffled after looking through it."))
- card_contents = shuffle(card_contents)
-
-/datum/component/storage/concrete/tcg/mass_remove_from_storage(atom/target, list/things, datum/progressbar/progress, trigger_on_found)
- . = ..()
- if(!things.len)
- qdel(parent)
-
-/datum/component/storage/concrete/tcg/proc/handle_empty_deck()
- var/list/contents = contents()
- //You can't have a deck of one card!
- if(contents.len == 1)
- var/obj/item/tcgcard_deck/deck = parent
- var/obj/item/tcgcard/card = contents[1]
- remove_from_storage(card, card.drop_location())
- card.flipped = deck.flipped
- card.update_icon_state()
- qdel(parent)
diff --git a/code/datums/components/storage/concrete/wallet.dm b/code/datums/components/storage/concrete/wallet.dm
deleted file mode 100644
index 3da70fb7294..00000000000
--- a/code/datums/components/storage/concrete/wallet.dm
+++ /dev/null
@@ -1,13 +0,0 @@
-/datum/component/storage/concrete/wallet/open_storage(mob/user)
- if(!isliving(user) || !user.CanReach(parent) || user.incapacitated())
- return FALSE
- if(locked)
- to_chat(user, span_warning("[parent] seems to be locked!"))
- return
-
- var/obj/item/storage/wallet/A = parent
- if(istype(A) && A.front_id && !issilicon(user) && !(A.item_flags & IN_STORAGE)) //if it's a wallet in storage seeing the full inventory is more useful
- var/obj/item/I = A.front_id
- INVOKE_ASYNC(src, .proc/attempt_put_in_hands, I, user)
- return TRUE
- return ..()
diff --git a/code/datums/components/storage/storage.dm b/code/datums/components/storage/storage.dm
deleted file mode 100644
index 37dc4b0de7c..00000000000
--- a/code/datums/components/storage/storage.dm
+++ /dev/null
@@ -1,960 +0,0 @@
-// External storage-related logic:
-// /mob/proc/ClickOn() in /_onclick/click.dm - clicking items in storages
-// /mob/living/Move() in /modules/mob/living/living.dm - hiding storage boxes on mob movement
-
-/datum/component/storage
- dupe_mode = COMPONENT_DUPE_UNIQUE
- ///If not null, all actions act on master and this is just an access point.
- var/datum/component/storage/concrete/master
-
- ///if this is set, only items, and their children, will fit
- var/list/can_hold
- ///if this is set, items, and their children, won't fit
- var/list/cant_hold
- ///if set, these items will be the exception to the max size of object that can fit.
- var/list/exception_hold
- /// If set can only contain stuff with this single trait present.
- var/list/can_hold_trait
-
- var/can_hold_description
-
- ///lazy list of mobs looking at the contents of this storage.
- var/list/mob/is_using
-
- ///when locked nothing can see inside or use it.
- var/locked = FALSE
-
- ///max size of objects that will fit.
- var/max_w_class = WEIGHT_CLASS_SMALL
- ///max combined sizes of objects that will fit.
- var/max_combined_w_class = 14
- ///max number of objects that will fit.
- var/max_items = 7
-
- var/emp_shielded = FALSE
-
- ///whether this makes a message when things are put in.
- var/silent = FALSE
- ///whether this can be clicked on items to pick it up rather than the other way around.
- var/click_gather = FALSE
- ///play rustle sound on interact.
- var/rustle_sound = TRUE
- ///allow empty verb which allows dumping on the floor of everything inside quickly.
- var/allow_quick_empty = FALSE
- ///allow toggle mob verb which toggles collecting all items from a tile.
- var/allow_quick_gather = FALSE
-
- var/collection_mode = COLLECT_EVERYTHING
-
- ///you put things "in" a bag, but "on" a tray.
- var/insert_preposition = "in"
-
- ///stack things of the same type and show as a single object with a number.
- var/display_numerical_stacking = FALSE
-
- ///storage display object
- var/atom/movable/screen/storage/boxes
- ///close button object
- var/atom/movable/screen/close/closer
-
- ///allow storage objects of the same or greater size.
- var/allow_big_nesting = FALSE
-
- ///interact on attack hand.
- var/attack_hand_interact = TRUE
- ///altclick interact
- var/quickdraw = FALSE
-
- var/datum/weakref/modeswitch_action_ref
-
- //Screen variables: Do not mess with these vars unless you know what you're doing. They're not defines so storage that isn't in the same location can be supported in the future.
- var/screen_max_columns = 7 //These two determine maximum screen sizes.
- var/screen_max_rows = INFINITY
- var/screen_pixel_x = 16 //These two are pixel values for screen loc of boxes and closer
- var/screen_pixel_y = 16
- var/screen_start_x = 4 //These two are where the storage starts being rendered, screen_loc wise.
- var/screen_start_y = 2
- //End
-
-/datum/component/storage/Initialize(datum/component/storage/concrete/master)
- if(!isatom(parent))
- return COMPONENT_INCOMPATIBLE
- if(master)
- change_master(master)
- boxes = new(null, src)
- closer = new(null, src)
- orient2hud()
-
- RegisterSignal(parent, COMSIG_CONTAINS_STORAGE, .proc/on_check)
- RegisterSignal(parent, COMSIG_IS_STORAGE_LOCKED, .proc/check_locked)
- RegisterSignal(parent, COMSIG_TRY_STORAGE_SHOW, .proc/signal_show_attempt)
- RegisterSignal(parent, COMSIG_TRY_STORAGE_INSERT, .proc/signal_insertion_attempt)
- RegisterSignal(parent, COMSIG_TRY_STORAGE_CAN_INSERT, .proc/signal_can_insert)
- RegisterSignal(parent, COMSIG_TRY_STORAGE_TAKE_TYPE, .proc/signal_take_type)
- RegisterSignal(parent, COMSIG_TRY_STORAGE_FILL_TYPE, .proc/signal_fill_type)
- RegisterSignal(parent, COMSIG_TRY_STORAGE_SET_LOCKSTATE, .proc/set_locked)
- RegisterSignal(parent, COMSIG_TRY_STORAGE_TAKE, .proc/signal_take_obj)
- RegisterSignal(parent, COMSIG_TRY_STORAGE_QUICK_EMPTY, .proc/signal_quick_empty)
- RegisterSignal(parent, COMSIG_TRY_STORAGE_HIDE_FROM, .proc/signal_hide_attempt)
- RegisterSignal(parent, COMSIG_TRY_STORAGE_HIDE_ALL, .proc/close_all)
- RegisterSignal(parent, COMSIG_TRY_STORAGE_RETURN_INVENTORY, .proc/signal_return_inv)
-
- RegisterSignal(parent, COMSIG_TOPIC, .proc/topic_handle)
-
- RegisterSignal(parent, COMSIG_PARENT_ATTACKBY, .proc/attackby)
-
- RegisterSignal(parent, COMSIG_ATOM_ATTACK_HAND, .proc/on_attack_hand)
- RegisterSignal(parent, COMSIG_ATOM_ATTACK_PAW, .proc/on_attack_hand)
- RegisterSignal(parent, COMSIG_ATOM_EMP_ACT, .proc/emp_act)
- RegisterSignal(parent, COMSIG_ATOM_ATTACK_GHOST, .proc/show_to_ghost)
- RegisterSignal(parent, COMSIG_ATOM_ENTERED, .proc/refresh_mob_views)
- RegisterSignal(parent, COMSIG_ATOM_EXITED, .proc/_remove_and_refresh)
- RegisterSignal(parent, COMSIG_ATOM_CANREACH, .proc/canreach_react)
-
- RegisterSignal(parent, COMSIG_ITEM_PRE_ATTACK, .proc/preattack_intercept)
- RegisterSignal(parent, COMSIG_ITEM_ATTACK_SELF, .proc/attack_self)
- RegisterSignal(parent, COMSIG_ITEM_PICKUP, .proc/signal_on_pickup)
- RegisterSignal(parent, COMSIG_ITEM_EQUIPPED, .proc/update_actions)
-
- RegisterSignal(parent, COMSIG_MOVABLE_POST_THROW, .proc/close_all)
- RegisterSignal(parent, COMSIG_MOVABLE_MOVED, .proc/on_move)
-
- RegisterSignal(parent, list(COMSIG_CLICK_ALT, COMSIG_ATOM_ATTACK_HAND_SECONDARY), .proc/on_open_storage_click)
- RegisterSignal(parent, COMSIG_PARENT_ATTACKBY_SECONDARY, .proc/on_open_storage_attackby)
- RegisterSignal(parent, COMSIG_MOUSEDROP_ONTO, .proc/mousedrop_onto)
- RegisterSignal(parent, COMSIG_MOUSEDROPPED_ONTO, .proc/mousedrop_receive)
-
- update_actions()
-
-/datum/component/storage/Destroy()
- close_all()
- QDEL_NULL(boxes)
- QDEL_NULL(closer)
- LAZYCLEARLIST(is_using)
- return ..()
-
-/datum/component/storage/PreTransfer()
- update_actions()
-
-/// Almost 100% of the time the lists passed into set_holdable are reused for each instance of the component
-/// Just fucking cache it 4head
-/// Yes I could generalize this, but I don't want anyone else using it. in fact, DO NOT COPY THIS
-/// If you find yourself needing this pattern, you're likely better off using static typecaches
-/// I'm not because I do not trust implementers of the storage component to use them, BUT
-/// IF I FIND YOU USING THIS PATTERN IN YOUR CODE I WILL BREAK YOU ACROSS MY KNEES
-/// ~Lemon
-GLOBAL_LIST_EMPTY(cached_storage_typecaches)
-
-/datum/component/storage/proc/set_holdable(list/can_hold_list, list/cant_hold_list)
- if(!islist(can_hold_list))
- can_hold_list = list(can_hold_list)
- if(!islist(cant_hold_list))
- cant_hold_list = list(cant_hold_list)
-
- can_hold_description = generate_hold_desc(can_hold_list)
- if (can_hold_list)
- var/unique_key = can_hold_list.Join("-")
- if(!GLOB.cached_storage_typecaches[unique_key])
- GLOB.cached_storage_typecaches[unique_key] = typecacheof(can_hold_list)
- can_hold = GLOB.cached_storage_typecaches[unique_key]
-
- if (cant_hold_list != null)
- var/unique_key = cant_hold_list.Join("-")
- if(!GLOB.cached_storage_typecaches[unique_key])
- GLOB.cached_storage_typecaches[unique_key] = typecacheof(cant_hold_list)
- cant_hold = GLOB.cached_storage_typecaches[unique_key]
-
-/datum/component/storage/proc/generate_hold_desc(can_hold_list)
- var/list/desc = list()
-
- for(var/valid_type in can_hold_list)
- var/obj/item/valid_item = valid_type
- desc += "\a [initial(valid_item.name)]"
-
- return "\n\t[span_notice("[desc.Join("\n\t")]")]"
-
-/datum/component/storage/proc/update_actions()
- SIGNAL_HANDLER
-
- if(!isitem(parent) || !allow_quick_gather)
- QDEL_NULL(modeswitch_action_ref)
- return
-
- var/datum/action/existing = modeswitch_action_ref?.resolve()
- if(!QDELETED(existing))
- return
-
- var/obj/item/item_parent = parent
- var/datum/action/modeswitch_action = item_parent.add_item_action(/datum/action/item_action/storage_gather_mode)
- RegisterSignal(modeswitch_action, COMSIG_ACTION_TRIGGER, .proc/action_trigger)
- modeswitch_action_ref = WEAKREF(modeswitch_action)
-
-/datum/component/storage/proc/change_master(datum/component/storage/concrete/new_master)
- if(new_master == src || (!isnull(new_master) && !istype(new_master)))
- return FALSE
- if(master)
- master.on_slave_unlink(src)
- master = new_master
- if(master)
- master.on_slave_link(src)
- return TRUE
-
-/datum/component/storage/proc/master()
- if(master == src)
- return //infinite loops yo.
- return master
-
-/datum/component/storage/proc/real_location()
- var/datum/component/storage/concrete/master = master()
- return master? master.real_location() : null
-
-/datum/component/storage/proc/canreach_react(datum/source, list/next)
- SIGNAL_HANDLER
-
- var/datum/component/storage/concrete/master = master()
- if(!master)
- return
- . = COMPONENT_ALLOW_REACH
- next += master.parent
- for(var/i in master.slaves)
- var/datum/component/storage/slave = i
- next += slave.parent
-
-/datum/component/storage/proc/on_move()
- SIGNAL_HANDLER
-
- var/atom/A = parent
- for(var/mob/living/L in can_see_contents())
- if(!L.CanReach(A))
- hide_from(L)
-
-/datum/component/storage/proc/attack_self(datum/source, mob/M)
- SIGNAL_HANDLER
-
- if(locked)
- to_chat(M, span_warning("[parent] seems to be locked!"))
- return FALSE
- if((M.get_active_held_item() == parent) && allow_quick_empty)
- INVOKE_ASYNC(src, .proc/quick_empty, M)
-
-/datum/component/storage/proc/preattack_intercept(datum/source, obj/O, mob/M, params)
- SIGNAL_HANDLER
-
- if(!isitem(O) || !click_gather || SEND_SIGNAL(O, COMSIG_CONTAINS_STORAGE))
- return FALSE
- . = COMPONENT_CANCEL_ATTACK_CHAIN
- if(locked)
- to_chat(M, span_warning("[parent] seems to be locked!"))
- return FALSE
- var/obj/item/I = O
- if(collection_mode == COLLECT_ONE)
- if(can_be_inserted(I, null, M))
- handle_item_insertion(I, null, M)
- return
- if(!isturf(I.loc))
- return
- INVOKE_ASYNC(src, .proc/async_preattack_intercept, I, M)
-
-///async functionality from preattack_intercept
-/datum/component/storage/proc/async_preattack_intercept(obj/item/attack_item, mob/pre_attack_mob)
- var/list/things = attack_item.loc.contents.Copy()
- if(collection_mode == COLLECT_SAME)
- things = typecache_filter_list(things, typecacheof(attack_item.type))
- var/len = length(things)
- if(!len)
- to_chat(pre_attack_mob, span_warning("You failed to pick up anything with [parent]!"))
- return
- var/datum/progressbar/progress = new(pre_attack_mob, len, attack_item.loc)
- var/list/rejections = list()
- while(do_after(pre_attack_mob, 1 SECONDS, parent, NONE, FALSE, CALLBACK(src, .proc/handle_mass_pickup, things, attack_item.loc, rejections, progress)))
- stoplag(1)
- progress.end_progress()
- to_chat(pre_attack_mob, span_notice("You put everything you could [insert_preposition] [parent]."))
-
-/datum/component/storage/proc/handle_mass_item_insertion(list/things, datum/component/storage/src_object, mob/user, datum/progressbar/progress)
- var/atom/source_real_location = src_object.real_location()
- for(var/obj/item/I in things)
- things -= I
- if(I.loc != source_real_location)
- continue
- if(user.active_storage != src_object)
- if(I.on_found(user))
- break
- if(can_be_inserted(I,FALSE,user))
- handle_item_insertion(I, TRUE, user)
- if (TICK_CHECK)
- progress.update(progress.goal - things.len)
- return TRUE
-
- progress.update(progress.goal - things.len)
- return FALSE
-
-/datum/component/storage/proc/handle_mass_pickup(list/things, atom/thing_loc, list/rejections, datum/progressbar/progress)
- var/atom/real_location = real_location()
- for(var/obj/item/I in things)
- things -= I
- if(I.loc != thing_loc)
- continue
- if(I.type in rejections) // To limit bag spamming: any given type only complains once
- continue
- if(!can_be_inserted(I, stop_messages = TRUE)) // Note can_be_inserted still makes noise when the answer is no
- if(real_location.contents.len >= max_items)
- break
- rejections += I.type // therefore full bags are still a little spammy
- continue
-
- handle_item_insertion(I, TRUE) //The TRUE stops the "You put the [parent] into [S]" insertion message from being displayed.
-
- if (TICK_CHECK)
- progress.update(progress.goal - things.len)
- return TRUE
-
- progress.update(progress.goal - things.len)
- return FALSE
-
-/datum/component/storage/proc/quick_empty(mob/M)
- var/atom/A = parent
- if(!M.canUseStorage() || !A.Adjacent(M) || M.incapacitated())
- return
- if(locked)
- to_chat(M, span_warning("[parent] seems to be locked!"))
- return FALSE
- A.add_fingerprint(M)
- to_chat(M, span_notice("You start dumping out [parent]."))
- var/turf/T = get_turf(A)
- var/list/things = contents()
- var/datum/progressbar/progress = new(M, length(things), T)
- while (do_after(M, 1 SECONDS, T, NONE, FALSE, CALLBACK(src, .proc/mass_remove_from_storage, T, things, progress)))
- stoplag(1)
- progress.end_progress()
-
-/datum/component/storage/proc/mass_remove_from_storage(atom/target, list/things, datum/progressbar/progress, trigger_on_found = TRUE)
- var/atom/real_location = real_location()
- for(var/obj/item/I in things)
- things -= I
- if(I.loc != real_location)
- continue
- remove_from_storage(I, target)
- I.pixel_x = rand(-10,10)
- I.pixel_y = rand(-10,10)
- if(trigger_on_found && I.on_found())
- return FALSE
- if(TICK_CHECK)
- progress.update(progress.goal - length(things))
- return TRUE
- progress.update(progress.goal - length(things))
- return FALSE
-
-/datum/component/storage/proc/do_quick_empty(atom/_target)
- if(!_target)
- _target = get_turf(parent)
- if(usr)
- hide_from(usr)
- var/list/contents = contents()
- var/atom/real_location = real_location()
- for(var/obj/item/I in contents)
- if(I.loc != real_location)
- continue
- remove_from_storage(I, _target)
- return TRUE
-
-/datum/component/storage/proc/set_locked(datum/source, new_state)
- SIGNAL_HANDLER
-
- locked = new_state
- if(locked)
- close_all()
-
-/datum/component/storage/proc/_process_numerical_display()
- . = list()
- var/atom/real_location = real_location()
- for(var/obj/item/I in real_location.contents)
- if(QDELETED(I))
- continue
- if(!.["[I.type]-[I.name]"])
- .["[I.type]-[I.name]"] = new /datum/numbered_display(I, 1)
- else
- var/datum/numbered_display/ND = .["[I.type]-[I.name]"]
- ND.number++
-
-//This proc determines the size of the inventory to be displayed. Please touch it only if you know what you're doing.
-/datum/component/storage/proc/orient2hud()
- var/atom/real_location = real_location()
- var/adjusted_contents = real_location.contents.len
-
- //Numbered contents display
- var/list/datum/numbered_display/numbered_contents
- if(display_numerical_stacking)
- numbered_contents = _process_numerical_display()
- adjusted_contents = numbered_contents.len
-
- var/columns = clamp(max_items, 1, screen_max_columns)
- var/rows = clamp(CEILING(adjusted_contents / columns, 1), 1, screen_max_rows)
- standard_orient_objs(rows, columns, numbered_contents)
-
-//This proc draws out the inventory and places the items on it. It uses the standard position.
-/datum/component/storage/proc/standard_orient_objs(rows, cols, list/obj/item/numerical_display_contents)
- boxes.screen_loc = "[screen_start_x]:[screen_pixel_x],[screen_start_y]:[screen_pixel_y] to [screen_start_x+cols-1]:[screen_pixel_x],[screen_start_y+rows-1]:[screen_pixel_y]"
- var/cx = screen_start_x
- var/cy = screen_start_y
- if(islist(numerical_display_contents))
- for(var/type in numerical_display_contents)
- var/datum/numbered_display/ND = numerical_display_contents[type]
- ND.sample_object.mouse_opacity = MOUSE_OPACITY_OPAQUE
- ND.sample_object.screen_loc = "[cx]:[screen_pixel_x],[cy]:[screen_pixel_y]"
- ND.sample_object.maptext = MAPTEXT("[(ND.number > 1)? "[ND.number]" : ""]")
- ND.sample_object.plane = ABOVE_HUD_PLANE
- cx++
- if(cx - screen_start_x >= cols)
- cx = screen_start_x
- cy++
- if(cy - screen_start_y >= rows)
- break
- else
- var/atom/real_location = real_location()
- for(var/obj/O in real_location)
- if(QDELETED(O))
- continue
- O.mouse_opacity = MOUSE_OPACITY_OPAQUE //This is here so storage items that spawn with contents correctly have the "click around item to equip"
- O.screen_loc = "[cx]:[screen_pixel_x],[cy]:[screen_pixel_y]"
- O.maptext = ""
- O.plane = ABOVE_HUD_PLANE
- cx++
- if(cx - screen_start_x >= cols)
- cx = screen_start_x
- cy++
- if(cy - screen_start_y >= rows)
- break
- closer.screen_loc = "[screen_start_x + cols]:[screen_pixel_x],[screen_start_y]:[screen_pixel_y]"
-
-/datum/component/storage/proc/show_to(mob/M)
- if(!M.client)
- return FALSE
- var/atom/real_location = real_location()
- if(M.active_storage != src && (M.stat == CONSCIOUS))
- for(var/obj/item/I in real_location)
- if(I.on_found(M))
- return FALSE
- if(M.active_storage)
- M.active_storage.hide_from(M)
- orient2hud()
- M.client.screen |= boxes
- M.client.screen |= closer
- M.client.screen |= real_location.contents
- M.set_active_storage(src)
- if(ismovable(real_location))
- var/atom/movable/movable_loc = real_location
- movable_loc.become_active_storage(src)
- LAZYOR(is_using, M)
- RegisterSignal(M, COMSIG_PARENT_QDELETING, .proc/mob_deleted)
- return TRUE
-
-/datum/component/storage/proc/mob_deleted(datum/source)
- SIGNAL_HANDLER
- hide_from(source)
-
-/datum/component/storage/proc/hide_from(mob/M)
- if(M.active_storage == src)
- M.set_active_storage(null)
- LAZYREMOVE(is_using, M)
-
- UnregisterSignal(M, COMSIG_PARENT_QDELETING)
- if(!M.client)
- return TRUE
- var/atom/real_location = real_location()
- if(!length(is_using) && ismovable(real_location))
- var/atom/movable/movable_loc = real_location
- movable_loc.lose_active_storage(src)
-
- M.client.screen -= boxes
- M.client.screen -= closer
- M.client.screen -= real_location.contents
- return TRUE
-
-/datum/component/storage/proc/close(mob/M)
- hide_from(M)
-
-/datum/component/storage/proc/close_all()
- SIGNAL_HANDLER
-
- . = FALSE
- for(var/mob/M in can_see_contents())
- close(M)
- . = TRUE //returns TRUE if any mobs actually got a close(M) call
-
-/datum/component/storage/proc/emp_act(datum/source, severity)
- SIGNAL_HANDLER
-
- if(emp_shielded)
- return
- var/datum/component/storage/concrete/master = master()
- master.emp_act(source, severity)
-
-//This proc draws out the inventory and places the items on it. tx and ty are the upper left tile and mx, my are the bottm right.
-//The numbers are calculated from the bottom-left The bottom-left slot being 1,1.
-/datum/component/storage/proc/orient_objs(tx, ty, mx, my)
- var/atom/real_location = real_location()
- var/cx = tx
- var/cy = ty
- boxes.screen_loc = "[tx]:,[ty] to [mx],[my]"
- for(var/obj/O in real_location)
- if(QDELETED(O))
- continue
- O.screen_loc = "[cx],[cy]"
- O.plane = ABOVE_HUD_PLANE
- cx++
- if(cx > mx)
- cx = tx
- cy--
- closer.screen_loc = "[mx+1],[my]"
-
-//Resets something that is being removed from storage.
-/datum/component/storage/proc/_removal_reset(atom/movable/thing)
- if(!istype(thing))
- return FALSE
- var/datum/component/storage/concrete/master = master()
- if(!istype(master))
- return FALSE
- return master._removal_reset(thing)
-
-/datum/component/storage/proc/_remove_and_refresh(datum/source, atom/movable/gone, direction)
- SIGNAL_HANDLER
-
- _removal_reset(gone)
- refresh_mob_views()
-
-//Call this proc to handle the removal of an item from the storage item. The item will be moved to the new_location target, if that is null it's being deleted
-/datum/component/storage/proc/remove_from_storage(atom/movable/AM, atom/new_location)
- if(!istype(AM))
- return FALSE
- var/datum/component/storage/concrete/master = master()
- if(!istype(master))
- return FALSE
- return master.remove_from_storage(AM, new_location)
-
-/datum/component/storage/proc/refresh_mob_views()
- SIGNAL_HANDLER
-
- var/list/seeing = can_see_contents()
- for(var/i in seeing)
- show_to(i)
- return TRUE
-
-/datum/component/storage/proc/can_see_contents()
- var/list/cansee = list()
- for(var/mob/M in is_using)
- if(M.active_storage == src && M.client)
- cansee |= M
- else
- LAZYREMOVE(is_using, M)
- UnregisterSignal(M, COMSIG_PARENT_QDELETING)
- return cansee
-
-//Tries to dump content
-/datum/component/storage/proc/dump_content_at(atom/dest_object, mob/M)
- var/atom/A = parent
- var/atom/dump_destination = get_dumping_location(dest_object)
- if(M.CanReach(A) && dump_destination && M.CanReach(dump_destination))
- if(locked)
- to_chat(M, span_warning("[parent] seems to be locked!"))
- return FALSE
- if(dump_destination.storage_contents_dump_act(src, M))
- playsound(A, SFX_RUSTLE, 50, TRUE, -5)
- return TRUE
- return FALSE
-
-/datum/component/storage/proc/get_dumping_location(atom/dest_object)
- var/datum/component/storage/storage = dest_object.GetComponent(/datum/component/storage)
- if(storage)
- return storage.real_location()
- return dest_object.get_dumping_location()
-
-//This proc is called when you want to place an item into the storage item.
-/datum/component/storage/proc/attackby(datum/source, obj/item/I, mob/M, params)
- SIGNAL_HANDLER
-
- if(!I.attackby_storage_insert(src, parent, M))
- return FALSE
- . = TRUE //no afterattack
- if(iscyborg(M))
- return
- if(!can_be_inserted(I, FALSE, M))
- var/atom/real_location = real_location()
- if(real_location.contents.len >= max_items) //don't use items on the backpack if they don't fit
- return TRUE
- return FALSE
- handle_item_insertion(I, FALSE, M)
-
-/datum/component/storage/proc/return_inv(recursive)
- var/list/ret = list()
- ret |= contents()
- if(recursive)
- for(var/i in ret.Copy())
- var/atom/A = i
- SEND_SIGNAL(A, COMSIG_TRY_STORAGE_RETURN_INVENTORY, ret, TRUE)
- return ret
-
-/datum/component/storage/proc/contents() //ONLY USE IF YOU NEED TO COPY CONTENTS OF REAL LOCATION, COPYING IS NOT AS FAST AS DIRECT ACCESS!
- var/atom/real_location = real_location()
- return real_location.contents.Copy()
-
-//Abuses the fact that lists are just references, or something like that.
-/datum/component/storage/proc/signal_return_inv(datum/source, list/interface, recursive = TRUE)
- SIGNAL_HANDLER
-
- if(!islist(interface))
- return FALSE
- interface |= return_inv(recursive)
- return TRUE
-
-/datum/component/storage/proc/topic_handle(datum/source, user, href_list)
- SIGNAL_HANDLER
-
- if(href_list["show_valid_pocket_items"])
- handle_show_valid_items(source, user)
-
-/datum/component/storage/proc/handle_show_valid_items(datum/source, user)
- to_chat(user, span_notice("[source] can hold: [can_hold_description]"))
-
-/datum/component/storage/proc/mousedrop_onto(datum/source, atom/over_object, mob/M)
- SIGNAL_HANDLER
-
- set waitfor = FALSE
- . = COMPONENT_NO_MOUSEDROP
- if(!ismob(M))
- return
- if(!over_object)
- return
- if(ismecha(M.loc)) // stops inventory actions in a mech
- return
- if(M.incapacitated() || !M.canUseStorage())
- return
- var/atom/A = parent
- A.add_fingerprint(M)
- // this must come before the screen objects only block, dunno why it wasn't before
- if(over_object == M)
- user_show_to_mob(M)
- if(!istype(over_object, /atom/movable/screen))
- INVOKE_ASYNC(src, .proc/dump_content_at, over_object, M)
- return
- if(A.loc != M)
- return
- playsound(A, SFX_RUSTLE, 50, TRUE, -5)
- if(istype(over_object, /atom/movable/screen/inventory/hand))
- var/atom/movable/screen/inventory/hand/H = over_object
- M.putItemFromInventoryInHandIfPossible(A, H.held_index)
- return
- A.add_fingerprint(M)
-
-/datum/component/storage/proc/user_show_to_mob(mob/M, force = FALSE)
- var/atom/A = parent
- if(!istype(M))
- return FALSE
- A.add_fingerprint(M)
- if(locked && !force)
- to_chat(M, span_warning("[parent] seems to be locked!"))
- return FALSE
- if(force || M.CanReach(parent, view_only = TRUE))
- show_to(M)
-
-/datum/component/storage/proc/mousedrop_receive(datum/source, atom/movable/O, mob/M)
- SIGNAL_HANDLER
-
- if(isitem(O))
- var/obj/item/I = O
- if(iscarbon(M) || isdrone(M))
- var/mob/living/L = M
- if(!L.incapacitated() && I == L.get_active_held_item())
- if(!SEND_SIGNAL(I, COMSIG_CONTAINS_STORAGE) && can_be_inserted(I, FALSE)) //If it has storage it should be trying to dump, not insert.
- handle_item_insertion(I, FALSE, L)
-
-//This proc return 1 if the item can be picked up and 0 if it can't.
-//Set the stop_messages to stop it from printing messages
-/datum/component/storage/proc/can_be_inserted(obj/item/I, stop_messages = FALSE, mob/M)
- if(!istype(I) || (I.item_flags & ABSTRACT))
- return FALSE //Not an item
- if(I == parent)
- return FALSE //no paradoxes for you
- var/atom/real_location = real_location()
- var/atom/host = parent
- if(real_location == I.loc)
- return FALSE //Means the item is already in the storage item
- if(locked)
- if(M && !stop_messages)
- host.add_fingerprint(M)
- to_chat(M, span_warning("[host] seems to be locked!"))
- return FALSE
- if(real_location.contents.len >= max_items)
- if(!stop_messages)
- to_chat(M, span_warning("[host] is full, make some space!"))
- return FALSE //Storage item is full
- if(length(can_hold))
- if(!is_type_in_typecache(I, can_hold))
- if(!stop_messages)
- to_chat(M, span_warning("[host] cannot hold [I]!"))
- return FALSE
- if(is_type_in_typecache(I, cant_hold) || HAS_TRAIT(I, TRAIT_NO_STORAGE_INSERT) || (can_hold_trait && !HAS_TRAIT(I, can_hold_trait))) //Items which this container can't hold.
- if(!stop_messages)
- to_chat(M, span_warning("[host] cannot hold [I]!"))
- return FALSE
- if(I.w_class > max_w_class && !is_type_in_typecache(I, exception_hold))
- if(!stop_messages)
- to_chat(M, span_warning("[I] is too big for [host]!"))
- return FALSE
- var/datum/component/storage/biggerfish = real_location.loc.GetComponent(/datum/component/storage)
- if(biggerfish && biggerfish.max_w_class < max_w_class) //return false if we are inside of another container, and that container has a smaller max_w_class than us (like if we're a bag in a box)
- if(!stop_messages)
- to_chat(M, span_warning("[I] can't fit in [host] while [real_location.loc] is in the way!"))
- return FALSE
- var/sum_w_class = I.w_class
- for(var/obj/item/_I in real_location)
- sum_w_class += _I.w_class //Adds up the combined w_classes which will be in the storage item if the item is added to it.
- if(sum_w_class > max_combined_w_class)
- if(!stop_messages)
- to_chat(M, span_warning("[I] won't fit in [host], make some space!"))
- return FALSE
- if(isitem(host))
- var/obj/item/IP = host
- var/datum/component/storage/STR_I = I.GetComponent(/datum/component/storage)
- if((I.w_class >= IP.w_class) && STR_I && !allow_big_nesting)
- if(!stop_messages)
- to_chat(M, span_warning("[IP] cannot hold [I] as it's a storage item of the same size!"))
- return FALSE //To prevent the stacking of same sized storage items.
- if(HAS_TRAIT(I, TRAIT_NODROP)) //SHOULD be handled in unEquip, but better safe than sorry.
- if(!stop_messages)
- to_chat(M, span_warning("\the [I] is stuck to your hand, you can't put it in \the [host]!"))
- return FALSE
- var/datum/component/storage/concrete/master = master()
- if(!istype(master))
- return FALSE
- return master.slave_can_insert_object(src, I, stop_messages, M)
-
-/datum/component/storage/proc/_insert_physical_item(obj/item/I, override = FALSE)
- return FALSE
-
-//This proc handles items being inserted. It does not perform any checks of whether an item can or can't be inserted. That's done by can_be_inserted()
-//The prevent_warning parameter will stop the insertion message from being displayed. It is intended for cases where you are inserting multiple items at once,
-//such as when picking up all the items on a tile with one click.
-/datum/component/storage/proc/handle_item_insertion(obj/item/I, prevent_warning = FALSE, mob/M, datum/component/storage/remote)
- var/atom/parent = src.parent
- var/datum/component/storage/concrete/master = master()
- if(!istype(master))
- return FALSE
- if(silent)
- prevent_warning = TRUE
- if(M)
- parent.add_fingerprint(M)
- . = master.handle_item_insertion_from_slave(src, I, prevent_warning, M)
-
-/datum/component/storage/proc/mob_item_insertion_feedback(mob/user, mob/M, obj/item/I, override = FALSE)
- if(silent && !override)
- return
- if(rustle_sound)
- playsound(parent, SFX_RUSTLE, 50, TRUE, -5)
- for(var/mob/viewing in viewers(user, null))
- if(M == viewing)
- to_chat(usr, span_notice("You put [I] [insert_preposition]to [parent]."))
- else if(in_range(M, viewing)) //If someone is standing close enough, they can tell what it is...
- viewing.show_message(span_notice("[M] puts [I] [insert_preposition]to [parent]."), MSG_VISUAL)
- else if(I && I.w_class >= 3) //Otherwise they can only see large or normal items from a distance...
- viewing.show_message(span_notice("[M] puts [I] [insert_preposition]to [parent]."), MSG_VISUAL)
-
-/datum/component/storage/proc/update_icon()
- if(isobj(parent))
- var/obj/O = parent
- O.update_appearance()
-
-/datum/component/storage/proc/signal_insertion_attempt(datum/source, obj/item/I, mob/M, silent = FALSE, force = FALSE)
- SIGNAL_HANDLER
-
- if((!force && !can_be_inserted(I, TRUE, M)) || (I == parent))
- return FALSE
- return handle_item_insertion(I, silent, M)
-
-/datum/component/storage/proc/signal_can_insert(datum/source, obj/item/I, mob/M, silent = FALSE)
- SIGNAL_HANDLER
-
- return can_be_inserted(I, silent, M)
-
-/datum/component/storage/proc/show_to_ghost(datum/source, mob/dead/observer/M)
- SIGNAL_HANDLER
-
- return user_show_to_mob(M, TRUE)
-
-/datum/component/storage/proc/signal_show_attempt(datum/source, mob/showto, force = FALSE)
- SIGNAL_HANDLER
-
- return user_show_to_mob(showto, force)
-
-/datum/component/storage/proc/on_check()
- SIGNAL_HANDLER
-
- return TRUE
-
-/datum/component/storage/proc/check_locked()
- SIGNAL_HANDLER
-
- return locked
-
-/datum/component/storage/proc/signal_take_type(datum/source, type, atom/destination, amount = INFINITY, check_adjacent = FALSE, force = FALSE, mob/user, list/inserted)
- SIGNAL_HANDLER
-
- if(!force)
- if(check_adjacent)
- if(!user || !user.CanReach(destination) || !user.CanReach(parent))
- return FALSE
- var/list/taking = typecache_filter_list(contents(), typecacheof(type))
- if(taking.len > amount)
- taking.len = amount
- if(inserted) //duplicated code for performance, don't bother checking retval/checking for list every item.
- for(var/i in taking)
- if(remove_from_storage(i, destination))
- inserted |= i
- else
- for(var/i in taking)
- remove_from_storage(i, destination)
- return TRUE
-
-/datum/component/storage/proc/remaining_space_items()
- var/atom/real_location = real_location()
- return max(0, max_items - real_location.contents.len)
-
-/datum/component/storage/proc/signal_fill_type(datum/source, type, amount = 20, force = FALSE)
- SIGNAL_HANDLER
-
- var/atom/real_location = real_location()
- if(!force)
- amount = min(remaining_space_items(), amount)
- for(var/i in 1 to amount)
- if(!handle_item_insertion(new type(real_location), TRUE))
- return i > 1 //return TRUE only if at least one insertion has been successful.
- if(QDELETED(src))
- return TRUE
- return TRUE
-
-
-/datum/component/storage/proc/on_attack_hand(datum/source, mob/user)
- SIGNAL_HANDLER
-
- var/atom/A = parent
- if(!attack_hand_interact)
- return
- if(user.active_storage == src && A.loc == user) //if you're already looking inside the storage item
- user.active_storage.close(user)
- close(user)
- . = COMPONENT_CANCEL_ATTACK_CHAIN
- return
-
- if(rustle_sound)
- playsound(A, SFX_RUSTLE, 50, TRUE, -5)
-
- if(ishuman(user))
- var/mob/living/carbon/human/H = user
- if(H.l_store == A && !H.get_active_held_item()) //Prevents opening if it's in a pocket.
- . = COMPONENT_CANCEL_ATTACK_CHAIN
- INVOKE_ASYNC(H, /mob.proc/put_in_hands, A)
- H.l_store = null
- return
- if(H.r_store == A && !H.get_active_held_item())
- . = COMPONENT_CANCEL_ATTACK_CHAIN
- INVOKE_ASYNC(H, /mob.proc/put_in_hands, A)
- H.r_store = null
- return
-
- if(A.loc == user)
- . = COMPONENT_CANCEL_ATTACK_CHAIN
- if(locked)
- to_chat(user, span_warning("[parent] seems to be locked!"))
- else
- show_to(user)
-
-
-/datum/component/storage/proc/signal_on_pickup(datum/source, mob/user)
- SIGNAL_HANDLER
-
- update_actions()
- for(var/mob/M in can_see_contents() - user)
- close(M)
-
-/datum/component/storage/proc/signal_take_obj(datum/source, atom/movable/AM, new_loc, force = FALSE)
- SIGNAL_HANDLER
-
- if(!(AM in real_location()))
- return FALSE
- return remove_from_storage(AM, new_loc)
-
-/datum/component/storage/proc/signal_quick_empty(datum/source, atom/loctarget)
- SIGNAL_HANDLER
-
- return do_quick_empty(loctarget)
-
-/datum/component/storage/proc/signal_hide_attempt(datum/source, mob/target)
- SIGNAL_HANDLER
-
- return hide_from(target)
-
-
-/datum/component/storage/proc/open_storage(mob/user)
- if(!user.CanReach(parent))
- user.balloon_alert(user, "can't reach!")
- return FALSE
- if(!isliving(user) || user.incapacitated())
- return FALSE
- if(locked)
- to_chat(user, span_warning("[parent] seems to be locked!"))
- return FALSE
-
- . = TRUE
- var/atom/A = parent
- if(!quickdraw)
- A.add_fingerprint(user)
- user_show_to_mob(user)
- playsound(A, SFX_RUSTLE, 50, TRUE, -5)
- return
-
- var/obj/item/to_remove = locate() in real_location()
- if(!to_remove)
- return
-
- INVOKE_ASYNC(src, .proc/attempt_put_in_hands, to_remove, user)
-
-/datum/component/storage/proc/on_open_storage_click(datum/source, mob/user, list/modifiers)
- SIGNAL_HANDLER
-
- if(open_storage(user))
- return COMPONENT_CANCEL_ATTACK_CHAIN
- if(LAZYACCESS(modifiers, RIGHT_CLICK))
- return COMPONENT_SECONDARY_CANCEL_ATTACK_CHAIN
-
-/datum/component/storage/proc/on_open_storage_attackby(datum/source, obj/item/weapon, mob/user, params)
- SIGNAL_HANDLER
-
- if(open_storage(user))
- return COMPONENT_SECONDARY_CANCEL_ATTACK_CHAIN
-
-///attempt to put an item from contents into the users hands
-/datum/component/storage/proc/attempt_put_in_hands(obj/item/to_remove, mob/user)
- var/atom/parent_as_atom = parent
-
- parent_as_atom.add_fingerprint(user)
- remove_from_storage(to_remove, get_turf(user))
- if(!user.put_in_hands(to_remove))
- to_chat(user, span_notice("You fumble for [to_remove] and it falls on the floor."))
- return
- user.visible_message(span_warning("[user] draws [to_remove] from [parent]!"), span_notice("You draw [to_remove] from [parent]."))
-
-/datum/component/storage/proc/action_trigger(datum/signal_source, datum/action/source)
- SIGNAL_HANDLER
-
- gather_mode_switch(source.owner)
- return COMPONENT_ACTION_BLOCK_TRIGGER
-
-/datum/component/storage/proc/gather_mode_switch(mob/user)
- collection_mode = (collection_mode+1)%3
- switch(collection_mode)
- if(COLLECT_SAME)
- to_chat(user, span_notice("[parent] now picks up all items of a single type at once."))
- if(COLLECT_EVERYTHING)
- to_chat(user, span_notice("[parent] now picks up all items in a tile at once."))
- if(COLLECT_ONE)
- to_chat(user, span_notice("[parent] now picks up one item at a time."))
diff --git a/code/datums/elements/item_scaling.dm b/code/datums/elements/item_scaling.dm
index 1f804beee16..490a762bbcb 100644
--- a/code/datums/elements/item_scaling.dm
+++ b/code/datums/elements/item_scaling.dm
@@ -42,10 +42,10 @@
// Make sure overlays also inherit the scaling.
ADD_KEEP_TOGETHER(target, ITEM_SCALING_TRAIT)
- // Object scaled when dropped/thrown OR when exiting a storage component.
- RegisterSignal(target, list(COMSIG_ITEM_DROPPED, COMSIG_STORAGE_EXITED), .proc/scale_overworld)
+ // Object scaled when dropped/thrown OR when exiting a storage object.
+ RegisterSignal(target, list(COMSIG_ITEM_DROPPED, COMSIG_ATOM_EXITED), .proc/scale_overworld)
// Object scaled when placed in an inventory slot OR when entering a storage component.
- RegisterSignal(target, list(COMSIG_ITEM_EQUIPPED, COMSIG_STORAGE_ENTERED), .proc/scale_storage)
+ RegisterSignal(target, list(COMSIG_ITEM_EQUIPPED, COMSIG_ATOM_ENTERED), .proc/scale_storage)
/**
* Detach proc for the item_scaling element.
@@ -58,8 +58,8 @@
UnregisterSignal(target, list(
COMSIG_ITEM_PICKUP,
COMSIG_ITEM_DROPPED,
- COMSIG_STORAGE_ENTERED,
- COMSIG_STORAGE_EXITED,
+ COMSIG_ATOM_ENTERED,
+ COMSIG_ATOM_EXITED,
))
REMOVE_KEEP_TOGETHER(target, ITEM_SCALING_TRAIT)
@@ -82,7 +82,7 @@
scalable_object.transform = M.Scale(scaling)
/**
- * Signal handler for COMSIG_ITEM_DROPPED or COMSIG_STORAGE_EXITED
+ * Signal handler for COMSIG_ITEM_DROPPED or COMSIG_ATOM_EXITED
*
* Longer detailed paragraph about the proc
* including any relevant detail
@@ -95,7 +95,7 @@
scale(source, overworld_scaling)
/**
- * Signal handler for COMSIG_ITEM_EQUIPPED or COMSIG_STORAGE_ENTERED.
+ * Signal handler for COMSIG_ITEM_EQUIPPED or COMSIG_ATOM_ENTERED.
*
* Longer detailed paragraph about the proc
* including any relevant detail
diff --git a/code/datums/quirks/_quirk.dm b/code/datums/quirks/_quirk.dm
index 0e5f0816020..2510e8233aa 100644
--- a/code/datums/quirks/_quirk.dm
+++ b/code/datums/quirks/_quirk.dm
@@ -161,7 +161,7 @@
var/mob/living/carbon/human/human_holder = quirk_holder
// post_add() can be called via delayed callback. Check they still have a backpack equipped before trying to open it.
if(human_holder.back)
- SEND_SIGNAL(human_holder.back, COMSIG_TRY_STORAGE_SHOW, human_holder)
+ human_holder.back.atom_storage.show_contents(human_holder)
for(var/chat_string in where_items_spawned)
to_chat(quirk_holder, chat_string)
diff --git a/code/datums/storage/storage.dm b/code/datums/storage/storage.dm
new file mode 100644
index 00000000000..3eee1a40609
--- /dev/null
+++ b/code/datums/storage/storage.dm
@@ -0,0 +1,1063 @@
+/**
+ * Datumized Storage
+ * Eliminates the need for custom signals specifically for the storage component, and attaches a storage variable (atom_storage) to every atom.
+ * The parent and real_location variables are both weakrefs, so they must be resolved before they can be used.
+ * If you're looking to create custom storage type behaviors, check ../subtypes
+ */
+/datum/storage
+ /// the actual item we're attached to
+ var/datum/weakref/parent
+ /// the actual item we're storing in
+ var/datum/weakref/real_location
+
+ /// if this is set, only items, and their children, will fit
+ var/list/can_hold
+ /// if this is set, items, and their children, won't fit
+ var/list/cant_hold
+ /// if set, these items will be the exception to the max size of object that can fit.
+ var/list/exception_hold
+ /// if set can only contain stuff with this single trait present.
+ var/list/can_hold_trait
+
+ /// whether or not we should have those cute little animations
+ var/animated = TRUE
+
+ var/max_slots = 7
+ /// max weight class for a single item being inserted
+ var/max_specific_storage = WEIGHT_CLASS_NORMAL
+ /// max combined weight classes the storage can hold
+ var/max_total_storage = 14
+
+ /// list of all the mobs currently viewing the contents
+ var/list/is_using = list()
+
+ var/locked = FALSE
+ /// whether or not we should open when clicked
+ var/attack_hand_interact = TRUE
+ /// whether or not we allow storage objects of the same size inside
+ var/allow_big_nesting = FALSE
+
+ /// should we be allowed to pickup an object by clicking it
+ var/allow_quick_gather = FALSE
+ /// show we allow emptying all contents by using the storage object in hand
+ var/allow_quick_empty = FALSE
+ /// the mode for collection when allow_quick_gather is enabled
+ var/collection_mode = COLLECT_ONE
+
+ /// shows what we can hold in examine text
+ var/can_hold_description
+
+ /// contents shouldn't be emped
+ var/emp_shielded
+
+ /// you put things *in* a bag, but *on* a plate
+ var/insert_preposition = "in"
+
+ /// don't show any chat messages regarding inserting items
+ var/silent = FALSE
+ /// play a rustling sound when interacting with the bag
+ var/rustle_sound = TRUE
+
+ /// alt click takes an item out instead of opening up storage
+ var/quickdraw = FALSE
+
+ /// instead of displaying multiple items of the same type, display them as numbered contents
+ var/numerical_stacking = FALSE
+
+ /// storage display object
+ var/atom/movable/screen/storage/boxes
+ /// close button object
+ var/atom/movable/screen/close/closer
+
+ /// maximum amount of columns a storage object can have
+ var/screen_max_columns = 7
+ var/screen_max_rows = INFINITY
+ /// pixel location of the boxes and close button
+ var/screen_pixel_x = 16
+ var/screen_pixel_y = 16
+ /// where storage starts being rendered, screen_loc wise
+ var/screen_start_x = 4
+ var/screen_start_y = 2
+
+ var/datum/weakref/modeswitch_action_ref
+
+/datum/storage/New(atom/parent, max_slots, max_specific_storage, max_total_storage, numerical_stacking, allow_quick_gather, allow_quick_empty, collection_mode, attack_hand_interact)
+ boxes = new(null, src)
+ closer = new(null, src)
+
+ src.parent = WEAKREF(parent)
+ src.real_location = src.parent
+ src.max_slots = max_slots || src.max_slots
+ src.max_specific_storage = max_specific_storage || src.max_specific_storage
+ src.max_total_storage = max_total_storage || src.max_total_storage
+ src.numerical_stacking = numerical_stacking || src.numerical_stacking
+ src.allow_quick_gather = allow_quick_gather || src.allow_quick_gather
+ src.allow_quick_empty = allow_quick_empty || src.allow_quick_empty
+ src.collection_mode = collection_mode || src.collection_mode
+ src.attack_hand_interact = attack_hand_interact || src.attack_hand_interact
+
+ var/atom/resolve_parent = src.parent?.resolve()
+ var/atom/resolve_location = src.real_location?.resolve()
+
+ if(!resolve_parent)
+ stack_trace("storage could not resolve parent weakref")
+ qdel(src)
+ return
+
+ if(!resolve_location)
+ stack_trace("storage could not resolve location weakref")
+ qdel(src)
+ return
+
+ RegisterSignal(resolve_parent, list(COMSIG_ATOM_ATTACK_PAW, COMSIG_ATOM_ATTACK_HAND), .proc/handle_attack)
+ RegisterSignal(resolve_parent, COMSIG_MOUSEDROP_ONTO, .proc/mousedrop_onto)
+ RegisterSignal(resolve_parent, COMSIG_MOUSEDROPPED_ONTO, .proc/mousedropped_onto)
+
+ RegisterSignal(resolve_parent, COMSIG_ATOM_EMP_ACT, .proc/emp_act)
+ RegisterSignal(resolve_parent, COMSIG_PARENT_ATTACKBY, .proc/attackby)
+ RegisterSignal(resolve_parent, COMSIG_ITEM_PRE_ATTACK, .proc/intercept_preattack)
+ RegisterSignal(resolve_parent, COMSIG_OBJ_DECONSTRUCT, .proc/deconstruct)
+
+ RegisterSignal(resolve_parent, COMSIG_ITEM_ATTACK_SELF, .proc/mass_empty)
+
+ RegisterSignal(resolve_parent, list(COMSIG_ATOM_ATTACK_HAND_SECONDARY, COMSIG_CLICK_ALT, COMSIG_ATOM_ATTACK_GHOST), .proc/open_storage)
+
+ RegisterSignal(resolve_location, COMSIG_ATOM_ENTERED, .proc/handle_enter)
+ RegisterSignal(resolve_location, COMSIG_ATOM_EXITED, .proc/handle_exit)
+ RegisterSignal(resolve_parent, COMSIG_MOVABLE_MOVED, .proc/close_distance)
+ RegisterSignal(resolve_parent, COMSIG_ITEM_EQUIPPED, .proc/update_actions)
+
+ RegisterSignal(resolve_parent, COMSIG_TOPIC, .proc/topic_handle)
+
+ orient_to_hud()
+
+/datum/storage/Destroy()
+ parent = null
+ real_location = null
+ boxes = null
+ closer = null
+
+ for(var/mob/person in is_using)
+ if(person.active_storage == src)
+ person.active_storage = null
+
+ is_using.Cut()
+
+ return ..()
+
+/datum/storage/proc/deconstruct()
+ SIGNAL_HANDLER
+
+ remove_all()
+
+/// Automatically ran on all object insertions: flag marking and view refreshing.
+/datum/storage/proc/handle_enter(datum/source, obj/item/arrived)
+ SIGNAL_HANDLER
+
+ if(!istype(arrived))
+ return
+
+ arrived.item_flags |= IN_STORAGE
+
+ refresh_views()
+
+ arrived.on_enter_storage(src)
+
+/// Automatically ran on all object removals: flag marking and view refreshing.
+/datum/storage/proc/handle_exit(datum/source, obj/item/gone)
+ SIGNAL_HANDLER
+
+ if(!istype(gone))
+ return
+
+ gone.item_flags &= ~IN_STORAGE
+
+ remove_and_refresh(gone)
+
+ gone.on_exit_storage(src)
+
+/**
+ * Sets where items are physically being stored in the case it shouldn't be on the parent.
+ *
+ * @param atom/real the new real location of the datum
+ * @param should_drop if TRUE, all the items in the old real location will be dropped
+ */
+/datum/storage/proc/set_real_location(atom/real, should_drop = FALSE)
+ if(!real)
+ return
+
+ var/atom/resolve_location = src.real_location?.resolve()
+ if(!resolve_location)
+ return
+
+ var/atom/resolve_parent = src.parent?.resolve()
+ if(!resolve_parent)
+ return
+
+ if(should_drop)
+ remove_all(src, get_turf(resolve_parent))
+
+ resolve_location.flags_1 &= ~HAS_DISASSOCIATED_STORAGE_1
+ real.flags_1 |= HAS_DISASSOCIATED_STORAGE_1
+
+ UnregisterSignal(resolve_location, list(COMSIG_ATOM_ENTERED, COMSIG_ATOM_EXITED))
+
+ RegisterSignal(real, COMSIG_ATOM_ENTERED, .proc/handle_enter)
+ RegisterSignal(real, COMSIG_ATOM_EXITED, .proc/handle_exit)
+
+ real_location = WEAKREF(real)
+
+/datum/storage/proc/topic_handle(datum/source, user, href_list)
+ SIGNAL_HANDLER
+
+ if(href_list["show_valid_pocket_items"])
+ handle_show_valid_items(source, user)
+
+/datum/storage/proc/handle_show_valid_items(datum/source, user)
+ to_chat(user, span_notice("[source] can hold: [can_hold_description]"))
+
+/// Almost 100% of the time the lists passed into set_holdable are reused for each instance of the component
+/// Just fucking cache it 4head
+/// Yes I could generalize this, but I don't want anyone else using it. in fact, DO NOT COPY THIS
+/// If you find yourself needing this pattern, you're likely better off using static typecaches
+/// I'm not because I do not trust implementers of the storage component to use them, BUT
+/// IF I FIND YOU USING THIS PATTERN IN YOUR CODE I WILL BREAK YOU ACROSS MY KNEES
+/// ~Lemon
+GLOBAL_LIST_EMPTY(cached_storage_typecaches)
+
+/datum/storage/proc/set_holdable(list/can_hold_list = null, list/cant_hold_list = null)
+ if(!islist(can_hold_list))
+ can_hold_list = list(can_hold_list)
+ if(!islist(cant_hold_list))
+ cant_hold_list = list(cant_hold_list)
+
+ can_hold_description = generate_hold_desc(can_hold_list)
+
+ if (can_hold_list)
+ var/unique_key = can_hold_list.Join("-")
+ if(!GLOB.cached_storage_typecaches[unique_key])
+ GLOB.cached_storage_typecaches[unique_key] = typecacheof(can_hold_list)
+ can_hold = GLOB.cached_storage_typecaches[unique_key]
+
+ if (cant_hold_list != null)
+ var/unique_key = cant_hold_list.Join("-")
+ if(!GLOB.cached_storage_typecaches[unique_key])
+ GLOB.cached_storage_typecaches[unique_key] = typecacheof(cant_hold_list)
+ cant_hold = GLOB.cached_storage_typecaches[unique_key]
+
+/// Generates a description, primarily for clothing storage.
+/datum/storage/proc/generate_hold_desc(can_hold_list)
+ var/list/desc = list()
+
+ for(var/valid_type in can_hold_list)
+ var/obj/item/valid_item = valid_type
+ desc += "\a [initial(valid_item.name)]"
+
+ return "\n\t[span_notice("[desc.Join("\n\t")]")]"
+
+/// Updates the action button for toggling collectmode.
+/datum/storage/proc/update_actions()
+ SIGNAL_HANDLER
+
+ var/obj/item/resolve_parent = parent?.resolve()
+ if(!resolve_parent)
+ return
+
+ if(!istype(resolve_parent) || !allow_quick_gather)
+ QDEL_NULL(modeswitch_action_ref)
+ return
+
+ var/datum/action/existing = modeswitch_action_ref?.resolve()
+ if(!QDELETED(existing))
+ return
+
+ var/datum/action/modeswitch_action = resolve_parent.add_item_action(/datum/action/item_action/storage_gather_mode)
+ RegisterSignal(modeswitch_action, COMSIG_ACTION_TRIGGER, .proc/action_trigger)
+ modeswitch_action_ref = WEAKREF(modeswitch_action)
+
+/// Refreshes and item to be put back into the real world, out of storage.
+/datum/storage/proc/reset_item(obj/item/thing)
+ thing.layer = initial(thing.layer)
+ thing.plane = initial(thing.plane)
+ thing.mouse_opacity = initial(thing.mouse_opacity)
+ thing.screen_loc = null
+ if(thing.maptext)
+ thing.maptext = ""
+
+/**
+ * Checks if an item is capable of being inserted into the storage
+ *
+ * @param obj/item/to_insert the item we're checking
+ * @param messages if TRUE, will print out a message if the item is not valid
+ * @param force bypass locked storage
+ */
+/datum/storage/proc/can_insert(obj/item/to_insert, mob/user, messages = TRUE, force = FALSE)
+ var/obj/item/resolve_parent = parent?.resolve()
+ if(!resolve_parent)
+ return
+
+ var/obj/item/resolve_location = real_location?.resolve()
+ if(!resolve_location)
+ return
+
+ if(!isitem(to_insert))
+ return FALSE
+
+ if(locked && !force)
+ return FALSE
+
+ if((to_insert == resolve_parent) || (to_insert == real_location))
+ return FALSE
+
+ if(to_insert.w_class > max_specific_storage && !is_type_in_typecache(to_insert, exception_hold))
+ if(messages)
+ to_chat(user, span_warning("\The [to_insert] is too big for \the [resolve_parent]!"))
+ return FALSE
+
+ if(resolve_location.contents.len >= max_slots)
+ if(messages)
+ to_chat(user, span_warning("\The [to_insert] can't fit into \the [resolve_parent]! Make some space!"))
+ return FALSE
+
+ var/total_weight = to_insert.w_class
+
+ for(var/obj/item/thing in resolve_location)
+ total_weight += thing.w_class
+
+ if(total_weight > max_total_storage)
+ if(messages)
+ to_chat(user, span_warning("\The [to_insert] can't fit into \the [resolve_parent]! Make some space!"))
+ return FALSE
+
+ if(length(can_hold))
+ if(!is_type_in_typecache(to_insert, can_hold))
+ if(messages)
+ to_chat(user, span_warning("\The [resolve_parent] cannot hold \the [to_insert]!"))
+ return FALSE
+
+ if(is_type_in_typecache(to_insert, cant_hold) || HAS_TRAIT(to_insert, TRAIT_NO_STORAGE_INSERT) || (can_hold_trait && !HAS_TRAIT(to_insert, can_hold_trait)))
+ if(messages)
+ to_chat(user, span_warning("\The [resolve_parent] cannot hold \the [to_insert]!"))
+ return FALSE
+
+ var/datum/storage/biggerfish = resolve_parent.loc.atom_storage // this is valid if the container our resolve_parent is being held in is a storage item
+
+ if(biggerfish && biggerfish.max_specific_storage < max_specific_storage)
+ if(messages)
+ to_chat(user, span_warning("[to_insert] can't fit in [resolve_parent] while [resolve_parent.loc] is in the way!"))
+ return FALSE
+
+ if(istype(resolve_parent))
+ var/datum/storage/item_storage = to_insert.atom_storage
+ if((to_insert.w_class >= resolve_parent.w_class) && item_storage && !allow_big_nesting)
+ if(messages)
+ to_chat(user, span_warning("[resolve_parent] cannot hold [to_insert] as it's a storage item of the same size!"))
+ return FALSE
+
+ return TRUE
+
+/**
+ * Attempts to insert an item into the storage
+ *
+ * @param datum/source used by the signal handler
+ * @param obj/item/to_insert the item we're inserting
+ * @param mob/user the user who is inserting the item
+ * @param override see item_insertion_feedback()
+ * @param force bypass locked storage
+ */
+/datum/storage/proc/attempt_insert(datum/source, obj/item/to_insert, mob/user, override = FALSE, force = FALSE)
+ SIGNAL_HANDLER
+
+ var/obj/item/resolve_location = real_location?.resolve()
+ if(!resolve_location)
+ return
+
+ if(!can_insert(to_insert, user, force = force))
+ return FALSE
+
+ to_insert.item_flags |= IN_STORAGE
+
+ to_insert.forceMove(resolve_location)
+ item_insertion_feedback(user, to_insert, override)
+
+ return TRUE
+
+/**
+ * Inserts every time in a given list, with a progress bar
+ *
+ * @param mob/user the user who is inserting the items
+ * @param list/things the list of items to insert
+ * @param atom/thing_loc the location of the items (used to make sure an item hasn't moved during pickup)
+ * @param list/rejections a list used to make sure we only complain once about an invalid insertion
+ * @param datum/progressbar/progress the progressbar used to show the progress of the insertion
+ */
+/datum/storage/proc/handle_mass_pickup(mob/user, list/things, atom/thing_loc, list/rejections, datum/progressbar/progress)
+ var/obj/item/resolve_parent = parent?.resolve()
+ if(!resolve_parent)
+ return
+
+ var/obj/item/resolve_location = real_location?.resolve()
+ if(!resolve_location)
+ return
+
+ for(var/obj/item/thing in things)
+ things -= thing
+ if(thing.loc != thing_loc)
+ continue
+ if(thing.type in rejections) // To limit bag spamming: any given type only complains once
+ continue
+ if(!attempt_insert(resolve_parent, thing, user, TRUE)) // Note can_be_inserted still makes noise when the answer is no
+ if(resolve_location.contents.len >= max_slots)
+ break
+ rejections += thing.type // therefore full bags are still a little spammy
+ continue
+
+ if (TICK_CHECK)
+ progress.update(progress.goal - things.len)
+ return TRUE
+
+ progress.update(progress.goal - things.len)
+ return FALSE
+
+/**
+ * Used to transfer all the items inside of us to another atom
+ *
+ * @param mob/user the user who is transferring the items
+ * @param atom/going_to the atom we're transferring to
+ */
+/datum/storage/proc/handle_mass_transfer(mob/user, atom/going_to)
+ var/obj/item/resolve_location = real_location?.resolve()
+ if(!resolve_location)
+ return
+
+ if(!going_to.atom_storage)
+ return
+
+ for (var/atom/thing in resolve_location.contents)
+ going_to.atom_storage.attempt_insert(src, thing, user)
+
+/**
+ * Provides visual feedback in chat for an item insertion
+ *
+ * @param mob/user the user who is inserting the item
+ * @param obj/item/thing the item we're inserting
+ * @param override skip feedback, only do animation check
+ */
+/datum/storage/proc/item_insertion_feedback(mob/user, obj/item/thing, override = FALSE)
+ var/obj/item/resolve_parent = parent?.resolve()
+ if(!resolve_parent)
+ return
+
+ if(animated)
+ animate_parent()
+
+ if(override)
+ return
+
+ if(silent)
+ return
+
+ if(rustle_sound)
+ playsound(resolve_parent, SFX_RUSTLE, 50, TRUE, -5)
+
+ to_chat(user, span_notice("You put [thing] [insert_preposition]to [resolve_parent]."))
+
+ for(var/mob/viewing in oviewers(user, null))
+ if(in_range(user, viewing))
+ viewing.show_message(span_notice("[user] puts [thing] [insert_preposition]to [resolve_parent]."), MSG_VISUAL)
+ return
+ if(thing && thing.w_class >= 3)
+ viewing.show_message(span_notice("[user] puts [thing] [insert_preposition]to [resolve_parent]."), MSG_VISUAL)
+ return
+
+/**
+ * Attempts to remove an item from the storage
+ *
+ * @param obj/item/thing the object we're removing
+ * @param atom/newLoc where we're placing the item
+ * @param silent if TRUE, we won't play any exit sounds
+ */
+/datum/storage/proc/attempt_remove(obj/item/thing, atom/newLoc, silent = FALSE)
+ var/obj/item/resolve_parent = parent?.resolve()
+ if(!resolve_parent)
+ return
+
+ if(istype(thing))
+ if(ismob(resolve_parent.loc))
+ var/mob/mobparent = resolve_parent.loc
+ thing.dropped(mobparent, TRUE)
+
+ if(newLoc)
+ reset_item(thing)
+ thing.forceMove(newLoc)
+
+ if(rustle_sound && !silent)
+ playsound(resolve_parent, SFX_RUSTLE, 50, TRUE, -5)
+ else
+ thing.moveToNullspace()
+
+ thing.item_flags &= ~IN_STORAGE
+
+ if(animated)
+ animate_parent()
+
+ refresh_views()
+
+ if(isobj(resolve_parent))
+ resolve_parent.update_appearance()
+
+ return TRUE
+
+/**
+ * Removes everything inside of our storage
+ *
+ * @param atom/target where we're placing the item
+ */
+/datum/storage/proc/remove_all(atom/target)
+ var/obj/item/resolve_parent = parent?.resolve()
+ if(!resolve_parent)
+ return
+
+ var/obj/item/resolve_location = real_location?.resolve()
+ if(!resolve_location)
+ return
+
+ if(!target)
+ target = get_turf(resolve_parent)
+
+ for(var/obj/item/thing in resolve_location)
+ if(thing.loc != resolve_location)
+ continue
+ attempt_remove(thing, target, silent = TRUE)
+
+/**
+ * Removes only a specific type of item from our storage
+ *
+ * @param type the type of item to remove
+ * @param amount how many we should attempt to pick up at one time
+ * @param check_adjacent if TRUE, we'll check adjacent locations for the item type
+ * @param force if TRUE, we'll bypass the check_adjacent check all together
+ * @param mob/user the user who is removing the items
+ * @param list/inserted a list passed to attempt_remove for ultimate removal
+ */
+/datum/storage/proc/remove_type(type, atom/destination, amount = INFINITY, check_adjacent = FALSE, force = FALSE, mob/user, list/inserted)
+ var/obj/item/resolve_location = real_location?.resolve()
+ if(!resolve_location)
+ return
+
+ if(!force)
+ if(check_adjacent)
+ if(!user || !user.CanReach(destination) || !user.CanReach(parent))
+ return FALSE
+ var/list/taking = typecache_filter_list(resolve_location.contents, typecacheof(type))
+ if(taking.len > amount)
+ taking.len = amount
+ if(inserted) //duplicated code for performance, don't bother checking retval/checking for list every item.
+ for(var/i in taking)
+ if(attempt_remove(i, destination))
+ inserted |= i
+ else
+ for(var/i in taking)
+ attempt_remove(i, destination)
+ return TRUE
+
+/// Signal handler for remove_all()
+/datum/storage/proc/mass_empty(datum/source, atom/location, force)
+ SIGNAL_HANDLER
+
+ if(!allow_quick_empty && !force)
+ return
+
+ remove_all(get_turf(location))
+
+/**
+ * Recursive proc to get absolutely EVERYTHING inside a storage item, including the contents of inner items.
+ *
+ * @param list/interface the list we're adding objects to
+ * @param recursive whether or not we're checking inside of inner items
+ */
+/datum/storage/proc/return_inv(list/interface, recursive = TRUE)
+ if(!islist(interface))
+ return FALSE
+
+ var/obj/item/resolve_location = real_location?.resolve()
+ if(!resolve_location)
+ return
+
+ var/list/ret = list()
+ ret |= resolve_location.contents
+ if(recursive)
+ for(var/i in ret.Copy())
+ var/atom/atom = i
+ atom.atom_storage?.return_inv(ret, TRUE)
+
+ interface |= ret
+
+ return TRUE
+
+/**
+ * Resets an object, removes it from our screen, and refreshes the view.
+ *
+ * @param atom/movable/gone the object leaving our storage
+ */
+/datum/storage/proc/remove_and_refresh(atom/movable/gone)
+ SIGNAL_HANDLER
+
+ for(var/mob/user in is_using)
+ if(user.client)
+ var/client/cuser = user.client
+ cuser.screen -= gone
+
+ reset_item(gone)
+ refresh_views()
+
+/// Signal handler for the emp_act() of all contents
+/datum/storage/proc/emp_act(datum/source, severity)
+ SIGNAL_HANDLER
+
+ var/obj/item/resolve_location = real_location?.resolve()
+ if(!resolve_location)
+ return
+
+ if(emp_shielded)
+ return
+
+ for(var/atom/thing in resolve_location)
+ thing.emp_act(severity)
+
+/// Signal handler for preattack from an object.
+/datum/storage/proc/intercept_preattack(datum/source, obj/item/thing, mob/user, params)
+ SIGNAL_HANDLER
+
+ if(!istype(thing) || !allow_quick_gather || thing.atom_storage)
+ return FALSE
+
+ if(collection_mode == COLLECT_ONE)
+ attempt_insert(source, thing, user)
+ return TRUE
+
+ if(!isturf(thing.loc))
+ return TRUE
+
+ INVOKE_ASYNC(src, .proc/collect_on_turf, thing, user)
+ return TRUE
+
+/**
+ * Collects every item of a type on a turf.
+ *
+ * @param obj/item/thing the initial object to pick up
+ * @param mob/user the user who is picking up the items
+ */
+/datum/storage/proc/collect_on_turf(obj/item/thing, mob/user)
+ var/obj/item/resolve_parent = parent?.resolve()
+ if(!resolve_parent)
+ return
+
+ var/list/turf_things = thing.loc.contents.Copy()
+
+ if(collection_mode == COLLECT_SAME)
+ turf_things = typecache_filter_list(turf_things, typecacheof(thing.type))
+
+ var/amount = length(turf_things)
+ if(!amount)
+ to_chat(user, span_warning("You failed to pick up anything with [resolve_parent]!"))
+ return
+
+ var/datum/progressbar/progress = new(user, amount, thing.loc)
+ var/list/rejections = list()
+
+ while(do_after(user, 1 SECONDS, resolve_parent, NONE, FALSE, CALLBACK(src, .proc/handle_mass_pickup, user, turf_things, thing.loc, rejections, progress)))
+ stoplag(1)
+
+ progress.end_progress()
+ to_chat(user, span_notice("You put everything you could [insert_preposition]to [resolve_parent]."))
+
+/// Signal handler for whenever we drag the storage somewhere.
+/datum/storage/proc/mousedrop_onto(datum/source, atom/over_object, mob/user)
+ SIGNAL_HANDLER
+
+ var/obj/item/resolve_parent = parent?.resolve()
+ if(!resolve_parent)
+ return
+
+ if(!istype(user))
+ return
+ if(!over_object)
+ return
+ if(ismecha(user.loc))
+ return
+ if(user.incapacitated() || !user.canUseStorage())
+ return
+
+ resolve_parent.add_fingerprint(user)
+
+ if(over_object == user)
+ open_storage(resolve_parent, user)
+
+ if(!istype(over_object, /atom/movable/screen))
+ INVOKE_ASYNC(src, .proc/dump_content_at, over_object, user)
+ return
+
+ if(resolve_parent.loc != user)
+ return
+
+ if(rustle_sound)
+ playsound(resolve_parent, SFX_RUSTLE, 50, TRUE, -5)
+
+ if(istype(over_object, /atom/movable/screen/inventory/hand))
+ var/atom/movable/screen/inventory/hand/hand = over_object
+ user.putItemFromInventoryInHandIfPossible(resolve_parent, hand.held_index)
+ return
+
+/**
+ * Dumps all of our contents at a specific location.
+ *
+ * @param atom/dest_object where to dump to
+ * @param mob/user the user who is dumping the contents
+ */
+/datum/storage/proc/dump_content_at(atom/dest_object, mob/user)
+ var/obj/item/resolve_parent = parent?.resolve()
+ if(!resolve_parent)
+ return
+
+ var/obj/item/resolve_location = real_location?.resolve()
+ if(!resolve_location)
+ return
+
+ if(user.CanReach(resolve_parent) && dest_object && user.CanReach(dest_object))
+ if(locked)
+ return
+ if(dest_object.storage_contents_dump_act(resolve_parent, user))
+ return
+
+/// Signal handler for whenever something gets mouse-dropped onto us.
+/datum/storage/proc/mousedropped_onto(datum/source, obj/item/dropping, mob/user)
+ SIGNAL_HANDLER
+
+ var/obj/item/resolve_parent = parent?.resolve()
+
+ if(!resolve_parent)
+ return
+ if(!istype(dropping))
+ return
+
+ if(iscarbon(user) || isdrone(user))
+ var/mob/living/user_living = user
+ if(!user_living.incapacitated() && dropping == user_living.get_active_held_item())
+ if(!dropping.atom_storage && can_insert(dropping, user)) //If it has storage it should be trying to dump, not insert.
+ attempt_insert(src, dropping, user)
+
+/// Signal handler for whenever we're attacked by an object.
+/datum/storage/proc/attackby(datum/source, obj/item/thing, mob/user, params)
+ SIGNAL_HANDLER
+
+ var/obj/item/resolve_parent = parent?.resolve()
+ if(!resolve_parent)
+ return
+
+ if(!thing.attackby_storage_insert(src, resolve_parent, user))
+ return FALSE
+
+ if(iscyborg(user))
+ return TRUE
+
+ attempt_insert(resolve_parent, thing, user)
+ return TRUE
+
+/// Signal handler for whenever we're attacked by a mob.
+/datum/storage/proc/handle_attack(datum/source, mob/user)
+ SIGNAL_HANDLER
+
+ var/obj/item/resolve_parent = parent?.resolve()
+ if(!resolve_parent)
+ return
+ if(!attack_hand_interact)
+ return
+ if(user.active_storage == src && resolve_parent.loc == user)
+ user.active_storage.hide_contents(user)
+ hide_contents(user)
+ return TRUE
+ if(ishuman(user))
+ var/mob/living/carbon/human/hum = user
+ if(hum.l_store == resolve_parent && !hum.get_active_held_item())
+ INVOKE_ASYNC(hum, /mob.proc/put_in_hands, resolve_parent)
+ hum.l_store = null
+ return
+ if(hum.r_store == resolve_parent && !hum.get_active_held_item())
+ INVOKE_ASYNC(hum, /mob.proc/put_in_hands, resolve_parent)
+ hum.r_store = null
+ return
+
+ if(resolve_parent.loc == user)
+ open_storage(resolve_parent, user)
+ return TRUE
+
+/// Generates the numbers on an item in storage to show stacking.
+/datum/storage/proc/process_numerical_display()
+ var/obj/item/resolve_location = real_location?.resolve()
+ if(!resolve_location)
+ return
+
+ var/list/toreturn = list()
+
+ for(var/obj/item/thing in resolve_location.contents)
+ var/total_amnt = 1
+
+ if(istype(thing, /obj/item/stack))
+ var/obj/item/stack/things = thing
+ total_amnt = things.amount
+
+ if(!toreturn["[thing.type]-[thing.name]"])
+ toreturn["[thing.type]-[thing.name]"] = new /datum/numbered_display(thing, total_amnt)
+ else
+ var/datum/numbered_display/numberdisplay = toreturn["[thing.type]-[thing.name]"]
+ numberdisplay.number += total_amnt
+
+ return toreturn
+
+/// Updates the storage UI to fit all objects inside storage.
+/datum/storage/proc/orient_to_hud()
+ var/obj/item/resolve_location = real_location?.resolve()
+ if(!resolve_location)
+ return
+
+ var/adjusted_contents = resolve_location.contents.len
+
+ //Numbered contents display
+ var/list/datum/numbered_display/numbered_contents
+ if(numerical_stacking)
+ numbered_contents = process_numerical_display()
+ adjusted_contents = numbered_contents.len
+
+ var/columns = clamp(max_slots, 1, screen_max_columns)
+ var/rows = clamp(CEILING(adjusted_contents / columns, 1), 1, screen_max_rows)
+
+ orient_item_boxes(rows, columns, numbered_contents)
+
+/// Generates the actual UI objects, their location, and alignments whenever we open storage up.
+/datum/storage/proc/orient_item_boxes(rows, cols, list/obj/item/numerical_display_contents)
+ var/obj/item/resolve_location = real_location?.resolve()
+ if(!resolve_location)
+ return
+
+ boxes.screen_loc = "[screen_start_x]:[screen_pixel_x],[screen_start_y]:[screen_pixel_y] to [screen_start_x+cols-1]:[screen_pixel_x],[screen_start_y+rows-1]:[screen_pixel_y]"
+ var/current_x = screen_start_x
+ var/current_y = screen_start_y
+
+ if(islist(numerical_display_contents))
+ for(var/type in numerical_display_contents)
+ var/datum/numbered_display/numberdisplay = numerical_display_contents[type]
+
+ numberdisplay.sample_object.mouse_opacity = MOUSE_OPACITY_OPAQUE
+ numberdisplay.sample_object.screen_loc = "[current_x]:[screen_pixel_x],[current_y]:[screen_pixel_y]"
+ numberdisplay.sample_object.maptext = MAPTEXT("[(numberdisplay.number > 1)? "[numberdisplay.number]" : ""]")
+ numberdisplay.sample_object.plane = ABOVE_HUD_PLANE
+
+ current_x++
+
+ if(current_x - screen_start_x >= cols)
+ current_x = screen_start_x
+ current_y++
+
+ if(current_y - screen_start_y >= rows)
+ break
+
+ else
+ for(var/obj/item in resolve_location)
+ item.mouse_opacity = MOUSE_OPACITY_OPAQUE
+ item.screen_loc = "[current_x]:[screen_pixel_x],[current_y]:[screen_pixel_y]"
+ item.maptext = ""
+ item.plane = ABOVE_HUD_PLANE
+
+ current_x++
+
+ if(current_x - screen_start_x >= cols)
+ current_x = screen_start_x
+ current_y++
+
+ if(current_y - screen_start_y >= rows)
+ break
+
+ closer.screen_loc = "[screen_start_x + cols]:[screen_pixel_x],[screen_start_y]:[screen_pixel_y]"
+
+/// Signal handler for when we're showing ourselves to a mob.
+/datum/storage/proc/open_storage(datum/source, mob/toshow)
+ SIGNAL_HANDLER
+
+ var/obj/item/resolve_parent = parent?.resolve()
+ if(!resolve_parent)
+ return
+
+ var/obj/item/resolve_location = real_location?.resolve()
+ if(!resolve_location)
+ return
+
+ if(!toshow.CanReach(resolve_parent))
+ resolve_parent.balloon_alert(toshow, "can't reach!")
+ return FALSE
+
+ if(!isliving(toshow) || toshow.incapacitated())
+ return FALSE
+
+ if(locked)
+ if(!silent)
+ to_chat(toshow, span_warning("[pick("Ka-chunk!", "Ka-chink!", "Plunk!", "Glorf!")] \The [resolve_parent] appears to be locked!"))
+ return FALSE
+
+ if(!quickdraw || toshow.get_active_held_item())
+ show_contents(toshow)
+
+ if(animated)
+ animate_parent()
+
+ if(rustle_sound)
+ playsound(resolve_parent, SFX_RUSTLE, 50, TRUE, -5)
+
+ return TRUE
+
+ var/obj/item/to_remove = locate() in resolve_location
+
+ if(!to_remove)
+ return TRUE
+
+ attempt_remove(to_remove)
+
+ INVOKE_ASYNC(src, .proc/put_in_hands_async, toshow, to_remove)
+
+ if(!silent)
+ toshow.visible_message(span_warning("[toshow] draws [to_remove] from [resolve_parent]!"), span_notice("You draw [to_remove] from [resolve_parent]."))
+
+ return TRUE
+
+/// Async version of putting something into a mobs hand.
+/datum/storage/proc/put_in_hands_async(mob/toshow, obj/item/toremove)
+ if(!toshow.put_in_hands(toremove))
+ if(!silent)
+ to_chat(toshow, span_notice("You fumble for [toremove] and it falls on the floor."))
+ return TRUE
+
+/// Signal handler for whenever a mob walks away with us, close if they can't reach us.
+/datum/storage/proc/close_distance(datum/source)
+ SIGNAL_HANDLER
+
+ var/obj/item/resolve_parent = parent?.resolve()
+ if(!resolve_parent)
+ return
+
+ for(var/mob/user in can_see_contents())
+ if (!user.CanReach(resolve_parent))
+ hide_contents(user)
+
+/// Close the storage UI for everyone viewing us.
+/datum/storage/proc/close_all()
+ for(var/mob/user in is_using)
+ hide_contents(user)
+
+/// Refresh the views of everyone currently viewing the storage.
+/datum/storage/proc/refresh_views()
+ for (var/mob/user in can_see_contents())
+ show_contents(user)
+
+/// Checks who is currently capable of viewing our storage (and is.)
+/datum/storage/proc/can_see_contents()
+ var/list/seeing = list()
+ for (var/mob/user in is_using)
+ if(user.active_storage == src && user.client)
+ seeing += user
+ else
+ is_using -= user
+ return seeing
+
+/**
+ * Show our storage to a mob.
+ *
+ * @param mob/toshow the mob to show the storage to
+ */
+/datum/storage/proc/show_contents(mob/toshow)
+ var/obj/item/resolve_location = real_location?.resolve()
+ if(!resolve_location)
+ return
+
+ if(!toshow.client)
+ return
+
+ if(toshow.active_storage != src && (toshow.stat == CONSCIOUS))
+ for(var/obj/item/thing in resolve_location)
+ if(thing.on_found(toshow))
+ toshow.active_storage.hide_contents(toshow)
+
+ if(toshow.active_storage)
+ toshow.active_storage.hide_contents(toshow)
+
+ toshow.active_storage = src
+
+ if(ismovable(resolve_location))
+ var/atom/movable/movable_loc = resolve_location
+ movable_loc.become_active_storage(src)
+
+ orient_to_hud()
+
+ is_using |= toshow
+
+ toshow.client.screen |= boxes
+ toshow.client.screen |= closer
+ toshow.client.screen |= resolve_location.contents
+
+/**
+ * Hide our storage from a mob.
+ *
+ * @param mob/toshow the mob to hide the storage from
+ */
+/datum/storage/proc/hide_contents(mob/toshow)
+ var/obj/item/resolve_location = real_location?.resolve()
+ if(!resolve_location)
+ return
+
+ if(!toshow.client)
+ return TRUE
+ if(toshow.active_storage == src)
+ toshow.active_storage = null
+
+ if(!length(is_using) && ismovable(resolve_location))
+ var/atom/movable/movable_loc = resolve_location
+ movable_loc.lose_active_storage(src)
+
+ is_using -= toshow
+
+ toshow.client.screen -= boxes
+ toshow.client.screen -= closer
+ toshow.client.screen -= resolve_location.contents
+
+/datum/storage/proc/action_trigger(datum/signal_source, datum/action/source)
+ SIGNAL_HANDLER
+
+ toggle_collection_mode(source.owner)
+ return TRUE
+
+/**
+ * Toggles the collectmode of our storage.
+ *
+ * @param mob/toshow the mob toggling us
+ */
+/datum/storage/proc/toggle_collection_mode(mob/user)
+ var/obj/item/resolve_parent = parent?.resolve()
+ if(!resolve_parent)
+ return
+
+ collection_mode = (collection_mode+1)%3
+ switch(collection_mode)
+ if(COLLECT_SAME)
+ to_chat(user, span_notice("[resolve_parent] now picks up all items of a single type at once."))
+ if(COLLECT_EVERYTHING)
+ to_chat(user, span_notice("[resolve_parent] now picks up all items in a tile at once."))
+ if(COLLECT_ONE)
+ to_chat(user, span_notice("[resolve_parent] now picks up one item at a time."))
+
+/// Gives a spiffy animation to our parent to represent opening and closing.
+/datum/storage/proc/animate_parent()
+ var/obj/item/resolve_parent = parent?.resolve()
+ if(!resolve_parent)
+ return
+
+ animate(resolve_parent, time = 1.5, loop = 0, transform = matrix().Scale(1.07, 0.9))
+ animate(time = 2, transform = null)
diff --git a/code/datums/storage/subtypes/bag_of_holding.dm b/code/datums/storage/subtypes/bag_of_holding.dm
new file mode 100644
index 00000000000..b891cc6e68c
--- /dev/null
+++ b/code/datums/storage/subtypes/bag_of_holding.dm
@@ -0,0 +1,34 @@
+/datum/storage/bag_of_holding/attempt_insert(datum/source, obj/item/to_insert, mob/user, override, force)
+ var/obj/item/resolve_parent = parent?.resolve()
+ if(!resolve_parent)
+ return
+
+ var/list/obj/item/storage/backpack/holding/matching = typecache_filter_list(to_insert.get_all_contents(), typecacheof(/obj/item/storage/backpack/holding))
+ matching -= resolve_parent
+
+ if(istype(to_insert, /obj/item/storage/backpack/holding) || matching.len)
+ INVOKE_ASYNC(src, .proc/recursive_insertion, to_insert, user)
+ return
+
+ return ..()
+
+/datum/storage/bag_of_holding/proc/recursive_insertion(obj/item/to_insert, mob/living/user)
+ var/obj/item/resolve_parent = parent?.resolve()
+ if(!resolve_parent)
+ return
+
+ var/safety = tgui_alert(user, "Doing this will have extremely dire consequences for the station and its crew. Be sure you know what you're doing.", "Put in [to_insert.name]?", list("Proceed", "Abort"))
+ if(safety != "Proceed" || QDELETED(to_insert) || QDELETED(resolve_parent) || QDELETED(user) || !user.canUseTopic(resolve_parent, BE_CLOSE, iscarbon(user)))
+ return
+
+ var/turf/loccheck = get_turf(resolve_parent)
+ to_chat(user, span_danger("The Bluespace interfaces of the two devices catastrophically malfunction!"))
+ qdel(to_insert)
+ playsound(loccheck,'sound/effects/supermatter.ogg', 200, TRUE)
+
+ message_admins("[ADMIN_LOOKUPFLW(user)] detonated a bag of holding at [ADMIN_VERBOSEJMP(loccheck)].")
+ log_game("[key_name(user)] detonated a bag of holding at [loc_name(loccheck)].")
+
+ user.gib(TRUE, TRUE, TRUE)
+ new/obj/boh_tear(loccheck)
+ qdel(resolve_parent)
diff --git a/code/datums/storage/subtypes/cards.dm b/code/datums/storage/subtypes/cards.dm
new file mode 100644
index 00000000000..18f0d276bf9
--- /dev/null
+++ b/code/datums/storage/subtypes/cards.dm
@@ -0,0 +1,66 @@
+/**
+ *A storage component to be used on card piles, for use as hands/decks/discard piles. Don't use on something that's not a card pile!
+ */
+/datum/storage/tcg
+ max_specific_storage = WEIGHT_CLASS_TINY
+ max_slots = 30
+ max_total_storage = WEIGHT_CLASS_TINY * 30
+
+/datum/storage/tcg/New()
+ . = ..()
+ set_holdable(list(/obj/item/tcgcard))
+
+/datum/storage/tcg/attempt_remove(silent = FALSE)
+ . = ..()
+ handle_empty_deck()
+
+/datum/storage/tcg/show_contents(mob/to_show)
+ . = ..()
+
+ var/obj/item/resolve_parent = parent?.resolve()
+ if(!resolve_parent)
+ return
+
+ to_show.visible_message(span_notice("[to_show] starts to look through the contents of \the [resolve_parent]!"), \
+ span_notice("You begin looking into the contents of \the [resolve_parent]!"))
+
+/datum/storage/tcg/hide_contents()
+ . = ..()
+ var/obj/item/resolve_parent = parent?.resolve()
+ if(!resolve_parent)
+ return
+
+ var/obj/item/resolve_location = real_location?.resolve()
+ if(!resolve_location)
+ return
+
+ resolve_location.visible_message(span_notice("\the [resolve_parent] is shuffled after looking through it."))
+ resolve_location.contents = shuffle(resolve_location.contents)
+
+/datum/storage/tcg/remove_all()
+ . = ..()
+
+ var/obj/item/resolve_parent = parent?.resolve()
+ if(!resolve_parent)
+ return
+
+ if(!resolve_parent.contents.len)
+ qdel(resolve_parent)
+
+/datum/storage/tcg/proc/handle_empty_deck()
+ var/obj/item/resolve_parent = parent?.resolve()
+ if(!resolve_parent)
+ return
+
+ var/obj/item/resolve_location = real_location?.resolve()
+ if(!real_location)
+ return
+
+ //You can't have a deck of one card!
+ if(resolve_location.contents.len == 1)
+ var/obj/item/tcgcard_deck/deck = resolve_location
+ var/obj/item/tcgcard/card = resolve_location.contents[1]
+ attempt_remove(card, card.drop_location())
+ card.flipped = deck.flipped
+ card.update_icon_state()
+ qdel(resolve_parent)
diff --git a/code/datums/storage/subtypes/extract_inventory.dm b/code/datums/storage/subtypes/extract_inventory.dm
new file mode 100644
index 00000000000..9dfc07bb23c
--- /dev/null
+++ b/code/datums/storage/subtypes/extract_inventory.dm
@@ -0,0 +1,43 @@
+/datum/storage/extract_inventory
+ max_total_storage = WEIGHT_CLASS_TINY * 3
+ max_slots = 3
+ insert_preposition = "in"
+ attack_hand_interact = FALSE
+ quickdraw = FALSE
+ locked = TRUE
+ rustle_sound = FALSE
+ silent = TRUE
+
+/datum/storage/extract_inventory/New()
+ . = ..()
+ set_holdable(/obj/item/food/monkeycube)
+
+ var/obj/item/slimecross/reproductive/parentSlimeExtract = parent?.resolve()
+ if(!parentSlimeExtract)
+ return
+
+ if(!istype(parentSlimeExtract, /obj/item/slimecross/reproductive))
+ stack_trace("storage subtype extract_inventory incompatible with [parentSlimeExtract]")
+ qdel(src)
+
+/datum/storage/extract_inventory/proc/processCubes(mob/user)
+ var/obj/item/slimecross/reproductive/parentSlimeExtract = parent?.resolve()
+ if(!parentSlimeExtract)
+ return
+
+ message_admins(parentSlimeExtract.contents.len)
+ if(parentSlimeExtract.contents.len >= max_slots)
+ QDEL_LIST(parentSlimeExtract.contents)
+ createExtracts(user)
+
+/datum/storage/extract_inventory/proc/createExtracts(mob/user)
+ var/obj/item/slimecross/reproductive/parentSlimeExtract = parent?.resolve()
+ if(!parentSlimeExtract)
+ return
+
+ var/cores = rand(1,4)
+ playsound(parentSlimeExtract, 'sound/effects/splat.ogg', 40, TRUE)
+ parentSlimeExtract.last_produce = world.time
+ to_chat(user, span_notice("[parentSlimeExtract] briefly swells to a massive size, and expels [cores] extract[cores > 1 ? "s":""]!"))
+ for(var/i in 1 to cores)
+ new parentSlimeExtract.extract_type(parentSlimeExtract.drop_location())
diff --git a/code/datums/storage/subtypes/implant.dm b/code/datums/storage/subtypes/implant.dm
new file mode 100644
index 00000000000..998e19a587c
--- /dev/null
+++ b/code/datums/storage/subtypes/implant.dm
@@ -0,0 +1,10 @@
+/datum/storage/implant
+ max_specific_storage = WEIGHT_CLASS_NORMAL
+ max_total_storage = 6
+ max_slots = 2
+ silent = TRUE
+ allow_big_nesting = TRUE
+
+/datum/storage/implant/New()
+ . = ..()
+ set_holdable(cant_hold_list = list(/obj/item/disk/nuclear))
diff --git a/code/datums/components/storage/concrete/pockets.dm b/code/datums/storage/subtypes/pockets.dm
similarity index 63%
rename from code/datums/components/storage/concrete/pockets.dm
rename to code/datums/storage/subtypes/pockets.dm
index e6b6a3170f3..49d05155b2b 100644
--- a/code/datums/components/storage/concrete/pockets.dm
+++ b/code/datums/storage/subtypes/pockets.dm
@@ -1,28 +1,33 @@
-/datum/component/storage/concrete/pockets
- max_items = 2
- max_w_class = WEIGHT_CLASS_SMALL
- max_combined_w_class = 50
+/datum/storage/pockets
+ max_slots = 2
+ max_specific_storage = WEIGHT_CLASS_SMALL
+ max_total_storage = 50
rustle_sound = FALSE
-/datum/component/storage/concrete/pockets/handle_item_insertion(obj/item/I, prevent_warning, mob/user)
+/datum/storage/pockets/attempt_insert(datum/source, obj/item/to_insert, mob/user, override, force)
. = ..()
- if(. && silent && !prevent_warning)
+
+ var/obj/item/resolve_parent = parent?.resolve()
+ if(!resolve_parent)
+ return
+
+ if(. && silent && !override)
if(quickdraw)
- to_chat(user, span_notice("You discreetly slip [I] into [parent]. Right-click [parent] to remove it."))
+ to_chat(user, span_notice("You discreetly slip [to_insert] into [resolve_parent]. Right-click [resolve_parent] to remove it."))
else
- to_chat(user, span_notice("You discreetly slip [I] into [parent]."))
+ to_chat(user, span_notice("You discreetly slip [to_insert] into [resolve_parent]."))
-/datum/component/storage/concrete/pockets/small
- max_items = 1
- max_w_class = WEIGHT_CLASS_SMALL
+/datum/storage/pockets/small
+ max_slots = 1
+ max_specific_storage = WEIGHT_CLASS_SMALL
attack_hand_interact = FALSE
-/datum/component/storage/concrete/pockets/tiny
- max_items = 1
- max_w_class = WEIGHT_CLASS_TINY
+/datum/storage/pockets/tiny
+ max_slots = 1
+ max_specific_storage = WEIGHT_CLASS_TINY
attack_hand_interact = FALSE
-/datum/component/storage/concrete/pockets/small/fedora/Initialize()
+/datum/storage/pockets/small/fedora/New()
. = ..()
var/static/list/exception_cache = typecacheof(list(
/obj/item/katana,
@@ -33,35 +38,36 @@
))
exception_hold = exception_cache
-/datum/component/storage/concrete/pockets/small/fedora/detective
+/datum/storage/pockets/small/fedora/detective
attack_hand_interact = TRUE // so the detectives would discover pockets in their hats
-/datum/component/storage/concrete/pockets/chefhat
+/datum/storage/pockets/chefhat
attack_hand_interact = TRUE
- max_items = 1
- max_w_class = WEIGHT_CLASS_NORMAL
+ max_slots = 1
+ max_specific_storage = WEIGHT_CLASS_NORMAL
-/datum/component/storage/concrete/pockets/chefhat/Initialize()
+/datum/storage/pockets/chefhat/New()
. = ..()
set_holdable(list(
/obj/item/clothing/head/mob_holder,
/obj/item/food/deadmouse
))
-/datum/component/storage/concrete/pockets/chefhat/can_be_inserted(obj/item/I, stop_messages, mob/M)
+/datum/storage/pockets/chefhat/can_insert(obj/item/to_insert, mob/user, messages, force)
. = ..()
- if(istype(I,/obj/item/clothing/head/mob_holder))
- var/obj/item/clothing/head/mob_holder/mausholder = I
+ if(istype(to_insert, /obj/item/clothing/head/mob_holder))
+ var/obj/item/clothing/head/mob_holder/mausholder = to_insert
if(locate(/mob/living/simple_animal/mouse) in mausholder.contents)
return
return FALSE
-/datum/component/storage/concrete/pockets/shoes
+/datum/storage/pockets/shoes
+ max_slots = 2
attack_hand_interact = FALSE
quickdraw = TRUE
silent = TRUE
-/datum/component/storage/concrete/pockets/shoes/Initialize()
+/datum/storage/pockets/shoes/New()
. = ..()
set_holdable(list(
/obj/item/knife,
@@ -92,7 +98,7 @@
/obj/item/toy/crayon/spraycan)
)
-/datum/component/storage/concrete/pockets/shoes/clown/Initialize()
+/datum/storage/pockets/shoes/clown/New()
. = ..()
set_holdable(list(
/obj/item/knife,
@@ -124,13 +130,11 @@
/obj/item/toy/crayon/spraycan)
)
-/datum/component/storage/concrete/pockets/pocketprotector
- max_items = 3
- max_w_class = WEIGHT_CLASS_TINY
- var/atom/original_parent
+/datum/storage/pockets/pocketprotector
+ max_slots = 3
+ max_specific_storage = WEIGHT_CLASS_TINY
-/datum/component/storage/concrete/pockets/pocketprotector/Initialize()
- original_parent = parent
+/datum/storage/pockets/pocketprotector/New()
. = ..()
set_holdable(list( //Same items as a PDA
/obj/item/pen,
@@ -140,15 +144,12 @@
/obj/item/clothing/mask/cigarette)
)
-/datum/component/storage/concrete/pockets/pocketprotector/real_location()
- // if the component is reparented to a jumpsuit, the items still go in the protector
- return original_parent
-
-/datum/component/storage/concrete/pockets/helmet
+/datum/storage/pockets/helmet
+ max_slots = 2
quickdraw = TRUE
- max_combined_w_class = 6
+ max_total_storage = 6
-/datum/component/storage/concrete/pockets/helmet/Initialize()
+/datum/storage/pockets/helmet/New()
. = ..()
set_holdable(list(/obj/item/reagent_containers/food/drinks/bottle/vodka,
/obj/item/reagent_containers/food/drinks/bottle/molotov,
@@ -156,12 +157,12 @@
/obj/item/ammo_box/a762))
-/datum/component/storage/concrete/pockets/void_cloak
+/datum/storage/pockets/void_cloak
quickdraw = TRUE
- max_combined_w_class = 5 // 2 small items + 1 tiny item, or 1 normal item + 1 small item
- max_items = 3
+ max_total_storage = 5 // 2 small items + 1 tiny item, or 1 normal item + 1 small item
+ max_slots = 3
-/datum/component/storage/concrete/pockets/void_cloak/Initialize()
+/datum/storage/pockets/void_cloak/New()
. = ..()
set_holdable(list(
/obj/item/ammo_box/a762/lionhunter,
diff --git a/code/game/atoms.dm b/code/game/atoms.dm
index 229a18bc281..921228f93de 100644
--- a/code/game/atoms.dm
+++ b/code/game/atoms.dm
@@ -162,6 +162,9 @@
/// forensics datum, contains fingerprints, fibres, blood_dna and hiddenprints on this atom
var/datum/forensics/forensics
+ /// the datum handler for our contents - see create_storage() for creation method
+ var/datum/storage/atom_storage
+
/**
* Called when an atom is created in byond (built in engine proc)
*
@@ -314,6 +317,9 @@
if(forensics)
QDEL_NULL(forensics)
+ if(atom_storage)
+ QDEL_NULL(atom_storage)
+
orbiters = null // The component is attached to us normaly and will be deleted elsewhere
LAZYCLEARLIST(overlays)
@@ -327,6 +333,43 @@
return ..()
+/// A quick and easy way to create a storage datum for an atom
+/atom/proc/create_storage(
+ max_slots,
+ max_specific_storage,
+ max_total_storage,
+ numerical_stacking = FALSE,
+ allow_quick_gather = FALSE,
+ allow_quick_empty = FALSE,
+ collection_mode = COLLECT_ONE,
+ attack_hand_interact = TRUE,
+ list/canhold,
+ list/canthold,
+ type = /datum/storage,
+)
+
+ if(atom_storage)
+ QDEL_NULL(atom_storage)
+
+ atom_storage = new type(src, max_slots, max_specific_storage, max_total_storage, numerical_stacking, allow_quick_gather, collection_mode, attack_hand_interact)
+
+ if(canhold || canthold)
+ atom_storage.set_holdable(canhold, canthold)
+
+ return atom_storage
+
+/// A quick and easy way to /clone/ a storage datum for an atom (does not copy over contents, only the datum details)
+/atom/proc/clone_storage(datum/storage/cloning)
+ if(atom_storage)
+ QDEL_NULL(atom_storage)
+
+ atom_storage = new cloning.type(src, cloning.max_slots, cloning.max_specific_storage, cloning.max_total_storage, cloning.numerical_stacking, cloning.allow_quick_gather, cloning.collection_mode, cloning.attack_hand_interact)
+
+ if(cloning.can_hold || cloning.cant_hold)
+ atom_storage.set_holdable(cloning.can_hold, cloning.cant_hold)
+
+ return atom_storage
+
/atom/proc/handle_ricochet(obj/projectile/ricocheting_projectile)
var/turf/p_turf = get_turf(ricocheting_projectile)
var/face_direction = get_dir(src, p_turf)
@@ -991,8 +1034,8 @@
* TODO these should be purely component items that intercept the atom clicks higher in the
* call chain
*/
-/atom/proc/storage_contents_dump_act(obj/item/storage/src_object, mob/user)
- if(GetComponent(/datum/component/storage))
+/atom/proc/storage_contents_dump_act(obj/item/src_object, mob/user)
+ if(atom_storage)
return component_storage_contents_dump_act(src_object, user)
return FALSE
@@ -1005,19 +1048,17 @@
* TODO these should be purely component items that intercept the atom clicks higher in the
* call chain
*/
-/atom/proc/component_storage_contents_dump_act(datum/component/storage/src_object, mob/user)
- var/list/things = src_object.contents()
+/atom/proc/component_storage_contents_dump_act(obj/item/src_object, mob/user)
+ var/list/things = src_object.contents
var/datum/progressbar/progress = new(user, things.len, src)
- var/datum/component/storage/STR = GetComponent(/datum/component/storage)
- while (do_after(user, 1 SECONDS, src, NONE, FALSE, CALLBACK(STR, /datum/component/storage.proc/handle_mass_item_insertion, things, src_object, user, progress)))
+ while (do_after(user, 1 SECONDS, src, NONE, FALSE, CALLBACK(src_object.atom_storage, /datum/storage.proc/handle_mass_transfer, user, src)))
stoplag(1)
progress.end_progress()
- to_chat(user, span_notice("You dump as much of [src_object.parent]'s contents [STR.insert_preposition]to [src] as you can."))
- STR.orient2hud(user)
- src_object.orient2hud(user)
+ to_chat(user, span_notice("You dump as much of [src_object]'s contents [atom_storage.insert_preposition]to [src] as you can."))
+ atom_storage.orient_to_hud(user)
+ src_object.atom_storage.orient_to_hud(user)
if(user.active_storage) //refresh the HUD to show the transfered contents
- user.active_storage.close(user)
- user.active_storage.show_to(user)
+ user.active_storage.refresh_views()
return TRUE
///Get the best place to dump the items contained in the source storage item?
diff --git a/code/game/atoms_movable.dm b/code/game/atoms_movable.dm
index ffc89ecbe69..f124448629d 100644
--- a/code/game/atoms_movable.dm
+++ b/code/game/atoms_movable.dm
@@ -880,17 +880,17 @@
UNSETEMPTY(movable_loc.important_recursive_contents)
///called when this movable becomes the parent of a storage component that is currently being viewed by a player. uses important_recursive_contents
-/atom/movable/proc/become_active_storage(datum/component/storage/component_source)
+/atom/movable/proc/become_active_storage(datum/storage/source)
if(!HAS_TRAIT(src, TRAIT_ACTIVE_STORAGE))
for(var/atom/movable/location as anything in get_nested_locs(src) + src)
LAZYADDASSOCLIST(location.important_recursive_contents, RECURSIVE_CONTENTS_ACTIVE_STORAGE, src)
- ADD_TRAIT(src, TRAIT_ACTIVE_STORAGE, component_source)
+ ADD_TRAIT(src, TRAIT_ACTIVE_STORAGE, REF(source))
///called when this movable's storage component is no longer viewed by any players, unsets important_recursive_contents
-/atom/movable/proc/lose_active_storage(datum/component/storage/component_source)
+/atom/movable/proc/lose_active_storage(datum/storage/source)
if(!HAS_TRAIT(src, TRAIT_ACTIVE_STORAGE))
return
- REMOVE_TRAIT(src, TRAIT_ACTIVE_STORAGE, component_source)
+ REMOVE_TRAIT(src, TRAIT_ACTIVE_STORAGE, REF(source))
if(HAS_TRAIT(src, TRAIT_ACTIVE_STORAGE))
return
@@ -1198,12 +1198,12 @@
return blocker_opinion
/// called when this atom is removed from a storage item, which is passed on as S. The loc variable is already set to the new destination before this is called.
-/atom/movable/proc/on_exit_storage(datum/component/storage/concrete/master_storage)
- SEND_SIGNAL(src, COMSIG_STORAGE_EXITED, master_storage)
+/atom/movable/proc/on_exit_storage(datum/storage/master_storage)
+ return
/// called when this atom is added into a storage item, which is passed on as S. The loc variable is already set to the storage item.
-/atom/movable/proc/on_enter_storage(datum/component/storage/concrete/master_storage)
- SEND_SIGNAL(src, COMSIG_STORAGE_ENTERED, master_storage)
+/atom/movable/proc/on_enter_storage(datum/storage/master_storage)
+ return
/atom/movable/proc/get_spacemove_backup()
for(var/checked_range in orange(1, get_turf(src)))
diff --git a/code/game/machinery/_machinery.dm b/code/game/machinery/_machinery.dm
index c57ba341b3b..4add7d36756 100644
--- a/code/game/machinery/_machinery.dm
+++ b/code/game/machinery/_machinery.dm
@@ -924,10 +924,10 @@
var/obj/item/stack/secondary_inserted = new secondary_stack.merge_type(null,used_amt)
component_parts += secondary_inserted
else
- if(SEND_SIGNAL(replacer_tool, COMSIG_TRY_STORAGE_TAKE, secondary_part, src))
+ if(replacer_tool.atom_storage.attempt_remove(secondary_part, src))
component_parts += secondary_part
secondary_part.forceMove(src)
- SEND_SIGNAL(replacer_tool, COMSIG_TRY_STORAGE_INSERT, primary_part, null, null, TRUE)
+ replacer_tool.atom_storage.attempt_insert(replacer_tool, primary_part, user, TRUE)
component_parts -= primary_part
to_chat(user, span_notice("[capitalize(primary_part.name)] replaced with [secondary_part.name]."))
shouldplaysound = 1 //Only play the sound when parts are actually replaced!
diff --git a/code/game/machinery/constructable_frame.dm b/code/game/machinery/constructable_frame.dm
index 2d4abb2dafa..6fa7295d49e 100644
--- a/code/game/machinery/constructable_frame.dm
+++ b/code/game/machinery/constructable_frame.dm
@@ -255,7 +255,7 @@
req_components[path] -= used_amt
else
added_components[part] = path
- if(SEND_SIGNAL(replacer, COMSIG_TRY_STORAGE_TAKE, part, src))
+ if(replacer.atom_storage.attempt_remove(part, src))
req_components[path]--
for(var/obj/item/part in added_components)
diff --git a/code/game/machinery/launch_pad.dm b/code/game/machinery/launch_pad.dm
index 85f412ee8a4..88871ed632f 100644
--- a/code/game/machinery/launch_pad.dm
+++ b/code/game/machinery/launch_pad.dm
@@ -309,7 +309,7 @@
pad.update_indicator()
pad.closed = FALSE
user.transferItemToLoc(src, pad, TRUE)
- SEND_SIGNAL(src, COMSIG_TRY_STORAGE_HIDE_ALL)
+ atom_storage.close_all()
/obj/item/storage/briefcase/launchpad/attackby(obj/item/I, mob/user, params)
if(istype(I, /obj/item/launchpad_remote))
diff --git a/code/game/objects/items.dm b/code/game/objects/items.dm
index e5ce21c40b9..4d99dfdd626 100644
--- a/code/game/objects/items.dm
+++ b/code/game/objects/items.dm
@@ -544,7 +544,7 @@ GLOBAL_DATUM_INIT(welding_sparks, /mutable_appearance, mutable_appearance('icons
//If the item is in a storage item, take it out
- SEND_SIGNAL(loc, COMSIG_TRY_STORAGE_TAKE, src, user.loc, TRUE)
+ loc.atom_storage?.attempt_remove(src, user.loc, silent = TRUE)
if(QDELETED(src)) //moving it out of the storage to the floor destroyed it.
return
@@ -579,7 +579,7 @@ GLOBAL_DATUM_INIT(welding_sparks, /mutable_appearance, mutable_appearance('icons
return
//If the item is in a storage item, take it out
- SEND_SIGNAL(loc, COMSIG_TRY_STORAGE_TAKE, src, user.loc, TRUE)
+ loc.atom_storage?.attempt_remove(src, user.loc, silent = TRUE)
if(QDELETED(src)) //moving it out of the storage to the floor destroyed it.
return
@@ -768,9 +768,9 @@ GLOBAL_DATUM_INIT(welding_sparks, /mutable_appearance, mutable_appearance('icons
else
return
-/obj/item/on_exit_storage(datum/component/storage/concrete/master_storage)
+/obj/item/on_exit_storage(datum/storage/master_storage)
. = ..()
- var/atom/location = master_storage.real_location()
+ var/atom/location = master_storage.real_location?.resolve()
do_drop_animation(location)
/obj/item/throw_impact(atom/hit_atom, datum/thrownthing/throwingdatum)
@@ -819,8 +819,8 @@ GLOBAL_DATUM_INIT(welding_sparks, /mutable_appearance, mutable_appearance('icons
/obj/item/proc/remove_item_from_storage(atom/newLoc) //please use this if you're going to snowflake an item out of a obj/item/storage
if(!newLoc)
return FALSE
- if(SEND_SIGNAL(loc, COMSIG_CONTAINS_STORAGE))
- return SEND_SIGNAL(loc, COMSIG_TRY_STORAGE_TAKE, src, newLoc, TRUE)
+ if(loc.atom_storage)
+ return loc.atom_storage.attempt_remove(src, newLoc, silent = TRUE)
return FALSE
/// Returns the icon used for overlaying the object on a belt
@@ -971,7 +971,7 @@ GLOBAL_DATUM_INIT(welding_sparks, /mutable_appearance, mutable_appearance('icons
/obj/item/MouseEntered(location, control, params)
. = ..()
- if(get(src, /mob) == usr && !QDELETED(src))
+ if(((get(src, /mob) == usr) || src.loc.atom_storage || (src.item_flags & IN_STORAGE)) && !QDELETED(src))
var/mob/living/L = usr
if(usr.client.prefs.read_preference(/datum/preference/toggle/enable_tooltips))
var/timedelay = usr.client.prefs.read_preference(/datum/preference/numeric/tooltip_delay) / 100
@@ -992,8 +992,8 @@ GLOBAL_DATUM_INIT(welding_sparks, /mutable_appearance, mutable_appearance('icons
remove_filter("hover_outline")
/obj/item/proc/apply_outline(outline_color = null)
- if(get(src, /mob) != usr || QDELETED(src) || isobserver(usr)) //cancel if the item isn't in an inventory, is being deleted, or if the person hovering is a ghost (so that people spectating you don't randomly make your items glow)
- return
+ if(((get(src, /mob) != usr) && !src.loc.atom_storage && !(src.item_flags & IN_STORAGE)) || QDELETED(src) || isobserver(usr)) //cancel if the item isn't in an inventory, is being deleted, or if the person hovering is a ghost (so that people spectating you don't randomly make your items glow)
+ return FALSE
var/theme = lowertext(usr.client?.prefs?.read_preference(/datum/preference/choiced/ui_style))
if(!outline_color) //if we weren't provided with a color, take the theme's color
switch(theme) //yeah it kinda has to be this way
@@ -1345,7 +1345,7 @@ GLOBAL_DATUM_INIT(welding_sparks, /mutable_appearance, mutable_appearance('icons
return
/// Whether or not this item can be put into a storage item through attackby
-/obj/item/proc/attackby_storage_insert(datum/component/storage, atom/storage_holder, mob/user)
+/obj/item/proc/attackby_storage_insert(datum/storage, atom/storage_holder, mob/user)
return TRUE
/obj/item/proc/do_pickup_animation(atom/target)
@@ -1385,6 +1385,9 @@ GLOBAL_DATUM_INIT(welding_sparks, /mutable_appearance, mutable_appearance('icons
if(!istype(loc, /turf))
return
+ if(!istype(moving_from))
+ return
+
var/turf/current_turf = get_turf(src)
var/direction = get_dir(moving_from, current_turf)
var/from_x = moving_from.base_pixel_x
diff --git a/code/game/objects/items/crayons.dm b/code/game/objects/items/crayons.dm
index d8ff5c984bc..8a3b81b265b 100644
--- a/code/game/objects/items/crayons.dm
+++ b/code/game/objects/items/crayons.dm
@@ -599,9 +599,7 @@
/obj/item/storage/crayons/Initialize(mapload)
. = ..()
- var/datum/component/storage/STR = GetComponent(/datum/component/storage)
- STR.max_items = 7
- STR.set_holdable(list(/obj/item/toy/crayon))
+ create_storage(canhold = list(/obj/item/toy/crayon))
/obj/item/storage/crayons/PopulateContents()
new /obj/item/toy/crayon/red(src)
@@ -822,7 +820,7 @@
return SECONDARY_ATTACK_CONTINUE_CHAIN
-/obj/item/toy/crayon/spraycan/attackby_storage_insert(datum/component/storage, atom/storage_holder, mob/user)
+/obj/item/toy/crayon/spraycan/attackby_storage_insert(datum/storage, atom/storage_holder, mob/user)
return is_capped
/obj/item/toy/crayon/spraycan/update_icon_state()
diff --git a/code/game/objects/items/devices/portable_chem_mixer.dm b/code/game/objects/items/devices/portable_chem_mixer.dm
index ba904a534eb..a5b634fe61a 100644
--- a/code/game/objects/items/devices/portable_chem_mixer.dm
+++ b/code/game/objects/items/devices/portable_chem_mixer.dm
@@ -18,13 +18,11 @@
///If the UI has the pH meter shown
var/show_ph = TRUE
-/obj/item/storage/portable_chem_mixer/ComponentInitialize()
+/obj/item/storage/portable_chem_mixer/Initialize()
. = ..()
- var/datum/component/storage/STR = GetComponent(/datum/component/storage)
- STR.max_combined_w_class = 200
- STR.max_items = 50
- STR.insert_preposition = "in"
- STR.set_holdable(list(
+ atom_storage.max_total_storage = 200
+ atom_storage.max_slots = 50
+ atom_storage.set_holdable(list(
/obj/item/reagent_containers/glass/beaker,
/obj/item/reagent_containers/glass/bottle,
/obj/item/reagent_containers/food/drinks/waterbottle,
@@ -40,8 +38,7 @@
return ..()
/obj/item/storage/portable_chem_mixer/attackby(obj/item/I, mob/user, params)
- var/locked = SEND_SIGNAL(src, COMSIG_IS_STORAGE_LOCKED)
- if (istype(I, /obj/item/reagent_containers) && !(I.item_flags & ABSTRACT) && I.is_open_container() && locked)
+ if (istype(I, /obj/item/reagent_containers) && !(I.item_flags & ABSTRACT) && I.is_open_container() && atom_storage.locked)
var/obj/item/reagent_containers/B = I
. = TRUE //no afterattack
if(!user.transferItemToLoc(B, src))
@@ -70,7 +67,7 @@
return
/obj/item/storage/portable_chem_mixer/update_icon_state()
- if(!SEND_SIGNAL(src, COMSIG_IS_STORAGE_LOCKED))
+ if(!atom_storage.locked)
icon_state = "portablechemicalmixer_open"
return ..()
if(beaker)
@@ -81,8 +78,7 @@
/obj/item/storage/portable_chem_mixer/AltClick(mob/living/user)
- var/locked = SEND_SIGNAL(src, COMSIG_IS_STORAGE_LOCKED)
- if(!locked)
+ if(!atom_storage.locked)
return ..()
if(!can_interact(user) || !user.canUseTopic(src, BE_CLOSE, FALSE, NO_TK))
return
@@ -90,11 +86,10 @@
update_appearance()
/obj/item/storage/portable_chem_mixer/CtrlClick(mob/living/user)
- var/locked = SEND_SIGNAL(src, COMSIG_IS_STORAGE_LOCKED)
- SEND_SIGNAL(src, COMSIG_TRY_STORAGE_SET_LOCKSTATE, !locked)
- if (!locked)
+ atom_storage.locked = !atom_storage.locked
+ if (!atom_storage.locked)
update_contents()
- if (locked)
+ if (atom_storage.locked)
replace_beaker(user)
update_appearance()
playsound(src, 'sound/items/screwdriver2.ogg', 50)
@@ -122,17 +117,15 @@
if (loc != user)
return ..()
else
- var/locked = SEND_SIGNAL(src, COMSIG_IS_STORAGE_LOCKED)
- if (!locked)
+ if (!atom_storage.locked)
return ..()
- if(SEND_SIGNAL(src, COMSIG_IS_STORAGE_LOCKED))
+ if(atom_storage?.locked)
ui_interact(user)
return
/obj/item/storage/portable_chem_mixer/attack_self(mob/user)
if(loc == user)
- var/locked = SEND_SIGNAL(src, COMSIG_IS_STORAGE_LOCKED)
- if (locked)
+ if (atom_storage.locked)
ui_interact(user)
return
else
diff --git a/code/game/objects/items/dice.dm b/code/game/objects/items/dice.dm
index 22e18207cc2..6e61c32c8ad 100644
--- a/code/game/objects/items/dice.dm
+++ b/code/game/objects/items/dice.dm
@@ -8,10 +8,8 @@
/obj/item/storage/dice/Initialize(mapload)
. = ..()
- var/datum/component/storage/storage = GetComponent(/datum/component/storage)
- storage.allow_quick_gather = TRUE
- storage.click_gather = TRUE
- storage.set_holdable(list(/obj/item/dice))
+ atom_storage.allow_quick_gather = TRUE
+ atom_storage.set_holdable(list(/obj/item/dice))
/obj/item/storage/dice/PopulateContents()
new /obj/item/dice/d4(src)
diff --git a/code/game/objects/items/implants/implant_storage.dm b/code/game/objects/items/implants/implant_storage.dm
index c0f1a7af754..a87451c4627 100644
--- a/code/game/objects/items/implants/implant_storage.dm
+++ b/code/game/objects/items/implants/implant_storage.dm
@@ -7,31 +7,34 @@
/obj/item/implant/storage/activate()
. = ..()
- SEND_SIGNAL(src, COMSIG_TRY_STORAGE_SHOW, imp_in, TRUE)
+ atom_storage?.open_storage(src, imp_in)
/obj/item/implant/storage/removed(source, silent = FALSE, special = 0)
if(!special)
- var/datum/component/storage/lostimplant = GetComponent(/datum/component/storage/concrete/implant)
var/mob/living/implantee = source
- for (var/obj/item/I in lostimplant.contents())
+
+ var/atom/resolve_parent = atom_storage.parent?.resolve()
+ if(!resolve_parent)
+ return
+
+ for (var/obj/item/I in resolve_parent.contents)
I.add_mob_blood(implantee)
- lostimplant.do_quick_empty()
+ atom_storage.remove_all(implantee)
implantee.visible_message(span_warning("A bluespace pocket opens around [src] as it exits [implantee], spewing out its contents and rupturing the surrounding tissue!"))
implantee.apply_damage(20, BRUTE, BODY_ZONE_CHEST)
- qdel(lostimplant)
+ qdel(atom_storage)
return ..()
/obj/item/implant/storage/implant(mob/living/target, mob/user, silent = FALSE, force = FALSE)
for(var/X in target.implants)
if(istype(X, type))
var/obj/item/implant/storage/imp_e = X
- var/datum/component/storage/STR = imp_e.GetComponent(/datum/component/storage)
- if(!STR || (STR && STR.max_items < max_slot_stacking))
- imp_e.AddComponent(/datum/component/storage/concrete/implant)
+ if(!imp_e.atom_storage || (imp_e.atom_storage && imp_e.atom_storage.max_slots < max_slot_stacking))
+ imp_e.create_storage(type = /datum/storage/implant)
qdel(src)
return TRUE
return FALSE
- AddComponent(/datum/component/storage/concrete/implant)
+ create_storage(type = /datum/storage/implant)
return ..()
diff --git a/code/game/objects/items/mail.dm b/code/game/objects/items/mail.dm
index 54973e2916d..5d4459c77b4 100644
--- a/code/game/objects/items/mail.dm
+++ b/code/game/objects/items/mail.dm
@@ -268,14 +268,13 @@
worn_icon_state = "mailbag"
resistance_flags = FLAMMABLE
-/obj/item/storage/bag/mail/ComponentInitialize()
+/obj/item/storage/bag/mail/Initialize()
. = ..()
- var/datum/component/storage/storage = GetComponent(/datum/component/storage)
- storage.max_w_class = WEIGHT_CLASS_NORMAL
- storage.max_combined_w_class = 42
- storage.max_items = 21
- storage.display_numerical_stacking = FALSE
- storage.set_holdable(list(
+ atom_storage.max_specific_storage = WEIGHT_CLASS_NORMAL
+ atom_storage.max_total_storage = 42
+ atom_storage.max_slots = 21
+ atom_storage.numerical_stacking = FALSE
+ atom_storage.set_holdable(list(
/obj/item/mail,
/obj/item/delivery/small,
/obj/item/paper
diff --git a/code/game/objects/items/melee/misc.dm b/code/game/objects/items/melee/misc.dm
index 3006069931f..fcbff5025f9 100644
--- a/code/game/objects/items/melee/misc.dm
+++ b/code/game/objects/items/melee/misc.dm
@@ -86,13 +86,13 @@
final_block_chance = 0 //Don't bring a sword to a gunfight
return ..()
-/obj/item/melee/sabre/on_exit_storage(datum/component/storage/concrete/container)
- var/obj/item/storage/belt/sabre/sabre = container.real_location()
+/obj/item/melee/sabre/on_exit_storage(datum/storage/container)
+ var/obj/item/storage/belt/sabre/sabre = container.real_location?.resolve()
if(istype(sabre))
playsound(sabre, 'sound/items/unsheath.ogg', 25, TRUE)
-/obj/item/melee/sabre/on_enter_storage(datum/component/storage/concrete/container)
- var/obj/item/storage/belt/sabre/sabre = container.real_location()
+/obj/item/melee/sabre/on_enter_storage(datum/storage/container)
+ var/obj/item/storage/belt/sabre/sabre = container.real_location?.resolve()
if(istype(sabre))
playsound(sabre, 'sound/items/sheath.ogg', 25, TRUE)
diff --git a/code/game/objects/items/religion.dm b/code/game/objects/items/religion.dm
index 9a8810ff350..2541d737bee 100644
--- a/code/game/objects/items/religion.dm
+++ b/code/game/objects/items/religion.dm
@@ -254,8 +254,7 @@
/obj/item/storage/backpack/bannerpack/Initialize(mapload)
. = ..()
- var/datum/component/storage/STR = GetComponent(/datum/component/storage)
- STR.max_combined_w_class = 27 //6 more then normal, for the tradeoff of declaring yourself an antag at all times.
+ atom_storage.max_total_storage = 27 //6 more then normal, for the tradeoff of declaring yourself an antag at all times.
/obj/item/storage/backpack/bannerpack/red
name = "red banner backpack"
diff --git a/code/game/objects/items/stacks/stack.dm b/code/game/objects/items/stacks/stack.dm
index ef097aa51b6..b67c15f12cf 100644
--- a/code/game/objects/items/stacks/stack.dm
+++ b/code/game/objects/items/stacks/stack.dm
@@ -670,6 +670,7 @@
var/obj/item/stack/F = new type(user? user : drop_location(), amount, FALSE, mats_per_unit)
. = F
F.copy_evidences(src)
+ loc.atom_storage?.refresh_views()
if(user)
if(!user.put_in_hands(F, merge_stacks = FALSE))
F.forceMove(user.drop_location())
diff --git a/code/game/objects/items/storage/backpack.dm b/code/game/objects/items/storage/backpack.dm
index 8a4bffbbfd4..2fa57439c32 100644
--- a/code/game/objects/items/storage/backpack.dm
+++ b/code/game/objects/items/storage/backpack.dm
@@ -21,21 +21,17 @@
resistance_flags = NONE
max_integrity = 300
-/obj/item/storage/backpack/ComponentInitialize()
+/obj/item/storage/backpack/Initialize()
. = ..()
- var/datum/component/storage/STR = GetComponent(/datum/component/storage)
- STR.max_combined_w_class = 21
- STR.max_w_class = WEIGHT_CLASS_NORMAL
- STR.max_items = 21
+ create_storage(max_slots = 21, max_total_storage = 21)
/*
* Backpack Types
*/
-/obj/item/storage/backpack/old/ComponentInitialize()
+/obj/item/storage/backpack/old/Initialize()
. = ..()
- var/datum/component/storage/STR = GetComponent(/datum/component/storage)
- STR.max_combined_w_class = 12
+ atom_storage.max_total_storage = 12
/obj/item/bag_of_holding_inert
name = "inert bag of holding"
@@ -57,14 +53,12 @@
resistance_flags = FIRE_PROOF
item_flags = NO_MAT_REDEMPTION
armor = list(MELEE = 0, BULLET = 0, LASER = 0, ENERGY = 0, BOMB = 0, BIO = 0, FIRE = 60, ACID = 50)
- component_type = /datum/component/storage/concrete/bluespace/bag_of_holding
-/obj/item/storage/backpack/holding/ComponentInitialize()
+/obj/item/storage/backpack/holding/Initialize()
. = ..()
- var/datum/component/storage/STR = GetComponent(/datum/component/storage)
- STR.allow_big_nesting = TRUE
- STR.max_w_class = WEIGHT_CLASS_GIGANTIC
- STR.max_combined_w_class = 35
+
+ create_storage(max_specific_storage = WEIGHT_CLASS_GIGANTIC, max_total_storage = 35, max_slots = 30, type = /datum/storage/bag_of_holding)
+ atom_storage.allow_big_nesting = TRUE
/obj/item/storage/backpack/holding/suicide_act(mob/living/user)
user.visible_message(span_suicide("[user] is jumping into [src]! It looks like [user.p_theyre()] trying to commit suicide."))
@@ -85,11 +79,10 @@
. = ..()
regenerate_presents()
-/obj/item/storage/backpack/santabag/ComponentInitialize()
+/obj/item/storage/backpack/santabag/Initialize()
. = ..()
- var/datum/component/storage/STR = GetComponent(/datum/component/storage)
- STR.max_w_class = WEIGHT_CLASS_NORMAL
- STR.max_combined_w_class = 60
+ atom_storage.max_specific_storage = WEIGHT_CLASS_NORMAL
+ atom_storage.max_total_storage = 60
/obj/item/storage/backpack/santabag/suicide_act(mob/user)
user.visible_message(span_suicide("[user] places [src] over [user.p_their()] head and pulls it tight! It looks like [user.p_they()] [user.p_are()]n't in the Christmas spirit..."))
@@ -98,17 +91,14 @@
/obj/item/storage/backpack/santabag/proc/regenerate_presents()
addtimer(CALLBACK(src, .proc/regenerate_presents), 30 SECONDS)
- var/mob/M = get(loc, /mob)
- if(!istype(M))
+ var/mob/user = get(loc, /mob)
+ if(!istype(user))
return
- if(M.mind && HAS_TRAIT(M.mind, TRAIT_CANNOT_OPEN_PRESENTS))
- var/datum/component/storage/STR = GetComponent(/datum/component/storage)
+ if(user.mind && HAS_TRAIT(user.mind, TRAIT_CANNOT_OPEN_PRESENTS))
var/turf/floor = get_turf(src)
- var/obj/item/I = new /obj/item/a_gift/anything(floor)
- if(STR.can_be_inserted(I, stop_messages=TRUE))
- STR.handle_item_insertion(I, prevent_warning=TRUE)
- else
- qdel(I)
+ var/obj/item/thing = new /obj/item/a_gift/anything(floor)
+ if(!atom_storage.attempt_insert(src, thing, user, override = TRUE))
+ qdel(thing)
/obj/item/storage/backpack/cultpack
@@ -314,12 +304,8 @@
/obj/item/storage/backpack/satchel/flat/Initialize(mapload)
. = ..()
AddElement(/datum/element/undertile, TRAIT_T_RAY_VISIBLE, INVISIBILITY_OBSERVER, use_anchor = TRUE)
-
-/obj/item/storage/backpack/satchel/flat/ComponentInitialize()
- . = ..()
- var/datum/component/storage/STR = GetComponent(/datum/component/storage)
- STR.max_combined_w_class = 15
- STR.set_holdable(null, list(/obj/item/storage/backpack/satchel/flat)) //muh recursive backpacks)
+ atom_storage.max_total_storage = 15
+ atom_storage.set_holdable(cant_hold_list = list(/obj/item/storage/backpack/satchel/flat)) //muh recursive backpacks)
/obj/item/storage/backpack/satchel/flat/PopulateContents()
var/datum/supply_pack/costumes_toys/randomised/contraband/C = new
@@ -345,10 +331,9 @@
inhand_icon_state = "duffel"
slowdown = 1
-/obj/item/storage/backpack/duffelbag/ComponentInitialize()
+/obj/item/storage/backpack/duffelbag/Initialize()
. = ..()
- var/datum/component/storage/STR = GetComponent(/datum/component/storage)
- STR.max_combined_w_class = 30
+ atom_storage.max_total_storage = 30
/obj/item/storage/backpack/duffelbag/cursed
name = "living duffel bag"
@@ -498,10 +483,9 @@
slowdown = 0
resistance_flags = FIRE_PROOF
-/obj/item/storage/backpack/duffelbag/syndie/ComponentInitialize()
+/obj/item/storage/backpack/duffelbag/syndie/Initialize()
. = ..()
- var/datum/component/storage/STR = GetComponent(/datum/component/storage)
- STR.silent = TRUE
+ atom_storage.silent = TRUE
/obj/item/storage/backpack/duffelbag/syndie/hitman
desc = "A large duffel bag for holding extra things. There is a Nanotrasen logo on the back."
@@ -655,11 +639,10 @@
new /obj/item/grenade/syndieminibomb(src)
// For ClownOps.
-/obj/item/storage/backpack/duffelbag/clown/syndie/ComponentInitialize()
+/obj/item/storage/backpack/duffelbag/clown/syndie/Initialize()
. = ..()
- var/datum/component/storage/STR = GetComponent(/datum/component/storage)
slowdown = 0
- STR.silent = TRUE
+ atom_storage.silent = TRUE
/obj/item/storage/backpack/duffelbag/clown/syndie/PopulateContents()
new /obj/item/modular_computer/tablet/pda/clown(src)
diff --git a/code/game/objects/items/storage/bags.dm b/code/game/objects/items/storage/bags.dm
index af6eb003a55..8ffd47933a8 100644
--- a/code/game/objects/items/storage/bags.dm
+++ b/code/game/objects/items/storage/bags.dm
@@ -20,13 +20,11 @@
slot_flags = ITEM_SLOT_BELT
w_class = WEIGHT_CLASS_BULKY
-/obj/item/storage/bag/ComponentInitialize()
+/obj/item/storage/bag/Initialize()
. = ..()
- var/datum/component/storage/STR = GetComponent(/datum/component/storage)
- STR.allow_quick_gather = TRUE
- STR.allow_quick_empty = TRUE
- STR.display_numerical_stacking = TRUE
- STR.click_gather = TRUE
+ atom_storage.allow_quick_gather = TRUE
+ atom_storage.allow_quick_empty = TRUE
+ atom_storage.numerical_stacking = TRUE
// -----------------------------
// Trash bag
@@ -43,13 +41,12 @@
///If true, can be inserted into the janitor cart
var/insertable = TRUE
-/obj/item/storage/bag/trash/ComponentInitialize()
+/obj/item/storage/bag/trash/Initialize()
. = ..()
- var/datum/component/storage/STR = GetComponent(/datum/component/storage)
- STR.max_w_class = WEIGHT_CLASS_SMALL
- STR.max_combined_w_class = 30
- STR.max_items = 30
- STR.set_holdable(null, list(/obj/item/disk/nuclear))
+ atom_storage.max_specific_storage = WEIGHT_CLASS_SMALL
+ atom_storage.max_total_storage = 30
+ atom_storage.max_slots = 30
+ atom_storage.set_holdable(cant_hold_list = list(/obj/item/disk/nuclear))
/obj/item/storage/bag/trash/suicide_act(mob/user)
user.visible_message(span_suicide("[user] puts [src] over [user.p_their()] head and starts chomping at the insides! Disgusting!"))
@@ -87,11 +84,10 @@
inhand_icon_state = "bluetrashbag"
item_flags = NO_MAT_REDEMPTION
-/obj/item/storage/bag/trash/bluespace/ComponentInitialize()
+/obj/item/storage/bag/trash/bluespace/Initialize()
. = ..()
- var/datum/component/storage/STR = GetComponent(/datum/component/storage)
- STR.max_combined_w_class = 60
- STR.max_items = 60
+ atom_storage.max_total_storage = 60
+ atom_storage.max_slots = 60
/obj/item/storage/bag/trash/bluespace/cyborg
insertable = FALSE
@@ -108,17 +104,17 @@
worn_icon_state = "satchel"
slot_flags = ITEM_SLOT_BELT | ITEM_SLOT_POCKETS
w_class = WEIGHT_CLASS_NORMAL
- component_type = /datum/component/storage/concrete/stack
var/spam_protection = FALSE //If this is TRUE, the holder won't receive any messages when they fail to pick up ore through crossing it
var/mob/listeningTo
-/obj/item/storage/bag/ore/ComponentInitialize()
+/obj/item/storage/bag/ore/Initialize(mapload)
. = ..()
- var/datum/component/storage/concrete/stack/STR = GetComponent(/datum/component/storage/concrete/stack)
- STR.allow_quick_empty = TRUE
- STR.set_holdable(list(/obj/item/stack/ore))
- STR.max_w_class = WEIGHT_CLASS_HUGE
- STR.max_combined_stack_amount = 50
+ atom_storage.max_specific_storage = WEIGHT_CLASS_HUGE
+ atom_storage.max_total_storage = 50
+ atom_storage.numerical_stacking = TRUE
+ atom_storage.allow_quick_empty = TRUE
+ atom_storage.allow_quick_gather = TRUE
+ atom_storage.set_holdable(list(/obj/item/stack/ore))
/obj/item/storage/bag/ore/equipped(mob/user)
. = ..()
@@ -126,7 +122,7 @@
return
if(listeningTo)
UnregisterSignal(listeningTo, COMSIG_MOVABLE_MOVED)
- RegisterSignal(user, COMSIG_MOVABLE_MOVED, .proc/Pickup_ores)
+ RegisterSignal(user, COMSIG_MOVABLE_MOVED, .proc/pickup_ores)
listeningTo = user
/obj/item/storage/bag/ore/dropped()
@@ -135,24 +131,27 @@
UnregisterSignal(listeningTo, COMSIG_MOVABLE_MOVED)
listeningTo = null
-/obj/item/storage/bag/ore/proc/Pickup_ores(mob/living/user)
+/obj/item/storage/bag/ore/proc/pickup_ores(mob/living/user)
SIGNAL_HANDLER
+
var/show_message = FALSE
var/obj/structure/ore_box/box
- var/turf/tile = user.loc
- if (!isturf(tile))
+ var/turf/tile = get_turf(user)
+
+ if(!isturf(tile))
return
- if (istype(user.pulling, /obj/structure/ore_box))
+
+ if(istype(user.pulling, /obj/structure/ore_box))
box = user.pulling
- var/datum/component/storage/STR = GetComponent(/datum/component/storage)
- if(STR)
- for(var/A in tile)
- if (!is_type_in_typecache(A, STR.can_hold))
+
+ if(atom_storage)
+ for(var/thing in tile)
+ if(!is_type_in_typecache(thing, atom_storage.can_hold))
continue
- if (box)
- user.transferItemToLoc(A, box)
+ if(box)
+ user.transferItemToLoc(thing, box)
show_message = TRUE
- else if(SEND_SIGNAL(src, COMSIG_TRY_STORAGE_INSERT, A, user, TRUE))
+ else if(atom_storage.attempt_insert(src, thing, user))
show_message = TRUE
else
if(!spam_protection)
@@ -161,12 +160,14 @@
continue
if(show_message)
playsound(user, SFX_RUSTLE, 50, TRUE)
+
if (box)
user.visible_message(span_notice("[user] offloads the ores beneath [user.p_them()] into [box]."), \
- span_notice("You offload the ores beneath you into your [box]."))
+ span_notice("You offload the ores beneath you into your [box]."))
else
user.visible_message(span_notice("[user] scoops up the ores beneath [user.p_them()]."), \
span_notice("You scoop up the ores beneath you with your [name]."))
+
spam_protection = FALSE
/obj/item/storage/bag/ore/cyborg
@@ -177,12 +178,11 @@
desc = "A revolution in convenience, this satchel allows for huge amounts of ore storage. It's been outfitted with anti-malfunction safety measures."
icon_state = "satchel_bspace"
-/obj/item/storage/bag/ore/holding/ComponentInitialize()
+/obj/item/storage/bag/ore/holding/Initialize()
. = ..()
- var/datum/component/storage/concrete/stack/STR = GetComponent(/datum/component/storage/concrete/stack)
- STR.max_items = INFINITY
- STR.max_combined_w_class = INFINITY
- STR.max_combined_stack_amount = INFINITY
+ atom_storage.max_slots = INFINITY
+ atom_storage.max_specific_storage = INFINITY
+ atom_storage.max_total_storage = INFINITY
// -----------------------------
// Plant bag
@@ -195,13 +195,12 @@
worn_icon_state = "plantbag"
resistance_flags = FLAMMABLE
-/obj/item/storage/bag/plants/ComponentInitialize()
+/obj/item/storage/bag/plants/Initialize()
. = ..()
- var/datum/component/storage/STR = GetComponent(/datum/component/storage)
- STR.max_w_class = WEIGHT_CLASS_NORMAL
- STR.max_combined_w_class = 100
- STR.max_items = 100
- STR.set_holdable(list(
+ atom_storage.max_specific_storage = WEIGHT_CLASS_NORMAL
+ atom_storage.max_total_storage = 100
+ atom_storage.max_slots = 100
+ atom_storage.set_holdable(list(
/obj/item/food/grown,
/obj/item/graft,
/obj/item/grown,
@@ -243,8 +242,7 @@
// -----------------------------
// Sheet Snatcher
// -----------------------------
-// Because it stacks stacks, this doesn't operate normally.
-// However, making it a storage/bag allows us to reuse existing code in some places. -Sayu
+// sorry sayu your sheet snatcher is now OBSOLETE but i'm leaving it because idc
/obj/item/storage/bag/sheetsnatcher
name = "sheet snatcher"
@@ -254,20 +252,20 @@
worn_icon_state = "satchel"
var/capacity = 300; //the number of sheets it can carry.
- component_type = /datum/component/storage/concrete/stack
-/obj/item/storage/bag/sheetsnatcher/ComponentInitialize()
+/obj/item/storage/bag/sheetsnatcher/Initialize()
. = ..()
- var/datum/component/storage/concrete/stack/STR = GetComponent(/datum/component/storage/concrete/stack)
- STR.allow_quick_empty = TRUE
- STR.set_holdable(list(
+ atom_storage.allow_quick_empty = TRUE
+ atom_storage.allow_quick_gather = TRUE
+ atom_storage.numerical_stacking = TRUE
+ atom_storage.set_holdable(list(
/obj/item/stack/sheet
),
list(
/obj/item/stack/sheet/mineral/sandstone,
/obj/item/stack/sheet/mineral/wood,
))
- STR.max_combined_stack_amount = 300
+ atom_storage.max_total_storage = capacity / 2
// -----------------------------
// Sheet Snatcher (Cyborg)
@@ -278,11 +276,6 @@
desc = ""
capacity = 500//Borgs get more because >specialization
-/obj/item/storage/bag/sheetsnatcher/borg/ComponentInitialize()
- . = ..()
- var/datum/component/storage/concrete/stack/STR = GetComponent(/datum/component/storage/concrete/stack)
- STR.max_combined_stack_amount = 500
-
// -----------------------------
// Book bag
// -----------------------------
@@ -295,14 +288,12 @@
worn_icon_state = "bookbag"
resistance_flags = FLAMMABLE
-/obj/item/storage/bag/books/ComponentInitialize()
+/obj/item/storage/bag/books/Initialize()
. = ..()
- var/datum/component/storage/STR = GetComponent(/datum/component/storage)
- STR.max_w_class = WEIGHT_CLASS_NORMAL
- STR.max_combined_w_class = 21
- STR.max_items = 7
- STR.display_numerical_stacking = FALSE
- STR.set_holdable(list(
+ atom_storage.max_specific_storage = WEIGHT_CLASS_NORMAL
+ atom_storage.max_total_storage = 21
+ atom_storage.max_slots = 7
+ atom_storage.set_holdable(list(
/obj/item/book,
/obj/item/spellbook,
/obj/item/storage/book,
@@ -326,11 +317,10 @@
custom_materials = list(/datum/material/iron=3000)
custom_price = PAYCHECK_CREW * 0.6
-/obj/item/storage/bag/tray/ComponentInitialize()
+/obj/item/storage/bag/tray/Initialize()
. = ..()
- var/datum/component/storage/STR = GetComponent(/datum/component/storage)
- STR.max_w_class = WEIGHT_CLASS_BULKY //Plates are required bulky to keep them out of backpacks
- STR.set_holdable(list(
+ atom_storage.max_specific_storage = WEIGHT_CLASS_BULKY //Plates are required bulky to keep them out of backpacks
+ atom_storage.set_holdable(list(
/obj/item/clothing/mask/cigarette,
/obj/item/food,
/obj/item/kitchen,
@@ -345,14 +335,14 @@
/obj/item/storage/fancy,
/obj/item/trash,
)) //Should cover: Bottles, Beakers, Bowls, Booze, Glasses, Food, Food Containers, Food Trash, Organs, Tobacco Products, Lighters, and Kitchen Tools.
- STR.insert_preposition = "on"
- STR.max_items = 7
+ atom_storage.insert_preposition = "on"
+ atom_storage.max_slots = 7
/obj/item/storage/bag/tray/attack(mob/living/M, mob/living/user)
. = ..()
// Drop all the things. All of them.
var/list/obj/item/oldContents = contents.Copy()
- SEND_SIGNAL(src, COMSIG_TRY_STORAGE_QUICK_EMPTY)
+ atom_storage.remove_all(user)
// Make each item scatter a bit
for(var/obj/item/tray_item in oldContents)
do_scatter(tray_item)
@@ -414,13 +404,11 @@
desc = "A bag for storing pills, patches, and bottles."
resistance_flags = FLAMMABLE
-/obj/item/storage/bag/chemistry/ComponentInitialize()
+/obj/item/storage/bag/chemistry/Initialize()
. = ..()
- var/datum/component/storage/STR = GetComponent(/datum/component/storage)
- STR.max_combined_w_class = 200
- STR.max_items = 50
- STR.insert_preposition = "in"
- STR.set_holdable(list(
+ atom_storage.max_total_storage = 200
+ atom_storage.max_slots = 50
+ atom_storage.set_holdable(list(
/obj/item/reagent_containers/chem_pack,
/obj/item/reagent_containers/dropper,
/obj/item/reagent_containers/food/drinks/waterbottle,
@@ -443,13 +431,11 @@
desc = "A bag for the safe transportation and disposal of biowaste and other virulent materials."
resistance_flags = FLAMMABLE
-/obj/item/storage/bag/bio/ComponentInitialize()
+/obj/item/storage/bag/bio/Initialize()
. = ..()
- var/datum/component/storage/STR = GetComponent(/datum/component/storage)
- STR.max_combined_w_class = 200
- STR.max_items = 25
- STR.insert_preposition = "in"
- STR.set_holdable(list(
+ atom_storage.max_total_storage = 200
+ atom_storage.max_slots = 25
+ atom_storage.set_holdable(list(
/obj/item/bodypart,
/obj/item/food/monkeycube,
/obj/item/healthanalyzer,
@@ -474,13 +460,11 @@
desc = "A bag for the storage and transport of anomalous materials."
resistance_flags = FLAMMABLE
-/obj/item/storage/bag/xeno/ComponentInitialize()
+/obj/item/storage/bag/xeno/Initialize()
. = ..()
- var/datum/component/storage/STR = GetComponent(/datum/component/storage)
- STR.max_combined_w_class = 200
- STR.max_items = 25
- STR.insert_preposition = "in"
- STR.set_holdable(list(
+ atom_storage.max_total_storage = 200
+ atom_storage.max_slots = 25
+ atom_storage.set_holdable(list(
/obj/item/bodypart,
/obj/item/food/deadmouse,
/obj/item/food/monkeycube,
@@ -507,14 +491,12 @@
slot_flags = ITEM_SLOT_BELT | ITEM_SLOT_POCKETS
resistance_flags = FLAMMABLE
-/obj/item/storage/bag/construction/ComponentInitialize()
+/obj/item/storage/bag/construction/Initialize()
. = ..()
- var/datum/component/storage/STR = GetComponent(/datum/component/storage)
- STR.max_combined_w_class = 100
- STR.max_items = 50
- STR.max_w_class = WEIGHT_CLASS_SMALL
- STR.insert_preposition = "in"
- STR.set_holdable(list(
+ atom_storage.max_total_storage = 100
+ atom_storage.max_slots = 50
+ atom_storage.max_specific_storage = WEIGHT_CLASS_SMALL
+ atom_storage.set_holdable(list(
/obj/item/assembly,
/obj/item/circuitboard,
/obj/item/electronics,
@@ -532,13 +514,12 @@
inhand_icon_state = "quiver"
worn_icon_state = "harpoon_quiver"
-/obj/item/storage/bag/harpoon_quiver/ComponentInitialize()
+/obj/item/storage/bag/harpoon_quiver/Initialize()
. = ..()
- var/datum/component/storage/STR = GetComponent(/datum/component/storage)
- STR.max_w_class = WEIGHT_CLASS_TINY
- STR.max_items = 40
- STR.max_combined_w_class = 100
- STR.set_holdable(list(
+ atom_storage.max_specific_storage = WEIGHT_CLASS_TINY
+ atom_storage.max_slots = 40
+ atom_storage.max_total_storage = 100
+ atom_storage.set_holdable(list(
/obj/item/ammo_casing/caseless/harpoon
))
diff --git a/code/game/objects/items/storage/basket.dm b/code/game/objects/items/storage/basket.dm
index faf11e2c828..73904d99ab6 100644
--- a/code/game/objects/items/storage/basket.dm
+++ b/code/game/objects/items/storage/basket.dm
@@ -5,8 +5,7 @@
w_class = WEIGHT_CLASS_BULKY
resistance_flags = FLAMMABLE
-/obj/item/storage/basket/ComponentInitialize()
+/obj/item/storage/basket/Initialize()
. = ..()
- var/datum/component/storage/STR = GetComponent(/datum/component/storage)
- STR.max_w_class = WEIGHT_CLASS_NORMAL
- STR.max_combined_w_class = 21
+ atom_storage.max_specific_storage = WEIGHT_CLASS_NORMAL
+ atom_storage.max_total_storage = 21
diff --git a/code/game/objects/items/storage/belt.dm b/code/game/objects/items/storage/belt.dm
index 9ecfa0a5822..3fc62d89f34 100644
--- a/code/game/objects/items/storage/belt.dm
+++ b/code/game/objects/items/storage/belt.dm
@@ -41,12 +41,11 @@
drop_sound = 'sound/items/handling/toolbelt_drop.ogg'
pickup_sound = 'sound/items/handling/toolbelt_pickup.ogg'
-/obj/item/storage/belt/utility/ComponentInitialize()
+/obj/item/storage/belt/utility/Initialize()
. = ..()
- var/datum/component/storage/STR = GetComponent(/datum/component/storage)
- STR.max_w_class = WEIGHT_CLASS_NORMAL
- STR.max_combined_w_class = 21
- STR.set_holdable(list(
+ atom_storage.max_specific_storage = WEIGHT_CLASS_NORMAL
+ atom_storage.max_total_storage = 21
+ atom_storage.set_holdable(list(
/obj/item/airlock_painter,
/obj/item/analyzer,
/obj/item/assembly/signaler,
@@ -206,12 +205,11 @@
inhand_icon_state = "medical"
worn_icon_state = "medical"
-/obj/item/storage/belt/medical/ComponentInitialize()
+/obj/item/storage/belt/medical/Initialize()
. = ..()
- var/datum/component/storage/STR = GetComponent(/datum/component/storage)
- STR.max_w_class = WEIGHT_CLASS_NORMAL
- STR.max_combined_w_class = 21
- STR.set_holdable(list(
+ atom_storage.max_specific_storage = WEIGHT_CLASS_NORMAL
+ atom_storage.max_total_storage = 21
+ atom_storage.set_holdable(list(
/obj/item/bikehorn/rubberducky,
/obj/item/blood_filter,
/obj/item/bonesetter,
@@ -320,12 +318,11 @@
worn_icon_state = "security"
content_overlays = TRUE
-/obj/item/storage/belt/security/ComponentInitialize()
+/obj/item/storage/belt/security/Initialize()
. = ..()
- var/datum/component/storage/STR = GetComponent(/datum/component/storage)
- STR.max_items = 5
- STR.max_w_class = WEIGHT_CLASS_NORMAL
- STR.set_holdable(list(
+ atom_storage.max_slots = 5
+ atom_storage.max_specific_storage = WEIGHT_CLASS_NORMAL
+ atom_storage.set_holdable(list(
/obj/item/ammo_box,
/obj/item/ammo_casing/shotgun,
/obj/item/assembly/flash/handheld,
@@ -360,10 +357,9 @@
content_overlays = FALSE
custom_premium_price = PAYCHECK_COMMAND * 3
-/obj/item/storage/belt/security/webbing/ComponentInitialize()
+/obj/item/storage/belt/security/webbing/Initialize()
. = ..()
- var/datum/component/storage/STR = GetComponent(/datum/component/storage)
- STR.max_items = 6
+ atom_storage.max_slots = 6
/obj/item/storage/belt/mining
name = "explorer's webbing"
@@ -373,13 +369,12 @@
worn_icon_state = "explorer1"
w_class = WEIGHT_CLASS_BULKY
-/obj/item/storage/belt/mining/ComponentInitialize()
+/obj/item/storage/belt/mining/Initialize()
. = ..()
- var/datum/component/storage/STR = GetComponent(/datum/component/storage)
- STR.max_items = 6
- STR.max_w_class = WEIGHT_CLASS_NORMAL
- STR.max_combined_w_class = 20
- STR.set_holdable(list(
+ atom_storage.max_slots = 6
+ atom_storage.max_specific_storage = WEIGHT_CLASS_NORMAL
+ atom_storage.max_total_storage = 20
+ atom_storage.set_holdable(list(
/obj/item/analyzer,
/obj/item/clothing/gloves,
/obj/item/crowbar,
@@ -435,10 +430,9 @@
inhand_icon_state = "ebelt"
worn_icon_state = "ebelt"
-/obj/item/storage/belt/mining/primitive/ComponentInitialize()
+/obj/item/storage/belt/mining/primitive/Initialize()
. = ..()
- var/datum/component/storage/STR = GetComponent(/datum/component/storage)
- STR.max_items = 5
+ atom_storage.max_slots = 5
/obj/item/storage/belt/soulstone
name = "soul stone belt"
@@ -447,11 +441,10 @@
inhand_icon_state = "soulstonebelt"
worn_icon_state = "soulstonebelt"
-/obj/item/storage/belt/soulstone/ComponentInitialize()
+/obj/item/storage/belt/soulstone/Initialize()
. = ..()
- var/datum/component/storage/STR = GetComponent(/datum/component/storage)
- STR.max_items = 6
- STR.set_holdable(list(
+ atom_storage.max_slots = 6
+ atom_storage.set_holdable(list(
/obj/item/soulstone
))
@@ -471,11 +464,10 @@
worn_icon_state = "championbelt"
custom_materials = list(/datum/material/gold=400)
-/obj/item/storage/belt/champion/ComponentInitialize()
+/obj/item/storage/belt/champion/Initialize()
. = ..()
- var/datum/component/storage/STR = GetComponent(/datum/component/storage)
- STR.max_items = 1
- STR.set_holdable(list(
+ atom_storage.max_slots = 1
+ atom_storage.set_holdable(list(
/obj/item/clothing/mask/luchador
))
@@ -494,10 +486,9 @@
worn_icon_state = "militarywebbing"
resistance_flags = FIRE_PROOF
-/obj/item/storage/belt/military/ComponentInitialize()
+/obj/item/storage/belt/military/Initialize()
. = ..()
- var/datum/component/storage/STR = GetComponent(/datum/component/storage)
- STR.max_w_class = WEIGHT_CLASS_SMALL
+ atom_storage.max_specific_storage = WEIGHT_CLASS_SMALL
/obj/item/storage/belt/military/snack
name = "tactical snack rig"
@@ -507,12 +498,11 @@
var/sponsor = pick("Donk Co.", "Waffle Co.", "Roffle Co.", "Gorlax Marauders", "Tiger Cooperative")
desc = "A set of snack-tical webbing worn by athletes of the [sponsor] VR sports division."
-/obj/item/storage/belt/military/snack/ComponentInitialize()
+/obj/item/storage/belt/military/snack/Initialize()
. = ..()
- var/datum/component/storage/STR = GetComponent(/datum/component/storage)
- STR.max_items = 6
- STR.max_w_class = WEIGHT_CLASS_SMALL
- STR.set_holdable(list(
+ atom_storage.max_slots = 6
+ atom_storage.max_specific_storage = WEIGHT_CLASS_SMALL
+ atom_storage.set_holdable(list(
/obj/item/food,
/obj/item/reagent_containers/food/drinks
))
@@ -578,10 +568,9 @@
inhand_icon_state = "security"
worn_icon_state = "assault"
-/obj/item/storage/belt/military/assault/ComponentInitialize()
+/obj/item/storage/belt/military/assault/Initialize()
. = ..()
- var/datum/component/storage/STR = GetComponent(/datum/component/storage)
- STR.max_items = 6
+ atom_storage.max_slots = 6
/obj/item/storage/belt/military/assault/full/PopulateContents()
generate_items_inside(list(
@@ -596,14 +585,13 @@
inhand_icon_state = "security"
worn_icon_state = "grenadebeltnew"
-/obj/item/storage/belt/grenade/ComponentInitialize()
+/obj/item/storage/belt/grenade/Initialize()
. = ..()
- var/datum/component/storage/STR = GetComponent(/datum/component/storage)
- STR.max_items = 30
- STR.display_numerical_stacking = TRUE
- STR.max_combined_w_class = 60
- STR.max_w_class = WEIGHT_CLASS_BULKY
- STR.set_holdable(list(
+ atom_storage.max_slots = 30
+ atom_storage.numerical_stacking = TRUE
+ atom_storage.max_total_storage = 60
+ atom_storage.max_specific_storage = WEIGHT_CLASS_BULKY
+ atom_storage.set_holdable(list(
/obj/item/food/grown/cherry_bomb,
/obj/item/food/grown/firelemon,
/obj/item/grenade,
@@ -636,11 +624,10 @@
inhand_icon_state = "soulstonebelt"
worn_icon_state = "soulstonebelt"
-/obj/item/storage/belt/wands/ComponentInitialize()
+/obj/item/storage/belt/wands/Initialize()
. = ..()
- var/datum/component/storage/STR = GetComponent(/datum/component/storage)
- STR.max_items = 6
- STR.set_holdable(list(
+ atom_storage.max_slots = 6
+ atom_storage.set_holdable(list(
/obj/item/gun/magic/wand
))
@@ -663,12 +650,11 @@
inhand_icon_state = "janibelt"
worn_icon_state = "janibelt"
-/obj/item/storage/belt/janitor/ComponentInitialize()
+/obj/item/storage/belt/janitor/Initialize()
. = ..()
- var/datum/component/storage/STR = GetComponent(/datum/component/storage)
- STR.max_items = 6
- STR.max_w_class = WEIGHT_CLASS_NORMAL // Set to this so the light replacer can fit.
- STR.set_holdable(list(
+ atom_storage.max_slots = 6
+ atom_storage.max_specific_storage = WEIGHT_CLASS_NORMAL // Set to this so the light replacer can fit.
+ atom_storage.set_holdable(list(
/obj/item/assembly/mousetrap,
/obj/item/clothing/gloves,
/obj/item/flashlight,
@@ -699,13 +685,12 @@
inhand_icon_state = "bandolier"
worn_icon_state = "bandolier"
-/obj/item/storage/belt/bandolier/ComponentInitialize()
+/obj/item/storage/belt/bandolier/Initialize()
. = ..()
- var/datum/component/storage/STR = GetComponent(/datum/component/storage)
- STR.max_items = 18
- STR.max_combined_w_class = 18
- STR.display_numerical_stacking = TRUE
- STR.set_holdable(list(
+ atom_storage.max_slots = 18
+ atom_storage.max_total_storage = 18
+ atom_storage.numerical_stacking = TRUE
+ atom_storage.set_holdable(list(
/obj/item/ammo_casing/a762,
/obj/item/ammo_casing/shotgun,
))
@@ -719,11 +704,10 @@
dying_key = DYE_REGISTRY_FANNYPACK
custom_price = PAYCHECK_CREW * 2
-/obj/item/storage/belt/fannypack/ComponentInitialize()
+/obj/item/storage/belt/fannypack/Initialize()
. = ..()
- var/datum/component/storage/STR = GetComponent(/datum/component/storage)
- STR.max_items = 3
- STR.max_w_class = WEIGHT_CLASS_SMALL
+ atom_storage.max_slots = 3
+ atom_storage.max_specific_storage = WEIGHT_CLASS_SMALL
/obj/item/storage/belt/fannypack/black
name = "black fannypack"
@@ -793,14 +777,14 @@
worn_icon_state = "sheath"
w_class = WEIGHT_CLASS_BULKY
-/obj/item/storage/belt/sabre/ComponentInitialize()
+/obj/item/storage/belt/sabre/Initialize()
. = ..()
AddElement(/datum/element/update_icon_updates_onmob)
- var/datum/component/storage/STR = GetComponent(/datum/component/storage)
- STR.max_items = 1
- STR.rustle_sound = FALSE
- STR.max_w_class = WEIGHT_CLASS_BULKY
- STR.set_holdable(list(
+
+ atom_storage.max_slots = 1
+ atom_storage.rustle_sound = FALSE
+ atom_storage.max_specific_storage = WEIGHT_CLASS_BULKY
+ atom_storage.set_holdable(list(
/obj/item/melee/sabre,
))
@@ -842,12 +826,11 @@
worn_icon_state = "plantbelt"
content_overlays = TRUE
-/obj/item/storage/belt/plant/ComponentInitialize()
+/obj/item/storage/belt/plant/Initialize()
. = ..()
- var/datum/component/storage/STR = GetComponent(/datum/component/storage)
- STR.max_items = 6
- STR.max_w_class = WEIGHT_CLASS_NORMAL
- STR.set_holdable(list(
+ atom_storage.max_slots = 6
+ atom_storage.max_specific_storage = WEIGHT_CLASS_NORMAL
+ atom_storage.set_holdable(list(
/obj/item/cultivator,
/obj/item/geneshears,
/obj/item/graft,
diff --git a/code/game/objects/items/storage/book.dm b/code/game/objects/items/storage/book.dm
index b6e296ccd1a..e2a7f040bc9 100644
--- a/code/game/objects/items/storage/book.dm
+++ b/code/game/objects/items/storage/book.dm
@@ -10,10 +10,9 @@
resistance_flags = FLAMMABLE
var/title = "book"
-/obj/item/storage/book/ComponentInitialize()
+/obj/item/storage/book/Initialize()
. = ..()
- var/datum/component/storage/STR = GetComponent(/datum/component/storage)
- STR.max_items = 1
+ atom_storage.max_slots = 1
/obj/item/storage/book/attack_self(mob/user)
to_chat(user, span_notice("The pages of [title] have been cut out!"))
diff --git a/code/game/objects/items/storage/boxes.dm b/code/game/objects/items/storage/boxes.dm
index 8e15a8ee4ae..83dacd2aace 100644
--- a/code/game/objects/items/storage/boxes.dm
+++ b/code/game/objects/items/storage/boxes.dm
@@ -462,10 +462,9 @@
for(var/i in 1 to 6)
new donktype(src)
-/obj/item/storage/box/donkpockets/ComponentInitialize()
+/obj/item/storage/box/donkpockets/Initialize()
. = ..()
- var/datum/component/storage/STR = GetComponent(/datum/component/storage)
- STR.set_holdable(list(/obj/item/food/donkpocket))
+ atom_storage.set_holdable(list(/obj/item/food/donkpocket))
/obj/item/storage/box/donkpockets/donkpocketspicy
name = "box of spicy-flavoured donk-pockets"
@@ -504,11 +503,10 @@
illustration = null
var/cube_type = /obj/item/food/monkeycube
-/obj/item/storage/box/monkeycubes/ComponentInitialize()
+/obj/item/storage/box/monkeycubes/Initialize()
. = ..()
- var/datum/component/storage/STR = GetComponent(/datum/component/storage)
- STR.max_items = 7
- STR.set_holdable(list(/obj/item/food/monkeycube))
+ atom_storage.max_slots = 7
+ atom_storage.set_holdable(list(/obj/item/food/monkeycube))
/obj/item/storage/box/monkeycubes/PopulateContents()
for(var/i in 1 to 5)
@@ -524,11 +522,10 @@
icon_state = "monkeycubebox"
illustration = null
-/obj/item/storage/box/gorillacubes/ComponentInitialize()
+/obj/item/storage/box/gorillacubes/Initialize()
. = ..()
- var/datum/component/storage/STR = GetComponent(/datum/component/storage)
- STR.max_items = 3
- STR.set_holdable(list(/obj/item/food/monkeycube))
+ atom_storage.max_slots = 3
+ atom_storage.set_holdable(list(/obj/item/food/monkeycube))
/obj/item/storage/box/gorillacubes/PopulateContents()
for(var/i in 1 to 3)
@@ -682,15 +679,15 @@
icon_state = "spbox"
illustration = ""
-/obj/item/storage/box/snappops/ComponentInitialize()
+/obj/item/storage/box/snappops/Initialize()
. = ..()
- var/datum/component/storage/STR = GetComponent(/datum/component/storage)
- STR.set_holdable(list(/obj/item/toy/snappop))
- STR.max_items = 8
+ atom_storage.set_holdable(list(/obj/item/toy/snappop))
+ atom_storage.max_slots = 8
/obj/item/storage/box/snappops/PopulateContents()
- SEND_SIGNAL(src, COMSIG_TRY_STORAGE_FILL_TYPE, /obj/item/toy/snappop)
-
+ for(var/i in 1 to 8)
+ new /obj/item/toy/snappop(src)
+
/obj/item/storage/box/matches
name = "matchbox"
desc = "A small box of Almost But Not Quite Plasma Premium Matches."
@@ -706,14 +703,14 @@
base_icon_state = "matchbox"
illustration = null
-/obj/item/storage/box/matches/ComponentInitialize()
+/obj/item/storage/box/matches/Initialize()
. = ..()
- var/datum/component/storage/STR = GetComponent(/datum/component/storage)
- STR.max_items = 10
- STR.set_holdable(list(/obj/item/match))
+ atom_storage.max_slots = 10
+ atom_storage.set_holdable(list(/obj/item/match))
/obj/item/storage/box/matches/PopulateContents()
- SEND_SIGNAL(src, COMSIG_TRY_STORAGE_FILL_TYPE, /obj/item/match)
+ for(var/i in 1 to 10)
+ new /obj/item/match(src)
/obj/item/storage/box/matches/attackby(obj/item/match/W as obj, mob/user as mob, params)
if(istype(W, /obj/item/match))
@@ -741,13 +738,12 @@
righthand_file = 'icons/mob/inhands/equipment/medical_righthand.dmi'
foldable = /obj/item/stack/sheet/cardboard //BubbleWrap
-/obj/item/storage/box/lights/ComponentInitialize()
+/obj/item/storage/box/lights/Initialize()
. = ..()
- var/datum/component/storage/STR = GetComponent(/datum/component/storage)
- STR.max_items = 21
- STR.set_holdable(list(/obj/item/light/tube, /obj/item/light/bulb))
- STR.max_combined_w_class = 21
- STR.click_gather = FALSE //temp workaround to re-enable filling the light replacer with the box
+ atom_storage.max_slots = 21
+ atom_storage.set_holdable(list(/obj/item/light/tube, /obj/item/light/bulb))
+ atom_storage.max_total_storage = 21
+ atom_storage.allow_quick_gather = FALSE //temp workaround to re-enable filling the light replacer with the box
/obj/item/storage/box/lights/bulbs/PopulateContents()
for(var/i in 1 to 21)
@@ -1239,11 +1235,10 @@
foldable = null
custom_price = PAYCHECK_CREW
-/obj/item/storage/box/gum/ComponentInitialize()
+/obj/item/storage/box/gum/Initialize()
. = ..()
- var/datum/component/storage/STR = GetComponent(/datum/component/storage)
- STR.set_holdable(list(/obj/item/food/bubblegum))
- STR.max_items = 4
+ atom_storage.set_holdable(list(/obj/item/food/bubblegum))
+ atom_storage.max_slots = 4
/obj/item/storage/box/gum/PopulateContents()
for(var/i in 1 to 4)
diff --git a/code/game/objects/items/storage/briefcase.dm b/code/game/objects/items/storage/briefcase.dm
index 3390fb4fd87..1edca978656 100644
--- a/code/game/objects/items/storage/briefcase.dm
+++ b/code/game/objects/items/storage/briefcase.dm
@@ -16,11 +16,10 @@
max_integrity = 150
var/folder_path = /obj/item/folder //this is the path of the folder that gets spawned in New()
-/obj/item/storage/briefcase/ComponentInitialize()
+/obj/item/storage/briefcase/Initialize()
. = ..()
- var/datum/component/storage/STR = GetComponent(/datum/component/storage)
- STR.max_w_class = WEIGHT_CLASS_NORMAL
- STR.max_combined_w_class = 21
+ atom_storage.max_specific_storage = WEIGHT_CLASS_NORMAL
+ atom_storage.max_total_storage = 21
/obj/item/storage/briefcase/PopulateContents()
new /obj/item/pen(src)
diff --git a/code/game/objects/items/storage/fancy.dm b/code/game/objects/items/storage/fancy.dm
index bdc8d1b461c..b8193f0c74c 100644
--- a/code/game/objects/items/storage/fancy.dm
+++ b/code/game/objects/items/storage/fancy.dm
@@ -21,16 +21,22 @@
var/contents_tag = "errors"
/// What type of thing to fill this storage with.
var/spawn_type = null
+ /// How many of the things to fill this storage with.
+ var/spawn_count = 0
/// Whether the container is open or not
var/is_open = FALSE
/// What this container folds up into when it's empty.
var/obj/fold_result = /obj/item/stack/sheet/cardboard
+/obj/item/storage/fancy/Initialize()
+ . = ..()
+
+ atom_storage.max_slots = spawn_count
+
/obj/item/storage/fancy/PopulateContents()
if(!spawn_type)
return
- var/datum/component/storage/STR = GetComponent(/datum/component/storage)
- for(var/i = 1 to STR.max_items)
+ for(var/i = 1 to spawn_count)
new spawn_type(src)
/obj/item/storage/fancy/update_icon_state()
@@ -80,16 +86,15 @@
icon_state = "donutbox_open" //composite image used for mapping
base_icon_state = "donutbox"
spawn_type = /obj/item/food/donut/plain
+ spawn_count = 6
is_open = TRUE
appearance_flags = KEEP_TOGETHER|LONG_GLIDE
custom_premium_price = PAYCHECK_COMMAND * 1.75
contents_tag = "donut"
-/obj/item/storage/fancy/donut_box/ComponentInitialize()
+/obj/item/storage/fancy/donut_box/Initialize()
. = ..()
- var/datum/component/storage/STR = GetComponent(/datum/component/storage)
- STR.max_items = 6
- STR.set_holdable(list(/obj/item/food/donut))
+ atom_storage.set_holdable(list(/obj/item/food/donut))
/obj/item/storage/fancy/donut_box/PopulateContents()
. = ..()
@@ -131,13 +136,12 @@
name = "egg box"
desc = "A carton for containing eggs."
spawn_type = /obj/item/food/egg
+ spawn_count = 12
contents_tag = "egg"
-/obj/item/storage/fancy/egg_box/ComponentInitialize()
+/obj/item/storage/fancy/egg_box/Initialize()
. = ..()
- var/datum/component/storage/STR = GetComponent(/datum/component/storage)
- STR.max_items = 12
- STR.set_holdable(list(/obj/item/food/egg))
+ atom_storage.set_holdable(list(/obj/item/food/egg))
/*
* Candle Box
@@ -154,14 +158,10 @@
throwforce = 2
slot_flags = ITEM_SLOT_BELT
spawn_type = /obj/item/candle
+ spawn_count = 5
is_open = TRUE
contents_tag = "candle"
-/obj/item/storage/fancy/candle_box/ComponentInitialize()
- . = ..()
- var/datum/component/storage/STR = GetComponent(/datum/component/storage)
- STR.max_items = 5
-
/obj/item/storage/fancy/candle_box/attack_self(mob/user)
if(!contents.len)
new fold_result(user.drop_location())
@@ -184,6 +184,7 @@
throwforce = 0
slot_flags = ITEM_SLOT_BELT
spawn_type = /obj/item/clothing/mask/cigarette/space_cigarette
+ spawn_count = 6
custom_price = PAYCHECK_CREW
age_restricted = TRUE
contents_tag = "cigarette"
@@ -208,15 +209,13 @@
spawn_coupon = FALSE
name = "discarded cigarette packet"
desc = "An old cigarette packet with the back torn off, worth less than nothing now."
- var/datum/component/storage/STR = GetComponent(/datum/component/storage)
- STR.max_items = 0
+ atom_storage.max_slots = 0
return
-/obj/item/storage/fancy/cigarettes/ComponentInitialize()
+/obj/item/storage/fancy/cigarettes/Initialize()
. = ..()
- var/datum/component/storage/STR = GetComponent(/datum/component/storage)
- STR.max_items = 6
- STR.set_holdable(list(/obj/item/clothing/mask/cigarette, /obj/item/lighter))
+ atom_storage.quickdraw = TRUE
+ atom_storage.set_holdable(list(/obj/item/clothing/mask/cigarette, /obj/item/lighter))
/obj/item/storage/fancy/cigarettes/examine(mob/user)
. = ..()
@@ -225,18 +224,6 @@
if(spawn_coupon)
. += span_notice("There's a coupon on the back of the pack! You can tear it off once it's empty.")
-/obj/item/storage/fancy/cigarettes/AltClick(mob/user)
- if(!user.canUseTopic(src, BE_CLOSE, NO_DEXTERITY, FALSE, TRUE))
- return
- var/obj/item/clothing/mask/cigarette/W = locate(/obj/item/clothing/mask/cigarette) in contents
- if(W && contents.len > 0)
- SEND_SIGNAL(src, COMSIG_TRY_STORAGE_TAKE, W, user)
- user.put_in_hands(W)
- contents -= W
- to_chat(user, span_notice("You take \a [W] out of the pack."))
- else
- to_chat(user, span_notice("There are no [contents_tag]s left in the pack."))
-
/obj/item/storage/fancy/cigarettes/update_icon_state()
. = ..()
icon_state = "[base_icon_state][contents.len ? null : "_empty"]"
@@ -267,24 +254,6 @@
. += "[use_icon_state]_[cig_position]"
cig_position++
-/obj/item/storage/fancy/cigarettes/attack(mob/living/carbon/target, mob/living/carbon/user)
- if(!istype(target))
- return
-
- var/obj/item/clothing/mask/cigarette/cig = locate() in contents
- if(!cig)
- to_chat(user, span_notice("There are no [contents_tag]s left in the pack."))
- return
- if(target != user || !contents.len || user.wear_mask)
- return ..()
-
- SEND_SIGNAL(src, COMSIG_TRY_STORAGE_TAKE, cig, target)
- target.equip_to_slot_if_possible(cig, ITEM_SLOT_MASK)
- contents -= cig
- to_chat(user, span_notice("You take \a [cig] out of the pack."))
- return
-
-
/obj/item/storage/fancy/cigarettes/dromedaryco
name = "\improper DromedaryCo packet"
desc = "A packet of six imported DromedaryCo cancer sticks. A label on the packaging reads, \"Wouldn't a slow death make a change?\""
@@ -388,11 +357,10 @@
spawn_type = /obj/item/rollingpaper
custom_price = PAYCHECK_LOWER
-/obj/item/storage/fancy/rollingpapers/ComponentInitialize()
+/obj/item/storage/fancy/rollingpapers/Initialize()
. = ..()
- var/datum/component/storage/STR = GetComponent(/datum/component/storage)
- STR.max_items = 10
- STR.set_holdable(list(/obj/item/rollingpaper))
+ atom_storage.max_slots = 10
+ atom_storage.set_holdable(list(/obj/item/rollingpaper))
///Overrides to do nothing because fancy boxes are fucking insane.
/obj/item/storage/fancy/rollingpapers/update_icon_state()
@@ -417,14 +385,13 @@
w_class = WEIGHT_CLASS_NORMAL
contents_tag = "premium cigar"
spawn_type = /obj/item/clothing/mask/cigarette/cigar
+ spawn_count = 5
spawn_coupon = FALSE
display_cigs = FALSE
-/obj/item/storage/fancy/cigarettes/cigars/ComponentInitialize()
+/obj/item/storage/fancy/cigarettes/cigars/Initialize()
. = ..()
- var/datum/component/storage/STR = GetComponent(/datum/component/storage)
- STR.max_items = 5
- STR.set_holdable(list(/obj/item/clothing/mask/cigarette/cigar))
+ atom_storage.set_holdable(list(/obj/item/clothing/mask/cigarette/cigar))
/obj/item/storage/fancy/cigarettes/cigars/update_icon_state()
. = ..()
@@ -469,12 +436,11 @@
righthand_file = 'icons/mob/inhands/misc/food_righthand.dmi'
contents_tag = "chocolate"
spawn_type = /obj/item/food/tinychocolate
+ spawn_count = 8
-/obj/item/storage/fancy/heart_box/ComponentInitialize()
+/obj/item/storage/fancy/heart_box/Initialize()
. = ..()
- var/datum/component/storage/STR = GetComponent(/datum/component/storage)
- STR.max_items = 8
- STR.set_holdable(list(/obj/item/food/tinychocolate))
+ atom_storage.set_holdable(list(/obj/item/food/tinychocolate))
/obj/item/storage/fancy/nugget_box
@@ -485,9 +451,8 @@
base_icon_state = "nuggetbox"
contents_tag = "nugget"
spawn_type = /obj/item/food/nugget
+ spawn_count = 6
-/obj/item/storage/fancy/nugget_box/ComponentInitialize()
+/obj/item/storage/fancy/nugget_box/Initialize()
. = ..()
- var/datum/component/storage/STR = GetComponent(/datum/component/storage)
- STR.max_items = 6
- STR.set_holdable(list(/obj/item/food/nugget))
+ atom_storage.set_holdable(list(/obj/item/food/nugget))
diff --git a/code/game/objects/items/storage/garment.dm b/code/game/objects/items/storage/garment.dm
index 53892fd28ce..74cde69244b 100644
--- a/code/game/objects/items/storage/garment.dm
+++ b/code/game/objects/items/storage/garment.dm
@@ -30,15 +30,14 @@
name = "chief engineer's garment bag"
desc = "A bag for storing extra clothes and shoes. This one belongs to the chief engineer."
-/obj/item/storage/bag/garment/ComponentInitialize()
+/obj/item/storage/bag/garment/Initialize()
. = ..()
- var/datum/component/storage/STR = GetComponent(/datum/component/storage)
- STR.max_w_class = WEIGHT_CLASS_NORMAL
- STR.display_numerical_stacking = FALSE
- STR.max_combined_w_class = 200
- STR.max_items = 15
- STR.insert_preposition = "in"
- STR.set_holdable(list(
+ atom_storage.max_specific_storage = WEIGHT_CLASS_NORMAL
+ atom_storage.numerical_stacking = FALSE
+ atom_storage.max_total_storage = 200
+ atom_storage.max_slots = 15
+ atom_storage.insert_preposition = "in"
+ atom_storage.set_holdable(list(
/obj/item/clothing,
))
diff --git a/code/game/objects/items/storage/holsters.dm b/code/game/objects/items/storage/holsters.dm
index 8115d891699..650a32801db 100644
--- a/code/game/objects/items/storage/holsters.dm
+++ b/code/game/objects/items/storage/holsters.dm
@@ -17,12 +17,11 @@
. = ..()
REMOVE_TRAIT(user, TRAIT_GUNFLIP, CLOTHING_TRAIT)
-/obj/item/storage/belt/holster/ComponentInitialize()
+/obj/item/storage/belt/holster/Initialize()
. = ..()
- var/datum/component/storage/STR = GetComponent(/datum/component/storage)
- STR.max_items = 1
- STR.max_w_class = WEIGHT_CLASS_NORMAL
- STR.set_holdable(list(
+ atom_storage.max_slots = 1
+ atom_storage.max_total_storage = 16
+ atom_storage.set_holdable(list(
/obj/item/gun/ballistic/automatic/pistol,
/obj/item/gun/ballistic/revolver,
/obj/item/gun/energy/e_gun/mini,
@@ -36,12 +35,11 @@
name = "thermal shoulder holsters"
desc = "A rather plain pair of shoulder holsters with a bit of insulated padding inside. Meant to hold a twinned pair of thermal pistols, but can fit several kinds of energy handguns as well."
-/obj/item/storage/belt/holster/thermal/ComponentInitialize()
+/obj/item/storage/belt/holster/thermal/Initialize()
. = ..()
- var/datum/component/storage/STR = GetComponent(/datum/component/storage)
- STR.max_items = 2
- STR.max_w_class = WEIGHT_CLASS_NORMAL
- STR.set_holdable(list(
+ atom_storage.max_slots = 2
+ atom_storage.max_specific_storage = WEIGHT_CLASS_NORMAL
+ atom_storage.set_holdable(list(
/obj/item/gun/energy/e_gun/mini,
/obj/item/gun/energy/disabler,
/obj/item/gun/energy/dueling,
@@ -60,12 +58,11 @@
desc = "A holster able to carry handguns and some ammo. WARNING: Badasses only."
w_class = WEIGHT_CLASS_BULKY
-/obj/item/storage/belt/holster/detective/ComponentInitialize()
+/obj/item/storage/belt/holster/detective/Initialize()
. = ..()
- var/datum/component/storage/STR = GetComponent(/datum/component/storage)
- STR.max_items = 3
- STR.max_w_class = WEIGHT_CLASS_NORMAL
- STR.set_holdable(list(
+ atom_storage.max_slots = 3
+ atom_storage.max_specific_storage = WEIGHT_CLASS_NORMAL
+ atom_storage.set_holdable(list(
/obj/item/gun/ballistic/automatic/pistol,
/obj/item/ammo_box/magazine/m9mm, // Pistol magazines.
/obj/item/ammo_box/magazine/m9mm_aps,
@@ -119,10 +116,9 @@
chameleon_action.initialize_disguises()
add_item_action(chameleon_action)
-/obj/item/storage/belt/holster/chameleon/ComponentInitialize()
+/obj/item/storage/belt/holster/chameleon/Initialize()
. = ..()
- var/datum/component/storage/STR = GetComponent(/datum/component/storage)
- STR.silent = TRUE
+ atom_storage.silent = TRUE
/obj/item/storage/belt/holster/chameleon/emp_act(severity)
. = ..()
@@ -134,12 +130,11 @@
. = ..()
chameleon_action.emp_randomise(INFINITY)
-/obj/item/storage/belt/holster/chameleon/ComponentInitialize()
+/obj/item/storage/belt/holster/chameleon/Initialize()
. = ..()
- var/datum/component/storage/STR = GetComponent(/datum/component/storage)
- STR.max_items = 2
- STR.max_w_class = WEIGHT_CLASS_NORMAL
- STR.set_holdable(list(
+ atom_storage.max_slots = 2
+ atom_storage.max_total_storage = WEIGHT_CLASS_NORMAL
+ atom_storage.set_holdable(list(
/obj/item/gun/ballistic/automatic/pistol,
/obj/item/ammo_box/magazine/m9mm,
/obj/item/ammo_box/magazine/m9mm_aps,
@@ -164,12 +159,11 @@
worn_icon_state = "syndicate_holster"
w_class = WEIGHT_CLASS_BULKY
-/obj/item/storage/belt/holster/nukie/ComponentInitialize()
+/obj/item/storage/belt/holster/nukie/Initialize()
. = ..()
- var/datum/component/storage/STR = GetComponent(/datum/component/storage)
- STR.max_items = 2
- STR.max_w_class = WEIGHT_CLASS_BULKY
- STR.set_holdable(list(
+ atom_storage.max_slots = 2
+ atom_storage.max_specific_storage = WEIGHT_CLASS_BULKY
+ atom_storage.set_holdable(list(
/obj/item/gun, // ALL guns.
/obj/item/ammo_box/magazine, // ALL magazines.
/obj/item/ammo_box/c38, //There isn't a speedloader parent type, so I just put these three here by hand.
diff --git a/code/game/objects/items/storage/lockbox.dm b/code/game/objects/items/storage/lockbox.dm
index 47e72082e23..b005081c052 100644
--- a/code/game/objects/items/storage/lockbox.dm
+++ b/code/game/objects/items/storage/lockbox.dm
@@ -13,27 +13,26 @@
var/icon_closed = "lockbox"
var/icon_broken = "lockbox+b"
-/obj/item/storage/lockbox/ComponentInitialize()
+/obj/item/storage/lockbox/Initialize()
. = ..()
- var/datum/component/storage/STR = GetComponent(/datum/component/storage)
- STR.max_w_class = WEIGHT_CLASS_NORMAL
- STR.max_combined_w_class = 14
- STR.max_items = 4
- STR.locked = TRUE
+ atom_storage.max_specific_storage = WEIGHT_CLASS_NORMAL
+ atom_storage.max_total_storage = 14
+ atom_storage.max_slots = 4
+ atom_storage.locked = TRUE
/obj/item/storage/lockbox/attackby(obj/item/W, mob/user, params)
- var/locked = SEND_SIGNAL(src, COMSIG_IS_STORAGE_LOCKED)
+ var/locked = atom_storage.locked
if(W.GetID())
if(broken)
to_chat(user, span_danger("It appears to be broken."))
return
if(allowed(user))
- SEND_SIGNAL(src, COMSIG_TRY_STORAGE_SET_LOCKSTATE, !locked)
- locked = SEND_SIGNAL(src, COMSIG_IS_STORAGE_LOCKED)
+ atom_storage.locked = !locked
+ locked = atom_storage.locked
if(locked)
icon_state = icon_locked
to_chat(user, span_danger("You lock the [src.name]!"))
- SEND_SIGNAL(src, COMSIG_TRY_STORAGE_HIDE_ALL)
+ atom_storage.close_all()
return
else
icon_state = icon_closed
@@ -50,7 +49,7 @@
/obj/item/storage/lockbox/emag_act(mob/user)
if(!broken)
broken = TRUE
- SEND_SIGNAL(src, COMSIG_TRY_STORAGE_SET_LOCKSTATE, FALSE)
+ atom_storage.locked = FALSE
desc += "It appears to be broken."
icon_state = src.icon_broken
if(user)
@@ -97,22 +96,21 @@
icon_closed = "medalbox"
icon_broken = "medalbox+b"
-/obj/item/storage/lockbox/medal/ComponentInitialize()
+/obj/item/storage/lockbox/medal/Initialize()
. = ..()
- var/datum/component/storage/STR = GetComponent(/datum/component/storage)
- STR.max_w_class = WEIGHT_CLASS_SMALL
- STR.max_items = 10
- STR.max_combined_w_class = 20
- STR.set_holdable(list(/obj/item/clothing/accessory/medal))
+ atom_storage.max_specific_storage = WEIGHT_CLASS_SMALL
+ atom_storage.max_slots = 10
+ atom_storage.max_total_storage = 20
+ atom_storage.set_holdable(list(/obj/item/clothing/accessory/medal))
/obj/item/storage/lockbox/medal/examine(mob/user)
. = ..()
- if(!SEND_SIGNAL(src, COMSIG_IS_STORAGE_LOCKED))
+ if(!atom_storage.locked)
. += span_notice("Alt-click to [open ? "close":"open"] it.")
/obj/item/storage/lockbox/medal/AltClick(mob/user)
if(user.canUseTopic(src, BE_CLOSE))
- if(!SEND_SIGNAL(src, COMSIG_IS_STORAGE_LOCKED))
+ if(!atom_storage.locked)
open = (open ? FALSE : TRUE)
update_appearance()
..()
@@ -129,8 +127,7 @@
new /obj/item/clothing/accessory/medal/conduct(src)
/obj/item/storage/lockbox/medal/update_icon_state()
- var/locked = SEND_SIGNAL(src, COMSIG_IS_STORAGE_LOCKED)
- if(locked)
+ if(atom_storage?.locked)
icon_state = "medalbox+l"
return ..()
@@ -145,8 +142,7 @@
. = ..()
if(!contents || !open)
return
- var/locked = SEND_SIGNAL(src, COMSIG_IS_STORAGE_LOCKED)
- if(locked)
+ if(atom_storage?.locked)
return
for(var/i in 1 to contents.len)
var/obj/item/clothing/accessory/medal/M = contents[i]
@@ -240,8 +236,8 @@
to_chat(user, span_warning("Bank account does not match with buyer!"))
return
- SEND_SIGNAL(src, COMSIG_TRY_STORAGE_SET_LOCKSTATE, !privacy_lock)
- privacy_lock = SEND_SIGNAL(src, COMSIG_IS_STORAGE_LOCKED)
+ atom_storage.locked = !privacy_lock
+ privacy_lock = atom_storage.locked
user.visible_message(span_notice("[user] [privacy_lock ? "" : "un"]locks [src]'s privacy lock."),
span_notice("You [privacy_lock ? "" : "un"]lock [src]'s privacy lock."))
diff --git a/code/game/objects/items/storage/medkit.dm b/code/game/objects/items/storage/medkit.dm
index b6ced74e03b..8ed34642744 100644
--- a/code/game/objects/items/storage/medkit.dm
+++ b/code/game/objects/items/storage/medkit.dm
@@ -60,13 +60,12 @@
inhand_icon_state = "medkit"
desc = "A high capacity aid kit for doctors, full of medical supplies and basic surgical equipment"
-/obj/item/storage/medkit/surgery/ComponentInitialize()
+/obj/item/storage/medkit/surgery/Initialize()
. = ..()
- var/datum/component/storage/STR = GetComponent(/datum/component/storage)
- STR.max_w_class = WEIGHT_CLASS_NORMAL //holds the same equipment as a medibelt
- STR.max_items = 12
- STR.max_combined_w_class = 24
- STR.set_holdable(list(
+ atom_storage.max_specific_storage = WEIGHT_CLASS_NORMAL //holds the same equipment as a medibelt
+ atom_storage.max_slots = 12
+ atom_storage.max_total_storage = 24
+ atom_storage.set_holdable(list(
/obj/item/healthanalyzer,
/obj/item/dnainjector,
/obj/item/reagent_containers/dropper,
@@ -259,10 +258,9 @@
icon_state = "medkit_tactical"
damagetype_healed = "all"
-/obj/item/storage/medkit/tactical/ComponentInitialize()
+/obj/item/storage/medkit/tactical/Initialize()
. = ..()
- var/datum/component/storage/STR = GetComponent(/datum/component/storage)
- STR.max_w_class = WEIGHT_CLASS_NORMAL
+ atom_storage.max_specific_storage = WEIGHT_CLASS_NORMAL
/obj/item/storage/medkit/tactical/PopulateContents()
if(empty)
@@ -318,12 +316,10 @@
righthand_file = 'icons/mob/inhands/equipment/medical_righthand.dmi'
w_class = WEIGHT_CLASS_SMALL
-/obj/item/storage/pill_bottle/ComponentInitialize()
+/obj/item/storage/pill_bottle/Initialize()
. = ..()
- var/datum/component/storage/STR = GetComponent(/datum/component/storage)
- STR.allow_quick_gather = TRUE
- STR.click_gather = TRUE
- STR.set_holdable(list(/obj/item/reagent_containers/pill))
+ atom_storage.allow_quick_gather = TRUE
+ atom_storage.set_holdable(list(/obj/item/reagent_containers/pill))
/obj/item/storage/pill_bottle/suicide_act(mob/user)
user.visible_message(span_suicide("[user] is trying to get the cap off [src]! It looks like [user.p_theyre()] trying to commit suicide!"))
@@ -528,12 +524,11 @@
/// var to prevent it freezing the same things over and over
var/cooling = FALSE
-/obj/item/storage/organbox/ComponentInitialize()
+/obj/item/storage/organbox/Initialize()
. = ..()
- var/datum/component/storage/STR = GetComponent(/datum/component/storage)
- STR.max_w_class = WEIGHT_CLASS_BULKY /// you have to remove it from your bag before opening it but I think that's fine
- STR.max_combined_w_class = 21
- STR.set_holdable(list(
+ atom_storage.max_specific_storage = WEIGHT_CLASS_BULKY /// you have to remove it from your bag before opening it but I think that's fine
+ atom_storage.max_total_storage = 21
+ atom_storage.set_holdable(list(
/obj/item/organ,
/obj/item/bodypart,
/obj/item/food/icecream
@@ -543,7 +538,7 @@
. = ..()
create_reagents(100, TRANSPARENT)
RegisterSignal(src, COMSIG_ATOM_ENTERED, .proc/freeze)
- RegisterSignal(src, COMSIG_TRY_STORAGE_TAKE, .proc/unfreeze)
+ RegisterSignal(src, COMSIG_ATOM_EXITED, .proc/unfreeze)
START_PROCESSING(SSobj, src)
/obj/item/storage/organbox/process(delta_time)
diff --git a/code/game/objects/items/storage/secure.dm b/code/game/objects/items/storage/secure.dm
index 89cd747da22..9b31d7009da 100644
--- a/code/game/objects/items/storage/secure.dm
+++ b/code/game/objects/items/storage/secure.dm
@@ -33,11 +33,10 @@
var/can_hack_open = TRUE
-/obj/item/storage/secure/ComponentInitialize()
+/obj/item/storage/secure/Initialize()
. = ..()
- var/datum/component/storage/STR = GetComponent(/datum/component/storage)
- STR.max_w_class = WEIGHT_CLASS_SMALL
- STR.max_combined_w_class = 14
+ atom_storage.max_specific_storage = WEIGHT_CLASS_SMALL
+ atom_storage.max_total_storage = 14
/obj/item/storage/secure/examine(mob/user)
. = ..()
@@ -45,7 +44,7 @@
. += "The service panel is currently [panel_open ? "unscrewed" : "screwed shut"]."
/obj/item/storage/secure/tool_act(mob/living/user, obj/item/tool)
- if(can_hack_open && SEND_SIGNAL(src, COMSIG_IS_STORAGE_LOCKED))
+ if(can_hack_open && atom_storage.locked)
return ..()
else
return FALSE
@@ -78,7 +77,7 @@
to_chat(user, span_warning("You must unscrew the service panel before you can pulse the wiring!"))
/obj/item/storage/secure/attack_self(mob/user)
- var/locked = SEND_SIGNAL(src, COMSIG_IS_STORAGE_LOCKED)
+ var/locked = atom_storage.locked
user.set_machine(src)
var/dat = text("[]
\n\nLock Status: []",src, (locked ? "LOCKED" : "UNLOCKED"))
var/message = "Code"
@@ -100,7 +99,7 @@
lock_code = entered_code
lock_set = TRUE
else if ((entered_code == lock_code) && lock_set)
- SEND_SIGNAL(src, COMSIG_TRY_STORAGE_SET_LOCKSTATE, FALSE)
+ atom_storage.locked = TRUE
cut_overlays()
add_overlay(icon_opened)
entered_code = null
@@ -108,10 +107,10 @@
entered_code = "ERROR"
else
if (href_list["type"] == "R")
- SEND_SIGNAL(src, COMSIG_TRY_STORAGE_SET_LOCKSTATE, TRUE)
+ atom_storage.locked = FALSE
cut_overlays()
entered_code = null
- SEND_SIGNAL(src, COMSIG_TRY_STORAGE_HIDE_FROM, usr)
+ atom_storage.hide_contents(usr)
else
entered_code += text("[]", sanitize_text(href_list["type"]))
if (length(entered_code) > 5)
@@ -144,11 +143,10 @@
new /obj/item/paper(src)
new /obj/item/pen(src)
-/obj/item/storage/secure/briefcase/ComponentInitialize()
+/obj/item/storage/secure/briefcase/Initialize()
. = ..()
- var/datum/component/storage/STR = GetComponent(/datum/component/storage)
- STR.max_combined_w_class = 21
- STR.max_w_class = WEIGHT_CLASS_NORMAL
+ atom_storage.max_total_storage = 21
+ atom_storage.max_specific_storage = WEIGHT_CLASS_NORMAL
///Syndie variant of Secure Briefcase. Contains space cash, slightly more robust.
/obj/item/storage/secure/briefcase/syndie
@@ -174,11 +172,10 @@
MAPPING_DIRECTIONAL_HELPERS(/obj/item/storage/secure/safe, 32)
-/obj/item/storage/secure/safe/ComponentInitialize()
+/obj/item/storage/secure/safe/Initialize()
. = ..()
- var/datum/component/storage/STR = GetComponent(/datum/component/storage)
- STR.set_holdable(null, list(/obj/item/storage/secure/briefcase))
- STR.max_w_class = 8 //??
+ atom_storage.set_holdable(cant_hold_list = list(/obj/item/storage/secure/briefcase))
+ atom_storage.max_specific_storage = WEIGHT_CLASS_GIGANTIC
/obj/item/storage/secure/safe/PopulateContents()
new /obj/item/paper(src)
@@ -219,7 +216,7 @@ MAPPING_DIRECTIONAL_HELPERS(/obj/item/storage/secure/safe/caps_spare, 32)
lock_code = SSid_access.spare_id_safe_code
lock_set = TRUE
- SEND_SIGNAL(src, COMSIG_TRY_STORAGE_SET_LOCKSTATE, TRUE)
+ atom_storage.locked = TRUE
/obj/item/storage/secure/safe/caps_spare/PopulateContents()
new /obj/item/card/id/advanced/gold/captains_spare(src)
diff --git a/code/game/objects/items/storage/sixpack.dm b/code/game/objects/items/storage/sixpack.dm
index 9d626d5bbab..dd67c5d222a 100644
--- a/code/game/objects/items/storage/sixpack.dm
+++ b/code/game/objects/items/storage/sixpack.dm
@@ -21,13 +21,12 @@
. = ..()
update_appearance()
-/obj/item/storage/cans/ComponentInitialize()
+/obj/item/storage/cans/Initialize()
. = ..()
- var/datum/component/storage/STR = GetComponent(/datum/component/storage)
- STR.max_w_class = WEIGHT_CLASS_SMALL
- STR.max_combined_w_class = 12
- STR.max_items = 6
- STR.set_holdable(list(
+ atom_storage.max_specific_storage = WEIGHT_CLASS_SMALL
+ atom_storage.max_total_storage = 12
+ atom_storage.max_slots = 6
+ atom_storage.set_holdable(list(
/obj/item/reagent_containers/food/drinks/soda_cans,
/obj/item/reagent_containers/food/drinks/bottle/beer,
/obj/item/reagent_containers/food/drinks/bottle/ale,
diff --git a/code/game/objects/items/storage/storage.dm b/code/game/objects/items/storage/storage.dm
index f4dfa226af9..dafe93f01fa 100644
--- a/code/game/objects/items/storage/storage.dm
+++ b/code/game/objects/items/storage/storage.dm
@@ -3,7 +3,6 @@
icon = 'icons/obj/storage.dmi'
w_class = WEIGHT_CLASS_NORMAL
var/rummage_if_nodrop = TRUE
- var/component_type = /datum/component/storage/concrete
/// Should we preload the contents of this type?
/// BE CAREFUL, THERE'S SOME REALLY NASTY SHIT IN THIS TYPEPATH
/// SANTA IS EVIL
@@ -11,13 +10,14 @@
/obj/item/storage/Initialize(mapload)
. = ..()
+
+ create_storage()
+
PopulateContents()
+
for (var/obj/item/item in src)
item.item_flags |= IN_STORAGE
-/obj/item/storage/ComponentInitialize()
- AddComponent(component_type)
-
/obj/item/storage/AllowDrop()
return FALSE
@@ -37,8 +37,7 @@
/obj/item/storage/doStrip(mob/who)
if(HAS_TRAIT(src, TRAIT_NODROP) && rummage_if_nodrop)
- var/datum/component/storage/CP = GetComponent(/datum/component/storage)
- CP.do_quick_empty()
+ atom_storage.remove_all()
return TRUE
return ..()
@@ -48,8 +47,7 @@
/obj/item/storage/proc/PopulateContents()
/obj/item/storage/proc/emptyStorage()
- var/datum/component/storage/ST = GetComponent(/datum/component/storage)
- ST.do_quick_empty()
+ atom_storage.remove_all()
/obj/item/storage/Destroy()
for(var/obj/important_thing in contents)
diff --git a/code/game/objects/items/storage/toolbox.dm b/code/game/objects/items/storage/toolbox.dm
index 2c64585b7e3..b44c548cd0b 100644
--- a/code/game/objects/items/storage/toolbox.dm
+++ b/code/game/objects/items/storage/toolbox.dm
@@ -38,10 +38,9 @@
if(has_latches)
. += latches
-/obj/item/storage/toolbox/ComponentInitialize()
+/obj/item/storage/toolbox/Initialize()
. = ..()
- var/datum/component/storage/STR = GetComponent(/datum/component/storage)
- STR.max_w_class = WEIGHT_CLASS_NORMAL
+ atom_storage.max_specific_storage = WEIGHT_CLASS_NORMAL
/obj/item/storage/toolbox/suicide_act(mob/user)
user.visible_message(span_suicide("[user] robusts [user.p_them()]self with [src]! It looks like [user.p_theyre()] trying to commit suicide!"))
@@ -102,10 +101,9 @@
force = 5
w_class = WEIGHT_CLASS_NORMAL
-/obj/item/storage/toolbox/mechanical/old/heirloom/ComponentInitialize()
+/obj/item/storage/toolbox/mechanical/old/heirloom/Initialize()
. = ..()
- var/datum/component/storage/STR = GetComponent(/datum/component/storage)
- STR.max_w_class = WEIGHT_CLASS_SMALL
+ atom_storage.max_specific_storage = WEIGHT_CLASS_SMALL
/obj/item/storage/toolbox/mechanical/old/heirloom/PopulateContents()
return
@@ -170,10 +168,9 @@
throwforce = 18
material_flags = NONE
-/obj/item/storage/toolbox/syndicate/ComponentInitialize()
+/obj/item/storage/toolbox/syndicate/Initialize()
. = ..()
- var/datum/component/storage/STR = GetComponent(/datum/component/storage)
- STR.silent = TRUE
+ atom_storage.silent = TRUE
/obj/item/storage/toolbox/syndicate/PopulateContents()
new /obj/item/screwdriver/nuke(src)
@@ -208,11 +205,10 @@
w_class = WEIGHT_CLASS_GIGANTIC //Holds more than a regular toolbox!
material_flags = NONE
-/obj/item/storage/toolbox/artistic/ComponentInitialize()
+/obj/item/storage/toolbox/artistic/Initialize()
. = ..()
- var/datum/component/storage/STR = GetComponent(/datum/component/storage)
- STR.max_combined_w_class = 20
- STR.max_items = 10
+ atom_storage.max_total_storage = 20
+ atom_storage.max_slots = 10
/obj/item/storage/toolbox/artistic/PopulateContents()
new /obj/item/storage/crayons(src)
@@ -275,13 +271,12 @@
w_class = WEIGHT_CLASS_NORMAL
has_latches = FALSE
-/obj/item/storage/toolbox/infiltrator/ComponentInitialize()
+/obj/item/storage/toolbox/infiltrator/Initialize()
. = ..()
- var/datum/component/storage/STR = GetComponent(/datum/component/storage)
- STR.max_items = 10
- STR.max_w_class = WEIGHT_CLASS_NORMAL
- STR.max_combined_w_class = 24
- STR.set_holdable(list(
+ atom_storage.max_slots = 10
+ atom_storage.max_specific_storage = WEIGHT_CLASS_NORMAL
+ atom_storage.max_total_storage = 24
+ atom_storage.set_holdable(list(
/obj/item/clothing/head/helmet/infiltrator,
/obj/item/clothing/suit/armor/vest/infiltrator,
/obj/item/clothing/under/syndicate/bloodred,
diff --git a/code/game/objects/items/storage/uplink_kits.dm b/code/game/objects/items/storage/uplink_kits.dm
index b02c974e1ed..a9f50856558 100644
--- a/code/game/objects/items/storage/uplink_kits.dm
+++ b/code/game/objects/items/storage/uplink_kits.dm
@@ -385,11 +385,10 @@
/obj/item/storage/box/syndie_kit/space
name = "boxed space suit and helmet"
-/obj/item/storage/box/syndie_kit/space/ComponentInitialize()
+/obj/item/storage/box/syndie_kit/space/Initialize()
. = ..()
- var/datum/component/storage/STR = GetComponent(/datum/component/storage)
- STR.max_w_class = WEIGHT_CLASS_NORMAL
- STR.set_holdable(list(/obj/item/clothing/suit/space/syndicate, /obj/item/clothing/head/helmet/space/syndicate))
+ atom_storage.max_specific_storage = WEIGHT_CLASS_NORMAL
+ atom_storage.set_holdable(list(/obj/item/clothing/suit/space/syndicate, /obj/item/clothing/head/helmet/space/syndicate))
/obj/item/storage/box/syndie_kit/space/PopulateContents()
if(prob(50))
@@ -411,10 +410,9 @@
/obj/item/storage/box/syndie_kit/chemical
name = "chemical kit"
-/obj/item/storage/box/syndie_kit/chemical/ComponentInitialize()
+/obj/item/storage/box/syndie_kit/chemical/Initialize()
. = ..()
- var/datum/component/storage/STR = GetComponent(/datum/component/storage)
- STR.max_items = 14
+ atom_storage.max_slots = 14
/obj/item/storage/box/syndie_kit/chemical/PopulateContents()
new /obj/item/reagent_containers/glass/bottle/polonium(src)
diff --git a/code/game/objects/items/storage/wallets.dm b/code/game/objects/items/storage/wallets.dm
index 093f664803b..5906b510340 100644
--- a/code/game/objects/items/storage/wallets.dm
+++ b/code/game/objects/items/storage/wallets.dm
@@ -5,17 +5,15 @@
w_class = WEIGHT_CLASS_SMALL
resistance_flags = FLAMMABLE
slot_flags = ITEM_SLOT_ID
- component_type = /datum/component/storage/concrete/wallet
var/obj/item/card/id/front_id = null
var/list/combined_access
var/cached_flat_icon
-/obj/item/storage/wallet/ComponentInitialize()
+/obj/item/storage/wallet/Initialize()
. = ..()
- var/datum/component/storage/STR = GetComponent(/datum/component/storage/concrete/wallet)
- STR.max_items = 4
- STR.set_holdable(list(
+ atom_storage.max_slots = 4
+ atom_storage.set_holdable(list(
/obj/item/stack/spacecash,
/obj/item/holochip,
/obj/item/card,
diff --git a/code/game/objects/items/tcg/tcg.dm b/code/game/objects/items/tcg/tcg.dm
index b1f89cf21c9..3ff00f4e1b2 100644
--- a/code/game/objects/items/tcg/tcg.dm
+++ b/code/game/objects/items/tcg/tcg.dm
@@ -184,7 +184,7 @@ GLOBAL_LIST_EMPTY(tcgcard_radial_choices)
/obj/item/tcgcard_deck/Initialize(mapload)
. = ..()
- LoadComponent(/datum/component/storage/concrete/tcg)
+ create_storage(type = /datum/storage/tcg)
/obj/item/tcgcard_deck/update_icon_state()
if(!flipped)
@@ -284,7 +284,7 @@ GLOBAL_LIST_EMPTY(tcgcard_radial_choices)
return
contents = shuffle(contents)
if(user.active_storage)
- user.active_storage.close(user)
+ user.active_storage.hide_contents(user)
if(visable)
user.visible_message(span_notice("[user] shuffles \the [src]!"), \
span_notice("You shuffle \the [src]!"))
@@ -396,10 +396,9 @@ GLOBAL_LIST_EMPTY(tcgcard_radial_choices)
/obj/item/storage/card_binder/Initialize(mapload)
. = ..()
- var/datum/component/storage/STR = GetComponent(/datum/component/storage)
- STR.set_holdable(list(/obj/item/tcgcard))
- STR.max_combined_w_class = 120
- STR.max_items = 60
+ atom_storage.set_holdable(list(/obj/item/tcgcard))
+ atom_storage.max_total_storage = 120
+ atom_storage.max_slots = 60
///Returns a list of cards ids of card_cnt weighted by rarity from the pack's tables that have matching series, with gnt_cnt of the guarenteed table.
/obj/item/cardpack/proc/buildCardListWithRarity(card_cnt, rarity_cnt)
diff --git a/code/game/objects/structures/crates_lockers/closets.dm b/code/game/objects/structures/crates_lockers/closets.dm
index 79e4295b65b..9a3ccb49928 100644
--- a/code/game/objects/structures/crates_lockers/closets.dm
+++ b/code/game/objects/structures/crates_lockers/closets.dm
@@ -248,7 +248,7 @@
break
for(var/i in reverse_range(location.get_all_contents()))
var/atom/movable/thing = i
- SEND_SIGNAL(thing, COMSIG_TRY_STORAGE_HIDE_ALL)
+ thing.atom_storage?.close_all()
/obj/structure/closet/proc/open(mob/living/user, force = FALSE)
if(!can_open(user, force))
diff --git a/code/game/objects/structures/crates_lockers/crates/bins.dm b/code/game/objects/structures/crates_lockers/crates/bins.dm
index 5f7faf406fb..4b68e9fce4c 100644
--- a/code/game/objects/structures/crates_lockers/crates/bins.dm
+++ b/code/game/objects/structures/crates_lockers/crates/bins.dm
@@ -28,7 +28,7 @@
var/obj/item/storage/bag/trash/T = W
to_chat(user, span_notice("You fill the bag."))
for(var/obj/item/O in src)
- SEND_SIGNAL(T, COMSIG_TRY_STORAGE_INSERT, O, user, TRUE)
+ T.atom_storage?.attempt_insert(T, O, user, TRUE)
T.update_appearance()
do_animate()
return TRUE
diff --git a/code/game/objects/structures/tables_racks.dm b/code/game/objects/structures/tables_racks.dm
index 912a9eea96c..22d536e9681 100644
--- a/code/game/objects/structures/tables_racks.dm
+++ b/code/game/objects/structures/tables_racks.dm
@@ -209,7 +209,7 @@
for(var/x in T.contents)
var/obj/item/item = x
AfterPutItemOnTable(item, user)
- SEND_SIGNAL(I, COMSIG_TRY_STORAGE_QUICK_EMPTY, drop_location())
+ I.atom_storage.remove_all(drop_location())
user.visible_message(span_notice("[user] empties [I] on [src]."))
return
// If the tray IS empty, continue on (tray will be placed on the table like other items)
diff --git a/code/game/turfs/turf.dm b/code/game/turfs/turf.dm
index d014ceea7cb..87b3e0546a5 100755
--- a/code/game/turfs/turf.dm
+++ b/code/game/turfs/turf.dm
@@ -452,20 +452,21 @@ GLOBAL_LIST_EMPTY(station_turfs)
/turf/proc/Bless()
new /obj/effect/blessing(src)
-/turf/storage_contents_dump_act(datum/component/storage/src_object, mob/user)
+/turf/storage_contents_dump_act(atom/src_object, mob/user)
. = ..()
if(.)
return
- if(length(src_object.contents()))
- to_chat(usr, span_notice("You start dumping out the contents..."))
- if(!do_after(usr,20,target=src_object.parent))
+ if(!src_object.atom_storage)
+ return
+ var/atom/resolve_parent = src_object.atom_storage.real_location?.resolve()
+ if(!resolve_parent)
+ return FALSE
+ if(length(resolve_parent.contents))
+ to_chat(user, span_notice("You start dumping out the contents of [src_object]..."))
+ if(!do_after(user, 20, target=resolve_parent))
return FALSE
- var/list/things = src_object.contents()
- var/datum/progressbar/progress = new(user, things.len, src)
- while (do_after(usr, 1 SECONDS, src, NONE, FALSE, CALLBACK(src_object, /datum/component/storage.proc/mass_remove_from_storage, src, things, progress)))
- stoplag(1)
- progress.end_progress()
+ src_object.atom_storage.remove_all(src)
return TRUE
diff --git a/code/modules/antagonists/clown_ops/clown_weapons.dm b/code/modules/antagonists/clown_ops/clown_weapons.dm
index 3c5584c894f..4cb548d9071 100644
--- a/code/modules/antagonists/clown_ops/clown_weapons.dm
+++ b/code/modules/antagonists/clown_ops/clown_weapons.dm
@@ -20,7 +20,11 @@
armor = list(MELEE = 25, BULLET = 25, LASER = 25, ENERGY = 25, BOMB = 50, BIO = 90, FIRE = 70, ACID = 50)
strip_delay = 70
resistance_flags = NONE
- pocket_storage_component_path = /datum/component/storage/concrete/pockets/shoes
+
+/obj/item/clothing/shoes/clown_shoes/combat/Initialize(mapload)
+ . = ..()
+
+ create_storage(type = /datum/storage/pockets/shoes)
/// Recharging rate in PPS (peels per second)
#define BANANA_SHOES_RECHARGE_RATE 17
@@ -34,11 +38,13 @@
armor = list(MELEE = 25, BULLET = 25, LASER = 25, ENERGY = 25, BOMB = 50, BIO = 50, FIRE = 90, ACID = 50)
strip_delay = 70
resistance_flags = NONE
- pocket_storage_component_path = /datum/component/storage/concrete/pockets/shoes
always_noslip = TRUE
/obj/item/clothing/shoes/clown_shoes/banana_shoes/combat/Initialize(mapload)
. = ..()
+
+ create_storage(type = /datum/storage/pockets/shoes)
+
var/datum/component/material_container/bananium = GetComponent(/datum/component/material_container)
bananium.insert_amount_mat(BANANA_SHOES_MAX_CHARGE, /datum/material/bananium)
START_PROCESSING(SSobj, src)
diff --git a/code/modules/antagonists/cult/cult.dm b/code/modules/antagonists/cult/cult.dm
index 689a92343a1..56318bf5286 100644
--- a/code/modules/antagonists/cult/cult.dm
+++ b/code/modules/antagonists/cult/cult.dm
@@ -126,7 +126,7 @@
else
to_chat(mob, span_danger("You have a [item_name] in your [where]."))
if(where == "backpack")
- SEND_SIGNAL(mob.back, COMSIG_TRY_STORAGE_SHOW, mob)
+ mob.back.atom_storage?.show_contents(mob)
return TRUE
/datum/antagonist/cult/apply_innate_effects(mob/living/mob_override)
diff --git a/code/modules/antagonists/heretic/items/heretic_armor.dm b/code/modules/antagonists/heretic/items/heretic_armor.dm
index 7092cf120e8..55d42e0b48c 100644
--- a/code/modules/antagonists/heretic/items/heretic_armor.dm
+++ b/code/modules/antagonists/heretic/items/heretic_armor.dm
@@ -60,8 +60,12 @@
body_parts_covered = CHEST|GROIN|ARMS
// slightly worse than normal cult robes
armor = list(MELEE = 30, BULLET = 30, LASER = 30,ENERGY = 30, BOMB = 15, BIO = 0, FIRE = 0, ACID = 0)
- pocket_storage_component_path = /datum/component/storage/concrete/pockets/void_cloak
alternative_mode = TRUE
+
+/obj/item/clothing/suit/hooded/cultrobes/void/Initialize(mapload)
+ . = ..()
+
+ create_storage(type = /datum/storage/pockets/void_cloak)
/obj/item/clothing/suit/hooded/cultrobes/void/Initialize(mapload)
. = ..()
diff --git a/code/modules/clothing/chameleon.dm b/code/modules/clothing/chameleon.dm
index 240b8c68e9c..8aafde978f9 100644
--- a/code/modules/clothing/chameleon.dm
+++ b/code/modules/clothing/chameleon.dm
@@ -602,12 +602,14 @@
desc = "A pair of black shoes."
resistance_flags = NONE
armor = list(MELEE = 10, BULLET = 10, LASER = 10, ENERGY = 0, BOMB = 0, BIO = 90, FIRE = 50, ACID = 50)
- pocket_storage_component_path = /datum/component/storage/concrete/pockets/shoes
var/datum/action/item_action/chameleon/change/chameleon_action
/obj/item/clothing/shoes/chameleon/Initialize(mapload)
. = ..()
+
+ create_storage(type = /datum/storage/pockets/shoes)
+
chameleon_action = new(src)
chameleon_action.chameleon_type = /obj/item/clothing/shoes
chameleon_action.chameleon_name = "Shoes"
@@ -665,10 +667,7 @@
chameleon_action.initialize_disguises()
add_item_action(chameleon_action)
-/obj/item/storage/belt/chameleon/ComponentInitialize()
- . = ..()
- var/datum/component/storage/STR = GetComponent(/datum/component/storage)
- STR.silent = TRUE
+ atom_storage.silent = TRUE
/obj/item/storage/belt/chameleon/emp_act(severity)
. = ..()
diff --git a/code/modules/clothing/clothing.dm b/code/modules/clothing/clothing.dm
index 5772f8ba1c8..e7b6c0d75cb 100644
--- a/code/modules/clothing/clothing.dm
+++ b/code/modules/clothing/clothing.dm
@@ -287,20 +287,19 @@
if(30 to 59)
. += span_danger("The [zone_name] is partially shredded.")
- var/datum/component/storage/pockets = GetComponent(/datum/component/storage)
- if(pockets)
+ if(atom_storage)
var/list/how_cool_are_your_threads = list("")
- if(pockets.attack_hand_interact)
+ if(atom_storage.attack_hand_interact)
how_cool_are_your_threads += "[src]'s storage opens when clicked.\n"
else
how_cool_are_your_threads += "[src]'s storage opens when dragged to yourself.\n"
- if (pockets.can_hold?.len) // If pocket type can hold anything, vs only specific items
- how_cool_are_your_threads += "[src] can store [pockets.max_items] item\s.\n"
+ if (atom_storage.can_hold?.len) // If pocket type can hold anything, vs only specific items
+ how_cool_are_your_threads += "[src] can store [atom_storage.max_slots] item\s.\n"
else
- how_cool_are_your_threads += "[src] can store [pockets.max_items] item\s that are [weight_class_to_text(pockets.max_w_class)] or smaller.\n"
- if(pockets.quickdraw)
+ how_cool_are_your_threads += "[src] can store [atom_storage.max_slots] item\s that are [weight_class_to_text(atom_storage.max_specific_storage)] or smaller.\n"
+ if(atom_storage.quickdraw)
how_cool_are_your_threads += "You can quickly remove an item from [src] using Right-Click.\n"
- if(pockets.silent)
+ if(atom_storage.silent)
how_cool_are_your_threads += "Adding or removing items from [src] makes no noise.\n"
how_cool_are_your_threads += ""
. += how_cool_are_your_threads.Join()
diff --git a/code/modules/clothing/head/fedora.dm b/code/modules/clothing/head/fedora.dm
index 3207609cc90..c3f7074841c 100644
--- a/code/modules/clothing/head/fedora.dm
+++ b/code/modules/clothing/head/fedora.dm
@@ -3,7 +3,11 @@
icon_state = "fedora"
inhand_icon_state = "fedora"
desc = "A really cool hat if you're a mobster. A really lame hat if you're not."
- pocket_storage_component_path = /datum/component/storage/concrete/pockets/small/fedora
+
+/obj/item/clothing/head/fedora/Initialize(mapload)
+ . = ..()
+
+ create_storage(type = /datum/storage/pockets/small/fedora)
/obj/item/clothing/head/fedora/white
name = "white fedora"
diff --git a/code/modules/clothing/head/helmet.dm b/code/modules/clothing/head/helmet.dm
index 09c710a3bd6..c9fd22b3f85 100644
--- a/code/modules/clothing/head/helmet.dm
+++ b/code/modules/clothing/head/helmet.dm
@@ -340,7 +340,11 @@
icon_state = "rus_helmet"
inhand_icon_state = "rus_helmet"
armor = list(MELEE = 25, BULLET = 30, LASER = 0, ENERGY = 10, BOMB = 10, BIO = 0, FIRE = 20, ACID = 50, WOUND = 5)
- pocket_storage_component_path = /datum/component/storage/concrete/pockets/helmet
+
+/obj/item/clothing/head/helmet/rus_helmet/Initialize(mapload)
+ . = ..()
+
+ create_storage(type = /datum/storage/pockets/helmet)
/obj/item/clothing/head/helmet/rus_ushanka
name = "battle ushanka"
diff --git a/code/modules/clothing/head/jobs.dm b/code/modules/clothing/head/jobs.dm
index f942c3397bb..7ed8a101b8d 100644
--- a/code/modules/clothing/head/jobs.dm
+++ b/code/modules/clothing/head/jobs.dm
@@ -13,11 +13,15 @@
strip_delay = 10
equip_delay_other = 10
- pocket_storage_component_path = /datum/component/storage/concrete/pockets/chefhat
dog_fashion = /datum/dog_fashion/head/chef
///the chance that the movements of a mouse inside of this hat get relayed to the human wearing the hat
var/mouse_control_probability = 20
+/obj/item/clothing/head/chefhat/Initialize(mapload)
+ . = ..()
+
+ create_storage(type = /datum/storage/pockets/chefhat)
+
/obj/item/clothing/head/chefhat/i_am_assuming_direct_control
desc = "The commander in chef's head wear. Upon closer inspection, there seem to be dozens of tiny levers, buttons, dials, and screens inside of this hat. What the hell...?"
mouse_control_probability = 100
@@ -94,11 +98,13 @@
armor = list(MELEE = 25, BULLET = 5, LASER = 25, ENERGY = 35, BOMB = 0, BIO = 0, FIRE = 30, ACID = 50, WOUND = 5)
icon_state = "detective"
var/candy_cooldown = 0
- pocket_storage_component_path = /datum/component/storage/concrete/pockets/small/fedora/detective
dog_fashion = /datum/dog_fashion/head/detective
/obj/item/clothing/head/fedora/det_hat/Initialize(mapload)
. = ..()
+
+ create_storage(type = /datum/storage/pockets/small/fedora/detective)
+
new /obj/item/reagent_containers/food/drinks/flask/det(src)
/obj/item/clothing/head/fedora/det_hat/examine(mob/user)
diff --git a/code/modules/clothing/head/religious.dm b/code/modules/clothing/head/religious.dm
index cd4e5b4ad1f..29eb4c2aeb2 100644
--- a/code/modules/clothing/head/religious.dm
+++ b/code/modules/clothing/head/religious.dm
@@ -17,10 +17,18 @@
name = "white taqiyah"
desc = "An extra-mustahabb way of showing your devotion to Allah."
icon_state = "taqiyahwhite"
- pocket_storage_component_path = /datum/component/storage/concrete/pockets/small
+
+/obj/item/clothing/head/taqiyahwhite/Initialize(mapload)
+ . = ..()
+
+ create_storage(type = /datum/storage/pockets/small)
/obj/item/clothing/head/taqiyahred
name = "red taqiyah"
desc = "An extra-mustahabb way of showing your devotion to Allah."
icon_state = "taqiyahred"
- pocket_storage_component_path = /datum/component/storage/concrete/pockets/small
+
+/obj/item/clothing/head/taqiyahred/Initialize(mapload)
+ . = ..()
+
+ create_storage(type = /datum/storage/pockets/small)
diff --git a/code/modules/clothing/outfits/standard.dm b/code/modules/clothing/outfits/standard.dm
index 0ed64495fea..bea204111c0 100644
--- a/code/modules/clothing/outfits/standard.dm
+++ b/code/modules/clothing/outfits/standard.dm
@@ -252,11 +252,11 @@
for(var/obj/item/briefcase_item in sec_briefcase)
qdel(briefcase_item)
for(var/i = 3 to 0 step -1)
- SEND_SIGNAL(sec_briefcase, COMSIG_TRY_STORAGE_INSERT, new /obj/item/stack/spacecash/c1000, null, TRUE, TRUE)
- SEND_SIGNAL(sec_briefcase, COMSIG_TRY_STORAGE_INSERT, new /obj/item/gun/energy/recharge/ebow, null, TRUE, TRUE)
- SEND_SIGNAL(sec_briefcase, COMSIG_TRY_STORAGE_INSERT, new /obj/item/gun/ballistic/revolver/mateba, null, TRUE, TRUE)
- SEND_SIGNAL(sec_briefcase, COMSIG_TRY_STORAGE_INSERT, new /obj/item/ammo_box/a357, null, TRUE, TRUE)
- SEND_SIGNAL(sec_briefcase, COMSIG_TRY_STORAGE_INSERT, new /obj/item/grenade/c4/x4, null, TRUE, TRUE)
+ sec_briefcase.contents += new /obj/item/stack/spacecash/c1000
+ sec_briefcase.contents += new /obj/item/gun/energy/recharge/ebow
+ sec_briefcase.contents += new /obj/item/gun/ballistic/revolver/mateba
+ sec_briefcase.contents += new /obj/item/ammo_box/a357
+ sec_briefcase.contents += new /obj/item/grenade/c4/x4
var/obj/item/modular_computer/tablet/pda/heads/pda = H.belt
pda.saved_identification = H.real_name
diff --git a/code/modules/clothing/outfits/vv_outfit.dm b/code/modules/clothing/outfits/vv_outfit.dm
index 3718e6bdef5..bedd65010f9 100644
--- a/code/modules/clothing/outfits/vv_outfit.dm
+++ b/code/modules/clothing/outfits/vv_outfit.dm
@@ -107,10 +107,10 @@
O.vv_values = result
//Copy backpack contents if exist.
var/obj/item/backpack = get_item_by_slot(ITEM_SLOT_BACK)
- if(istype(backpack) && SEND_SIGNAL(backpack, COMSIG_CONTAINS_STORAGE))
+ if(istype(backpack) && backpack.atom_storage)
var/list/bp_stuff = list()
var/list/typecounts = list()
- SEND_SIGNAL(backpack, COMSIG_TRY_STORAGE_RETURN_INVENTORY, bp_stuff, FALSE)
+ backpack.atom_storage.return_inv(bp_stuff, FALSE)
for(var/obj/item/I in bp_stuff)
if(typecounts[I.type])
typecounts[I.type] += 1
diff --git a/code/modules/clothing/shoes/boots.dm b/code/modules/clothing/shoes/boots.dm
index 58b0f9832cd..dbec77cd09a 100644
--- a/code/modules/clothing/shoes/boots.dm
+++ b/code/modules/clothing/shoes/boots.dm
@@ -8,9 +8,13 @@
armor = list(MELEE = 25, BULLET = 25, LASER = 25, ENERGY = 25, BOMB = 50, BIO = 90, FIRE = 70, ACID = 50)
strip_delay = 40
resistance_flags = NONE
- pocket_storage_component_path = /datum/component/storage/concrete/pockets/shoes
lace_time = 12 SECONDS
+/obj/item/clothing/shoes/combat/Initialize(mapload)
+ . = ..()
+
+ create_storage(type = /datum/storage/pockets/shoes)
+
/obj/item/clothing/shoes/combat/sneakboots
name = "sneakboots"
desc = "These boots have special noise cancelling soles. Perfect for stealth, if it wasn't for the color scheme."
@@ -37,9 +41,13 @@
equip_delay_other = 50
resistance_flags = NONE
armor = list(MELEE = 0, BULLET = 0, LASER = 0, ENERGY = 0, BOMB = 0, BIO = 90, FIRE = 0, ACID = 0)
- pocket_storage_component_path = /datum/component/storage/concrete/pockets/shoes
can_be_tied = FALSE
+/obj/item/clothing/shoes/jackboots/Initialize(mapload)
+ . = ..()
+
+ create_storage(type = /datum/storage/pockets/shoes)
+
/obj/item/clothing/shoes/jackboots/fast
slowdown = -1
@@ -53,9 +61,13 @@
min_cold_protection_temperature = SHOES_MIN_TEMP_PROTECT
heat_protection = FEET|LEGS
max_heat_protection_temperature = SHOES_MAX_TEMP_PROTECT
- pocket_storage_component_path = /datum/component/storage/concrete/pockets/shoes
lace_time = 8 SECONDS
+/obj/item/clothing/shoes/winterboots/Initialize(mapload)
+ . = ..()
+
+ create_storage(type = /datum/storage/pockets/shoes)
+
/obj/item/clothing/shoes/winterboots/ice_boots
name = "ice hiking boots"
desc = "A pair of winter boots with special grips on the bottom, designed to prevent slipping on frozen surfaces."
@@ -73,10 +85,14 @@
armor = list(MELEE = 0, BULLET = 0, LASER = 0, ENERGY = 0, BOMB = 0, BIO = 80, FIRE = 0, ACID = 0)
strip_delay = 20
equip_delay_other = 40
- pocket_storage_component_path = /datum/component/storage/concrete/pockets/shoes
lace_time = 8 SECONDS
species_exception = list(/datum/species/golem/uranium)
+/obj/item/clothing/shoes/workboots/Initialize(mapload)
+ . = ..()
+
+ create_storage(type = /datum/storage/pockets/shoes)
+
/obj/item/clothing/shoes/workboots/mining
name = "mining boots"
desc = "Steel-toed mining boots for mining in hazardous environments. Very good at keeping toes uncrushed."
@@ -88,9 +104,13 @@
desc = "Comfy shoes."
icon_state = "rus_shoes"
inhand_icon_state = "rus_shoes"
- pocket_storage_component_path = /datum/component/storage/concrete/pockets/shoes
lace_time = 8 SECONDS
+/obj/item/clothing/shoes/russian/Initialize(mapload)
+ . = ..()
+
+ create_storage(type = /datum/storage/pockets/shoes)
+
/obj/item/clothing/shoes/discoshoes
name = "green lizardskin shoes"
desc = "They may have lost some of their lustre over the years, but these green lizardskin shoes fit you perfectly."
diff --git a/code/modules/clothing/shoes/clown.dm b/code/modules/clothing/shoes/clown.dm
index 55a8a8ba6be..83324d934e9 100644
--- a/code/modules/clothing/shoes/clown.dm
+++ b/code/modules/clothing/shoes/clown.dm
@@ -4,13 +4,14 @@
icon_state = "clown"
inhand_icon_state = "clown_shoes"
slowdown = SHOES_SLOWDOWN+1
- pocket_storage_component_path = /datum/component/storage/concrete/pockets/shoes/clown
var/enabled_waddle = TRUE
lace_time = 20 SECONDS // how the hell do these laces even work??
species_exception = list(/datum/species/golem/bananium)
/obj/item/clothing/shoes/clown_shoes/Initialize(mapload)
. = ..()
+
+ create_storage(type = /datum/storage/pockets/shoes/clown)
LoadComponent(/datum/component/squeak, list('sound/effects/clownstep1.ogg'=1,'sound/effects/clownstep2.ogg'=1), 50, falloff_exponent = 20) //die off quick please
AddElement(/datum/element/swabable, CELL_LINE_TABLE_CLOWN, CELL_VIRUS_TABLE_GENERIC, rand(2,3), 0)
diff --git a/code/modules/clothing/shoes/costume.dm b/code/modules/clothing/shoes/costume.dm
index 764dab663c8..353c71ed007 100644
--- a/code/modules/clothing/shoes/costume.dm
+++ b/code/modules/clothing/shoes/costume.dm
@@ -13,9 +13,13 @@
desc = "A pair of costume boots fashioned after bird talons."
icon_state = "griffinboots"
inhand_icon_state = "griffinboots"
- pocket_storage_component_path = /datum/component/storage/concrete/pockets/shoes
lace_time = 8 SECONDS
+/obj/item/clothing/shoes/griffin/Initialize(mapload)
+ . = ..()
+
+ create_storage(type = /datum/storage/pockets/shoes)
+
/obj/item/clothing/shoes/singery
name = "yellow performer's boots"
desc = "These boots were made for dancing."
diff --git a/code/modules/clothing/shoes/cowboy.dm b/code/modules/clothing/shoes/cowboy.dm
index 80d6e94074f..b6fb0c8dde5 100644
--- a/code/modules/clothing/shoes/cowboy.dm
+++ b/code/modules/clothing/shoes/cowboy.dm
@@ -3,13 +3,15 @@
desc = "A small sticker lets you know they've been inspected for snakes, It is unclear how long ago the inspection took place..."
icon_state = "cowboy_brown"
armor = list(MELEE = 0, BULLET = 0, LASER = 0, ENERGY = 0, BOMB = 0, BIO = 90, FIRE = 0, ACID = 0) //these are quite tall
- pocket_storage_component_path = /datum/component/storage/concrete/pockets/shoes
custom_price = PAYCHECK_CREW
var/max_occupants = 4
can_be_tied = FALSE
/obj/item/clothing/shoes/cowboy/Initialize(mapload)
. = ..()
+
+ create_storage(type = /datum/storage/pockets/shoes)
+
if(prob(2))
//There's a snake in my boot
new /mob/living/simple_animal/hostile/retaliate/snake(src)
diff --git a/code/modules/clothing/shoes/gunboots.dm b/code/modules/clothing/shoes/gunboots.dm
index ff285afe509..85c239c4b75 100644
--- a/code/modules/clothing/shoes/gunboots.dm
+++ b/code/modules/clothing/shoes/gunboots.dm
@@ -5,7 +5,6 @@
inhand_icon_state = "jackboots"
lefthand_file = 'icons/mob/inhands/equipment/security_lefthand.dmi'
righthand_file = 'icons/mob/inhands/equipment/security_righthand.dmi'
- pocket_storage_component_path = /datum/component/storage/concrete/pockets/shoes
/// What projectile do we shoot?
var/projectile_type = /obj/projectile/bullet/c10mm
/// Each step, this is the chance we fire a shot
@@ -13,6 +12,9 @@
/obj/item/clothing/shoes/gunboots/Initialize(mapload)
. = ..()
+
+ create_storage(type = /datum/storage/pockets/shoes)
+
RegisterSignal(src, COMSIG_SHOES_STEP_ACTION, .proc/check_step)
/obj/item/clothing/shoes/gunboots/equipped(mob/user, slot)
diff --git a/code/modules/clothing/shoes/jumpboots.dm b/code/modules/clothing/shoes/jumpboots.dm
index b91a335e67a..f3a77ac5e7f 100644
--- a/code/modules/clothing/shoes/jumpboots.dm
+++ b/code/modules/clothing/shoes/jumpboots.dm
@@ -4,7 +4,6 @@
icon_state = "jetboots"
inhand_icon_state = "jetboots"
resistance_flags = FIRE_PROOF
- pocket_storage_component_path = /datum/component/storage/concrete/pockets/shoes
actions_types = list(/datum/action/item_action/bhop)
armor = list(MELEE = 0, BULLET = 0, LASER = 0, ENERGY = 0, BOMB = 0, BIO = 90, FIRE = 0, ACID = 0)
strip_delay = 30
@@ -13,6 +12,11 @@
var/recharging_rate = 60 //default 6 seconds between each dash
var/recharging_time = 0 //time until next dash
+/obj/item/clothing/shoes/bhop/Initialize(mapload)
+ . = ..()
+
+ create_storage(type = /datum/storage/pockets/shoes)
+
/obj/item/clothing/shoes/bhop/ui_action_click(mob/user, action)
if(!isliving(user))
return
diff --git a/code/modules/clothing/suits/moth.dm b/code/modules/clothing/suits/moth.dm
index d0997c09457..89931c4fb83 100644
--- a/code/modules/clothing/suits/moth.dm
+++ b/code/modules/clothing/suits/moth.dm
@@ -13,7 +13,11 @@
/obj/item/clothing/suit/mothcoat/original
desc = "An old-school flightsuit from the moth fleet. A perfect token of mothic survivalistic and adaptable attitude, yet a bitter reminder that with the loss of their home planet and institution of the fleet, their beloved wings remain as a burden to bear, condemned to never fly again."
greyscale_colors = "#dfa409"
- pocket_storage_component_path = /datum/component/storage/concrete/pockets
+
+/obj/item/clothing/suit/mothcoat/original/Initialize(mapload)
+ . = ..()
+
+ create_storage(type = /datum/storage/pockets)
/obj/item/clothing/suit/mothcoat/winter
name = "mothic mantella"
diff --git a/code/modules/clothing/under/accessories.dm b/code/modules/clothing/under/accessories.dm
index 5ee14d66d9a..96ba7ad88d9 100755
--- a/code/modules/clothing/under/accessories.dm
+++ b/code/modules/clothing/under/accessories.dm
@@ -11,15 +11,9 @@
var/above_suit = TRUE
/// TRUE if shown as a small icon in corner, FALSE if overlayed
var/minimize_when_attached = TRUE
- /// Whether the accessory has any storage to apply to the clothing it's attached to.
- var/datum/component/storage/detached_pockets
/// What equipment slot the accessory attaches to.
var/attachment_slot = CHEST
-/obj/item/clothing/accessory/Destroy()
- set_detached_pockets(null)
- return ..()
-
/obj/item/clothing/accessory/proc/can_attach_accessory(obj/item/clothing/U, mob/user)
if(!attachment_slot || (U && U.body_parts_covered & attachment_slot))
return TRUE
@@ -27,12 +21,11 @@
to_chat(user, span_warning("There doesn't seem to be anywhere to put [src]..."))
/obj/item/clothing/accessory/proc/attach(obj/item/clothing/under/U, user)
- var/datum/component/storage/storage = GetComponent(/datum/component/storage)
- if(storage)
- if(SEND_SIGNAL(U, COMSIG_CONTAINS_STORAGE))
+ if(atom_storage)
+ if(U.atom_storage)
return FALSE
- U.TakeComponent(storage)
- set_detached_pockets(storage)
+ U.clone_storage(atom_storage)
+ U.atom_storage.set_real_location(src)
U.attached_accessory = src
forceMove(U)
layer = FLOAT_LAYER
@@ -57,8 +50,8 @@
return TRUE
/obj/item/clothing/accessory/proc/detach(obj/item/clothing/under/U, user)
- if(detached_pockets && detached_pockets.parent == U)
- TakeComponent(detached_pockets)
+ if(U.atom_storage && U.atom_storage.real_location?.resolve() == src)
+ QDEL_NULL(U.atom_storage)
U.armor = U.armor.detachArmor(armor)
@@ -75,16 +68,6 @@
U.attached_accessory = null
U.accessory_overlay = null
-/obj/item/clothing/accessory/proc/set_detached_pockets(new_pocket)
- if(detached_pockets)
- UnregisterSignal(detached_pockets, COMSIG_PARENT_QDELETING)
- detached_pockets = new_pocket
- if(detached_pockets)
- RegisterSignal(detached_pockets, COMSIG_PARENT_QDELETING, .proc/handle_pockets_del)
-
-/obj/item/clothing/accessory/proc/handle_pockets_del(datum/source)
- SIGNAL_HANDLER
- set_detached_pockets(null)
/obj/item/clothing/accessory/proc/on_uniform_equip(obj/item/clothing/under/U, user)
return
@@ -356,10 +339,12 @@
name = "pocket protector"
desc = "Can protect your clothing from ink stains, but you'll look like a nerd if you're using one."
icon_state = "pocketprotector"
- pocket_storage_component_path = /datum/component/storage/concrete/pockets/pocketprotector
/obj/item/clothing/accessory/pocketprotector/full/Initialize(mapload)
. = ..()
+
+ create_storage(type = /datum/storage/pockets/pocketprotector)
+
new /obj/item/pen/red(src)
new /obj/item/pen(src)
new /obj/item/pen/blue(src)
diff --git a/code/modules/detectivework/evidence.dm b/code/modules/detectivework/evidence.dm
index 0e1902a2a85..9ca6c7fac7f 100644
--- a/code/modules/detectivework/evidence.dm
+++ b/code/modules/detectivework/evidence.dm
@@ -28,7 +28,7 @@
if(!istype(I) || I.anchored)
return
- if(SEND_SIGNAL(loc, COMSIG_CONTAINS_STORAGE) && SEND_SIGNAL(I, COMSIG_CONTAINS_STORAGE))
+ if(loc.atom_storage && I.atom_storage)
to_chat(user, span_warning("No matter what way you try, you can't get [I] to fit inside [src]."))
return TRUE //begone infinite storage ghosts, begone from me
@@ -53,8 +53,8 @@
return
if(!isturf(I.loc)) //If it isn't on the floor. Do some checks to see if it's in our hands or a box. Otherwise give up.
- if(SEND_SIGNAL(I.loc, COMSIG_CONTAINS_STORAGE)) //in a container.
- SEND_SIGNAL(I.loc, COMSIG_TRY_STORAGE_TAKE, I, src)
+ if(I.loc.atom_storage) //in a container.
+ I.loc.atom_storage.attempt_remove(I, src)
if(!user.dropItemToGround(I))
return
diff --git a/code/modules/events/wizard/rpgloot.dm b/code/modules/events/wizard/rpgloot.dm
index 6907fa99be7..a26be5c09e5 100644
--- a/code/modules/events/wizard/rpgloot.dm
+++ b/code/modules/events/wizard/rpgloot.dm
@@ -86,10 +86,10 @@ GLOBAL_DATUM(rpgloot_controller, /datum/rpgloot_controller)
if(istype(fantasy_item, /obj/item/storage))
var/obj/item/storage/storage_item = fantasy_item
- var/datum/component/storage/storage_component = storage_item.GetComponent(/datum/component/storage)
- if(prob(upgrade_scroll_chance) && storage_item.contents.len < storage_component.max_items && !storage_item.invisibility)
+ var/datum/storage/storage_component = storage_item.atom_storage
+ if(prob(upgrade_scroll_chance) && storage_item.contents.len < storage_component.max_slots && !storage_item.invisibility)
var/obj/item/upgradescroll/scroll = new(get_turf(storage_item))
- SEND_SIGNAL(storage_item, COMSIG_TRY_STORAGE_INSERT, scroll, null, TRUE, TRUE)
+ storage_item.atom_storage?.attempt_insert(storage_item, scroll, null, TRUE)
upgrade_scroll_chance = max(0,upgrade_scroll_chance-100)
if(isturf(scroll.loc))
qdel(scroll)
diff --git a/code/modules/explorer_drone/exodrone.dm b/code/modules/explorer_drone/exodrone.dm
index 357df208fd5..00628f7dfe7 100644
--- a/code/modules/explorer_drone/exodrone.dm
+++ b/code/modules/explorer_drone/exodrone.dm
@@ -71,10 +71,8 @@ GLOBAL_LIST_EMPTY(exodrone_launchers)
name_counter[name] = 1
GLOB.exodrones += src
/// Cargo storage
- var/datum/component/storage/storage = AddComponent(/datum/component/storage/concrete)
- storage.cant_hold = GLOB.blacklisted_cargo_types
- storage.max_w_class = WEIGHT_CLASS_NORMAL
- storage.max_items = EXODRONE_CARGO_SLOTS
+ create_storage(max_slots = EXODRONE_CARGO_SLOTS)
+ atom_storage.set_holdable(cant_hold_list = GLOB.blacklisted_cargo_types)
/obj/item/exodrone/Destroy()
. = ..()
@@ -148,8 +146,7 @@ GLOBAL_LIST_EMPTY(exodrone_launchers)
/// Resizes storage component depending on slots used by tools.
/obj/item/exodrone/proc/update_storage_size()
- var/datum/component/storage/storage = GetComponent(/datum/component/storage/concrete)
- storage.max_items = EXODRONE_CARGO_SLOTS - length(tools)
+ atom_storage.max_slots = EXODRONE_CARGO_SLOTS - length(tools)
/// Builds ui data for drone storage.
/obj/item/exodrone/proc/get_cargo_data()
diff --git a/code/modules/fishing/aquarium/aquarium_kit.dm b/code/modules/fishing/aquarium/aquarium_kit.dm
index 3221acce755..4e53bc2e46d 100644
--- a/code/modules/fishing/aquarium/aquarium_kit.dm
+++ b/code/modules/fishing/aquarium/aquarium_kit.dm
@@ -21,12 +21,14 @@
lefthand_file = 'icons/mob/inhands/equipment/medical_lefthand.dmi'
righthand_file = 'icons/mob/inhands/equipment/medical_righthand.dmi'
- component_type = /datum/component/storage/concrete/fish_case
-
/obj/item/storage/fish_case/Initialize(mapload)
ADD_TRAIT(src, TRAIT_FISH_SAFE_STORAGE, TRAIT_GENERIC) // Before populate so fish instatiates in ready container already
. = ..()
+ create_storage(max_slots = 1)
+ atom_storage.can_hold_trait = TRAIT_FISH_CASE_COMPATIBILE
+ atom_storage.can_hold_description = "fish and aquarium equipment"
+
///Fish case with single random fish inside.
/obj/item/storage/fish_case/random/PopulateContents()
. = ..()
diff --git a/code/modules/fishing/fishing_equipment.dm b/code/modules/fishing/fishing_equipment.dm
index 6ad286c5285..35447d79b51 100644
--- a/code/modules/fishing/fishing_equipment.dm
+++ b/code/modules/fishing/fishing_equipment.dm
@@ -70,12 +70,11 @@
inhand_icon_state = "artistic_toolbox"
material_flags = NONE
-/obj/item/storage/toolbox/ComponentInitialize()
+/obj/item/storage/toolbox/Initialize()
. = ..()
// Can hold fishing rod despite the size
var/static/list/exception_cache = typecacheof(/obj/item/fishing_rod)
- var/datum/component/storage/STR = GetComponent(/datum/component/storage)
- STR.exception_hold = exception_cache
+ atom_storage.exception_hold = exception_cache
/obj/item/storage/toolbox/fishing/PopulateContents()
new /obj/item/bait_can/worm(src)
diff --git a/code/modules/food_and_drinks/kitchen_machinery/deep_fryer.dm b/code/modules/food_and_drinks/kitchen_machinery/deep_fryer.dm
index 515d6d0f7a9..eae6a05d0d9 100644
--- a/code/modules/food_and_drinks/kitchen_machinery/deep_fryer.dm
+++ b/code/modules/food_and_drinks/kitchen_machinery/deep_fryer.dm
@@ -86,7 +86,7 @@ GLOBAL_LIST_INIT(oilfry_blacklisted_items, typecacheof(list(
if(default_deconstruction_screwdriver(user, "fryer_off", "fryer_off", weapon)) //where's the open maint panel icon?!
return
else
- if(is_type_in_typecache(weapon, deepfry_blacklisted_items) || is_type_in_typecache(weapon, GLOB.oilfry_blacklisted_items) || SEND_SIGNAL(weapon, COMSIG_CONTAINS_STORAGE) || HAS_TRAIT(weapon, TRAIT_NODROP) || (weapon.item_flags & (ABSTRACT | DROPDEL)))
+ if(is_type_in_typecache(weapon, deepfry_blacklisted_items) || is_type_in_typecache(weapon, GLOB.oilfry_blacklisted_items) || weapon.atom_storage || HAS_TRAIT(weapon, TRAIT_NODROP) || (weapon.item_flags & (ABSTRACT | DROPDEL)))
return ..()
else if(!frying && user.transferItemToLoc(weapon, src))
fry(weapon, user)
diff --git a/code/modules/food_and_drinks/kitchen_machinery/microwave.dm b/code/modules/food_and_drinks/kitchen_machinery/microwave.dm
index c6f8e7ec4e8..9cf843fe2e1 100644
--- a/code/modules/food_and_drinks/kitchen_machinery/microwave.dm
+++ b/code/modules/food_and_drinks/kitchen_machinery/microwave.dm
@@ -183,7 +183,7 @@
if(ingredients.len >= max_n_of_items)
to_chat(user, span_warning("\The [src] is full, you can't put anything in!"))
return TRUE
- if(SEND_SIGNAL(T, COMSIG_TRY_STORAGE_TAKE, S, src))
+ if(T.atom_storage.attempt_remove(S, src))
loaded++
ingredients += S
if(loaded)
diff --git a/code/modules/food_and_drinks/kitchen_machinery/processor.dm b/code/modules/food_and_drinks/kitchen_machinery/processor.dm
index 9155ef1a3fb..616d4700adf 100644
--- a/code/modules/food_and_drinks/kitchen_machinery/processor.dm
+++ b/code/modules/food_and_drinks/kitchen_machinery/processor.dm
@@ -93,7 +93,7 @@
continue
var/datum/food_processor_process/P = PROCESSOR_SELECT_RECIPE(S)
if(P)
- if(SEND_SIGNAL(T, COMSIG_TRY_STORAGE_TAKE, S, src))
+ if(T.atom_storage.attempt_remove(S, src))
LAZYADD(processor_contents, S)
loaded++
diff --git a/code/modules/food_and_drinks/kitchen_machinery/smartfridge.dm b/code/modules/food_and_drinks/kitchen_machinery/smartfridge.dm
index a67c76511d2..7f3036ee8c4 100644
--- a/code/modules/food_and_drinks/kitchen_machinery/smartfridge.dm
+++ b/code/modules/food_and_drinks/kitchen_machinery/smartfridge.dm
@@ -155,8 +155,8 @@
else
return TRUE
else
- if(SEND_SIGNAL(O.loc, COMSIG_CONTAINS_STORAGE))
- return SEND_SIGNAL(O.loc, COMSIG_TRY_STORAGE_TAKE, O, src)
+ if(O.loc.atom_storage)
+ return O.loc.atom_storage.attempt_remove(O, src)
else
O.forceMove(src)
return TRUE
diff --git a/code/modules/holiday/easter.dm b/code/modules/holiday/easter.dm
index b49d491d40f..7c8b9c9cac7 100644
--- a/code/modules/holiday/easter.dm
+++ b/code/modules/holiday/easter.dm
@@ -36,8 +36,7 @@
/obj/item/storage/basket/easter/Initialize(mapload)
. = ..()
- var/datum/component/storage/STR = GetComponent(/datum/component/storage)
- STR.set_holdable(list(/obj/item/food/egg, /obj/item/food/chocolateegg, /obj/item/food/boiledegg, /obj/item/surprise_egg))
+ atom_storage.set_holdable(list(/obj/item/food/egg, /obj/item/food/chocolateegg, /obj/item/food/boiledegg, /obj/item/surprise_egg))
/obj/item/storage/basket/easter/proc/countEggs()
cut_overlays()
diff --git a/code/modules/hydroponics/biogenerator.dm b/code/modules/hydroponics/biogenerator.dm
index 945d0cd453c..22ebffa3869 100644
--- a/code/modules/hydroponics/biogenerator.dm
+++ b/code/modules/hydroponics/biogenerator.dm
@@ -113,7 +113,7 @@
for(var/obj/item/food/grown/G in PB.contents)
if(i >= max_items)
break
- if(SEND_SIGNAL(PB, COMSIG_TRY_STORAGE_TAKE, G, src))
+ if(PB.atom_storage.attempt_remove(G, src))
i++
if(i= mod.w_class)
+ var/datum/storage/holding_storage = mod.loc.atom_storage
+ if(!holding_storage || holding_storage.max_specific_storage >= mod.w_class)
return
mod.forceMove(drop_location())
diff --git a/code/modules/mod/modules/modules_general.dm b/code/modules/mod/modules/modules_general.dm
index 2dfeebafd1a..486593ce482 100644
--- a/code/modules/mod/modules/modules_general.dm
+++ b/code/modules/mod/modules/modules_general.dm
@@ -8,8 +8,6 @@
icon_state = "storage"
complexity = 3
incompatible_modules = list(/obj/item/mod/module/storage, /obj/item/mod/module/plate_compression)
- /// The storage component of the module.
- var/datum/component/storage/concrete/storage
/// Max weight class of items in the storage.
var/max_w_class = WEIGHT_CLASS_NORMAL
/// Max combined weight of all items in the storage.
@@ -19,35 +17,28 @@
/obj/item/mod/module/storage/Initialize(mapload)
. = ..()
- storage = AddComponent(/datum/component/storage/concrete)
- storage.max_w_class = max_w_class
- storage.max_combined_w_class = max_combined_w_class
- storage.max_items = max_items
- storage.allow_big_nesting = TRUE
- SEND_SIGNAL(src, COMSIG_TRY_STORAGE_SET_LOCKSTATE, TRUE)
+ create_storage(max_specific_storage = max_w_class, max_total_storage = max_combined_w_class, max_slots = max_items)
+ atom_storage.allow_big_nesting = TRUE
+ atom_storage.locked = TRUE
/obj/item/mod/module/storage/on_install()
- var/datum/component/storage/modstorage = mod.AddComponent(/datum/component/storage, storage)
- modstorage.max_w_class = max_w_class
- modstorage.max_combined_w_class = max_combined_w_class
- modstorage.max_items = max_items
- SEND_SIGNAL(src, COMSIG_TRY_STORAGE_SET_LOCKSTATE, FALSE)
- RegisterSignal(mod.chestplate, COMSIG_ITEM_PRE_UNEQUIP, .proc/on_chestplate_unequip)
+ var/datum/storage/modstorage = mod.create_storage(max_specific_storage = max_w_class, max_total_storage = max_combined_w_class, max_slots = max_items)
+ modstorage.set_real_location(src)
+ atom_storage.locked = FALSE
/obj/item/mod/module/storage/on_uninstall(deleting = FALSE)
- var/datum/component/storage/modstorage = mod.GetComponent(/datum/component/storage)
- storage.slaves -= modstorage
+ var/datum/storage/modstorage = mod.atom_storage
+ atom_storage.locked = TRUE
qdel(modstorage)
- UnregisterSignal(mod.chestplate, COMSIG_ITEM_PRE_UNEQUIP)
if(!deleting)
- SEND_SIGNAL(src, COMSIG_TRY_STORAGE_QUICK_EMPTY, drop_location())
- SEND_SIGNAL(src, COMSIG_TRY_STORAGE_SET_LOCKSTATE, TRUE)
+ atom_storage.remove_all(get_turf(src))
+ UnregisterSignal(mod.chestplate, COMSIG_ITEM_PRE_UNEQUIP)
/obj/item/mod/module/storage/proc/on_chestplate_unequip(obj/item/source, force, atom/newloc, no_move, invdrop, silent)
if(QDELETED(source) || !mod.wearer || newloc == mod.wearer || !mod.wearer.s_store)
return
to_chat(mod.wearer, span_notice("[src] tries to store [mod.wearer.s_store] inside itself."))
- SEND_SIGNAL(src, COMSIG_TRY_STORAGE_INSERT, mod.wearer.s_store, mod.wearer, TRUE)
+ atom_storage?.attempt_insert(src, mod.wearer.s_store, mod.wearer, TRUE)
/obj/item/mod/module/storage/large_capacity
name = "MOD expanded storage module"
diff --git a/code/modules/paperwork/handlabeler.dm b/code/modules/paperwork/handlabeler.dm
index e6532776af7..bf3e11ff398 100644
--- a/code/modules/paperwork/handlabeler.dm
+++ b/code/modules/paperwork/handlabeler.dm
@@ -88,7 +88,7 @@
qdel(I)
labels_left = initial(labels_left) //Yes, it's capped at its initial value
-/obj/item/hand_labeler/attackby_storage_insert(datum/component/storage, atom/storage_holder, mob/user)
+/obj/item/hand_labeler/attackby_storage_insert(datum/storage, atom/storage_holder, mob/user)
return !mode
/obj/item/hand_labeler/borg
diff --git a/code/modules/photography/photos/album.dm b/code/modules/photography/photos/album.dm
index bbf315f5e8f..3fd36d17a74 100644
--- a/code/modules/photography/photos/album.dm
+++ b/code/modules/photography/photos/album.dm
@@ -16,10 +16,9 @@
/obj/item/storage/photo_album/Initialize(mapload)
. = ..()
- var/datum/component/storage/STR = GetComponent(/datum/component/storage)
- STR.set_holdable(list(/obj/item/photo))
- STR.max_combined_w_class = 42
- STR.max_items = 21
+ atom_storage.set_holdable(list(/obj/item/photo))
+ atom_storage.max_total_storage = 42
+ atom_storage.max_slots = 21
LAZYADD(SSpersistence.photo_albums, src)
/obj/item/storage/photo_album/Destroy()
@@ -53,7 +52,7 @@
continue
var/obj/item/photo/old/P = load_photo_from_disk(i)
if(istype(P))
- if(!SEND_SIGNAL(src, COMSIG_TRY_STORAGE_INSERT, P, null, TRUE, TRUE))
+ if(!atom_storage?.attempt_insert(src, P, null, TRUE))
qdel(P)
/obj/item/storage/photo_album/hos
diff --git a/code/modules/power/cell.dm b/code/modules/power/cell.dm
index 3841b47bd1d..b2ad3beaeb7 100644
--- a/code/modules/power/cell.dm
+++ b/code/modules/power/cell.dm
@@ -255,7 +255,7 @@
/obj/item/stock_parts/cell/get_part_rating()
return maxcharge * 10 + charge
-/obj/item/stock_parts/cell/attackby_storage_insert(datum/component/storage, atom/storage_holder, mob/user)
+/obj/item/stock_parts/cell/attackby_storage_insert(datum/storage, atom/storage_holder, mob/user)
var/obj/item/mod/control/mod = storage_holder
return !(istype(mod) && mod.open)
diff --git a/code/modules/projectiles/guns/ballistic/bow.dm b/code/modules/projectiles/guns/ballistic/bow.dm
index 224f1dc09f0..a23f0cf3bd6 100644
--- a/code/modules/projectiles/guns/ballistic/bow.dm
+++ b/code/modules/projectiles/guns/ballistic/bow.dm
@@ -103,11 +103,10 @@
/obj/item/storage/bag/quiver/Initialize(mapload)
. = ..()
- var/datum/component/storage/storage = GetComponent(/datum/component/storage)
- storage.max_w_class = WEIGHT_CLASS_TINY
- storage.max_items = 40
- storage.max_combined_w_class = 100
- storage.set_holdable(list(
+ atom_storage.max_specific_storage = WEIGHT_CLASS_TINY
+ atom_storage.max_slots = 40
+ atom_storage.max_total_storage = 100
+ atom_storage.set_holdable(list(
/obj/item/ammo_casing/caseless/arrow
))
diff --git a/code/modules/projectiles/guns/energy/dueling.dm b/code/modules/projectiles/guns/energy/dueling.dm
index 2dcd6a9b252..2db258cb89f 100644
--- a/code/modules/projectiles/guns/energy/dueling.dm
+++ b/code/modules/projectiles/guns/energy/dueling.dm
@@ -317,15 +317,14 @@
icon_broken = "medalbox+b"
base_icon_state = "medalbox"
-/obj/item/storage/lockbox/dueling/ComponentInitialize()
+/obj/item/storage/lockbox/dueling/Initialize()
. = ..()
- var/datum/component/storage/STR = GetComponent(/datum/component/storage)
- STR.max_w_class = WEIGHT_CLASS_SMALL
- STR.max_items = 2
- STR.set_holdable(list(/obj/item/gun/energy/dueling))
+ atom_storage.max_specific_storage = WEIGHT_CLASS_SMALL
+ atom_storage.max_slots = 2
+ atom_storage.set_holdable(list(/obj/item/gun/energy/dueling))
/obj/item/storage/lockbox/dueling/update_icon_state()
- if(SEND_SIGNAL(src, COMSIG_IS_STORAGE_LOCKED))
+ if(atom_storage?.locked)
icon_state = icon_locked
return ..()
if(broken)
diff --git a/code/modules/reagents/chemistry/machinery/chem_master.dm b/code/modules/reagents/chemistry/machinery/chem_master.dm
index 3c7c895c537..90c066843bf 100644
--- a/code/modules/reagents/chemistry/machinery/chem_master.dm
+++ b/code/modules/reagents/chemistry/machinery/chem_master.dm
@@ -232,9 +232,8 @@
data["autoCondiStyle"] = CONDIMASTER_STYLE_AUTO
data["isPillBottleLoaded"] = bottle ? 1 : 0
if(bottle)
- var/datum/component/storage/STRB = bottle.GetComponent(/datum/component/storage)
data["pillBottleCurrentAmount"] = bottle.contents.len
- data["pillBottleMaxAmount"] = STRB.max_items
+ data["pillBottleMaxAmount"] = bottle.atom_storage.max_slots
var/beaker_contents[0]
if(beaker)
@@ -386,10 +385,8 @@
var/target_loc = drop_location()
var/drop_threshold = INFINITY
if(bottle)
- var/datum/component/storage/STRB = bottle.GetComponent(
- /datum/component/storage)
- if(STRB)
- drop_threshold = STRB.max_items - bottle.contents.len
+ if(bottle.atom_storage)
+ drop_threshold = bottle.atom_storage.max_slots - bottle.contents.len
target_loc = bottle
for(var/i in 1 to amount)
if(i-1 < drop_threshold)
diff --git a/code/modules/reagents/chemistry/machinery/reagentgrinder.dm b/code/modules/reagents/chemistry/machinery/reagentgrinder.dm
index 22bab9373c4..f334b28da76 100644
--- a/code/modules/reagents/chemistry/machinery/reagentgrinder.dm
+++ b/code/modules/reagents/chemistry/machinery/reagentgrinder.dm
@@ -174,7 +174,7 @@
//Fill machine with a bag!
if(istype(I, /obj/item/storage/bag))
var/list/inserted = list()
- if(SEND_SIGNAL(I, COMSIG_TRY_STORAGE_TAKE_TYPE, /obj/item/food/grown, src, limit - length(holdingitems), null, null, user, inserted))
+ if(I.atom_storage.remove_type(/obj/item/food/grown, src, limit - length(holdingitems), null, null, user, inserted))
for(var/i in inserted)
holdingitems[i] = TRUE
if(!I.contents.len)
diff --git a/code/modules/reagents/chemistry/reagents/food_reagents.dm b/code/modules/reagents/chemistry/reagents/food_reagents.dm
index 302db2b807f..987405050a2 100644
--- a/code/modules/reagents/chemistry/reagents/food_reagents.dm
+++ b/code/modules/reagents/chemistry/reagents/food_reagents.dm
@@ -177,7 +177,7 @@
if(is_type_in_typecache(exposed_obj, GLOB.oilfry_blacklisted_items) || (exposed_obj.resistance_flags & INDESTRUCTIBLE))
exposed_obj.loc.visible_message(span_notice("The hot oil has no effect on [exposed_obj]!"))
return
- if(SEND_SIGNAL(exposed_obj, COMSIG_CONTAINS_STORAGE))
+ if(exposed_obj.atom_storage)
exposed_obj.loc.visible_message(span_notice("The hot oil splatters about as [exposed_obj] touches it. It seems too full to cook properly!"))
return
exposed_obj.loc.visible_message(span_warning("[exposed_obj] rapidly fries as it's splashed with hot oil! Somehow."))
diff --git a/code/modules/recycling/disposal/bin.dm b/code/modules/recycling/disposal/bin.dm
index fd04f5c4c05..c61c7229121 100644
--- a/code/modules/recycling/disposal/bin.dm
+++ b/code/modules/recycling/disposal/bin.dm
@@ -259,15 +259,18 @@
return src
//How disposal handles getting a storage dump from a storage object
-/obj/machinery/disposal/storage_contents_dump_act(datum/component/storage/src_object, mob/user)
+/obj/machinery/disposal/storage_contents_dump_act(datum/storage/src_object, mob/user)
. = ..()
if(.)
return
- for(var/obj/item/I in src_object.parent)
+ var/atom/resolve_parent = src_object.real_location?.resolve()
+ if(!resolve_parent)
+ return FALSE
+ for(var/obj/item/I in resolve_parent)
if(user.active_storage != src_object)
if(I.on_found(user))
return
- src_object.remove_from_storage(I, src)
+ src_object.attempt_remove(I, src)
return TRUE
// Disposal bin
@@ -286,10 +289,9 @@
/obj/machinery/disposal/bin/attackby(obj/item/I, mob/user, params)
if(istype(I, /obj/item/storage/bag/trash)) //Not doing component overrides because this is a specific type.
var/obj/item/storage/bag/trash/T = I
- var/datum/component/storage/STR = T.GetComponent(/datum/component/storage)
to_chat(user, span_warning("You empty the bag."))
for(var/obj/item/O in T.contents)
- STR.remove_from_storage(O,src)
+ T.atom_storage.attempt_remove(O,src)
T.update_appearance()
update_appearance()
else
diff --git a/code/modules/research/stock_parts.dm b/code/modules/research/stock_parts.dm
index 6c4203371e3..8aab5b28eb9 100644
--- a/code/modules/research/stock_parts.dm
+++ b/code/modules/research/stock_parts.dm
@@ -10,11 +10,21 @@ If you create T5+ please take a pass at mech_fabricator.dm. The parts being good
lefthand_file = 'icons/mob/inhands/misc/devices_lefthand.dmi'
righthand_file = 'icons/mob/inhands/misc/devices_righthand.dmi'
w_class = WEIGHT_CLASS_HUGE
- component_type = /datum/component/storage/concrete/rped
var/works_from_distance = FALSE
var/pshoom_or_beepboopblorpzingshadashwoosh = 'sound/items/rped.ogg'
var/alt_sound = null
+/obj/item/storage/part_replacer/Initialize()
+ . = ..()
+
+ atom_storage.allow_quick_empty = TRUE
+ atom_storage.allow_quick_gather = TRUE
+ atom_storage.max_slots = 50
+ atom_storage.max_total_storage = 100
+ atom_storage.max_specific_storage = WEIGHT_CLASS_NORMAL
+ atom_storage.numerical_stacking = TRUE
+ atom_storage.set_holdable(list(/obj/item/stock_parts), null)
+
/obj/item/storage/part_replacer/pre_attack(obj/attacked_object, mob/living/user, params)
if(!istype(attacked_object, /obj/machinery) && !istype(attacked_object, /obj/structure/frame/machine))
return ..()
@@ -88,11 +98,14 @@ If you create T5+ please take a pass at mech_fabricator.dm. The parts being good
works_from_distance = TRUE
pshoom_or_beepboopblorpzingshadashwoosh = 'sound/items/pshoom.ogg'
alt_sound = 'sound/items/pshoom_2.ogg'
- component_type = /datum/component/storage/concrete/bluespace/rped
/obj/item/storage/part_replacer/bluespace/Initialize(mapload)
. = ..()
+ atom_storage.max_slots = 400
+ atom_storage.max_total_storage = 800
+ atom_storage.max_specific_storage = WEIGHT_CLASS_GIGANTIC
+
RegisterSignal(src, COMSIG_ATOM_ENTERED, .proc/on_part_entered)
RegisterSignal(src, COMSIG_ATOM_EXITED, .proc/on_part_exited)
diff --git a/code/modules/research/xenobiology/crossbreeding/reproductive.dm b/code/modules/research/xenobiology/crossbreeding/reproductive.dm
index 204cf215417..eb717e1449a 100644
--- a/code/modules/research/xenobiology/crossbreeding/reproductive.dm
+++ b/code/modules/research/xenobiology/crossbreeding/reproductive.dm
@@ -15,7 +15,6 @@ Reproductive extracts:
var/cooldown = 3 SECONDS
var/feedAmount = 3
var/last_produce = 0
- var/datum/component/storage/concrete/extract_inventory/slimeStorage
/obj/item/slimecross/reproductive/examine()
. = ..()
@@ -23,45 +22,42 @@ Reproductive extracts:
/obj/item/slimecross/reproductive/Initialize(mapload)
. = ..()
- slimeStorage = AddComponent(/datum/component/storage/concrete/extract_inventory)
+ create_storage(type = /datum/storage/extract_inventory)
/obj/item/slimecross/reproductive/attackby(obj/item/O, mob/user)
+ var/datum/storage/extract_inventory/slime_storage = atom_storage
+ if(!istype(slime_storage))
+ return
+
if((last_produce + cooldown) > world.time)
to_chat(user, span_warning("[src] is still digesting!"))
return
if(length(contents) >= feedAmount) //if for some reason the contents are full, but it didnt digest, attempt to digest again
to_chat(user, span_warning("[src] appears to be full but is not digesting! Maybe poking it stimulated it to digest."))
- slimeStorage.processCubes(src, user)
+ slime_storage?.processCubes(user)
return
if(istype(O, /obj/item/storage/bag/xeno))
var/list/inserted = list()
- SEND_SIGNAL(O, COMSIG_TRY_STORAGE_TAKE_TYPE, /obj/item/food/monkeycube, src, feedAmount - length(contents), TRUE, FALSE, user, inserted)
+ O.atom_storage.remove_type(/obj/item/food/monkeycube, src, feedAmount - length(contents), TRUE, FALSE, user, inserted)
if(inserted.len)
to_chat(user, span_notice("You feed [length(inserted)] Monkey Cube[p_s()] to [src], and it pulses gently."))
playsound(src, 'sound/items/eatfood.ogg', 20, TRUE)
- slimeStorage.processCubes(src, user)
+ slime_storage?.processCubes(user)
else
to_chat(user, span_warning("There are no monkey cubes in the bio bag!"))
return
else if(istype(O, /obj/item/food/monkeycube))
- slimeStorage.locked = FALSE //This weird unlock-then-lock nonsense brought to you courtesy of storage jank
- if(SEND_SIGNAL(src, COMSIG_TRY_STORAGE_INSERT, O, user, TRUE))
+ if(atom_storage?.attempt_insert(src, O, user, override = TRUE, force = TRUE))
to_chat(user, span_notice("You feed 1 Monkey Cube to [src], and it pulses gently."))
- slimeStorage.processCubes(src, user)
+ slime_storage?.processCubes(user)
playsound(src, 'sound/items/eatfood.ogg', 20, TRUE)
- slimeStorage.locked = TRUE //relock once its done inserting
return
else
- slimeStorage.locked = TRUE //it couldnt insert for some reason, relock it
to_chat(user, span_notice("The [src] rejects the Monkey Cube!")) //in case it fails to insert for whatever reason you get feedback
-/obj/item/slimecross/reproductive/Destroy()
- slimeStorage = null
- return ..()
-
/obj/item/slimecross/reproductive/grey
extract_type = /obj/item/slime_extract/grey
colour = "grey"
diff --git a/code/modules/research/xenobiology/xenobiology.dm b/code/modules/research/xenobiology/xenobiology.dm
index 69a51a8d874..6fddd6ac561 100644
--- a/code/modules/research/xenobiology/xenobiology.dm
+++ b/code/modules/research/xenobiology/xenobiology.dm
@@ -904,7 +904,7 @@
C.add_atom_colour("#FF0000", FIXED_COLOUR_PRIORITY)
qdel(src)
-/obj/item/slimepotion/speed/attackby_storage_insert(datum/component/storage, atom/storage_holder, mob/user)
+/obj/item/slimepotion/speed/attackby_storage_insert(datum/storage, atom/storage_holder, mob/user)
if(!isitem(storage_holder))
return TRUE
if(istype(storage_holder, /obj/item/mod/control))
diff --git a/code/modules/shuttle/emergency.dm b/code/modules/shuttle/emergency.dm
index 73b613d2970..4c2084fb627 100644
--- a/code/modules/shuttle/emergency.dm
+++ b/code/modules/shuttle/emergency.dm
@@ -712,7 +712,7 @@
/obj/item/storage/pod/attack_hand(mob/user, list/modifiers)
if (can_interact(user))
- SEND_SIGNAL(src, COMSIG_TRY_STORAGE_SHOW, user)
+ atom_storage?.show_contents(user)
return TRUE
/obj/item/storage/pod/MouseDrop(over_object, src_location, over_location)
diff --git a/code/modules/unit_tests/serving_tray.dm b/code/modules/unit_tests/serving_tray.dm
index 00e911ae509..706a1407edf 100644
--- a/code/modules/unit_tests/serving_tray.dm
+++ b/code/modules/unit_tests/serving_tray.dm
@@ -13,7 +13,7 @@
TEST_ASSERT_EQUAL((the_bread in test_tray.contents), FALSE, "The bread is on the serving tray at test start")
// set the tray to single item mode the dirty way
- var/datum/component/storage/tray_storage = test_tray.GetComponent(/datum/component/storage)
+ var/datum/storage/tray_storage = test_tray.atom_storage
tray_storage.collection_mode = COLLECT_ONE
test_tray.pre_attack(the_bread, human)
diff --git a/code/modules/vending/_vending.dm b/code/modules/vending/_vending.dm
index 0656327c4f9..4a6a1a62397 100644
--- a/code/modules/vending/_vending.dm
+++ b/code/modules/vending/_vending.dm
@@ -486,7 +486,7 @@ GLOBAL_LIST_EMPTY(vending_products)
to_chat(user, span_warning("[src]'s compartment is full."))
break
if(canLoadItem(the_item) && loadingAttempt(the_item,user))
- SEND_SIGNAL(T, COMSIG_TRY_STORAGE_TAKE, the_item, src, TRUE)
+ T.atom_storage?.attempt_remove(the_item, src)
loaded++
else
denied_items++
diff --git a/config/admins.txt b/config/admins.txt
index 9956a197b9b..a051d77535e 100644
--- a/config/admins.txt
+++ b/config/admins.txt
@@ -137,6 +137,7 @@ shizcalev = Game Master
NicBR = Game Master
LoserWasTaken = Game Master
Fikou = Game Master
+Magatsuchi = Game Master
Skoglol = Game Master
4dplanner = Game Master
Time-Green = Game Master
diff --git a/tgstation.dme b/tgstation.dme
index 83e39dc553d..85000b0f6b6 100644
--- a/tgstation.dme
+++ b/tgstation.dme
@@ -249,7 +249,6 @@
#include "code\__DEFINES\dcs\signals\signals_spatial_grid.dm"
#include "code\__DEFINES\dcs\signals\signals_specie.dm"
#include "code\__DEFINES\dcs\signals\signals_spell.dm"
-#include "code\__DEFINES\dcs\signals\signals_storage.dm"
#include "code\__DEFINES\dcs\signals\signals_subsystem.dm"
#include "code\__DEFINES\dcs\signals\signals_swab.dm"
#include "code\__DEFINES\dcs\signals\signals_techweb.dm"
@@ -774,6 +773,7 @@
#include "code\datums\components\explodable.dm"
#include "code\datums\components\faction_granter.dm"
#include "code\datums\components\fishing_spot.dm"
+#include "code\datums\components\food_storage.dm"
#include "code\datums\components\force_move.dm"
#include "code\datums\components\fov_handler.dm"
#include "code\datums\components\fullauto.dm"
@@ -896,19 +896,6 @@
#include "code\datums\components\riding\riding.dm"
#include "code\datums\components\riding\riding_mob.dm"
#include "code\datums\components\riding\riding_vehicle.dm"
-#include "code\datums\components\storage\food_storage.dm"
-#include "code\datums\components\storage\storage.dm"
-#include "code\datums\components\storage\concrete\_concrete.dm"
-#include "code\datums\components\storage\concrete\bag_of_holding.dm"
-#include "code\datums\components\storage\concrete\bluespace.dm"
-#include "code\datums\components\storage\concrete\extract_inventory.dm"
-#include "code\datums\components\storage\concrete\fish_case.dm"
-#include "code\datums\components\storage\concrete\implant.dm"
-#include "code\datums\components\storage\concrete\pockets.dm"
-#include "code\datums\components\storage\concrete\rped.dm"
-#include "code\datums\components\storage\concrete\stack.dm"
-#include "code\datums\components\storage\concrete\trading_cards.dm"
-#include "code\datums\components\storage\concrete\wallet.dm"
#include "code\datums\diseases\_disease.dm"
#include "code\datums\diseases\_MobProcs.dm"
#include "code\datums\diseases\adrenal_crisis.dm"
@@ -1198,6 +1185,12 @@
#include "code\datums\status_effects\debuffs\jitteriness.dm"
#include "code\datums\status_effects\debuffs\speech_debuffs.dm"
#include "code\datums\status_effects\debuffs\strandling.dm"
+#include "code\datums\storage\storage.dm"
+#include "code\datums\storage\subtypes\bag_of_holding.dm"
+#include "code\datums\storage\subtypes\cards.dm"
+#include "code\datums\storage\subtypes\extract_inventory.dm"
+#include "code\datums\storage\subtypes\implant.dm"
+#include "code\datums\storage\subtypes\pockets.dm"
#include "code\datums\votes\_vote_datum.dm"
#include "code\datums\votes\custom_vote.dm"
#include "code\datums\votes\map_vote.dm"