From 9e162aa6b6cc5da620e16f345a419a7b46aae2c8 Mon Sep 17 00:00:00 2001 From: Sun-Soaked <45698967+Sun-Soaked@users.noreply.github.com> Date: Tue, 7 Jan 2025 08:06:45 -0500 Subject: [PATCH] Soulifies Backpacks & Duffels (#3865) ## About The Pull Request Backpacks and Duffel bags can now carry bulky items, and Duffel bags now have more storage space. Backpacks cannot be opened while worn on your back. Duffels now cannot be opened unless placed on the ground. ## Why It's Good For The Game This gives satchel/messenger bag's low storage space an upside(access from back), while justifying putting bigger items in storage objects that really should be able to carry them. Duffel bags are now very well-storage spaced, and can be specialized as a kind of stash bag. Backpack and duffel bags may need to have even more storage space to compensate, but for now I've been pretty frugal in buffing it. It's soul. Soon you will understand my vision ## Changelog :cl: balance: Backpacks can now carry Bulky items, but can no longer be accessed while on your back. balance: Duffel bags can now carry more, but must be placed on the ground to be opened. /:cl: --------- Signed-off-by: Sun-Soaked <45698967+Sun-Soaked@users.noreply.github.com> Co-authored-by: Theos --- code/__DEFINES/storage.dm | 8 +-- code/datums/components/storage/storage.dm | 68 ++++++++++++++++--- code/game/objects/items.dm | 8 +++ code/game/objects/items/storage/backpack.dm | 20 +++++- code/game/objects/items/storage/ration.dm | 2 +- .../clothing/outfits/ert/roumain_ert.dm | 2 +- .../clothing/outfits/factions/minutemen.dm | 3 +- .../mob/living/carbon/human/species.dm | 2 +- code/modules/mob/living/carbon/inventory.dm | 2 +- 9 files changed, 96 insertions(+), 19 deletions(-) diff --git a/code/__DEFINES/storage.dm b/code/__DEFINES/storage.dm index 01d77e0df2f2..ac23c09538e6 100644 --- a/code/__DEFINES/storage.dm +++ b/code/__DEFINES/storage.dm @@ -76,16 +76,16 @@ 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_NORMAL +#define MAX_WEIGHT_CLASS_BACKPACK WEIGHT_CLASS_BULKY #define MAX_WEIGHT_CLASS_DUFFEL WEIGHT_CLASS_BULKY // max_volume for storages #define STORAGE_VOLUME_CONTAINER_S DEFAULT_VOLUME_NORMAL //4 small items #define STORAGE_VOLUME_CONTAINER_M (DEFAULT_VOLUME_NORMAL * 2) //8 small items #define STORAGE_VOLUME_SATCHEL (DEFAULT_VOLUME_NORMAL * 4) //4 normal items -#define STORAGE_VOLUME_BACKPACK (DEFAULT_VOLUME_NORMAL * 6) //1.5x satchel, 3 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 +#define STORAGE_VOLUME_BACKPACK (DEFAULT_VOLUME_NORMAL * 6) //3 bulky items +#define STORAGE_VOLUME_DUFFLEBAG (DEFAULT_VOLUME_NORMAL * 10) //~1.4X backpack, 5 bulky items +#define STORAGE_VOLUME_BAG_OF_HOLDING (DEFAULT_VOLUME_NORMAL * 10) //Whitelist for the suit storage slot on medical suits #define MEDICAL_SUIT_ALLOWED_ITEMS list( \ diff --git a/code/datums/components/storage/storage.dm b/code/datums/components/storage/storage.dm index 6350d737d31b..268802e14dce 100644 --- a/code/datums/components/storage/storage.dm +++ b/code/datums/components/storage/storage.dm @@ -25,7 +25,12 @@ var/list/mob/is_using //lazy list of mobs looking at the contents of this storage. 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/locked_flavor = "seems to be locked!" //prevents tochat messages related to locked from sending + + /// If the storage object can be accessed while equipped to slot by mob(e.g. backpack in back slot) + var/worn_access = TRUE + /// If the storage object can be accessed while being held anywhere on a mob + var/carry_access = TRUE /// Storage flags, including what kinds of limiters we use for how many items we can hold var/storage_flags = STORAGE_FLAGS_LEGACY_DEFAULT @@ -110,6 +115,7 @@ RegisterSignal(parent, COMSIG_ITEM_PRE_ATTACK, PROC_REF(preattack_intercept)) RegisterSignal(parent, COMSIG_ITEM_ATTACK_SELF, PROC_REF(attack_self)) RegisterSignal(parent, COMSIG_ITEM_PICKUP, PROC_REF(signal_on_pickup)) + RegisterSignal(parent, COMSIG_ITEM_EQUIPPED, PROC_REF(signal_on_equip)) RegisterSignal(parent, COMSIG_MOVABLE_POST_THROW, PROC_REF(close_all)) RegisterSignal(parent, COMSIG_MOVABLE_MOVED, PROC_REF(on_move)) @@ -222,7 +228,7 @@ SIGNAL_HANDLER if(locked) - to_chat(M, "[parent] seems to be [locked_flavor]!") + to_chat(M, "[parent] [locked_flavor]") return FALSE if((M.get_active_held_item() == parent) && allow_quick_empty) INVOKE_ASYNC(src, PROC_REF(quick_empty), M) @@ -233,8 +239,10 @@ if(!isitem(O) || !click_gather || SEND_SIGNAL(O, COMSIG_CONTAINS_STORAGE)) return FALSE . = COMPONENT_NO_ATTACK + if(!access_check()) + return FALSE if(locked) - to_chat(M, "[parent] seems to be [locked_flavor]!") + to_chat(M, "[parent] [locked_flavor]") return FALSE var/obj/item/I = O if(collection_mode == COLLECT_ONE) @@ -309,6 +317,8 @@ var/atom/A = parent if(!M.canUseStorage() || !A.Adjacent(M) || M.incapacitated()) return + if(!access_check()) + return FALSE if(locked) to_chat(M, "[parent] seems to be [locked_flavor]!") return FALSE @@ -426,6 +436,8 @@ var/atom/A = parent var/atom/dump_destination = dest_object.get_dumping_location() if(M.CanReach(A) && dump_destination && M.CanReach(dump_destination)) + if(!access_check()) + return FALSE if(locked) to_chat(M, "[parent] seems to be [locked_flavor]!") return FALSE @@ -530,6 +542,8 @@ if(locked && !force) to_chat(M, "[parent] seems to be [locked_flavor]!") return FALSE + if(!access_check()) + return FALSE if(force || M.CanReach(parent, view_only = TRUE)) if(use_sound && !silent) playsound(A, use_sound, 50, TRUE, -5) @@ -548,7 +562,7 @@ //This proc return 1 if the item can be picked up and 0 if it can't. //Set the stop_messages to stop it from printing messages -/datum/component/storage/proc/can_be_inserted(obj/item/I, stop_messages = FALSE, mob/M) +/datum/component/storage/proc/can_be_inserted(obj/item/I, stop_messages = FALSE, mob/M, bypass_access = FALSE) if(!istype(I) || (I.item_flags & ABSTRACT)) return FALSE //Not an item if(I == parent) @@ -557,6 +571,9 @@ var/atom/host = parent if(real_location == I.loc) return FALSE //Means the item is already in the storage item + if(!bypass_access)//For stuff like setting up outfits, setting up roundstart backpacks, etc. + if(!access_check()) + return FALSE if(locked) if(M && !stop_messages) host.add_fingerprint(M) @@ -660,17 +677,17 @@ var/obj/O = parent O.update_appearance() -/datum/component/storage/proc/signal_insertion_attempt(datum/source, obj/item/I, mob/M, silent = FALSE, force = FALSE) +/datum/component/storage/proc/signal_insertion_attempt(datum/source, obj/item/I, mob/M, silent = FALSE, force = FALSE, bypass_access = FALSE) SIGNAL_HANDLER - if((!force && !can_be_inserted(I, TRUE, M)) || (I == parent)) + if((!force && !can_be_inserted(I, TRUE, M, bypass_access)) || (I == parent)) return FALSE return handle_item_insertion(I, silent, M) -/datum/component/storage/proc/signal_can_insert(datum/source, obj/item/I, mob/M, silent = FALSE) +/datum/component/storage/proc/signal_can_insert(datum/source, obj/item/I, mob/M, silent = FALSE, bypass_access = FALSE) SIGNAL_HANDLER - return can_be_inserted(I, silent, M) + return can_be_inserted(I, silent, M, bypass_access) /datum/component/storage/proc/show_to_ghost(datum/source, mob/dead/observer/M) SIGNAL_HANDLER @@ -755,6 +772,8 @@ if(A.loc == user) . = COMPONENT_NO_ATTACK_HAND + if(!access_check()) + return FALSE if(locked) to_chat(user, "[parent] seems to be [locked_flavor]!") else @@ -769,6 +788,12 @@ for(var/mob/M in can_see_contents() - user) close(M) +/datum/component/storage/proc/signal_on_equip(datum/source, mob/user) + SIGNAL_HANDLER + + if(!worn_access) + close(user) + /datum/component/storage/proc/signal_take_obj(datum/source, atom/movable/AM, new_loc, force = FALSE) SIGNAL_HANDLER @@ -794,6 +819,8 @@ /datum/component/storage/proc/on_alt_click_async(datum/source, mob/user) if(!isliving(user) || !user.CanReach(parent) || user.incapacitated()) return + if(!access_check()) + return FALSE if(locked) to_chat(user, "[parent] seems to be [locked_flavor]!") return @@ -833,3 +860,28 @@ //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) + +//checks for mob-related storage access conditions +/datum/component/storage/proc/access_check(message = TRUE) + var/atom/ourparent = parent + var/datum/component/storage/otherstorage + + //if we are inside another storage object, let's move up and check access there instead + if(istype(ourparent.loc, /obj/item/storage)) + ourparent = ourparent.loc + //get our parent's storage component so we can check their access vars + otherstorage = ourparent.GetComponent(/datum/component/storage) + + if(ismob(ourparent.loc)) + var/mob/holder = ourparent.loc + + if(otherstorage? !otherstorage.carry_access : !carry_access) + if(message) + to_chat(holder, span_warning( "[ourparent] is too cumbersome to open inhand, you're going to have to set it down!")) + return FALSE + + if((otherstorage? !otherstorage.worn_access : !worn_access) && !holder.held_items.Find(ourparent)) + if(message) + to_chat(holder, span_warning( "Your arms aren't long enough to reach [ourparent] while it's on your back!")) + return FALSE + return TRUE diff --git a/code/game/objects/items.dm b/code/game/objects/items.dm index c4358a71714d..23de618975a8 100644 --- a/code/game/objects/items.dm +++ b/code/game/objects/items.dm @@ -421,6 +421,14 @@ GLOBAL_VAR_INIT(embedpocalypse, FALSE) // if true, all items will be able to emb if(anchored) return + //check if the item is inside another item's storage + if(istype(loc, /obj/item/storage)) + //if so, can we actually access it? + var/datum/component/storage/ourstorage = loc.GetComponent(/datum/component/storage) + if(!ourstorage.access_check()) + SEND_SIGNAL(loc, COMSIG_TRY_STORAGE_HIDE_FROM, user)//you're not supposed to be in here right now, punk! + return + if(resistance_flags & ON_FIRE) var/mob/living/carbon/C = user var/can_handle_hot = FALSE diff --git a/code/game/objects/items/storage/backpack.dm b/code/game/objects/items/storage/backpack.dm index d785eacd9c87..88dd8d3cb534 100644 --- a/code/game/objects/items/storage/backpack.dm +++ b/code/game/objects/items/storage/backpack.dm @@ -46,6 +46,15 @@ STR.max_volume = STORAGE_VOLUME_BACKPACK STR.max_w_class = MAX_WEIGHT_CLASS_BACKPACK STR.use_sound = 'sound/items/storage/unzip.ogg' + STR.worn_access = FALSE + +/obj/machinery/examine(mob/user) + . = ..() + var/datum/component/storage/bpack = GetComponent(/datum/component/storage) + if(bpack.worn_access == FALSE) + . += span_notice("You won't be able to open this once it's on your back.") + if(bpack.carry_access == FALSE) + . += span_notice("You'll have to set this down on the floor if you want to open it.") /* * Backpack Types @@ -192,8 +201,9 @@ /obj/item/storage/backpack/satchel/ComponentInitialize() . = ..() var/datum/component/storage/STR = GetComponent(/datum/component/storage) - STR.max_volume = STORAGE_VOLUME_BACKPACK + STR.max_volume = STORAGE_VOLUME_SATCHEL STR.max_w_class = MAX_WEIGHT_CLASS_M_CONTAINER + STR.worn_access = TRUE /obj/item/storage/backpack/satchel/leather name = "leather satchel" @@ -324,6 +334,13 @@ greyscale_icon_state = "satchel" greyscale_colors = list(list(15, 16), list(19, 13), list(13, 18)) +/obj/item/storage/backpack/messenger/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 + STR.worn_access = TRUE + /obj/item/storage/backpack/messenger/chem name = "chemistry messenger bag" desc = "A sterile backpack worn over one shoulder. This one is in Chemistry colors." @@ -404,6 +421,7 @@ 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) + STR.carry_access = FALSE /obj/item/storage/backpack/duffelbag/captain name = "captain's duffel bag" diff --git a/code/game/objects/items/storage/ration.dm b/code/game/objects/items/storage/ration.dm index 9a9e4a5a2617..9254e3014f7b 100644 --- a/code/game/objects/items/storage/ration.dm +++ b/code/game/objects/items/storage/ration.dm @@ -32,7 +32,7 @@ /obj/item/reagent_containers/food, /obj/item/ration_heater)) STR.locked = TRUE - STR.locked_flavor = "sealed closed" + STR.locked_flavor = "seems to be sealed closed!" /obj/item/storage/ration/proc/open_ration(mob/user) to_chat(user, "You tear open \the [src].") diff --git a/code/modules/clothing/outfits/ert/roumain_ert.dm b/code/modules/clothing/outfits/ert/roumain_ert.dm index efe7828173be..74802bdbba0b 100644 --- a/code/modules/clothing/outfits/ert/roumain_ert.dm +++ b/code/modules/clothing/outfits/ert/roumain_ert.dm @@ -32,7 +32,7 @@ l_pocket = /obj/item/ammo_box/a44roum_speedloader - backpack_contents = list(/obj/item/ammo_box/magazine/c45_firestorm_mag/pan = 3, /obj/item/ammo_box/a44roum_speedloader = 2, /obj/item/storage/box/ammo/a44roum) + backpack_contents = list(/obj/item/ammo_box/magazine/c45_firestorm_mag/pan = 2, /obj/item/ammo_box/a44roum_speedloader = 2, /obj/item/storage/box/ammo/a44roum) /datum/outfit/job/roumain/ert/vickland name = "ERT - Saint-Roumain Hunter (Vickland)" // vickland and candor diff --git a/code/modules/clothing/outfits/factions/minutemen.dm b/code/modules/clothing/outfits/factions/minutemen.dm index 3f99cc85087f..040acb06d7c4 100644 --- a/code/modules/clothing/outfits/factions/minutemen.dm +++ b/code/modules/clothing/outfits/factions/minutemen.dm @@ -224,8 +224,7 @@ l_hand = /obj/item/storage/briefcase - backpack = /obj/item/storage/backpack/satchel/leather - satchel = /obj/item/storage/backpack/satchel/leather + backpack = /obj/item/storage/backpack/industrial l_pocket = /obj/item/toy/crayon/white r_pocket = /obj/item/radio diff --git a/code/modules/mob/living/carbon/human/species.dm b/code/modules/mob/living/carbon/human/species.dm index 53de44fcd934..911532299839 100644 --- a/code/modules/mob/living/carbon/human/species.dm +++ b/code/modules/mob/living/carbon/human/species.dm @@ -1273,7 +1273,7 @@ GLOBAL_LIST_EMPTY(roundstart_races) return TRUE if(ITEM_SLOT_BACKPACK) if(H.back) - if(SEND_SIGNAL(H.back, COMSIG_TRY_STORAGE_CAN_INSERT, I, H, TRUE)) + if(SEND_SIGNAL(H.back, COMSIG_TRY_STORAGE_CAN_INSERT, I, H, TRUE, TRUE)) return TRUE return FALSE return FALSE //Unsupported slot diff --git a/code/modules/mob/living/carbon/inventory.dm b/code/modules/mob/living/carbon/inventory.dm index f1cbd3156723..63032ceb1eca 100644 --- a/code/modules/mob/living/carbon/inventory.dm +++ b/code/modules/mob/living/carbon/inventory.dm @@ -106,7 +106,7 @@ put_in_hands(I) update_inv_hands() if(ITEM_SLOT_BACKPACK) - if(!back || !SEND_SIGNAL(back, COMSIG_TRY_STORAGE_INSERT, I, src, TRUE)) + if(!back || !SEND_SIGNAL(back, COMSIG_TRY_STORAGE_INSERT, I, src, TRUE, FALSE, TRUE)) not_handled = TRUE if(ITEM_SLOT_ID) if(!wear_id || !SEND_SIGNAL(wear_id, COMSIG_TRY_STORAGE_INSERT, I, src, TRUE))