From 473f6325a13c69790354d0f9f3a138b979267862 Mon Sep 17 00:00:00 2001 From: Sun-Soaked <45698967+MemedHams@users.noreply.github.com> Date: Wed, 27 Sep 2023 11:07:38 -0400 Subject: [PATCH 01/21] if I was a storage_border_3 would you still love me --- code/__DEFINES/dcs/signals.dm | 4 + code/__DEFINES/inventory.dm | 14 - code/__DEFINES/layers.dm | 18 +- code/__DEFINES/storage.dm | 85 ++++++ code/__HELPERS/_lists.dm | 2 +- code/_globalvars/bitfields.dm | 8 + code/_onclick/hud/screen_objects.dm | 48 +-- code/_onclick/hud/storage.dm | 197 +++++++++++++ .../components/storage/concrete/_concrete.dm | 2 +- .../components/storage/concrete/rped.dm | 1 + .../components/storage/concrete/stack.dm | 1 + code/datums/components/storage/storage.dm | 236 +++++---------- code/datums/components/storage/ui.dm | 273 ++++++++++++++++++ code/datums/numbered_display.dm | 4 +- code/game/atoms.dm | 5 +- code/game/objects/items.dm | 16 +- code/game/objects/items/storage/backpack.dm | 19 +- code/game/objects/items/storage/bags.dm | 10 +- code/modules/mob/living/inhand_holder.dm | 3 +- icons/hud/screen_gen.dmi | Bin 104115 -> 104770 bytes shiptest.dme | 3 + 21 files changed, 716 insertions(+), 233 deletions(-) create mode 100644 code/__DEFINES/storage.dm create mode 100644 code/_onclick/hud/storage.dm create mode 100644 code/datums/components/storage/ui.dm diff --git a/code/__DEFINES/dcs/signals.dm b/code/__DEFINES/dcs/signals.dm index 4328e6da90aa..15220b259c3c 100644 --- a/code/__DEFINES/dcs/signals.dm +++ b/code/__DEFINES/dcs/signals.dm @@ -537,6 +537,10 @@ ///from [/obj/structure/closet/supplypod/proc/endlaunch]: #define COMSIG_SUPPLYPOD_LANDED "supplypodgoboom" +// Item mouse siganls +#define COMSIG_ITEM_MOUSE_EXIT "item_mouse_exit" //from base of obj/item/MouseExited(): (location, control, params) +#define COMSIG_ITEM_MOUSE_ENTER "item_mouse_enter" //from base of obj/item/MouseEntered(): (location, control, params) + ///Called when an item is being offered, from [/obj/item/proc/on_offered(mob/living/carbon/offerer)] #define COMSIG_ITEM_OFFERING "item_offering" ///Interrupts the offer proc diff --git a/code/__DEFINES/inventory.dm b/code/__DEFINES/inventory.dm index e644340cd333..546c710e5121 100644 --- a/code/__DEFINES/inventory.dm +++ b/code/__DEFINES/inventory.dm @@ -1,19 +1,5 @@ /*ALL DEFINES RELATED TO INVENTORY OBJECTS, MANAGEMENT, ETC, GO HERE*/ -//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 -/// Pockets can hold small and tiny items, (e.g. flashlight, multitool, grenades, GPS device) -#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 -/// Items that can be weilded or equipped but not stored in an inventory, (e.g. defibrillator, backpack, space suits) -#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 -/// Essentially means it cannot be picked up or placed in an inventory, (e.g. mech parts, safe) -#define WEIGHT_CLASS_GIGANTIC 6 - //Inventory depth: limits how many nested storage items you can access directly. //1: stuff in mob, 2: stuff in backpack, 3: stuff in box in backpack, etc #define INVENTORY_DEPTH 3 diff --git a/code/__DEFINES/layers.dm b/code/__DEFINES/layers.dm index fd61f4f1123b..40281eb3ded1 100644 --- a/code/__DEFINES/layers.dm +++ b/code/__DEFINES/layers.dm @@ -152,12 +152,22 @@ #define HUD_PLANE 42 #define HUD_LAYER 42 #define HUD_RENDER_TARGET "HUD_PLANE" -#define ABOVE_HUD_PLANE 43 -#define ABOVE_HUD_LAYER 43 +#define VOLUMETRIC_STORAGE_BOX_PLANE 44 +#define VOLUMETRIC_STORAGE_BOX_LAYER 44 +#define VOLUMETRIC_STORAGE_BOX_RENDER_TARGET "VOLUME_STORAGE_BOX_PLANE" + +#define VOLUMETRIC_STORAGE_ITEM_PLANE 46 +#define VOLUMETRIC_STORAGE_ITEM_LAYER 46 +#define VOLUMETRIC_STORAGE_ACTIVE_ITEM_LAYER 48 +#define VOLUMETRIC_STORAGE_ACTIVE_ITEM_PLANE 48 +#define VOLUMETRIC_STORAGE_ITEM_RENDER_TARGET "VOLUME_STORAGE_ITEM_PLANE" + +#define ABOVE_HUD_PLANE 50 +#define ABOVE_HUD_LAYER 50 #define ABOVE_HUD_RENDER_TARGET "ABOVE_HUD_PLANE" -#define SPLASHSCREEN_LAYER 54 -#define SPLASHSCREEN_PLANE 54 +#define SPLASHSCREEN_LAYER 75 +#define SPLASHSCREEN_PLANE 75 #define ADMIN_POPUP_LAYER 1 diff --git a/code/__DEFINES/storage.dm b/code/__DEFINES/storage.dm new file mode 100644 index 000000000000..7b2bfc5d18b7 --- /dev/null +++ b/code/__DEFINES/storage.dm @@ -0,0 +1,85 @@ +// storage_flags variable on /datum/component/storage + +// Storage limits. These can be combined (and usually are combined). +/// Check max_items and contents.len when trying to insert +#define STORAGE_LIMIT_MAX_ITEMS (1<<0) +/// Check max_combined_w_class. +#define STORAGE_LIMIT_COMBINED_W_CLASS (1<<1) +/// Use the new volume system. Will automatically force rendering to use the new volume/baystation scaling UI so this is kind of incompatible with stuff like stack storage etc etc. +#define STORAGE_LIMIT_VOLUME (1<<2) +/// Use max_w_class +#define STORAGE_LIMIT_MAX_W_CLASS (1<<3) + +#define STORAGE_FLAGS_LEGACY_DEFAULT (STORAGE_LIMIT_MAX_ITEMS | STORAGE_LIMIT_COMBINED_W_CLASS | STORAGE_LIMIT_MAX_W_CLASS) +#define STORAGE_FLAGS_VOLUME_DEFAULT (STORAGE_LIMIT_VOLUME | STORAGE_LIMIT_MAX_W_CLASS) + +// UI defines +/// Size of volumetric box icon +#define VOLUMETRIC_STORAGE_BOX_ICON_SIZE 32 +/// Size of EACH left/right border icon for volumetric boxes +#define VOLUMETRIC_STORAGE_BOX_BORDER_SIZE 1 +/// Minimum pixels an item must have in volumetric scaled storage UI +#define MINIMUM_PIXELS_PER_ITEM 16 +/// Maximum number of objects that will be allowed to be displayed using the volumetric display system. Arbitrary number to prevent server lockups. +#define MAXIMUM_VOLUMETRIC_ITEMS 256 +/// How much padding to give between items +#define VOLUMETRIC_STORAGE_ITEM_PADDING 3 +/// How much padding to give to edges +#define VOLUMETRIC_STORAGE_EDGE_PADDING 1 + +//ITEM INVENTORY WEIGHT, FOR w_class +/// Usually items smaller then a human hand, ex: Playing Cards, Lighter, Scalpel, Coins/Money +#define WEIGHT_CLASS_TINY 1 +/// Fits within a small pocket, ex: Flashlight, Multitool, Grenades, GPS Device +#define WEIGHT_CLASS_SMALL 2 +/// Fits within a small satchel, ex: Fire extinguisher, Stunbaton, Gas Mask, Metal Sheets +#define WEIGHT_CLASS_NORMAL 3 +/// Items that can be wielded or equipped, (e.g. defibrillator, backpack, space suits). (Often barely) fits inside backpacks and duffels. +#define WEIGHT_CLASS_BULKY 4 +/// Usually represents objects that require two hands to operate, (e.g. shotgun, two-handed melee weapons) May fit on some inventory slots. +#define WEIGHT_CLASS_HUGE 5 +/// Essentially means it cannot be picked up or placed in an inventory, ex: Mech Parts, Safe - Can not fit in Boh +#define WEIGHT_CLASS_GIGANTIC 6 + +// PLEASE KEEP ALL VOLUME DEFINES IN THIS FILE, it's going to be hell to keep track of them later. +#define DEFAULT_VOLUME_TINY 2 +#define DEFAULT_VOLUME_SMALL 3 +#define DEFAULT_VOLUME_NORMAL 4 +#define DEFAULT_VOLUME_BULKY 8 +#define DEFAULT_VOLUME_HUGE 16 +#define DEFAULT_VOLUME_GIGANTIC 32 + +GLOBAL_LIST_INIT(default_weight_class_to_volume, list( + "[WEIGHT_CLASS_TINY]" = DEFAULT_VOLUME_TINY, + "[WEIGHT_CLASS_SMALL]" = DEFAULT_VOLUME_SMALL, + "[WEIGHT_CLASS_NORMAL]" = DEFAULT_VOLUME_NORMAL, + "[WEIGHT_CLASS_BULKY]" = DEFAULT_VOLUME_BULKY, + "[WEIGHT_CLASS_HUGE]" = DEFAULT_VOLUME_HUGE, + "[WEIGHT_CLASS_GIGANTIC]" = DEFAULT_VOLUME_GIGANTIC + )) + +/// Macro for automatically getting the volume of an item from its w_class. +#define AUTO_SCALE_VOLUME(w_class) (GLOB.default_weight_class_to_volume["[w_class]"]) +/// Macro for automatically getting the volume of a storage item from its max_w_class and max_combined_w_class. +#define AUTO_SCALE_STORAGE_VOLUME(w_class, max_combined_w_class) (AUTO_SCALE_VOLUME(w_class) * (max_combined_w_class / w_class)) + +// Let's keep all of this in one place. given what we put above anyways.. + +// volume amount for items +#define ITEM_VOLUME_DISK DEFAULT_VOLUME_TINY +#define ITEM_VOLUME_MOB 45//just over half of a duffelbag. Prevents mob_holder stacking in volumetric + +// #define SAMPLE_VOLUME_AMOUNT 2 + +// max_weight_class for storages +// +#define MAX_WEIGHT_CLASS_S_CONTAINER WEIGHT_CLASS_SMALL +#define MAX_WEIGHT_CLASS_M_CONTAINER WEIGHT_CLASS_NORMAL +#define MAX_WEIGHT_CLASS_BACKPACK WEIGHT_CLASS_BULKY + +// max_volume for storages +#define STORAGE_VOLUME_CONTAINER_M (DEFAULT_VOLUME_NORMAL * 2) +#define STORAGE_VOLUME_SATCHEL (DEFAULT_VOLUME_NORMAL * 6) +#define STORAGE_VOLUME_BACKPACK (DEFAULT_VOLUME_NORMAL * 7) +#define STORAGE_VOLUME_DUFFLEBAG (DEFAULT_VOLUME_NORMAL * 10) +#define STORAGE_VOLUME_BAG_OF_HOLDING (DEFAULT_VOLUME_NORMAL * 20) diff --git a/code/__HELPERS/_lists.dm b/code/__HELPERS/_lists.dm index 39dccd4e64d7..eb380a38d2af 100644 --- a/code/__HELPERS/_lists.dm +++ b/code/__HELPERS/_lists.dm @@ -16,7 +16,7 @@ #define LAZYREMOVE(L, I) if(L) { L -= I; if(!length(L)) { L = null; } } #define LAZYADD(L, I) if(!L) { L = list(); } L += I; #define LAZYOR(L, I) if(!L) { L = list(); } L |= I; -#define LAZYFIND(L, V) L ? L.Find(V) : 0 +#define LAZYFIND(L, V) (L ? L.Find(V) : 0) #define LAZYACCESS(L, I) (L ? (isnum(I) ? (I > 0 && I <= length(L) ? L[I] : null) : L[I]) : null) #define LAZYSET(L, K, V) if(!L) { L = list(); } L[K] = V; #define LAZYISIN(L, V) (L ? (V in L) : FALSE) diff --git a/code/_globalvars/bitfields.dm b/code/_globalvars/bitfields.dm index 406f0bb0b101..3d1c5778ee3c 100644 --- a/code/_globalvars/bitfields.dm +++ b/code/_globalvars/bitfields.dm @@ -263,6 +263,14 @@ DEFINE_BITFIELD(zap_flags, list( "ZAP_OBJ_DAMAGE" = ZAP_OBJ_DAMAGE, )) + +DEFINE_BITFIELD(storage_flags, list( + "STORAGE_LIMIT_MAX_ITEMS" = STORAGE_LIMIT_MAX_ITEMS, + "STORAGE_LIMIT_MAX_W_CLASS" = STORAGE_LIMIT_MAX_W_CLASS, + "STORAGE_LIMIT_COMBINED_W_CLASS" = STORAGE_LIMIT_COMBINED_W_CLASS, + "STORAGE_LIMIT_VOLUME" = STORAGE_LIMIT_VOLUME, +)) + DEFINE_BITFIELD(bodytype, list( "BODYTYPE_ORGANIC" = BODYTYPE_ORGANIC, "BODYTYPE_ROBOTIC" = BODYTYPE_ROBOTIC, diff --git a/code/_onclick/hud/screen_objects.dm b/code/_onclick/hud/screen_objects.dm index 557096d83c82..f82acb84c3cc 100644 --- a/code/_onclick/hud/screen_objects.dm +++ b/code/_onclick/hud/screen_objects.dm @@ -241,20 +241,20 @@ user.swap_hand(held_index) return TRUE -/atom/movable/screen/close - name = "close" - layer = ABOVE_HUD_LAYER - plane = ABOVE_HUD_PLANE - icon_state = "backpack_close" +// /atom/movable/screen/close +// name = "close" +// layer = ABOVE_HUD_LAYER +// plane = ABOVE_HUD_PLANE +// icon_state = "backpack_close" -/atom/movable/screen/close/Initialize(mapload, new_master) - . = ..() - master = new_master +// /atom/movable/screen/close/Initialize(mapload, new_master) +// . = ..() +// master = new_master -/atom/movable/screen/close/Click() - var/datum/component/storage/S = master - S.hide_from(usr) - return TRUE +// /atom/movable/screen/close/Click() +// var/datum/component/storage/S = master +// S.hide_from(usr) +// return TRUE /atom/movable/screen/drop name = "drop" @@ -437,30 +437,6 @@ icon_state = "[base_icon_state][user.resting ? 0 : null]" return ..() -/atom/movable/screen/storage - name = "storage" - icon_state = "block" - screen_loc = "7,7 to 10,8" - layer = HUD_LAYER - plane = HUD_PLANE - -/atom/movable/screen/storage/Initialize(mapload, new_master) - . = ..() - master = new_master - -/atom/movable/screen/storage/Click(location, control, params) - if(world.time <= usr.next_move) - return TRUE - if(usr.incapacitated()) - return TRUE - if (ismecha(usr.loc)) // stops inventory actions in a mech - return TRUE - if(master) - var/obj/item/I = usr.get_active_held_item() - if(I) - master.attackby(null, I, usr, params) - return TRUE - /atom/movable/screen/throw_catch name = "throw/catch" icon = 'icons/hud/screen_midnight.dmi' diff --git a/code/_onclick/hud/storage.dm b/code/_onclick/hud/storage.dm new file mode 100644 index 000000000000..55156d9b0de5 --- /dev/null +++ b/code/_onclick/hud/storage.dm @@ -0,0 +1,197 @@ +/atom/movable/screen/storage + name = "storage" + var/insertion_click = FALSE + +/atom/movable/screen/storage/Initialize(mapload, new_master) + . = ..() + master = new_master + +/atom/movable/screen/storage/Click(location, control, params) + if(!insertion_click) + return ..() + if(hud?.mymob && (hud.mymob != usr)) + return + // just redirect clicks + if(master) + var/obj/item/I = usr.get_active_held_item() + if(I) + master.attackby(null, I, usr, params) + return TRUE + +/atom/movable/screen/storage/boxes + name = "storage" + icon_state = "block" + screen_loc = "7,7 to 10,8" + layer = HUD_LAYER + plane = HUD_PLANE + insertion_click = TRUE + +/atom/movable/screen/storage/close + name = "close" + layer = ABOVE_HUD_LAYER + plane = ABOVE_HUD_PLANE + icon_state = "backpack_close" + +/atom/movable/screen/storage/close/Click() + var/datum/component/storage/S = master + S.close(usr) + return TRUE + +/atom/movable/screen/storage/left + icon_state = "storage_start" + insertion_click = TRUE + +/atom/movable/screen/storage/right + icon_state = "storage_end" + insertion_click = TRUE + +/atom/movable/screen/storage/continuous + icon_state = "storage_continue" + insertion_click = TRUE + +/atom/movable/screen/storage/volumetric_box + icon_state = "stored_continue" + layer = VOLUMETRIC_STORAGE_BOX_LAYER + plane = VOLUMETRIC_STORAGE_BOX_PLANE + var/obj/item/our_item + +/atom/movable/screen/storage/volumetric_box/Initialize(mapload, new_master, obj/item/our_item) + src.our_item = our_item + RegisterSignal(our_item, COMSIG_ITEM_MOUSE_ENTER, .proc/on_item_mouse_enter) + RegisterSignal(our_item, COMSIG_ITEM_MOUSE_EXIT, .proc/on_item_mouse_exit) + return ..() + +/atom/movable/screen/storage/volumetric_box/Destroy() + makeItemInactive() + our_item = null + return ..() + +/atom/movable/screen/storage/volumetric_box/Click(location, control, params) + return our_item.Click(location, control, params) + +/atom/movable/screen/storage/volumetric_box/MouseDrop(atom/over, src_location, over_location, src_control, over_control, params) + return our_item.MouseDrop(over, src_location, over_location, src_control, over_control, params) + +/atom/movable/screen/storage/volumetric_box/MouseExited(location, control, params) + makeItemInactive() + +/atom/movable/screen/storage/volumetric_box/MouseEntered(location, control, params) + makeItemActive() + +/atom/movable/screen/storage/volumetric_box/proc/on_item_mouse_enter() + makeItemActive() + +/atom/movable/screen/storage/volumetric_box/proc/on_item_mouse_exit() + makeItemInactive() + +/atom/movable/screen/storage/volumetric_box/proc/makeItemInactive() + return + +/atom/movable/screen/storage/volumetric_box/proc/makeItemActive() + return + +/atom/movable/screen/storage/volumetric_box/center + icon_state = "stored_continue" + var/atom/movable/screen/storage/volumetric_edge/stored_left/left + var/atom/movable/screen/storage/volumetric_edge/stored_right/right + var/atom/movable/screen/storage/item_holder/holder + var/pixel_size + +/atom/movable/screen/storage/volumetric_box/center/Initialize(mapload, new_master, our_item) + left = new(null, src, our_item) + right = new(null, src, our_item) + return ..() + +/atom/movable/screen/storage/volumetric_box/center/Destroy() + QDEL_NULL(left) + QDEL_NULL(right) + vis_contents.Cut() + if(holder) + QDEL_NULL(holder) + return ..() + +/atom/movable/screen/storage/volumetric_box/center/proc/on_screen_objects() + return list(src) + +/** + * Sets the size of this box screen object and regenerates its left/right borders. This includes the actual border's size! + */ +/atom/movable/screen/storage/volumetric_box/center/proc/set_pixel_size(pixels) + if(pixel_size == pixels) + return + pixel_size = pixels + cut_overlays() + vis_contents.Cut() + //our icon size is 32 pixels. + var/multiplier = (pixels - (VOLUMETRIC_STORAGE_BOX_BORDER_SIZE * 2)) / VOLUMETRIC_STORAGE_BOX_ICON_SIZE + transform = matrix(multiplier, 0, 0, 0, 1, 0) + if(our_item) + if(holder) + qdel(holder) + holder = new(null, src, our_item) + holder.transform = matrix(1 / multiplier, 0, 0, 0, 1, 0) + holder.mouse_opacity = MOUSE_OPACITY_TRANSPARENT + holder.appearance_flags &= ~RESET_TRANSFORM + makeItemInactive() + vis_contents += holder + left.pixel_x = -((pixels - VOLUMETRIC_STORAGE_BOX_ICON_SIZE) * 0.5) - VOLUMETRIC_STORAGE_BOX_BORDER_SIZE + right.pixel_x = ((pixels - VOLUMETRIC_STORAGE_BOX_ICON_SIZE) * 0.5) + VOLUMETRIC_STORAGE_BOX_BORDER_SIZE + add_overlay(left) + add_overlay(right) + +/atom/movable/screen/storage/volumetric_box/center/makeItemInactive() + if(!holder) + return + holder.layer = VOLUMETRIC_STORAGE_ITEM_LAYER + holder.plane = VOLUMETRIC_STORAGE_ITEM_PLANE + +/atom/movable/screen/storage/volumetric_box/center/makeItemActive() + if(!holder) + return + holder.our_item.layer = VOLUMETRIC_STORAGE_ACTIVE_ITEM_LAYER //make sure we display infront of the others! + holder.our_item.plane = VOLUMETRIC_STORAGE_ACTIVE_ITEM_PLANE + +/atom/movable/screen/storage/volumetric_edge + layer = VOLUMETRIC_STORAGE_BOX_LAYER + plane = VOLUMETRIC_STORAGE_BOX_PLANE + +/atom/movable/screen/storage/volumetric_edge/Initialize(mapload, master, our_item) + src.master = master + return ..() + +/atom/movable/screen/storage/volumetric_edge/Click(location, control, params) + return master.Click(location, control, params) + +/atom/movable/screen/storage/volumetric_edge/MouseDrop(atom/over, src_location, over_location, src_control, over_control, params) + return master.MouseDrop(over, src_location, over_location, src_control, over_control, params) + +/atom/movable/screen/storage/volumetric_edge/MouseExited(location, control, params) + return master.MouseExited(location, control, params) + +/atom/movable/screen/storage/volumetric_edge/MouseEntered(location, control, params) + return master.MouseEntered(location, control, params) + +/atom/movable/screen/storage/volumetric_edge/stored_left + icon_state = "stored_start" + appearance_flags = APPEARANCE_UI | KEEP_APART | RESET_TRANSFORM // Yes I know RESET_TRANSFORM is in APPEARANCE_UI but we're hard-asserting this incase someone changes it. + +/atom/movable/screen/storage/volumetric_edge/stored_right + icon_state = "stored_end" + appearance_flags = APPEARANCE_UI | KEEP_APART | RESET_TRANSFORM + +/atom/movable/screen/storage/item_holder + var/obj/item/our_item + vis_flags = NONE + +/atom/movable/screen/storage/item_holder/Initialize(mapload, new_master, obj/item/I) + . = ..() + our_item = I + vis_contents += I + +/atom/movable/screen/storage/item_holder/Destroy() + vis_contents.Cut() + our_item = null + return ..() + +/atom/movable/screen/storage/item_holder/Click(location, control, params) + return our_item.Click(location, control, params) diff --git a/code/datums/components/storage/concrete/_concrete.dm b/code/datums/components/storage/concrete/_concrete.dm index 4198ba5b974d..b182ecce5bc9 100644 --- a/code/datums/components/storage/concrete/_concrete.dm +++ b/code/datums/components/storage/concrete/_concrete.dm @@ -57,7 +57,7 @@ _contents_limbo = null if(_user_limbo) for(var/i in _user_limbo) - show_to(i) + ui_show(i) _user_limbo = null /datum/component/storage/concrete/_insert_physical_item(obj/item/I, override = FALSE) diff --git a/code/datums/components/storage/concrete/rped.dm b/code/datums/components/storage/concrete/rped.dm index 455eb985f090..58a520d3a7bd 100644 --- a/code/datums/components/storage/concrete/rped.dm +++ b/code/datums/components/storage/concrete/rped.dm @@ -6,6 +6,7 @@ max_w_class = WEIGHT_CLASS_NORMAL max_combined_w_class = 100 max_items = 50 + storage_flags = STORAGE_FLAGS_LEGACY_DEFAULT display_numerical_stacking = TRUE /datum/component/storage/concrete/rped/can_be_inserted(obj/item/I, stop_messages, mob/M) diff --git a/code/datums/components/storage/concrete/stack.dm b/code/datums/components/storage/concrete/stack.dm index 319d1d4b3d41..19ea4fa58584 100644 --- a/code/datums/components/storage/concrete/stack.dm +++ b/code/datums/components/storage/concrete/stack.dm @@ -1,6 +1,7 @@ //Stack-only storage. /datum/component/storage/concrete/stack display_numerical_stacking = TRUE + storage_flags = STORAGE_FLAGS_LEGACY_DEFAULT var/max_combined_stack_amount = 300 max_w_class = WEIGHT_CLASS_NORMAL max_combined_w_class = WEIGHT_CLASS_NORMAL * 14 diff --git a/code/datums/components/storage/storage.dm b/code/datums/components/storage/storage.dm index f10332a3129a..66e054e06d43 100644 --- a/code/datums/components/storage/storage.dm +++ b/code/datums/components/storage/storage.dm @@ -26,9 +26,16 @@ var/locked = FALSE //when locked nothing can see inside or use it. var/locked_flavor = "locked" //prevents tochat messages related to locked from sending - var/max_w_class = WEIGHT_CLASS_SMALL //max size of objects that will fit. - var/max_combined_w_class = 14 //max combined sizes of objects that will fit. - var/max_items = 7 //max number of objects that will fit. + /// Storage flags, including what kinds of limiters we use for how many items we can hold + var/storage_flags = STORAGE_FLAGS_LEGACY_DEFAULT + /// Max w_class we can hold. Applies to [STORAGE_LIMIT_COMBINED_W_CLASS] and [STORAGE_LIMIT_VOLUME] + var/max_w_class = WEIGHT_CLASS_SMALL + /// Max combined w_class. Applies to [STORAGE_LIMIT_COMBINED_W_CLASS] + var/max_combined_w_class = WEIGHT_CLASS_SMALL * 7 + /// Max items we can hold. Applies to [STORAGE_LIMIT_MAX_ITEMS] + var/max_items = 7 + /// Max volume we can hold. Applies to [STORAGE_LIMIT_VOLUME]. Auto scaled on New() if unset. + var/max_volume var/emp_shielded = FALSE @@ -44,8 +51,8 @@ var/display_numerical_stacking = FALSE //stack things of the same type and show as a single object with a number. - var/atom/movable/screen/storage/boxes //storage display object - var/atom/movable/screen/close/closer //close button object + /// Ui objects by person. mob = list(objects) + var/list/ui_by_mob = list() var/allow_big_nesting = FALSE //allow storage objects of the same or greater size. @@ -63,14 +70,15 @@ var/screen_start_y = 2 //End + var/limited_random_access = FALSE //Quick if statement in accessible_items to determine if we care at all about what people can access at once. + var/limited_random_access_stack_position = 0 //If >0, can only access top items + var/limited_random_access_stack_bottom_up = FALSE + /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) @@ -113,11 +121,16 @@ /datum/component/storage/Destroy() close_all() - QDEL_NULL(boxes) - QDEL_NULL(closer) + wipe_ui_objects() LAZYCLEARLIST(is_using) return ..() +/datum/component/storage/proc/wipe_ui_objects() + for(var/i in ui_by_mob) + var/list/objects = ui_by_mob[i] + QDEL_LIST(objects) + ui_by_mob.Cut() + /datum/component/storage/PreTransfer() update_actions() @@ -171,6 +184,19 @@ var/datum/component/storage/concrete/master = master() return master? master.real_location() : null +//What players can access +//this proc can probably eat a refactor at some point. +/datum/component/storage/proc/accessible_items(random_access = TRUE) + var/list/contents = contents() + if(contents) + if(limited_random_access && random_access) + if(limited_random_access_stack_position && (length(contents) > limited_random_access_stack_position)) + if(limited_random_access_stack_bottom_up) + contents.Cut(1, limited_random_access_stack_position + 1) + else + contents.Cut(1, length(contents) - limited_random_access_stack_position + 1) + return contents + /datum/component/storage/proc/canreach_react(datum/source, list/next) SIGNAL_HANDLER @@ -189,7 +215,7 @@ var/atom/A = parent for(var/mob/living/L in can_see_contents()) if(!L.CanReach(A)) - hide_from(L) + ui_hide(L) /datum/component/storage/proc/attack_self(datum/source, mob/M) SIGNAL_HANDLER @@ -312,7 +338,7 @@ if(!_target) _target = get_turf(parent) if(usr) - hide_from(usr) + ui_hide(usr) var/list/contents = contents() var/atom/real_location = real_location() for(var/obj/item/I in contents) @@ -328,109 +354,12 @@ 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 = "[(ND.number > 1)? "[ND.number]" : ""]" - ND.sample_object.layer = ABOVE_HUD_LAYER - 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.layer = ABOVE_HUD_LAYER - 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) - 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() - M.client.screen -= boxes - M.client.screen -= closer - M.client.screen -= real_location.contents - return TRUE + ui_hide(source) /datum/component/storage/proc/close(mob/M) - hide_from(M) + ui_hide(usr) /datum/component/storage/proc/close_all() SIGNAL_HANDLER @@ -448,25 +377,6 @@ 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.layer = ABOVE_HUD_LAYER - 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)) @@ -477,9 +387,7 @@ return master._removal_reset(thing) /datum/component/storage/proc/_remove_and_refresh(datum/source, atom/movable/thing) - SIGNAL_HANDLER - - _removal_reset(thing) + _removal_reset(thing) // THIS NEEDS TO HAPPEN AFTER SO LAYERING DOESN'T BREAK! 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 @@ -496,7 +404,7 @@ var/list/seeing = can_see_contents() for(var/i in seeing) - show_to(i) + ui_show(i) return TRUE /datum/component/storage/proc/can_see_contents() @@ -615,7 +523,7 @@ to_chat(M, "[parent] seems to be [locked_flavor]!") return FALSE if(force || M.CanReach(parent, view_only = TRUE)) - show_to(M) + ui_show(M) /datum/component/storage/proc/mousedrop_receive(datum/source, atom/movable/O, mob/M) SIGNAL_HANDLER @@ -644,10 +552,6 @@ host.add_fingerprint(M) to_chat(M, "[host] seems to be [locked_flavor]!") return FALSE - if(real_location.contents.len >= max_items) - if(!stop_messages) - to_chat(M, "[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) @@ -657,22 +561,34 @@ if(!stop_messages) to_chat(M, "[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, "[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, "[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, "[I] won't fit in [host], make some space!") - return FALSE + // STORAGE LIMITS + if(storage_flags & STORAGE_LIMIT_MAX_ITEMS) + if(real_location.contents.len >= max_items) + if(!stop_messages) + to_chat(M, "[host] has too much junk in it, make some space!") + return FALSE //Storage item is full + if(storage_flags & STORAGE_LIMIT_MAX_W_CLASS) + if(I.w_class > max_w_class) + if(!stop_messages) + to_chat(M, "[I] is much too long for [host]!") + return FALSE + if(storage_flags & STORAGE_LIMIT_COMBINED_W_CLASS) + 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, "[I] won't fit in [host], make some space!") + return FALSE + if(storage_flags & STORAGE_LIMIT_VOLUME) + var/sum_volume = I.get_w_volume() + for(var/obj/item/_I in real_location) + sum_volume += _I.get_w_volume() + if(sum_volume > get_max_volume()) + if(!stop_messages) + to_chat(M, "[I] is too large to 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) @@ -822,7 +738,7 @@ if(locked) to_chat(user, "[parent] seems to be [locked_flavor]!") else - show_to(user) + ui_show(user) if(use_sound) playsound(A, use_sound, 50, TRUE, -5) @@ -848,7 +764,7 @@ /datum/component/storage/proc/signal_hide_attempt(datum/source, mob/target) SIGNAL_HANDLER - return hide_from(target) + return ui_hide(target) /datum/component/storage/proc/on_alt_click(datum/source, mob/user) SIGNAL_HANDLER @@ -895,3 +811,9 @@ to_chat(user, "[parent] now picks up all items in a tile at once.") if(COLLECT_ONE) to_chat(user, "[parent] now picks up one item at a time.") + +/** + * Gets our max volume + */ +/datum/component/storage/proc/get_max_volume() + return max_volume || AUTO_SCALE_STORAGE_VOLUME(max_w_class, max_combined_w_class) diff --git a/code/datums/components/storage/ui.dm b/code/datums/components/storage/ui.dm new file mode 100644 index 000000000000..e03b8132bc8f --- /dev/null +++ b/code/datums/components/storage/ui.dm @@ -0,0 +1,273 @@ +/** + * Generates a list of numbered_display datums for the numerical display system. + */ +/datum/component/storage/proc/_process_numerical_display() + . = list() + for(var/obj/item/I in accessible_items()) + if(QDELETED(I)) + continue + if(!.[I.type]) + .[I.type] = new /datum/numbered_display(I, 1, src) + else + var/datum/numbered_display/ND = .[I.type] + ND.number++ + +/** + * Orients all objects in legacy mode, and returns the objects to show to the user. + */ +/datum/component/storage/proc/orient2hud_legacy(mob/user, maxcolumns) + . = list() + var/list/accessible_contents = accessible_items() + var/adjusted_contents = length(accessible_contents) + var/atom/movable/screen/storage/close/ui_close + var/atom/movable/screen/storage/boxes/ui_boxes + + //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, maxcolumns ? maxcolumns : screen_max_columns) + var/rows = clamp(CEILING(adjusted_contents / columns, 1), 1, screen_max_rows) + + // First, boxes. + ui_boxes = get_ui_boxes() + ui_boxes.screen_loc = "[screen_start_x]:[screen_pixel_x],[screen_start_y]:[screen_pixel_y] to [screen_start_x+columns-1]:[screen_pixel_x],[screen_start_y+rows-1]:[screen_pixel_y]" + . += ui_boxes + // Then, closer. + ui_close = get_ui_close() + ui_close.screen_loc = "[screen_start_x + columns]:[screen_pixel_x],[screen_start_y]:[screen_pixel_y]" + . += ui_close + // Then orient the actual items. + var/cx = screen_start_x + var/cy = screen_start_y + if(islist(numbered_contents)) + for(var/type in numbered_contents) + var/datum/numbered_display/ND = numbered_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 = "[(ND.number > 1)? "[ND.number]" : ""]" + ND.sample_object.layer = ABOVE_HUD_LAYER + ND.sample_object.plane = ABOVE_HUD_PLANE + . += ND.sample_object + cx++ + if(cx - screen_start_x >= columns) + cx = screen_start_x + cy++ + if(cy - screen_start_y >= rows) + break + else + for(var/obj/O in accessible_items()) + if(QDELETED(O)) + continue + var/atom/movable/screen/storage/item_holder/D = new(null, src, O) + D.mouse_opacity = MOUSE_OPACITY_OPAQUE //This is here so storage items that spawn with contents correctly have the "click around item to equip" + D.screen_loc = "[cx]:[screen_pixel_x],[cy]:[screen_pixel_y]" + O.maptext = "" + O.layer = ABOVE_HUD_LAYER + O.plane = ABOVE_HUD_PLANE + . += D + cx++ + if(cx - screen_start_x >= columns) + cx = screen_start_x + cy++ + if(cy - screen_start_y >= rows) + break + +/** + * Orients all objects in .. volumetric mode. Does not support numerical display! + */ +/datum/component/storage/proc/orient2hud_volumetric(mob/user, maxcolumns) + . = list() + var/atom/movable/screen/storage/left/ui_left + var/atom/movable/screen/storage/continuous/ui_continuous + var/atom/movable/screen/storage/close/ui_close + + // Generate ui_item_blocks for missing ones and render+orient. + var/list/atom/contents = accessible_items() + // our volume + var/our_volume = get_max_volume() + var/horizontal_pixels = (maxcolumns * world.icon_size) - (VOLUMETRIC_STORAGE_EDGE_PADDING * 2) + var/max_horizontal_pixels = horizontal_pixels * screen_max_rows + // sigh loopmania time + var/used = 0 + // define outside for performance + var/volume + var/list/volume_by_item = list() + var/list/percentage_by_item = list() + for(var/obj/item/I in contents) + if(QDELETED(I)) + continue + volume = I.get_w_volume() + used += volume + volume_by_item[I] = volume + percentage_by_item[I] = volume / get_max_volume() + var/padding_pixels = ((length(percentage_by_item) - 1) * VOLUMETRIC_STORAGE_ITEM_PADDING) + VOLUMETRIC_STORAGE_EDGE_PADDING * 2 + var/min_pixels = (MINIMUM_PIXELS_PER_ITEM * length(percentage_by_item)) + padding_pixels + // do the check for fallback for when someone has too much gamer gear + if((min_pixels) > (max_horizontal_pixels + 4)) // 4 pixel grace zone + to_chat(user, "[parent] was showed to you in legacy mode due to your items overrunning the three row limit! Consider not carrying too much or bugging a maintainer to raise this limit!") + return orient2hud_legacy(user, maxcolumns) + // after this point we are sure we can somehow fit all items into our max number of rows. + + // determine rows + var/rows = clamp(CEILING(min_pixels / horizontal_pixels, 1), 1, screen_max_rows) + + var/overrun = FALSE + if(used > our_volume) + // congratulations we are now in overrun mode. everything will be crammed to minimum storage pixels. + to_chat(user, "[parent] rendered in overrun mode due to more items inside than the maximum volume supports.") + overrun = TRUE + + // how much we are using + var/using_horizontal_pixels = horizontal_pixels * rows + + // item padding + using_horizontal_pixels -= padding_pixels + + // define outside for marginal performance boost + var/obj/item/I + // start at this pixel from screen_start_x. + var/current_pixel = VOLUMETRIC_STORAGE_EDGE_PADDING + var/row = 1 + var/first = TRUE + + for(var/i in percentage_by_item) + I = i + var/percent = percentage_by_item[I] + var/atom/movable/screen/storage/volumetric_box/center/B = new /atom/movable/screen/storage/volumetric_box/center(null, src, I) + var/pixels_to_use = overrun? MINIMUM_PIXELS_PER_ITEM : max(using_horizontal_pixels * percent, MINIMUM_PIXELS_PER_ITEM) + var/addrow = FALSE + if(CEILING(pixels_to_use, 1) >= FLOOR(horizontal_pixels - current_pixel - VOLUMETRIC_STORAGE_EDGE_PADDING, 1)) + pixels_to_use = horizontal_pixels - current_pixel - VOLUMETRIC_STORAGE_EDGE_PADDING + addrow = TRUE + + // now that we have pixels_to_use, place our thing and add it to the returned list. + + B.screen_loc = "[screen_start_x]:[round(current_pixel + (pixels_to_use * 0.5) + (first? 0 : VOLUMETRIC_STORAGE_ITEM_PADDING), 1)],[screen_start_y+row-1]:[screen_pixel_y]" + // add the used pixels to pixel after we place the object + current_pixel += pixels_to_use + VOLUMETRIC_STORAGE_ITEM_PADDING + + // set various things + B.set_pixel_size(pixels_to_use) + B.name = I.name + + // finally add our things. + . += B.on_screen_objects() + + // go up a row if needed + if(addrow) + row++ + current_pixel = VOLUMETRIC_STORAGE_EDGE_PADDING + + // Then, continuous section. + ui_continuous = get_ui_continuous() + ui_continuous.screen_loc = "[screen_start_x]:[screen_pixel_x],[screen_start_y]:[screen_pixel_y] to [screen_start_x+maxcolumns-1]:[screen_pixel_x],[screen_start_y+rows-1]:[screen_pixel_y]" + . += ui_continuous + // Then, left. + ui_left = get_ui_left() + ui_left.screen_loc = "[screen_start_x]:[screen_pixel_x - 2],[screen_start_y]:[screen_pixel_y] to [screen_start_x]:[screen_pixel_x - 2],[screen_start_y+rows-1]:[screen_pixel_y]" + . += ui_left + // Then, closer, which is also our right element. + ui_close = get_ui_close() + ui_close.screen_loc = "[screen_start_x + maxcolumns]:[screen_pixel_x],[screen_start_y]:[screen_pixel_y] to [screen_start_x + maxcolumns]:[screen_pixel_x],[screen_start_y + row - 1]:[screen_pixel_y]" + . += ui_close + +/** + * Shows our UI to a mob. + */ +/datum/component/storage/proc/ui_show(mob/M) + if(!M.client) + return FALSE + if(ui_by_mob[M] || LAZYFIND(is_using, M)) + // something went horribly wrong + // hide first + ui_hide(M) + var/list/cview = getviewsize(M.client.view) + // in tiles + var/maxallowedscreensize = cview[1]-8 + // we got screen size, register signal + RegisterSignal(M, COMSIG_PARENT_QDELETING, .proc/on_logout, override = TRUE) + if(M.active_storage != src) + if(M.active_storage) + M.active_storage.ui_hide(M) + M.active_storage = src + LAZYOR(is_using, M) + if(volumetric_ui()) + //new volumetric ui bay-style + var/list/objects = orient2hud_volumetric(M, maxallowedscreensize) + M.client.screen |= objects + ui_by_mob[M] = objects + else + //old ui + var/list/objects = orient2hud_legacy(M, maxallowedscreensize) + M.client.screen |= objects + ui_by_mob[M] = objects + return TRUE + +/** + * VV hooked to ensure no lingering screen objects. + */ +/datum/component/storage/vv_edit_var(var_name, var_value) + var/list/old + if(var_name == NAMEOF(src, storage_flags)) + old = is_using.Copy() + for(var/i in is_using) + ui_hide(i) + . = ..() + if(old) + for(var/i in old) + ui_show(i) + +/** + * Proc triggered by signal to ensure logging out clients don't linger. + */ +/datum/component/storage/proc/on_logout(datum/source, client/C) + ui_hide(source) + +/** + * Hides our UI from a mob + */ +/datum/component/storage/proc/ui_hide(mob/M) + if(!M.client) + return TRUE + UnregisterSignal(M, list(COMSIG_PARENT_QDELETING)) + M.client.screen -= ui_by_mob[M] + var/list/objects = ui_by_mob[M] + QDEL_LIST(objects) + if(M.active_storage == src) + M.active_storage = null + LAZYREMOVE(is_using, M) + return TRUE + +/** + * Returns TRUE if we are using volumetric UI instead of box UI + */ +/datum/component/storage/proc/volumetric_ui() + var/atom/real_location = real_location() + return (storage_flags & STORAGE_LIMIT_VOLUME) && (length(real_location.contents) <= MAXIMUM_VOLUMETRIC_ITEMS) && !display_numerical_stacking + +/** + * Gets our ui_boxes, making it if it doesn't exist. + */ +/datum/component/storage/proc/get_ui_boxes() + return new /atom/movable/screen/storage/boxes(null, src) + +/** + * Gets our ui_left, making it if it doesn't exist. + */ +/datum/component/storage/proc/get_ui_left() + return new /atom/movable/screen/storage/left(null, src) + +/** + * Gets our ui_close, making it if it doesn't exist. + */ +/datum/component/storage/proc/get_ui_close() + return new /atom/movable/screen/storage/close(null, src) + +/** + * Gets our ui_continuous, making it if it doesn't exist. + */ +/datum/component/storage/proc/get_ui_continuous() + return new /atom/movable/screen/storage/continuous(null, src) diff --git a/code/datums/numbered_display.dm b/code/datums/numbered_display.dm index 9aa880aa75d9..b714be23fbbe 100644 --- a/code/datums/numbered_display.dm +++ b/code/datums/numbered_display.dm @@ -3,8 +3,8 @@ var/obj/item/sample_object var/number -/datum/numbered_display/New(obj/item/sample, _number = 1) +/datum/numbered_display/New(obj/item/sample, _number = 1, datum/component/storage/parent) if(!istype(sample)) qdel(src) - sample_object = sample + sample_object = new /atom/movable/screen/storage/item_holder(null, parent, sample) number = _number diff --git a/code/game/atoms.dm b/code/game/atoms.dm index 4628bb22f92f..68d2fbe1f67e 100644 --- a/code/game/atoms.dm +++ b/code/game/atoms.dm @@ -948,11 +948,8 @@ stoplag(1) progress.end_progress() to_chat(user, "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) 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.ui_show(user) return TRUE ///Get the best place to dump the items contained in the source storage item? diff --git a/code/game/objects/items.dm b/code/game/objects/items.dm index e13cca64caf9..45bd268134cc 100644 --- a/code/game/objects/items.dm +++ b/code/game/objects/items.dm @@ -69,8 +69,11 @@ GLOBAL_VAR_INIT(embedpocalypse, FALSE) // if true, all items will be able to emb ///Whether or not we use stealthy audio levels for this item's attack sounds var/stealthy_audio = FALSE - ///How large is the object, used for stuff like whether it can fit in backpacks or not + /// Weight class for how much storage capacity it uses and how big it physically is meaning storages can't hold it if their maximum weight class isn't as high as it. var/w_class = WEIGHT_CLASS_NORMAL + /// Volume override for the item, otherwise automatically calculated from w_class. + var/w_volume + ///This is used to determine on which slots an item can fit. var/slot_flags = 0 pass_flags = PASSTABLE @@ -863,11 +866,15 @@ GLOBAL_VAR_INIT(embedpocalypse, FALSE) // if true, all items will be able to emb . = ..() remove_outline() -/obj/item/MouseExited() +/obj/item/MouseExited(location,control,params) + SEND_SIGNAL(src, COMSIG_ITEM_MOUSE_EXIT, location, control, params) deltimer(tip_timer)//delete any in-progress timer if the mouse is moved off the item before it finishes closeToolTip(usr) remove_outline() +/obj/item/MouseEntered(location,control,params) + SEND_SIGNAL(src, COMSIG_ITEM_MOUSE_ENTER, location, control, params) + /obj/item/proc/apply_outline(colour = null) if(!(item_flags & IN_INVENTORY || item_flags & IN_STORAGE) || QDELETED(src) || isobserver(usr)) return @@ -986,6 +993,11 @@ GLOBAL_VAR_INIT(embedpocalypse, FALSE) // if true, all items will be able to emb dropped(M, FALSE) return ..() +/// Get an item's volume that it uses when being stored. +/obj/item/proc/get_w_volume() + // if w_volume is 0 you fucked up. + return w_volume || AUTO_SCALE_VOLUME(w_class) + /obj/item/proc/embedded(mob/living/carbon/human/embedded_mob) return diff --git a/code/game/objects/items/storage/backpack.dm b/code/game/objects/items/storage/backpack.dm index 05321933bfe2..cdd43be55c32 100644 --- a/code/game/objects/items/storage/backpack.dm +++ b/code/game/objects/items/storage/backpack.dm @@ -31,9 +31,9 @@ /obj/item/storage/backpack/ComponentInitialize() . = ..() 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 + STR.storage_flags = STORAGE_FLAGS_VOLUME_DEFAULT + STR.max_volume = STORAGE_VOLUME_BACKPACK + STR.max_w_class = MAX_WEIGHT_CLASS_BACKPACK STR.use_sound = 'sound/items/storage/unzip.ogg' /* @@ -58,9 +58,8 @@ /obj/item/storage/backpack/holding/ComponentInitialize() . = ..() 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 + STR.storage_flags = STORAGE_FLAGS_VOLUME_DEFAULT + STR.max_volume = STORAGE_VOLUME_BAG_OF_HOLDING /obj/item/storage/backpack/santabag name = "Santa's Gift Bag" @@ -223,6 +222,12 @@ greyscale_colors = list(list(11, 12), list(17, 18), list(10, 11)) supports_variations = VOX_VARIATION +/obj/item/storage/backpack/satchel/ComponentInitialize() + . = ..() + var/datum/component/storage/STR = GetComponent(/datum/component/storage) + STR.max_volume = STORAGE_VOLUME_SATCHEL + STR.max_w_class = MAX_WEIGHT_CLASS_M_CONTAINER + /obj/item/storage/backpack/satchel/leather name = "leather satchel" desc = "It's a very fancy satchel made with fine leather." @@ -442,7 +447,7 @@ /obj/item/storage/backpack/duffelbag/ComponentInitialize() . = ..() var/datum/component/storage/STR = GetComponent(/datum/component/storage) - STR.max_combined_w_class = 30 + STR.max_volume = STORAGE_VOLUME_DUFFLEBAG LAZYINITLIST(STR.exception_hold) // This code allows you to fit one mob holder into a duffel bag STR.exception_hold += typecacheof(/obj/item/clothing/head/mob_holder) diff --git a/code/game/objects/items/storage/bags.dm b/code/game/objects/items/storage/bags.dm index 910ea174c3a6..6cf80ed6dd80 100644 --- a/code/game/objects/items/storage/bags.dm +++ b/code/game/objects/items/storage/bags.dm @@ -46,9 +46,11 @@ . = ..() 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.max_combined_w_class = 50 + STR.max_items = 50 STR.set_holdable(null, list(/obj/item/disk/nuclear)) + STR.limited_random_access = TRUE + STR.limited_random_access_stack_position = 5 /obj/item/storage/bag/trash/update_icon_state() switch(contents.len) @@ -83,8 +85,8 @@ /obj/item/storage/bag/trash/bluespace/ComponentInitialize() . = ..() var/datum/component/storage/STR = GetComponent(/datum/component/storage) - STR.max_combined_w_class = 60 - STR.max_items = 60 + STR.max_combined_w_class = 75 + STR.max_items = 75 /obj/item/storage/bag/trash/bluespace/cyborg insertable = FALSE diff --git a/code/modules/mob/living/inhand_holder.dm b/code/modules/mob/living/inhand_holder.dm index e16dcf9e3326..f593a269cbd6 100644 --- a/code/modules/mob/living/inhand_holder.dm +++ b/code/modules/mob/living/inhand_holder.dm @@ -7,7 +7,8 @@ icon_state = "" slot_flags = NONE moth_edible = FALSE - w_class = 20 // so that only one can fit in a duffel bag + w_class = WEIGHT_CLASS_BULKY + w_volume = ITEM_VOLUME_MOB// so that only one can fit in a duffel bag var/mob/living/held_mob /obj/item/clothing/head/mob_holder/Initialize(mapload, mob/living/M, worn_state, head_icon, lh_icon, rh_icon, worn_slot_flags = NONE) diff --git a/icons/hud/screen_gen.dmi b/icons/hud/screen_gen.dmi index cad55a6ea29084c3bcc9f9dad9d2c4728caff208..b26bc7375dbb0d152efcc8e2cd61a773985cc4f5 100644 GIT binary patch delta 19466 zcmcG#XH*nTv@Sddg1kyrL6jg86qG?l@(?6vkR%x-=O8&X0t$$TWJyC5Br7=%K_us# za~_5vGcW^loA;dW-h0+}*8O$wk6G2-)m6Q#YS**(es)cHF>z}d@i$sv@dhyj0vVfc zC51qU*nKqLx=C5QH*>XdcC&GEgh0Gf`;wHMW@IQo4Gfo>#1?*=u1KpPVR$pCOvd|U zQ1S!(uH(Jc6Rn0jt^0J_0X}tjrz5_ zg4o-I?(S#1_O+AV`UaIi3HSC|YbM%Y3g318A8q7zWYl%RYiW(T+(jD(#f67!@BUCa z_eP&} zLH2YG%jJU|VFsofTVi;E8m4jqaR%O_pacE08wEle?CgRD}0pVyn*)%Z>7~XG7t9tWY_jsEWr2+ z;~jpNYw2nsG~wqVEU5(oDjcohtt;TA0ITZb*237Ry^AhcjKtTydb^K}94TSFeW;H6 zeNPTL@s}GYrY3)!qWfMaZOphS_X`_T+!w12?ow6!k-EJL&E%GMg3s z>7?|ax8v-6`1Z_WT&P#Ny%R!m&x}Fl)31@Y8m8ne-Tz%5H#|5kR4cCOh1T|tej^}% z`N}Wk(=Ai}nE}5@$zK{9otdU7`40&nSlVK4klkx_tV%zl4>idnua^A7rvXS33-pfe zQPIB$nX?x=d_~@pOeQJpf`kcpblm8Igqnr;6@9y9>Y3W{=;NuYt9=HF#M*b{O>$k1 z=%1TvPMXhRWn*H<``DgD@=Hhj{cr@wabF$n(>CbTcqt7ujH4oXa zv7cX%e`=BKopO89WtgXvEHg5A?WSOgNHnA~DlYCznNVEe7?y@7rzEMS`iUX!qP^AVWp-!M&W+L=o|b z?yfV79T{(~rMs&gKPqA`P)rYltfct@t!aAT_f@(+Y4W~AefzMABVK)e`7Aw>j`-T& zDq9WfnA$tls0j99BiCs8#g5kZeK;7buxC_;h5 zKOhL^Y>oL=R493u=M8(CtuEXY^=s;L;3%}H*|LwvZbwf>EkCgIo#aJ>NZrh|WNfbnC~8r?8ezh&A+d-%mYoeAZD zOF=4%Kq=G5)I`Ni3P)9Xxp+3w{ctC7=3=OwfBn#mZPH~Tri~-OqDl<^k;eJ>upZjR zahcJ9{~U@r7rT3`8V=SX9-Y$$Ft5`vEYqZ8!tMPpxlRKo9zFyfitdvLB9I{>B_x6W zzUBf8Y~v8!Pvbc|gQf)n9+!UmNnVucnBWKasPzHb#PI5gkYG$3(;mi%hH;q&XkM8) z$K5X^!0+JB4%~b#i8W@P(&Ozw2?E=7NNcw++ty8+s*bsrrc_s*G>y#YxcTN%-vyfn zuFL?JxD8RNsN{8}i`5cp@(c8cQzKjAKsuB!*Q|%e_yQa$R`611-ls6ux#Qy1U7$Jd z!z0ms|MpWD+5P=+vCe%%zsvW1ge3#MMKNC*qFzSdx{{UA_}H~thOq0e){0T#ep5`g6bl7O zBf@YLB>OAN1vA_$9hGL?l75D8(>NgKFJ6H)U|hVn2n*m=m^Q3Gz)I(Urc_`h@^U#H z2tanP_Zdy^#|M*0ORf4G1A{KYntp%Xg)bF_FAq9hbx;^+^o6Qz$60BkCEMi&#phI} zazAZh_~fi@My6)jM|VA~6ITC=`WS9hvde99N5V%gI>O>+6y_QQ?&5JsmAI!y470HbqrdIM|`(t9{hXjCDi zX>9DjmFMv1D3JF`QQ22wArQnWeaQ7@>ZS!CKJVcdY!Fa4hjlRH3v1YS=xdMRK=e)V zgsI|+Fzr^71Q3YKy%drMpo1XJ$3hIF*uUgpd znt@*cFpacK5QzCpcpxFzNKS@K04x?MN&lY}gGu?Pj--FOsT?VShNA#b!C~zb)pBc? z7SwCMWtyg(-^h~U(N7FfA`0MbI_6a*6T1OlXr>&J`qSJ*cJ=Yvxj&2Pn1XnIO8jBA$bS><01P^j|Cz)( ze!UE42H{5)m;86Ykg$Y0$bxDkI*=SYYdUO-gGeoG%5e{^~3Sb6o9TLZEmJd$Ga>j zLm<$gwMiW1a9xhnNY+I2D{M6XnJ}R+{IK_ZkGk z49J@~JTj=X)!H~g_+wMqmo`ApZ>hA%V6OHeg3vdOeF+UPFZWAF?2 zj#ho=8@$2UvK=cZVRT73TE%{;MN?5l8|&8A70S-C!_JHva*j{S$mU?nozQY3i=8?< zF4%8jM(>K@XsUnrz?F7#AOIvrUh@FvG%q6PeUKALnXh@^-#&ZVS)UiMD}qo!&_byM zecHS+i0I_NC__&N41UK;(~(?1{ey4txUb-@$FRTaT&3w01;PK;DH0RtP^+l6OBU3h zqCa;x$@@?iv}-Bi|L*52;~I_@3K;E*_Cw5gGny@c|^4kZDKGFlfQV7mB;4>5yAJSl$PEy zxep(VQat*fouKg;+l(KggbE$g}bMH>js|Ke6_GpRz2)&f?<>*TAVy za#ugCO(y%B*uz&r93TUAk*|%ax|2r6?s=_*!cDFEu*438{j1IV@2vM=Tr?H>-IL~J*Ado_cl$G zCO9@+)=He@=@RXkU@Qk8RWZ*bYLWUcr`+aa==wvz05M}I7VVEc2@i8qP|H$*i%eC1 z^-+pvHBdzWE+(a6azGvt+xDD>7+Oyjmb(zMC&aN>u%RFSXH~v+0Eek$;5gYUIF-CU)&siKdO6Fuk0$cRebvboy#8|?E|Kt03xiC@Jd#~JP!s%qs# zlw1Tli@|$&#$GlW!}lN9f;&scdv9Ubr=P!ir6m{;@A3VMaV`T11tTwGlbo=9`@je} z?f%HL%l7CKtNoSfrALTn59(3`~k8#m)KR?kSm zDB5HYI1|GDSVrz7x(}&ZE%3UsFhU@K0h!yiW5?~&G6FD|;pTI#Wu*JU_IcCga`Ee^ zeCnpJM)0G#Ah#${<_{GlW-o630~%Xt7Y*ud`}7!5J7`2Q~giM&-Ljm;ag4pKiMI(>eUtP_B%6c+vJB4b$BsyKu_?@@1ZfSNio^>iQl zF_@RZ6#D4u4Y_Z8GhGo-gf%Q++MYuUzmc2{q!EV;P*H%OvPk)A5i9~FS^p1(lH_DI zd%NX&skd_|&jtr^cbmmD7JqLZPxq7tJu#2RdgIN0DW(2s#N+>7V1aTzU~&DIpC9!e zBkyzerB6K-*UhM7Ld?{Z48S}0>7X8fm6fz3Z$W>`w;MhV?l9#>TK~;wmakhDuZGss4+n1<{=F4YY_*t1NiKV^$AKe5 z0+llZ3TH`b|FA7y0sRmOCWE3(_vNn&lwUhuqB&%3%EaD@>6qV+IH4-7{(^}}=`EbB z{p3U)D7Q4RnelG^UoQo7c#>f%@3S@72lwS>(Aw7&z1n-}6Rz0pU(q*i&m&L5NcZ&q zc;)|ur>SHz_AQ{9FxcWx_jvQbCL8yY(;+_n@)lMGFNoHvLbE&~leMqzP2$vBd)6h^ z1+^GU!~7omr+hKaF;0)=%S%Qr`0n197wF=*?^3#YS&<&6n1`_DMOvJY%!#^ri63O)=A2Kw4a0INj!A&RMsfHTPX#72L1T zp=YD8lIoYm#_sq68FHHK`5n8e<5hi!`#%fQNb~^yBKyQP&7!ICSf@&d<{X0&O3`wS zke0;nbg^o0e1iQc-t4sT&Dt4;66EeVfs4WRgMadr`LBxopT==_I+K6!?DNpfoFif^ zW6oqa;7~JBM^30Tl>VQ)K&^xbS4LLsdV404prA~>+~K{)oo3eiuV(nHbO@CG^T92? z{*dt2ZQey{=VBE?Zi0!c%T0@XQcO0595V{;WZV3Z<;7VH`fiS|b12d9ZgGiTwS%kv zCPggPznXb2cmRBBe!IYZ24JuLc*&!C*q=yps`#JJ*sHI%ZJlWhEgTmo!G6Ks@(Qu7 z(272vWaby(_%O@Tf-$l_HPZ|$QQ5A_>}$`da1Is1WIhm4HykC>~9yme8tq@>Q9|hm+IEV zpSxa2GQlBH&?BGdXJ(7=asH2re5ND6Yx7Cze&WmHq!#xs&xCF)FGiGo5!!R7Y-^#l zxaYozWDX04zVs2j0vm`A>3{LO)E3wlt5oRP!ovn{+Nbe^(NJa5P6`30lpHLtp}*W) znN_6BWsTFq@?J_W%8)9n$kL?+Q2xyBzx~0CI{5*!-O5f@piSD7YtY!iRfz6=E86Qy zNF^#v0I4$hw@Mce^@=0uYnPpbCuTfI((UaJvO66n<20jVg!qwwTb3{hL)c#O1zoSt zJK2Hsuq*L4+5B|~$pP?c^xl6F^uNYFYQ{>EHz3@v#`%N}WnUTF(x<%VFEvpa3}?E0 z;l{`WAs)N<5aP*4&+-O^7X$mbJ@|I!hEB2Gt8$a#EBG=|q5S&gi<_frf6^`aR)S^( zXjU+DzqMS^Um09GCV{s<@c6h4h`5T+zg`#>l`iNE>O|EjgFt7}a*c}W-o1NU+f*cw z?-O9hXa_zp&b6bVIrz&U%z1(5ARq}0(gZQAE;q*Mm=wL;d$w@-MTn&ot)i1c==Gb&`GNWSknsl9LsrBPc;p!+Rv3{k;kVSFO zk!>iRit~jwYD!5t2J8yfK975Y2X1mK(pbsYEPa{k@kDSPEH=g2Nl~Q`l8W6a$2my> z=I^^WTH?aXS>5&@uueUYvpy8uJiQ?N<~V+f#{u;F-n&v#rxC~`rKTPQP!7MHaTdC- zqRGSY3oM$@OpAI;)Ny21VNXe|jF)3v?~Agr6u#pIy)V1_{SR*{or4}WL|#fl)0!k)#<(qBZ%)%H)CRg5ybmo6uiDDU$e6bTT`&K)Ik(lHaI^P(sX2sD zofz_lKqGAd0^^vyeHA@Nz2PPZfTyoJHltQKAQNZx9;ej-L9_21L`swM=OD%r?>tTo zWRk}aJhrK|!T!U2nwfrunGl8H3=N%N^;qJxaT^|6F*XoXfk0R)=}1Nzy6VzVAlooz zrN;8yX&Mk4L&*J2wt<~#W7lKget6~WWXR$K!oS!t0~ESa!SzAMPu0fuG=KhCyB*s=hZvz- zzpfJ-ngI@vlnRf_VRF##G$Ap=_qKh%8Cfk%d`>hnt3=1XXOBFguctRj$ss4SC%FIp zUt+;IjA-^(KvB|eUa|+|*AFJUTx@}`t#mOR6>-v zaCc0!rHZ6brl-&VILThq@;kYpuXlVpyWdIfRNAu1mc3L$>#@%m$Zs|g>3)enrvr+F ze7dYT5U7@dp##o|^b2cmEiu0nuCYMu_hglhQMaFjIvkk_%XQ0cgD156eoD%DX0}43 z9|~jD*j)Un3nXTYQ#jccMe}lLGM^G$l5IA6l@(vXueNktOh!+BR&nY2|qcpb6D1z>^C+F8d zuv6RZD6hX3C=cF_D{PttmL+F7x%Qh|y9T<7!RIQu<(fZyX2kqh!010{0}&AN9rc&i z_=q0Am6u+{7_6(hvlwa!%F_JM_R7TpAff;1>ioBb0>@%YDzgEw+xp9xLyjb{?jH^| zP1*$q0?2J0TgJWP4enbDjJ0y}ccY=GX*Ph5gGXpz7{Y8M@MMW1`Ne$gGiu^TyQ(-M z$m3FH3NIdx8w-d{mNQ(5VHt>RXP28l0lz1=uqT?C5H(t#1OF}MgRrnpu%(Ks0OTm4 zl@x=1`j(l6WuamDpW3DTJR$iSJ#xq|#VdCWl2LtIr5V55MtU}9STAMHPO8&$<+J5* zy}EIT&CYi1(opRRr{P$I%E$_n3W7C(ZW2k|Eg&Fs8`P+cf68pQP2>vTFfOK)?2t)X z6%UHKFZ0BZQR94~**q*EX_GJ?I}3~P>~G0kYvYA#r*vLpTRlAWKOpcWwyGh-gg9AP zn(FNm{Qx&jb`Fk4rV!q7zSpz^5-}jUp~+Be*AS;rlPad>!itvMU=X~}B=0T|0G$ZT zlLe0c8rk(o*rO8w;pYm^(~w|n=}HZln@bthEPw8Q%Cmjm*%=m#vDtOt`|-PK3H5C| z6dY9f56L=EHp9ktm+|y^o}xc?w{F!j@mh%Z?9b&2ZEj3CXK6THyU5s}-U9>GuJ&+J z@5L678x@+^=u6pP4VZupyt=ML;f>#6Qb=Ji zWvsl{l@X|(x*a`U%2aawebCqMq{q@U5{ zALi*420>QlCo8VXW8gQ}67-*_Vvn zG?`Mh!BDgOLqQw1U*?Y@u9W1%?_>58M{TF8uLS#6~+4R zwwB)C)PcnZ7KZH9{eFJ76HL*4W!WdBcTO>vbKx`x_4OX^{SdtlP@0WSS<=sPp6Kdu z>f6R7)GRLnkWkuQsl~3=ZT|I4fn?PD^5l+`dDLLc+Hf?i_(u`i=r(>VlT9`Kg^5VQ zYqxge6Msa=2HbbI2#KWSuAmn~|NZ+u`dDP{={r`0PoMv;qM?xvw*m1P^=^z>lgKH) z%YDcKG4nQ5Q4B_VQ2{lm>8wTAkh8cr~#**h;3Oo8k9pxr-x&=#J;e zQ)t}>QS}V$P?%N_^_q`f-Q(OJ!A_nP1Gl)Aod!`izp6<6P$)pGI}cW>#AiHv`zwR* z@Dd=Tvk%q|8dJs2jF8qKZML$$Cy*mhGt~oIPsP=*6pdxs@-DN#Qga`ioNx50+yg&s zM}-@mTd@B>fhEMNPN$Dz`S zY6j`Q9_s~_UCw^gUS43Tu)Xw)&mejq^o{y9#C;rEIiwES3f4t&3T%%|_Is9sCWia5 zzA)CM0wN0#Oy)tnU6HR5sz)}$71V+RC4QbnUNt-l&i!(_qALlEO&MZQw@O)9B!EWE zW)t^*rhwVQV@=-iu0{y&1}#}Zd~{D9@(XyAd+h$rEvenw8-yooJO72~Cs zqLAx9ev*_f~-RrJi|UKPCbf+%p32)Ayc`I) zvGv({zgdQR80-3;?%t`j&E+?6nd4Fc89=~!1uz|A_Bbl6)BG=M zLoeS70(S&`Hgkm8z)zRb&z;znHVuVGSBPCPtR(yaX;L&+?!w8M$gWz1$}FGK+eV+t zS#W~?SgY0)9^Ah3uN1)IU!Cw%W&XKQ|BhVk=bl4SIHhQ9!xM1s_ST}cgG6+nlSU~c zq*v2C7ZMT&1USkO2L5OH&}S1$z*&LA`v128O%pY84eo_Hr3r;4b(|*%;U*s|Yoy{^ zRb1)x9uuzpv=M)m5&esA&4q?=?i*D*8sZdESf2thA)X3qN^DD7u}+Xc*W0DYNhQjZ`b6@)67X7+ZQ@?>1_wi`mldEX+QIXY_5|MzkER72&IJurWs z*5TP-w~0JO`W8*ux9=tnTqsA(m6is}aqah~_=Qq`D&Uol&-tEeEQ0LO@f_3AaqreF zYNuEpF!db!gkNM2xMqa~nOzDwT+yn2wd0&n?N)AzIee1;~GnwSgemmH~!NHN@fImqQVRCLs5v7wuO#U%J+lxDn8Mu+|fK9K_bHx=BDwrHio7zrZ|6-4O%RPLTbGqW~^xpB5Tb z>GWz21F4YJ`ebVgz%P2faccKpt+6apqagcKs6J9(eqv9~f6V~Lt?1oWjWDO#2E;B3zcXuA?aBEDZS z~e9;c`fX`L3$?6J&@Ah zUi;w3Zqy9WsBClkqxk+7K}ny;;5otDStN9r^TYFFMr-`EhAn=~_xW^H4t4a;96|`q zK@}OWmJglIfi{PSlNOSCmrupb)q8fd8&^A~@s9g7>)BJ`Ny7#(oHBZTDGom+aXAi! zYc@#ArsSG|#;k3QjroF3?AhVmiTPcTqI{0+v}|?wq17k5h#Zf6Y(!gBl`vYg9pyA@r5hAStAUueI!>x8X}MlrI^!=9Q8X>X|6k=jgN47%$S*s3q4d71P?+DpJ9DL{(qX zxV<0fk=bs}J}w=)m>^L^VxjMH$*UaqrS(V=LX^WR$R02oM6;g_94~NoX-|xyHeI7} z?u)h5&e5x^v*rgEOBDDS{ZL?qe{CTZfBAx<^l7pZ`x9_6efAGnAugov^jN-EHs*9} zlR!YJ7YY(&X|}8nZcp@lA1ir5!t8AnDx$sOWkUA!MFkBP;VW-9mk!%-oj!ThI?W!_sWN#e)N*r@>w4 zsTHvnkJ#iIO}5J7*}lFZ6!hEdgVQ}=`jojdRi1~8s2;L*I}Y4BeU+ljC68&3ywB$N zSp|mZqu(>wf41Y9wwzcSg}Go__=`p7rZ~o6ck7{tK2)_ddpY^U(mBI6;OPv+`Sc?e z*R(Lei%UX1crb>#x&T&Yll2m4`<3vb6Fz1>C>!C9 zJ=saR$6XF;&s4e9K+(XP?4eE8ZI+ntj}u&gy~URPfyJS=rb05k1OL52Q@edLGuZ?t z5wBm+6p|JPtGKYTQ4j{ zoOFWQUOnI_sxpZ+t7m7*xvzgHbzIV_;HjBfTcft9uXwhDOEd)egU08;u#$L&A84!+ z-a1Tl2Y?%EZQ(So%Wb6ISd{VYy3siYz)L@aB1f-0ckIcCH81OpYg3KB)mJM}F5&|z z^F$lvyDDs3`$?Ay>x6q43{)3mx9BjW73QpF{RL>OO{)XlVK^E^UEwAF=vMxo^t`mV;A8_ zBd;atG^Fg;w{|h=VrN~dLN7BnR|uu*>=4Hjs~loy;lDAlv9aNKKuf?u7l*}48`y*^|Y(3xIZ|{#!IzL?)ju%@RtUk!*0VI{1a*=t#5XgrNrBUH zmt!J>bv5vdoP$qA9r;k@iz=ZrCB6D#>LlwoNvGydZD5N9N9?Y>RSN}{WUprR5y?0qQchY5Tj>c{MI z@k3FkJ4+hfH|scTvzpy=tT8%ZtKYj4QHP>%y19$nPFn)On4jzHD|T6fjYZ41DQjO= zMy4)+c*08BX4l(W`z#!VVd>(y5b)Yt6mL^4AY~5#@PDHen@4P0mH#%`%@}^Lk5Mx} z!NP31TR;fd*uJ4s(RQ>g=LA4 zMye?lB8AF6Xn%Oyh!jigk>1w+@k<_=i3s05E#c3st53R;j<530*@yOpliSBSJu3m@ z5sbj56tX89ncF2q6*cVvuXDUW6div~U}CF$w1r?vC(&r-iTikyR)Ox*!FC~5Bi4y3 z`cEiD=kO1%wbq-^nDmPs>+`Dj>@)1tD3+|344WKFF6!_+m3A77_YlhpS~Y;&13f<% z|7CLXA_DnQser`uj+ldC%KnPVNfz{e2nKMmZ`W~O)Gbf7pRF0PzVM6_T{B6|It=V! zUzCnd>Hr; zM(qiS8%L&8FjR`z@#KV`>bvPC5uUS*s9F{~1#c5Tlf4+l0%qSt^lCJkC?;~pTl6Hj zBR0oAWElmyZVo>5-pca1fgw2YO;0aMJSM>x8Z#oOo|$hJNXo@O`LN z_5pTjzR7qIgmBG3nCv`K;xwf93E z>gn=2YaHyo3e6Gh3ks#+^md6SK_@HP9zG$6WQ5#C87eB`mKpU==}q(xJ@VL0Y(U!+ z+fp>MeXLwaphN1a*W1uoCXXyI7v55e^FDb+|FST0=(zjxT8N`5U3U<0{U+-zNkNaD zytFmN#FCvO4|N@GfF_iZ{5Ld5pwoCK#mRp0OBYkVG6g4nk+7%%5(8K%-A( z4l`AwMtdx494yfQQG@+K@sSVpt_JTt&KR5(TL5_UmC+ibbHWS-oe1|>YLi!FR#e^# zh35ovnGm_#L=yH+RSH$vz@1pwBDaE?cB#>vVC4}=)I8O%QetOk7dmAUa+8Dm9ms>j zdb@GUtIDTE>mbjEfL~?Sr1(@ns z3JAjofgEg0pd-ZP$5Nnj&FIycwp?pw&hhxQpDJU4_(L(gK>4M(JYu#(o}Bsr$G3jj``mqGa`m*23fG?oB?hr zqRWM=Gcq_9(#s4{d>gtEBh7jo*rEP113dHG56XV4zu^jyaw$|oholVDNl)h+eb-{s zaXCeA5v_VG%*OFN+yuXqaBhETsp5ef(ur5X&@Y@4$nlb@8sr6vJ8&n5Bq}4^y{iP> zP6jo6U_}Lgv_=QUY|}>2sfa8k{TTDV{LkvdhLHb8x*P#xcq_%k;#<&~#ft+9{GM2S zBGgdO&d{ISIeOf0DU`hN2{jRm>83qjtXk_Y``(VGQ!jxRFIXsGM{0nMQ?)_^s9S5> zg(V(kOa-$2S_gy~(*7s6C(>J>_UEs4a9QEi)SG7wa2_3H#G#`GTl4nGPIBAl06rC+=nqo@2qjjkaQ+3t+qf-5$= zkC5a^YSC`L*e8b20CmKs+dm$$$Dqq*j$m>Tp!E^m_x(@+ZXM5xL}BG4rSCQzWBJ*4 zdUS}g*n>OyrFkKvGL$+)@65iL5A%igGx{jx)YEc)-7YR0B7}1wY=-VVzOug*M!0RZ z$LO1hPj%sq@4l2UIx{^usUsAhYhz#J&LVwJ38cSdqKQ(N@rFcOr=C>)n(=g8s zo<^b5oTu57*uX*-vj*_TYoaUo>cY#|fxWVwZxeeg8t@hTg-J&fu3`amzp}Q--|MiC zzp)+I#;V>?Y%WLqe*HUkkoF?CV(M#-L*AU#3!~xpRMqf^i9g!6ax_Xmlx{5O;A&2R zF1|MSXMl0{?2?obLaAOA(JkZpEq?G5HJ!50$_Wg0CZ{m&@Zk33SM?mSU@u4px(U6p zV1diIYWXd2LVULOR+SlB+CK~sVtD?-CuO!}>FJe64_*H{Uo+1kyTJLG$&6e5YQqK+ zHGHyH3AQw=hYa%D-?mIv89qWy&3a6sX5`)g&sfFVr+MV$y@sKWg3Iv4@hZ*A%2HqN z(sEq82cmj*`i(a22arv9K3VB_dicgj4UrsLX^(q%U@t_R<7On~>dvV#GfuWUL zE7y7dim=m|6L1yatRx^$w@!hMXBza8?b-y8UT49FPH@&A3a_UMyR0>%T~l(7eJq*^ zFKwe`lZ-XgaDe282_Btm@OVFDmBWk-wUGo!p&b8B#OHI#UoMgaTxe58Z@RiKbd=2h zIu?#X?}%_aCLu1bcm%#v0?1(S_FF=xJN$E55g{+QT%PIg#(HAefuCM{z@4ohgz3Cm zMiHq^JUllQl=E}+&2we-RolkgVMAZ*#m)s1v0%cUz`aO9MM3T`!C?{(i0lT?JXfap zR+K!N=QAL->!t)4*(cb@V{SEW~1|?=V4fQ_H8~FkvcZj+Wm}e)@wfoUoh) z-Bk31shlxX6AW^S+Uhrbynp7LPg$kMJNYB^!E>SjJ|GDWPk=?7hH$nRRd}g?ulOp5 zW?S|FqAKM)^TQRYR=U-X>h>z!2_P^THh1~P7MEa}o-i&fkGjxn!B%@4*w~PTE*pcl zZ%_HV+~Rbd(uqLfnB>5X{3Y#jc#cDMul?hQyU>547+`mw>NPz6!aja3wCyu2WP86c zCgh4m&^-ig+Nev9Jc0o7dpO41aEOK=J`&L2U?+wqq*={)-cugy$nO|GJ1+jvEAd_a z=nc(%3l5*w22gfy+2Rp!CNkP*dc5U3lfO%V9H9ZB z+za{D$YYDkeF#K}OaEG+PvSCKwZ{amy1^$9$ZgrH!vqrp9=hw7 zWnaP0I+v69O%2|qSuto_vVPk;DJ+Qr&gV}-7Q@N+-qp7MRYcPem*1k|qXb{&a!hN` zxR>Bei!z*AhoL7 zZN$bdz8|(W*erZ2p%VEo?{|3)=WmYmd);ePW%A00I`Puq>LdanN4YshQ*|5*7FrA< zx+mVxVGgWa0Y%^n6p#q(X=g2{)D38&J?H!c;}%V+&N4lo8wMP-P~gsshqi7IWR&(Y zawi1*ZiM;kjv2LXt~lKK@|4S|x1ii4Lx0v}y2A6P-2Q1MB4E5~q{{T4F3+qtutk?w z^C^4|WiRe47)}8tr|YBpkj3cm54POM^g>bga399c;4#C(F3*ZNAC?qZxPO#l>#;zt zYebD6&iWl(i;&U5Djs8@2~#WbJ}|bXZxspVQl@BrpjklD&>QX+V~a@XV~1@+zO}a} zdQ3SaC|fEIxT@y_)at~df0mJ2CmGuvv~|_@@k;xQMF1**_4z&_vknEuaAxV z^Y5<8K{0MsiWhN*Lmg78vP{)}*4CRg_0LEGMPoVc@y%fiIh3S*O%MC&m$~E%ywT=s z6GEuVoTPULw|Jk;%%pgp&@{r>zl+jU^c`(Hw7}m?%-H4{hMjUAbCZ&z%6B3y$<9i>ZgDOVYU_9e8ZZSK!R1X`f$3 z$t$un{rO~Q9s;lV8~u+?aL2)sy$sT$oH6ze*Ry?Y4PvU(x3Ew7s1z?hDtQuV_V|lq zX1k2y;?umo)hb%sX634u_O~Q7utlFI3U8eFyFA@X8!tcYvl_51Kmz}Xu`J{HZI}Wy zc4<{H_}d>r+B8$^ew{@~ls z2)q_fB50>#Ny7%wCDqg`GpHb`*f#l7L8nEMpAZ=z+QT{nX#ThzWq?5*0$7+sQHk#?V~w;F$5o~aX$n<2+Z_SS6>7u z^e@6u1I9+WB-(7`qw>vmK_PSyTh4(m548|S+3wTc3Nl$yk#9&P#~4?v1r^45zYOWV zvv;PFjM7?11jM_GPnMRQl(v1iCV5j09z|bKw|7C4ipB`(qk}nTP?@LeppUn3LUp>A zNw|Rty9r?_w)rkCrPA~sIR7m1MU_IJTRu6a+oPyKjGz`yJ7z%ommUV*)!|#$rFa*^p|%&3i1V9nV=GSS;tVW#^imV;;1z9m|vG%SZ7)L{{?cDKUiXF~DEOmihcp-nD}Z+L0`^ zLFBtU-IAY=xS!elU?}lfAn6RcezS;ep*vOZ{p#ir@JQPXB2Mqqs{c7LqixKf?);!q z*W+8lWXgA=0;U)mCJQDT4f`LJUF%;S$d9;6CnkLylrwoE5j|i-Y52E*KCgS@8PWv$ z%+gI*aOkRoKeN0cxxT4NU04n0DOPqHtfQ4y<&R@TXcCN*oi7KEgi;|tSZDhw#2~!@WzkuV} z1g%`piZ3tL7|+cL!x*jOVyFspUNn{P+Zap-H!nW+V1ctB>mE33 z@yb*4ua&BR8iGbOxKqSM3ca4(`>Y28PAQ9cI$MaUyiM&rED z_)Bzh=c0c`*dUSqZMt87P;`}Y^i+5zN+LtrYH3gRa+o5Vxq)5M2ql$KTH9+&31P_&QBHxV>xBGry3HQ#7ilzfJN+pLp;=UlWN&NnH zuPqHY3cj_~-aAB?V8iYk2#$trC5>MolvJD$4&2WBq#Oa8x{CSMWC-6tC=})De0- zxjzsVW?ym}z@>zmW663H#I$#R-ZpYP+mxui;94^RqW3@hLJwB?+t*G5nhbCpP0zUx z@Y)eT&yhr}zi-zCQz-(k`X#C-o^3_!xhOX-bl2fnwYf)$%Gy>>f+ogN*Cnm!yr|1l z5cZ>RV&+t25#X+wFD;U2(nWRoC`F%UhR(lVc(piz+d5`pIhbS;v#%s`kBquk?N{RN z>^@-Zh^`ZTye}JY`ODz*?O7yqCXF<%?J~t61Z&0e}1N{-7QR9W* z(!fo9HgkROn(CZc!TkxnDv&yGFKK!D+b`7hn|B3jSpmJ8*Q@WM#7xe=g( zbqJ5#XDbULqq_40`|-ZJZy!wrSg(WJ`Lff!CZnn^)#OB42lYP;S;{Q@8s0Y=uly-K zBARVWR2y^9Od4t)HR!acVn~}F;rBU(-CsTNxqS>xWl zE8G78h^=Kx%x2(FNp*IWck|O*y%U9J@#~b|Re^FTa6W$x0FQn4l1GtnzOd>(D+Rj?}A6fnSGSC?>VhI_U$(G#C&z`~T^ zxfZ^^-!JXG{E>F`O!O9Sojl82IK0Mbzbm4(5>)3**2zKmL|6Z`v04{3-#+Byb0 z4{ypsIo3qyLpgKLcajTQxb;70;qjDRr?qmv#^yV*rSy9$2filWb}fHN){?~A@EVKCL&w~lqtb7YKT;<5J^G~idO_R%tD}`2tlAixQr4A(TYIJ zR1u7jgoH_km;fP$Apv^g_w~NqzTU^P_E``6?7i3b+iR`=c{Sv{6_*pGc7^AAo7K-b zMhW0{pD?Zxk>I76#{BKd)rRiaIZ0}}<0aFV`=Sp1_L`uy&lOUENZ|A@vRAR%cSWn- zl(1lYrua4B}g*dz#hqr_)(sqHSl*7u&+3CWw6 z>^?gB%4e#*&Zde?`+y>1U{3TU8z@ds)Ti<~7BwiiS7i|@w|KiL*M zTA$HCDk_qKVthcM3}?EZ3)2(*zR>`M+NpJMgjx^^+)!mmy+?Iuj2 z*k*IpL8oz>3-_L0 zcGo6JUJZLg7qU53c&E14Ab}R3frn;X<{mrCD5B%N|5K?>Ezhp4VkhONO;0SLxZpNX zZ_bpBDwT8;n*0`B;R)@C*d*lpGwzyj@52Jp655)L7Vjm~zCLBW+r5ZZm#s;_)mxdq zY@c)?G(T&(I^sDGCR!WkbK`(!k!js z*6Hw`9o1^!IcY_^f_qLc;n25$+TfIu*FM=Q`%Eit)xA(5Dn!?eD3mJ0gX5EYd2%V@ z-T8rvvA2H5ZlZjqY~nn5Jr?U^)7%d-W}6}$Cs^M3PwJ*Lw*fmSC!%N}178}E;r_L* z{mv`F(ar)K_bl#enEChvFRkZNp{Jf@C_-Cq7=k+RepL)0h5#1z-^G^%OT)r0fnr09 zvEx9LhM6vF^Prr|rO5~Q=+urTmKNU_*J=q@#E%$<#(m=|Si%$(6iE5E17{`b=`iz3 ziyFKs{H^H``>DB4%b9!SK6=*Y7|iHA(<5iC!2%E3Vn*sWIvq5)Tr^{h=-k{;d?9qyZ0T1S^GkO2f2%I35P?2AWwXwVrnU0Uof9&v0hd%R~Fto^E1zantt<996HA% zlCAF%Etu@o+WWPpK{JJ4T*`#mVh;h)Bv$XxPnnAdOAyhAR4@&;$7SUk7wT%>RGECQ zw@}tsYD65wUMEGj9b>;lYvmw28pocIJd9myz_Wjd^oq%pbPyCF{Fv)rl5Xa`dq{Ku0P<3< zAJZWZz41#9`vRk=S2dobUK!o6U!}sI6fKtXdw9opM1;36W7f+Yk&_}+HFn!I)UPMX z*Qg8Uf*C6?MjKFP7K1S$cj{Lv(qBik_a@43>7!NjW#ZF)95FCfkYra z+EIK8ibM}imWtx9G-fZHEInjm(id6ZcpnOiYah#{McVa`w61x6alAZhWb__XfZ>#~ zCP4oR!v$xdsx^`LK!CTWM`bP84`V;^Sn~A))nkfC9oZNtdj)nn5?|Q0>!^Nd^~cuV zY7qXfMnKh~`aco~J5{D)!3-RFJWw>(svdWWSlCy7?3-PJzV0)P7XV2?UwM~4=xPin zzW6QxT4Fg*)3nd=FyU(xW{3(T=s1+OVzgLUc~o#_cD53V$OyxTP1nF#&T50T6|jy~ z^Zms8Xl=YLqtO6-+r&g~=dN9b%OgpnP+_vgqU!r6y_9Zg%oZ2NXB>D81)tSW9$xM> IZWnL;2_HWakN^Mx delta 18809 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 Date: Wed, 27 Sep 2023 12:28:49 -0400 Subject: [PATCH 02/21] trash bag polishing and balance -makes ui less bad -makes bigger objects fit in trash bags(it's a trash bag goofus) --- code/datums/components/storage/ui.dm | 2 +- code/game/objects/items/storage/bags.dm | 5 +++-- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/code/datums/components/storage/ui.dm b/code/datums/components/storage/ui.dm index e03b8132bc8f..512e797abad7 100644 --- a/code/datums/components/storage/ui.dm +++ b/code/datums/components/storage/ui.dm @@ -28,7 +28,7 @@ numbered_contents = _process_numerical_display() adjusted_contents = numbered_contents.len - var/columns = clamp(max_items, 1, maxcolumns ? maxcolumns : screen_max_columns) + var/columns = limited_random_access_stack_position == 0 ? clamp(max_items, 1, maxcolumns ? maxcolumns : screen_max_columns) : limited_random_access_stack_position var/rows = clamp(CEILING(adjusted_contents / columns, 1), 1, screen_max_rows) // First, boxes. diff --git a/code/game/objects/items/storage/bags.dm b/code/game/objects/items/storage/bags.dm index 6cf80ed6dd80..5f7c1ccbe4f4 100644 --- a/code/game/objects/items/storage/bags.dm +++ b/code/game/objects/items/storage/bags.dm @@ -45,12 +45,12 @@ /obj/item/storage/bag/trash/ComponentInitialize() . = ..() var/datum/component/storage/STR = GetComponent(/datum/component/storage) - STR.max_w_class = WEIGHT_CLASS_SMALL + STR.max_w_class = WEIGHT_CLASS_NORMAL STR.max_combined_w_class = 50 STR.max_items = 50 STR.set_holdable(null, list(/obj/item/disk/nuclear)) STR.limited_random_access = TRUE - STR.limited_random_access_stack_position = 5 + STR.limited_random_access_stack_position = 3 /obj/item/storage/bag/trash/update_icon_state() switch(contents.len) @@ -87,6 +87,7 @@ var/datum/component/storage/STR = GetComponent(/datum/component/storage) STR.max_combined_w_class = 75 STR.max_items = 75 + STR.max_w_class = WEIGHT_CLASS_BULKY /obj/item/storage/bag/trash/bluespace/cyborg insertable = FALSE From 71763ff4f0f4716bce938634a3546665f3ac2ffd Mon Sep 17 00:00:00 2001 From: Sun-Soaked <45698967+MemedHams@users.noreply.github.com> Date: Wed, 27 Sep 2023 12:47:29 -0400 Subject: [PATCH 03/21] fixes trash I am the trash man --- code/datums/components/storage/ui.dm | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/code/datums/components/storage/ui.dm b/code/datums/components/storage/ui.dm index 512e797abad7..40c470296d34 100644 --- a/code/datums/components/storage/ui.dm +++ b/code/datums/components/storage/ui.dm @@ -28,7 +28,7 @@ numbered_contents = _process_numerical_display() adjusted_contents = numbered_contents.len - var/columns = limited_random_access_stack_position == 0 ? clamp(max_items, 1, maxcolumns ? maxcolumns : screen_max_columns) : limited_random_access_stack_position + var/columns = limited_random_access_stack_position == 0 ? clamp(max_items, 1, maxcolumns ? maxcolumns : screen_max_columns) : clamp(limited_random_access_stack_position, 1, maxcolumns ? maxcolumns : screen_max_columns) var/rows = clamp(CEILING(adjusted_contents / columns, 1), 1, screen_max_rows) // First, boxes. From a80aaf17741c99b420c58785c63564d09ae27b66 Mon Sep 17 00:00:00 2001 From: Sun-Soaked <45698967+MemedHams@users.noreply.github.com> Date: Wed, 27 Sep 2023 13:05:14 -0400 Subject: [PATCH 04/21] why did they do it like this huh??? huh? huh??? --- code/_onclick/hud/storage.dm | 5 +-- code/datums/components/storage/storage.dm | 4 +- code/datums/components/storage/ui.dm | 49 ++++++----------------- 3 files changed, 16 insertions(+), 42 deletions(-) diff --git a/code/_onclick/hud/storage.dm b/code/_onclick/hud/storage.dm index 55156d9b0de5..6e5a3c0eaa8f 100644 --- a/code/_onclick/hud/storage.dm +++ b/code/_onclick/hud/storage.dm @@ -113,9 +113,8 @@ /atom/movable/screen/storage/volumetric_box/center/proc/on_screen_objects() return list(src) -/** - * Sets the size of this box screen object and regenerates its left/right borders. This includes the actual border's size! - */ + +//Sets the size of this box screen object and regenerates its left/right borders. This includes the actual border's size! /atom/movable/screen/storage/volumetric_box/center/proc/set_pixel_size(pixels) if(pixel_size == pixels) return diff --git a/code/datums/components/storage/storage.dm b/code/datums/components/storage/storage.dm index 66e054e06d43..a88fe8ca2106 100644 --- a/code/datums/components/storage/storage.dm +++ b/code/datums/components/storage/storage.dm @@ -812,8 +812,6 @@ if(COLLECT_ONE) to_chat(user, "[parent] now picks up one item at a time.") -/** - * Gets our max volume - */ +//Gets our max volume /datum/component/storage/proc/get_max_volume() return max_volume || AUTO_SCALE_STORAGE_VOLUME(max_w_class, max_combined_w_class) diff --git a/code/datums/components/storage/ui.dm b/code/datums/components/storage/ui.dm index 40c470296d34..094751081dcc 100644 --- a/code/datums/components/storage/ui.dm +++ b/code/datums/components/storage/ui.dm @@ -1,6 +1,4 @@ -/** - * Generates a list of numbered_display datums for the numerical display system. - */ +// Generates a list of numbered_display datums for the numerical display system. /datum/component/storage/proc/_process_numerical_display() . = list() for(var/obj/item/I in accessible_items()) @@ -12,9 +10,7 @@ var/datum/numbered_display/ND = .[I.type] ND.number++ -/** - * Orients all objects in legacy mode, and returns the objects to show to the user. - */ +// Orients all objects in legacy mode, and returns the objects to show to the user. /datum/component/storage/proc/orient2hud_legacy(mob/user, maxcolumns) . = list() var/list/accessible_contents = accessible_items() @@ -75,9 +71,7 @@ if(cy - screen_start_y >= rows) break -/** - * Orients all objects in .. volumetric mode. Does not support numerical display! - */ +// Orients all objects in .. volumetric mode. Does not support numerical display! /datum/component/storage/proc/orient2hud_volumetric(mob/user, maxcolumns) . = list() var/atom/movable/screen/storage/left/ui_left @@ -174,9 +168,8 @@ ui_close.screen_loc = "[screen_start_x + maxcolumns]:[screen_pixel_x],[screen_start_y]:[screen_pixel_y] to [screen_start_x + maxcolumns]:[screen_pixel_x],[screen_start_y + row - 1]:[screen_pixel_y]" . += ui_close -/** - * Shows our UI to a mob. - */ + +// Shows our UI to a mob. /datum/component/storage/proc/ui_show(mob/M) if(!M.client) return FALSE @@ -206,9 +199,7 @@ ui_by_mob[M] = objects return TRUE -/** - * VV hooked to ensure no lingering screen objects. - */ +// VV hooked to ensure no lingering screen objects. /datum/component/storage/vv_edit_var(var_name, var_value) var/list/old if(var_name == NAMEOF(src, storage_flags)) @@ -220,15 +211,11 @@ for(var/i in old) ui_show(i) -/** - * Proc triggered by signal to ensure logging out clients don't linger. - */ +// Proc triggered by signal to ensure logging out clients don't linger. /datum/component/storage/proc/on_logout(datum/source, client/C) ui_hide(source) -/** - * Hides our UI from a mob - */ +// Hides our UI from a mob /datum/component/storage/proc/ui_hide(mob/M) if(!M.client) return TRUE @@ -241,33 +228,23 @@ LAZYREMOVE(is_using, M) return TRUE -/** - * Returns TRUE if we are using volumetric UI instead of box UI - */ +// Returns TRUE if we are using volumetric UI instead of box UI /datum/component/storage/proc/volumetric_ui() var/atom/real_location = real_location() return (storage_flags & STORAGE_LIMIT_VOLUME) && (length(real_location.contents) <= MAXIMUM_VOLUMETRIC_ITEMS) && !display_numerical_stacking -/** - * Gets our ui_boxes, making it if it doesn't exist. - */ +// Gets our ui_boxes, making it if it doesn't exist. /datum/component/storage/proc/get_ui_boxes() return new /atom/movable/screen/storage/boxes(null, src) -/** - * Gets our ui_left, making it if it doesn't exist. - */ +// Gets our ui_left, making it if it doesn't exist. /datum/component/storage/proc/get_ui_left() return new /atom/movable/screen/storage/left(null, src) -/** - * Gets our ui_close, making it if it doesn't exist. - */ +// Gets our ui_close, making it if it doesn't exist. /datum/component/storage/proc/get_ui_close() return new /atom/movable/screen/storage/close(null, src) -/** - * Gets our ui_continuous, making it if it doesn't exist. - */ +// Gets our ui_continuous, making it if it doesn't exist. /datum/component/storage/proc/get_ui_continuous() return new /atom/movable/screen/storage/continuous(null, src) From a12051cc2babcf56a7ec5f65bda821de145eee9e Mon Sep 17 00:00:00 2001 From: Sun-Soaked <45698967+MemedHams@users.noreply.github.com> Date: Wed, 27 Sep 2023 13:34:28 -0400 Subject: [PATCH 05/21] liar these were here already. I cut you in half with a huge sword --- code/__DEFINES/storage.dm | 22 +++++++++++----------- 1 file changed, 11 insertions(+), 11 deletions(-) diff --git a/code/__DEFINES/storage.dm b/code/__DEFINES/storage.dm index 7b2bfc5d18b7..0e33b51a94ee 100644 --- a/code/__DEFINES/storage.dm +++ b/code/__DEFINES/storage.dm @@ -2,16 +2,16 @@ // Storage limits. These can be combined (and usually are combined). /// Check max_items and contents.len when trying to insert -#define STORAGE_LIMIT_MAX_ITEMS (1<<0) +#define STORAGE_LIMIT_MAX_ITEMS(1<<0) /// Check max_combined_w_class. -#define STORAGE_LIMIT_COMBINED_W_CLASS (1<<1) +#define STORAGE_LIMIT_COMBINED_W_CLASS(1<<1) /// Use the new volume system. Will automatically force rendering to use the new volume/baystation scaling UI so this is kind of incompatible with stuff like stack storage etc etc. -#define STORAGE_LIMIT_VOLUME (1<<2) +#define STORAGE_LIMIT_VOLUME(1<<2) /// Use max_w_class -#define STORAGE_LIMIT_MAX_W_CLASS (1<<3) +#define STORAGE_LIMIT_MAX_W_CLASS(1<<3) -#define STORAGE_FLAGS_LEGACY_DEFAULT (STORAGE_LIMIT_MAX_ITEMS | STORAGE_LIMIT_COMBINED_W_CLASS | STORAGE_LIMIT_MAX_W_CLASS) -#define STORAGE_FLAGS_VOLUME_DEFAULT (STORAGE_LIMIT_VOLUME | STORAGE_LIMIT_MAX_W_CLASS) +#define STORAGE_FLAGS_LEGACY_DEFAULT(STORAGE_LIMIT_MAX_ITEMS | STORAGE_LIMIT_COMBINED_W_CLASS | STORAGE_LIMIT_MAX_W_CLASS) +#define STORAGE_FLAGS_VOLUME_DEFAULT(STORAGE_LIMIT_VOLUME | STORAGE_LIMIT_MAX_W_CLASS) // UI defines /// Size of volumetric box icon @@ -29,15 +29,15 @@ //ITEM INVENTORY WEIGHT, FOR w_class /// Usually items smaller then a human hand, ex: Playing Cards, Lighter, Scalpel, Coins/Money -#define WEIGHT_CLASS_TINY 1 +#define WEIGHT_CLASS_TINY 1 /// Fits within a small pocket, ex: Flashlight, Multitool, Grenades, GPS Device -#define WEIGHT_CLASS_SMALL 2 +#define WEIGHT_CLASS_SMALL 2 /// Fits within a small satchel, ex: Fire extinguisher, Stunbaton, Gas Mask, Metal Sheets -#define WEIGHT_CLASS_NORMAL 3 +#define WEIGHT_CLASS_NORMAL 3 /// Items that can be wielded or equipped, (e.g. defibrillator, backpack, space suits). (Often barely) fits inside backpacks and duffels. -#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) May fit on some inventory slots. -#define WEIGHT_CLASS_HUGE 5 +#define WEIGHT_CLASS_HUGE 5 /// Essentially means it cannot be picked up or placed in an inventory, ex: Mech Parts, Safe - Can not fit in Boh #define WEIGHT_CLASS_GIGANTIC 6 From c9502441289eead884c38decc7c5877f2fc84a5d Mon Sep 17 00:00:00 2001 From: Sun-Soaked <45698967+MemedHams@users.noreply.github.com> Date: Wed, 27 Sep 2023 13:39:29 -0400 Subject: [PATCH 06/21] screaming --- code/__DEFINES/storage.dm | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/code/__DEFINES/storage.dm b/code/__DEFINES/storage.dm index 0e33b51a94ee..169c9c4119cb 100644 --- a/code/__DEFINES/storage.dm +++ b/code/__DEFINES/storage.dm @@ -2,16 +2,16 @@ // Storage limits. These can be combined (and usually are combined). /// Check max_items and contents.len when trying to insert -#define STORAGE_LIMIT_MAX_ITEMS(1<<0) +#define STORAGE_LIMIT_MAX_ITEMS (1<<0) /// Check max_combined_w_class. -#define STORAGE_LIMIT_COMBINED_W_CLASS(1<<1) +#define STORAGE_LIMIT_COMBINED_W_CLASS (1<<1) /// Use the new volume system. Will automatically force rendering to use the new volume/baystation scaling UI so this is kind of incompatible with stuff like stack storage etc etc. -#define STORAGE_LIMIT_VOLUME(1<<2) +#define STORAGE_LIMIT_VOLUME (1<<2) /// Use max_w_class -#define STORAGE_LIMIT_MAX_W_CLASS(1<<3) +#define STORAGE_LIMIT_MAX_W_CLASS (1<<3) -#define STORAGE_FLAGS_LEGACY_DEFAULT(STORAGE_LIMIT_MAX_ITEMS | STORAGE_LIMIT_COMBINED_W_CLASS | STORAGE_LIMIT_MAX_W_CLASS) -#define STORAGE_FLAGS_VOLUME_DEFAULT(STORAGE_LIMIT_VOLUME | STORAGE_LIMIT_MAX_W_CLASS) +#define STORAGE_FLAGS_LEGACY_DEFAULT (STORAGE_LIMIT_MAX_ITEMS | STORAGE_LIMIT_COMBINED_W_CLASS | STORAGE_LIMIT_MAX_W_CLASS) +#define STORAGE_FLAGS_VOLUME_DEFAULT (STORAGE_LIMIT_VOLUME | STORAGE_LIMIT_MAX_W_CLASS) // UI defines /// Size of volumetric box icon From c26db2fcd69a4ceab88bddab661cff1a8f9c02e1 Mon Sep 17 00:00:00 2001 From: Sun-Soaked <45698967+MemedHams@users.noreply.github.com> Date: Wed, 27 Sep 2023 13:46:19 -0400 Subject: [PATCH 07/21] crying --- code/__DEFINES/storage.dm | 32 ++++++++++++++++---------------- 1 file changed, 16 insertions(+), 16 deletions(-) diff --git a/code/__DEFINES/storage.dm b/code/__DEFINES/storage.dm index 169c9c4119cb..da639984b852 100644 --- a/code/__DEFINES/storage.dm +++ b/code/__DEFINES/storage.dm @@ -42,12 +42,12 @@ #define WEIGHT_CLASS_GIGANTIC 6 // PLEASE KEEP ALL VOLUME DEFINES IN THIS FILE, it's going to be hell to keep track of them later. -#define DEFAULT_VOLUME_TINY 2 -#define DEFAULT_VOLUME_SMALL 3 -#define DEFAULT_VOLUME_NORMAL 4 -#define DEFAULT_VOLUME_BULKY 8 -#define DEFAULT_VOLUME_HUGE 16 -#define DEFAULT_VOLUME_GIGANTIC 32 +#define DEFAULT_VOLUME_TINY 2 +#define DEFAULT_VOLUME_SMALL 3 +#define DEFAULT_VOLUME_NORMAL 4 +#define DEFAULT_VOLUME_BULKY 8 +#define DEFAULT_VOLUME_HUGE 16 +#define DEFAULT_VOLUME_GIGANTIC 32 GLOBAL_LIST_INIT(default_weight_class_to_volume, list( "[WEIGHT_CLASS_TINY]" = DEFAULT_VOLUME_TINY, @@ -66,20 +66,20 @@ GLOBAL_LIST_INIT(default_weight_class_to_volume, list( // Let's keep all of this in one place. given what we put above anyways.. // volume amount for items -#define ITEM_VOLUME_DISK DEFAULT_VOLUME_TINY -#define ITEM_VOLUME_MOB 45//just over half of a duffelbag. Prevents mob_holder stacking in volumetric +#define ITEM_VOLUME_DISK DEFAULT_VOLUME_TINY +#define ITEM_VOLUME_MOB 45//just over half of a duffelbag. Prevents mob_holder stacking in volumetric // #define SAMPLE_VOLUME_AMOUNT 2 // max_weight_class for storages // -#define MAX_WEIGHT_CLASS_S_CONTAINER WEIGHT_CLASS_SMALL -#define MAX_WEIGHT_CLASS_M_CONTAINER WEIGHT_CLASS_NORMAL -#define MAX_WEIGHT_CLASS_BACKPACK WEIGHT_CLASS_BULKY +#define MAX_WEIGHT_CLASS_S_CONTAINER WEIGHT_CLASS_SMALL +#define MAX_WEIGHT_CLASS_M_CONTAINER WEIGHT_CLASS_NORMAL +#define MAX_WEIGHT_CLASS_BACKPACK WEIGHT_CLASS_BULKY // max_volume for storages -#define STORAGE_VOLUME_CONTAINER_M (DEFAULT_VOLUME_NORMAL * 2) -#define STORAGE_VOLUME_SATCHEL (DEFAULT_VOLUME_NORMAL * 6) -#define STORAGE_VOLUME_BACKPACK (DEFAULT_VOLUME_NORMAL * 7) -#define STORAGE_VOLUME_DUFFLEBAG (DEFAULT_VOLUME_NORMAL * 10) -#define STORAGE_VOLUME_BAG_OF_HOLDING (DEFAULT_VOLUME_NORMAL * 20) +#define STORAGE_VOLUME_CONTAINER_M (DEFAULT_VOLUME_NORMAL * 2) +#define STORAGE_VOLUME_SATCHEL (DEFAULT_VOLUME_NORMAL * 6) +#define STORAGE_VOLUME_BACKPACK (DEFAULT_VOLUME_NORMAL * 7) +#define STORAGE_VOLUME_DUFFLEBAG (DEFAULT_VOLUME_NORMAL * 10) +#define STORAGE_VOLUME_BAG_OF_HOLDING (DEFAULT_VOLUME_NORMAL * 20) From 2948b3e95afc6cff7b5b949efd3c4eb58063d592 Mon Sep 17 00:00:00 2001 From: Sun-Soaked <45698967+MemedHams@users.noreply.github.com> Date: Thu, 28 Sep 2023 08:37:21 -0400 Subject: [PATCH 08/21] balance guh --- code/__DEFINES/storage.dm | 35 +++++++++++---------- code/game/objects/items/storage/backpack.dm | 2 ++ code/game/objects/items/storage/belt.dm | 2 +- code/game/objects/items/storage/toolbox.dm | 2 +- 4 files changed, 22 insertions(+), 19 deletions(-) diff --git a/code/__DEFINES/storage.dm b/code/__DEFINES/storage.dm index da639984b852..49970eadb54d 100644 --- a/code/__DEFINES/storage.dm +++ b/code/__DEFINES/storage.dm @@ -19,7 +19,7 @@ /// Size of EACH left/right border icon for volumetric boxes #define VOLUMETRIC_STORAGE_BOX_BORDER_SIZE 1 /// Minimum pixels an item must have in volumetric scaled storage UI -#define MINIMUM_PIXELS_PER_ITEM 16 +#define MINIMUM_PIXELS_PER_ITEM 8 /// Maximum number of objects that will be allowed to be displayed using the volumetric display system. Arbitrary number to prevent server lockups. #define MAXIMUM_VOLUMETRIC_ITEMS 256 /// How much padding to give between items @@ -32,22 +32,22 @@ #define WEIGHT_CLASS_TINY 1 /// Fits within a small pocket, ex: Flashlight, Multitool, Grenades, GPS Device #define WEIGHT_CLASS_SMALL 2 -/// Fits within a small satchel, ex: Fire extinguisher, Stunbaton, Gas Mask, Metal Sheets +/// Can be carried in one hand comfortably, ex: Fire extinguisher, Stunbaton, Gas Mask, Metal Sheets #define WEIGHT_CLASS_NORMAL 3 -/// Items that can be wielded or equipped, (e.g. defibrillator, backpack, space suits). (Often barely) fits inside backpacks and duffels. +/// Items that can be wielded or equipped, (e.g. defibrillator, backpack, space suits). Often fits inside backpacks. #define WEIGHT_CLASS_BULKY 4 -/// Usually represents objects that require two hands to operate, (e.g. shotgun, two-handed melee weapons) May fit on some inventory slots. +/// Usually represents objects that require two hands to operate, (e.g. shotgun, two-handed melee weapons) May fit on some inventory slots or huge storage objects(like duffel bags) #define WEIGHT_CLASS_HUGE 5 /// Essentially means it cannot be picked up or placed in an inventory, ex: Mech Parts, Safe - Can not fit in Boh #define WEIGHT_CLASS_GIGANTIC 6 // PLEASE KEEP ALL VOLUME DEFINES IN THIS FILE, it's going to be hell to keep track of them later. -#define DEFAULT_VOLUME_TINY 2 -#define DEFAULT_VOLUME_SMALL 3 -#define DEFAULT_VOLUME_NORMAL 4 -#define DEFAULT_VOLUME_BULKY 8 -#define DEFAULT_VOLUME_HUGE 16 -#define DEFAULT_VOLUME_GIGANTIC 32 +#define DEFAULT_VOLUME_TINY 1 +#define DEFAULT_VOLUME_SMALL 2 +#define DEFAULT_VOLUME_NORMAL 6 +#define DEFAULT_VOLUME_BULKY 12 +#define DEFAULT_VOLUME_HUGE 24 +#define DEFAULT_VOLUME_GIGANTIC 48 GLOBAL_LIST_INIT(default_weight_class_to_volume, list( "[WEIGHT_CLASS_TINY]" = DEFAULT_VOLUME_TINY, @@ -67,19 +67,20 @@ GLOBAL_LIST_INIT(default_weight_class_to_volume, list( // volume amount for items #define ITEM_VOLUME_DISK DEFAULT_VOLUME_TINY -#define ITEM_VOLUME_MOB 45//just over half of a duffelbag. Prevents mob_holder stacking in volumetric +#define ITEM_VOLUME_CONTAINER_M 12 //makes nested toolboxes & toolbelts less efficient +#define ITEM_VOLUME_MOB 40//Just over half a duffel, prevents mob stacking // #define SAMPLE_VOLUME_AMOUNT 2 // max_weight_class for storages // -#define MAX_WEIGHT_CLASS_S_CONTAINER WEIGHT_CLASS_SMALL #define MAX_WEIGHT_CLASS_M_CONTAINER WEIGHT_CLASS_NORMAL #define MAX_WEIGHT_CLASS_BACKPACK WEIGHT_CLASS_BULKY +#define MAX_WEIGHT_CLASS_DUFFEL WEIGHT_CLASS_HUGE // max_volume for storages -#define STORAGE_VOLUME_CONTAINER_M (DEFAULT_VOLUME_NORMAL * 2) -#define STORAGE_VOLUME_SATCHEL (DEFAULT_VOLUME_NORMAL * 6) -#define STORAGE_VOLUME_BACKPACK (DEFAULT_VOLUME_NORMAL * 7) -#define STORAGE_VOLUME_DUFFLEBAG (DEFAULT_VOLUME_NORMAL * 10) -#define STORAGE_VOLUME_BAG_OF_HOLDING (DEFAULT_VOLUME_NORMAL * 20) +#define STORAGE_VOLUME_CONTAINER_M (DEFAULT_VOLUME_NORMAL * 8) //4 small items +#define STORAGE_VOLUME_SATCHEL (DEFAULT_VOLUME_NORMAL * 24) //4 normal items +#define STORAGE_VOLUME_BACKPACK (DEFAULT_VOLUME_NORMAL * 36) //6 normal items, or 3 bulky items +#define STORAGE_VOLUME_DUFFLEBAG (DEFAULT_VOLUME_NORMAL * 72) // 3 huge items, or 6 bulky items +#define STORAGE_VOLUME_BAG_OF_HOLDING (DEFAULT_VOLUME_NORMAL 54) //1.5X backpack diff --git a/code/game/objects/items/storage/backpack.dm b/code/game/objects/items/storage/backpack.dm index cdd43be55c32..a1af1c4877b9 100644 --- a/code/game/objects/items/storage/backpack.dm +++ b/code/game/objects/items/storage/backpack.dm @@ -443,11 +443,13 @@ item_state = "duffel" slowdown = 1 greyscale_colors = list(list(21, 11), list(14, 19), list(15, 16)) + w_class = WEIGHT_CLASS_HUGE /obj/item/storage/backpack/duffelbag/ComponentInitialize() . = ..() var/datum/component/storage/STR = GetComponent(/datum/component/storage) STR.max_volume = STORAGE_VOLUME_DUFFLEBAG + STR.max_w_class = MAX_WEIGHT_CLASS_DUFFEL LAZYINITLIST(STR.exception_hold) // This code allows you to fit one mob holder into a duffel bag STR.exception_hold += typecacheof(/obj/item/clothing/head/mob_holder) diff --git a/code/game/objects/items/storage/belt.dm b/code/game/objects/items/storage/belt.dm index 05b02e77f8b1..cff04430a1a3 100644 --- a/code/game/objects/items/storage/belt.dm +++ b/code/game/objects/items/storage/belt.dm @@ -10,7 +10,7 @@ attack_verb = list("whipped", "lashed", "disciplined") max_integrity = 300 equip_sound = 'sound/items/equip/toolbelt_equip.ogg' - w_class = WEIGHT_CLASS_BULKY + w_class = WEIGHT_CLASS_NORMAL var/content_overlays = FALSE //If this is true, the belt will gain overlays based on what it's holding supports_variations = VOX_VARIATION greyscale_icon_state = "belt" diff --git a/code/game/objects/items/storage/toolbox.dm b/code/game/objects/items/storage/toolbox.dm index 1daf6cf922a1..89ac1aa123f6 100644 --- a/code/game/objects/items/storage/toolbox.dm +++ b/code/game/objects/items/storage/toolbox.dm @@ -10,7 +10,7 @@ throwforce = 12 throw_speed = 2 throw_range = 7 - w_class = WEIGHT_CLASS_BULKY + w_class = WEIGHT_CLASS_NORMAL custom_materials = list(/datum/material/iron = 500) attack_verb = list("robusted") hitsound = 'sound/weapons/smash.ogg' From 5605b7ecd6b75b4ee6bef1d80f6d90b87eef1c73 Mon Sep 17 00:00:00 2001 From: Sun-Soaked <45698967+MemedHams@users.noreply.github.com> Date: Thu, 28 Sep 2023 09:49:17 -0400 Subject: [PATCH 09/21] oopsies --- code/__DEFINES/storage.dm | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/code/__DEFINES/storage.dm b/code/__DEFINES/storage.dm index 49970eadb54d..9cfe0a64f7db 100644 --- a/code/__DEFINES/storage.dm +++ b/code/__DEFINES/storage.dm @@ -83,4 +83,4 @@ GLOBAL_LIST_INIT(default_weight_class_to_volume, list( #define STORAGE_VOLUME_SATCHEL (DEFAULT_VOLUME_NORMAL * 24) //4 normal items #define STORAGE_VOLUME_BACKPACK (DEFAULT_VOLUME_NORMAL * 36) //6 normal items, or 3 bulky items #define STORAGE_VOLUME_DUFFLEBAG (DEFAULT_VOLUME_NORMAL * 72) // 3 huge items, or 6 bulky items -#define STORAGE_VOLUME_BAG_OF_HOLDING (DEFAULT_VOLUME_NORMAL 54) //1.5X backpack +#define STORAGE_VOLUME_BAG_OF_HOLDING (DEFAULT_VOLUME_NORMAL * 54) //1.5X backpack From c837844ca8061bcb0857c722ed51013742cd429c Mon Sep 17 00:00:00 2001 From: Sun-Soaked <45698967+MemedHams@users.noreply.github.com> Date: Thu, 28 Sep 2023 13:40:12 -0400 Subject: [PATCH 10/21] I was a stupid --- code/__DEFINES/storage.dm | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/code/__DEFINES/storage.dm b/code/__DEFINES/storage.dm index 9cfe0a64f7db..7ec54d4a7e7f 100644 --- a/code/__DEFINES/storage.dm +++ b/code/__DEFINES/storage.dm @@ -74,13 +74,15 @@ GLOBAL_LIST_INIT(default_weight_class_to_volume, list( // max_weight_class for storages // +#define MAX_WEIGHT_CLASS_S_CONTAINER WEIGHT_CLASS_SMALL #define MAX_WEIGHT_CLASS_M_CONTAINER WEIGHT_CLASS_NORMAL #define MAX_WEIGHT_CLASS_BACKPACK WEIGHT_CLASS_BULKY #define MAX_WEIGHT_CLASS_DUFFEL WEIGHT_CLASS_HUGE // max_volume for storages -#define STORAGE_VOLUME_CONTAINER_M (DEFAULT_VOLUME_NORMAL * 8) //4 small items -#define STORAGE_VOLUME_SATCHEL (DEFAULT_VOLUME_NORMAL * 24) //4 normal items -#define STORAGE_VOLUME_BACKPACK (DEFAULT_VOLUME_NORMAL * 36) //6 normal items, or 3 bulky items -#define STORAGE_VOLUME_DUFFLEBAG (DEFAULT_VOLUME_NORMAL * 72) // 3 huge items, or 6 bulky items -#define STORAGE_VOLUME_BAG_OF_HOLDING (DEFAULT_VOLUME_NORMAL * 54) //1.5X backpack +#define STORAGE_VOLUME_CONTAINER_S DEFAULT_VOLUME_NORMAL //3 small items +#define STORAGE_VOLUME_CONTAINER_M (DEFAULT_VOLUME_NORMAL * 2) //6 small items +#define STORAGE_VOLUME_SATCHEL (DEFAULT_VOLUME_NORMAL * 4) //4 normal items +#define STORAGE_VOLUME_BACKPACK (DEFAULT_VOLUME_NORMAL * 6) //6 normal items, or 3 bulky items +#define STORAGE_VOLUME_DUFFLEBAG (DEFAULT_VOLUME_NORMAL * 12) // 3 huge items, or 6 bulky items +#define STORAGE_VOLUME_BAG_OF_HOLDING (DEFAULT_VOLUME_NORMAL * 9) //1.5X backpack From 8919ec90276478f4cc83abcf071283f848c59d48 Mon Sep 17 00:00:00 2001 From: Sun-Soaked <45698967+MemedHams@users.noreply.github.com> Date: Mon, 6 Nov 2023 03:23:07 -0500 Subject: [PATCH 11/21] OOPS OOPSIES --- code/datums/components/storage/storage.dm | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/code/datums/components/storage/storage.dm b/code/datums/components/storage/storage.dm index 7fe22bd60e66..ca1d55927fdd 100644 --- a/code/datums/components/storage/storage.dm +++ b/code/datums/components/storage/storage.dm @@ -655,7 +655,7 @@ /datum/component/storage/proc/show_to_ghost(datum/source, mob/dead/observer/M) SIGNAL_HANDLER - return user_show_tou_mob(M, TRUE, TRUE) + return user_show_to_mob(M, TRUE, TRUE) /datum/component/storage/proc/signal_show_attempt(datum/source, mob/showto, force = FALSE) SIGNAL_HANDLER From d43b33e9b580412338bac9c4749cb154033886fc Mon Sep 17 00:00:00 2001 From: Sun-Soaked <45698967+MemedHams@users.noreply.github.com> Date: Wed, 8 Nov 2023 09:48:19 -0500 Subject: [PATCH 12/21] linters... --- code/_onclick/hud/storage.dm | 4 ++-- code/datums/components/storage/ui.dm | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/code/_onclick/hud/storage.dm b/code/_onclick/hud/storage.dm index 6e5a3c0eaa8f..7962c8ddf09d 100644 --- a/code/_onclick/hud/storage.dm +++ b/code/_onclick/hud/storage.dm @@ -57,8 +57,8 @@ /atom/movable/screen/storage/volumetric_box/Initialize(mapload, new_master, obj/item/our_item) src.our_item = our_item - RegisterSignal(our_item, COMSIG_ITEM_MOUSE_ENTER, .proc/on_item_mouse_enter) - RegisterSignal(our_item, COMSIG_ITEM_MOUSE_EXIT, .proc/on_item_mouse_exit) + RegisterSignal(our_item, COMSIG_ITEM_MOUSE_ENTER, PROC_REF(on_item_mouse_enter)) + RegisterSignal(our_item, COMSIG_ITEM_MOUSE_EXIT, PROC_REF(on_item_mouse_exit)) return ..() /atom/movable/screen/storage/volumetric_box/Destroy() diff --git a/code/datums/components/storage/ui.dm b/code/datums/components/storage/ui.dm index 094751081dcc..bac0fb3918f7 100644 --- a/code/datums/components/storage/ui.dm +++ b/code/datums/components/storage/ui.dm @@ -181,7 +181,7 @@ // in tiles var/maxallowedscreensize = cview[1]-8 // we got screen size, register signal - RegisterSignal(M, COMSIG_PARENT_QDELETING, .proc/on_logout, override = TRUE) + RegisterSignal(M, COMSIG_PARENT_QDELETING, PROC_REF(on_logout), override = TRUE) if(M.active_storage != src) if(M.active_storage) M.active_storage.ui_hide(M) From 5d193a7013947e5358ef975675a423142fd5b726 Mon Sep 17 00:00:00 2001 From: Sun-Soaked <45698967+MemedHams@users.noreply.github.com> Date: Mon, 19 Feb 2024 04:48:05 -0500 Subject: [PATCH 13/21] ouugh yeah --- code/datums/components/storage/storage.dm | 2 +- shiptest.dme | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/code/datums/components/storage/storage.dm b/code/datums/components/storage/storage.dm index ca1d55927fdd..ab96056dd69e 100644 --- a/code/datums/components/storage/storage.dm +++ b/code/datums/components/storage/storage.dm @@ -65,7 +65,7 @@ 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_pixel_y = 25 var/screen_start_x = 4 //These two are where the storage starts being rendered, screen_loc wise. var/screen_start_y = 2 //End diff --git a/shiptest.dme b/shiptest.dme index 18cb8e3ca1ea..e330c725b8ce 100644 --- a/shiptest.dme +++ b/shiptest.dme @@ -278,8 +278,8 @@ #include "code\_onclick\hud\revenanthud.dm" #include "code\_onclick\hud\robot.dm" #include "code\_onclick\hud\screen_objects.dm" -#include "code\_onclick\hud\storage.dm" #include "code\_onclick\hud\screentip.dm" +#include "code\_onclick\hud\storage.dm" #include "code\_onclick\hud\swarmer.dm" #include "code\controllers\admin.dm" #include "code\controllers\controller.dm" @@ -747,8 +747,8 @@ #include "code\datums\votes\_vote_datum.dm" #include "code\datums\votes\custom_vote.dm" #include "code\datums\votes\restart_vote.dm" -#include "code\datums\weather\weather.dm" #include "code\datums\votes\transfer_vote.dm" +#include "code\datums\weather\weather.dm" #include "code\datums\weather\weather_controller.dm" #include "code\datums\weather\weather_types\acid_rain.dm" #include "code\datums\weather\weather_types\ash_storm.dm" From c6eebacf7079d38305c4654d4726fd93941239b9 Mon Sep 17 00:00:00 2001 From: Sun-Soaked <45698967+MemedHams@users.noreply.github.com> Date: Mon, 19 Feb 2024 05:07:28 -0500 Subject: [PATCH 14/21] g! we waffle on balance a bit --- code/__DEFINES/storage.dm | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/code/__DEFINES/storage.dm b/code/__DEFINES/storage.dm index 7ec54d4a7e7f..0f1d6e1d7707 100644 --- a/code/__DEFINES/storage.dm +++ b/code/__DEFINES/storage.dm @@ -76,13 +76,13 @@ GLOBAL_LIST_INIT(default_weight_class_to_volume, list( // #define MAX_WEIGHT_CLASS_S_CONTAINER WEIGHT_CLASS_SMALL #define MAX_WEIGHT_CLASS_M_CONTAINER WEIGHT_CLASS_NORMAL -#define MAX_WEIGHT_CLASS_BACKPACK WEIGHT_CLASS_BULKY -#define MAX_WEIGHT_CLASS_DUFFEL WEIGHT_CLASS_HUGE +#define MAX_WEIGHT_CLASS_BACKPACK WEIGHT_CLASS_NORMA +#define MAX_WEIGHT_CLASS_DUFFEL WEIGHT_CLASS_BULKY // max_volume for storages #define STORAGE_VOLUME_CONTAINER_S DEFAULT_VOLUME_NORMAL //3 small items #define STORAGE_VOLUME_CONTAINER_M (DEFAULT_VOLUME_NORMAL * 2) //6 small items #define STORAGE_VOLUME_SATCHEL (DEFAULT_VOLUME_NORMAL * 4) //4 normal items #define STORAGE_VOLUME_BACKPACK (DEFAULT_VOLUME_NORMAL * 6) //6 normal items, or 3 bulky items -#define STORAGE_VOLUME_DUFFLEBAG (DEFAULT_VOLUME_NORMAL * 12) // 3 huge items, or 6 bulky items +#define STORAGE_VOLUME_DUFFLEBAG (DEFAULT_VOLUME_NORMAL * 8) // 2 huge items, or 4 bulky items #define STORAGE_VOLUME_BAG_OF_HOLDING (DEFAULT_VOLUME_NORMAL * 9) //1.5X backpack From 00f393274141472a45132c7d5c4a496171a60a08 Mon Sep 17 00:00:00 2001 From: Sun-Soaked <45698967+MemedHams@users.noreply.github.com> Date: Mon, 19 Feb 2024 05:44:20 -0500 Subject: [PATCH 15/21] whoops e --- code/__DEFINES/storage.dm | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/code/__DEFINES/storage.dm b/code/__DEFINES/storage.dm index 0f1d6e1d7707..1f2ff1313abe 100644 --- a/code/__DEFINES/storage.dm +++ b/code/__DEFINES/storage.dm @@ -76,7 +76,7 @@ GLOBAL_LIST_INIT(default_weight_class_to_volume, list( // #define MAX_WEIGHT_CLASS_S_CONTAINER WEIGHT_CLASS_SMALL #define MAX_WEIGHT_CLASS_M_CONTAINER WEIGHT_CLASS_NORMAL -#define MAX_WEIGHT_CLASS_BACKPACK WEIGHT_CLASS_NORMA +#define MAX_WEIGHT_CLASS_BACKPACK WEIGHT_CLASS_NORMAL #define MAX_WEIGHT_CLASS_DUFFEL WEIGHT_CLASS_BULKY // max_volume for storages From d5bbf0c6024fe6d691053a1a8e561be4e7e41d48 Mon Sep 17 00:00:00 2001 From: Sun-Soaked <45698967+MemedHams@users.noreply.github.com> Date: Mon, 19 Feb 2024 11:48:10 -0500 Subject: [PATCH 16/21] fixes port video james --- code/__DEFINES/storage.dm | 2 +- code/datums/components/storage/ui.dm | 9 ++++++--- 2 files changed, 7 insertions(+), 4 deletions(-) diff --git a/code/__DEFINES/storage.dm b/code/__DEFINES/storage.dm index 1f2ff1313abe..d04fdc7f0270 100644 --- a/code/__DEFINES/storage.dm +++ b/code/__DEFINES/storage.dm @@ -68,7 +68,7 @@ GLOBAL_LIST_INIT(default_weight_class_to_volume, list( // volume amount for items #define ITEM_VOLUME_DISK DEFAULT_VOLUME_TINY #define ITEM_VOLUME_CONTAINER_M 12 //makes nested toolboxes & toolbelts less efficient -#define ITEM_VOLUME_MOB 40//Just over half a duffel, prevents mob stacking +#define ITEM_VOLUME_MOB 40//prevents mob stacking // #define SAMPLE_VOLUME_AMOUNT 2 diff --git a/code/datums/components/storage/ui.dm b/code/datums/components/storage/ui.dm index bac0fb3918f7..e3e4c126d730 100644 --- a/code/datums/components/storage/ui.dm +++ b/code/datums/components/storage/ui.dm @@ -124,13 +124,15 @@ var/obj/item/I // start at this pixel from screen_start_x. var/current_pixel = VOLUMETRIC_STORAGE_EDGE_PADDING - var/row = 1 var/first = TRUE + var/row = 1 for(var/i in percentage_by_item) I = i var/percent = percentage_by_item[I] var/atom/movable/screen/storage/volumetric_box/center/B = new /atom/movable/screen/storage/volumetric_box/center(null, src, I) + // SNOWFLAKE: force it to icon until we unfuck storage/click passing + I.mouse_opacity = MOUSE_OPACITY_ICON var/pixels_to_use = overrun? MINIMUM_PIXELS_PER_ITEM : max(using_horizontal_pixels * percent, MINIMUM_PIXELS_PER_ITEM) var/addrow = FALSE if(CEILING(pixels_to_use, 1) >= FLOOR(horizontal_pixels - current_pixel - VOLUMETRIC_STORAGE_EDGE_PADDING, 1)) @@ -138,10 +140,10 @@ addrow = TRUE // now that we have pixels_to_use, place our thing and add it to the returned list. - B.screen_loc = "[screen_start_x]:[round(current_pixel + (pixels_to_use * 0.5) + (first? 0 : VOLUMETRIC_STORAGE_ITEM_PADDING), 1)],[screen_start_y+row-1]:[screen_pixel_y]" // add the used pixels to pixel after we place the object - current_pixel += pixels_to_use + VOLUMETRIC_STORAGE_ITEM_PADDING + current_pixel += pixels_to_use + (first? 0 : VOLUMETRIC_STORAGE_ITEM_PADDING) + first = FALSE //apply padding to everything after this // set various things B.set_pixel_size(pixels_to_use) @@ -153,6 +155,7 @@ // go up a row if needed if(addrow) row++ + first = TRUE //first in the row, don't apply between-item padding. current_pixel = VOLUMETRIC_STORAGE_EDGE_PADDING // Then, continuous section. From 9be0801553d15b6f2183361d02bd45d4c9f8e966 Mon Sep 17 00:00:00 2001 From: Sun-Soaked <45698967+MemedHams@users.noreply.github.com> Date: Sat, 16 Mar 2024 01:20:54 -0400 Subject: [PATCH 17/21] It's over --- code/datums/components/storage/storage.dm | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/code/datums/components/storage/storage.dm b/code/datums/components/storage/storage.dm index ab96056dd69e..746b6150f48d 100644 --- a/code/datums/components/storage/storage.dm +++ b/code/datums/components/storage/storage.dm @@ -359,7 +359,7 @@ ui_hide(source) /datum/component/storage/proc/close(mob/M) - ui_hide(usr) + ui_hide(M) /datum/component/storage/proc/close_all() SIGNAL_HANDLER From ad151fd5d2d04f2015094ae07964910f69829e9c Mon Sep 17 00:00:00 2001 From: Sun-Soaked <45698967+MemedHams@users.noreply.github.com> Date: Sun, 17 Mar 2024 14:39:16 -0400 Subject: [PATCH 18/21] fixes the screentips work on item in inventory again --- code/_onclick/hud/storage.dm | 2 ++ code/game/objects/items.dm | 4 +--- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/code/_onclick/hud/storage.dm b/code/_onclick/hud/storage.dm index 7962c8ddf09d..c10375df4e8b 100644 --- a/code/_onclick/hud/storage.dm +++ b/code/_onclick/hud/storage.dm @@ -76,6 +76,7 @@ makeItemInactive() /atom/movable/screen/storage/volumetric_box/MouseEntered(location, control, params) + . = ..() makeItemActive() /atom/movable/screen/storage/volumetric_box/proc/on_item_mouse_enter() @@ -168,6 +169,7 @@ return master.MouseExited(location, control, params) /atom/movable/screen/storage/volumetric_edge/MouseEntered(location, control, params) + . = ..() return master.MouseEntered(location, control, params) /atom/movable/screen/storage/volumetric_edge/stored_left diff --git a/code/game/objects/items.dm b/code/game/objects/items.dm index f747f3e6f475..a11a1df84ef4 100644 --- a/code/game/objects/items.dm +++ b/code/game/objects/items.dm @@ -845,6 +845,7 @@ GLOBAL_VAR_INIT(embedpocalypse, FALSE) // if true, all items will be able to emb /obj/item/MouseEntered(location, control, params) . = ..() + SEND_SIGNAL(src, COMSIG_ITEM_MOUSE_ENTER, location, control, params) if((item_flags & IN_INVENTORY || item_flags & IN_STORAGE) && usr.client.prefs.enable_tips && !QDELETED(src)) var/timedelay = usr.client.prefs.tip_delay/100 var/user = usr @@ -865,9 +866,6 @@ GLOBAL_VAR_INIT(embedpocalypse, FALSE) // if true, all items will be able to emb closeToolTip(usr) remove_outline() -/obj/item/MouseEntered(location,control,params) - SEND_SIGNAL(src, COMSIG_ITEM_MOUSE_ENTER, location, control, params) - /obj/item/proc/apply_outline(colour = null) if(!(item_flags & IN_INVENTORY || item_flags & IN_STORAGE) || QDELETED(src) || isobserver(usr)) return From 42f5b78659f6296e8b8324b4c465a1f9f6b8d0ce Mon Sep 17 00:00:00 2001 From: Sun-Soaked <45698967+MemedHams@users.noreply.github.com> Date: Sun, 24 Mar 2024 19:44:04 -0400 Subject: [PATCH 19/21] yeah. man --- code/game/objects/items/storage/backpack.dm | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/code/game/objects/items/storage/backpack.dm b/code/game/objects/items/storage/backpack.dm index 9b69ed9d729c..e11ebb2488df 100644 --- a/code/game/objects/items/storage/backpack.dm +++ b/code/game/objects/items/storage/backpack.dm @@ -20,7 +20,7 @@ righthand_file = 'icons/mob/inhands/equipment/backpack_righthand.dmi' pickup_sound = "rustle" drop_sound = "rustle" - w_class = WEIGHT_CLASS_BULKY + w_class = WEIGHT_CLASS_HUGE slot_flags = ITEM_SLOT_BACK //ERROOOOO resistance_flags = NONE max_integrity = 300 From 0780b3ca2be056d4e9f09f0ea8a5bcf285fcb8ce Mon Sep 17 00:00:00 2001 From: Sun-Soaked <45698967+MemedHams@users.noreply.github.com> Date: Sun, 24 Mar 2024 19:47:35 -0400 Subject: [PATCH 20/21] forgot about these --- code/__DEFINES/storage.dm | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/code/__DEFINES/storage.dm b/code/__DEFINES/storage.dm index d04fdc7f0270..cb657520e33f 100644 --- a/code/__DEFINES/storage.dm +++ b/code/__DEFINES/storage.dm @@ -34,9 +34,9 @@ #define WEIGHT_CLASS_SMALL 2 /// Can be carried in one hand comfortably, ex: Fire extinguisher, Stunbaton, Gas Mask, Metal Sheets #define WEIGHT_CLASS_NORMAL 3 -/// Items that can be wielded or equipped, (e.g. defibrillator, backpack, space suits). Often fits inside backpacks. +/// Items that can be wielded or equipped, (e.g. defibrillator, space suits). Often fits inside backpacks. #define WEIGHT_CLASS_BULKY 4 -/// Usually represents objects that require two hands to operate, (e.g. shotgun, two-handed melee weapons) May fit on some inventory slots or huge storage objects(like duffel bags) +/// Usually represents objects that require two hands to operate, (e.g. shotgun, two-handed melee weapons) May fit on some inventory slots #define WEIGHT_CLASS_HUGE 5 /// Essentially means it cannot be picked up or placed in an inventory, ex: Mech Parts, Safe - Can not fit in Boh #define WEIGHT_CLASS_GIGANTIC 6 From bd3b148fe433f101b0ab1f77848031bae70957a1 Mon Sep 17 00:00:00 2001 From: Sun-Soaked <45698967+MemedHams@users.noreply.github.com> Date: Sun, 7 Apr 2024 04:25:20 -0400 Subject: [PATCH 21/21] temp till pr 2 --- code/game/objects/items/storage/backpack.dm | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/code/game/objects/items/storage/backpack.dm b/code/game/objects/items/storage/backpack.dm index e11ebb2488df..91bf0d2dbccb 100644 --- a/code/game/objects/items/storage/backpack.dm +++ b/code/game/objects/items/storage/backpack.dm @@ -220,7 +220,7 @@ /obj/item/storage/backpack/satchel/ComponentInitialize() . = ..() var/datum/component/storage/STR = GetComponent(/datum/component/storage) - STR.max_volume = STORAGE_VOLUME_SATCHEL + STR.max_volume = STORAGE_VOLUME_BACKPACK STR.max_w_class = MAX_WEIGHT_CLASS_M_CONTAINER /obj/item/storage/backpack/satchel/leather