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"