Skip to content

Commit

Permalink
Soulifies Backpacks & Duffels (#3865)
Browse files Browse the repository at this point in the history
<!-- Write **BELOW** The Headers and **ABOVE** The comments else it may
not be viewable. -->
<!-- You can view Contributing.MD for a detailed description of the pull
request process. -->

## 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. 
<!-- Describe The Pull Request. Please be sure every change is
documented or this can delay review and even discourage maintainers from
merging your PR! -->

## 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
<!-- Please add a short description of why you think these changes would
benefit the game. If you can't justify it in words, it might not be
worth adding. -->

## 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:

<!-- Both :cl:'s are required for the changelog to work! You can put
your name to the right of the first :cl: if you want to overwrite your
GitHub username as author ingame. -->
<!-- You can use multiple of the same prefix (they're only used for the
icon ingame) and delete the unneeded ones. Despite some of the tags,
changelogs should generally represent how a player might be affected by
the changes rather than a summary of the PR's contents. -->

---------

Signed-off-by: Sun-Soaked <[email protected]>
Co-authored-by: Theos <[email protected]>
  • Loading branch information
Sun-Soaked and SomeguyManperson authored Jan 7, 2025
1 parent 39dcf08 commit 9e162aa
Show file tree
Hide file tree
Showing 9 changed files with 96 additions and 19 deletions.
8 changes: 4 additions & 4 deletions code/__DEFINES/storage.dm
Original file line number Diff line number Diff line change
Expand Up @@ -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( \
Expand Down
68 changes: 60 additions & 8 deletions code/datums/components/storage/storage.dm
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -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))
Expand Down Expand Up @@ -222,7 +228,7 @@
SIGNAL_HANDLER

if(locked)
to_chat(M, "<span class='warning'>[parent] seems to be [locked_flavor]!</span>")
to_chat(M, "<span class='warning'>[parent] [locked_flavor]</span>")
return FALSE
if((M.get_active_held_item() == parent) && allow_quick_empty)
INVOKE_ASYNC(src, PROC_REF(quick_empty), M)
Expand All @@ -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, "<span class='warning'>[parent] seems to be [locked_flavor]!</span>")
to_chat(M, "<span class='warning'>[parent] [locked_flavor]</span>")
return FALSE
var/obj/item/I = O
if(collection_mode == COLLECT_ONE)
Expand Down Expand Up @@ -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, "<span class='warning'>[parent] seems to be [locked_flavor]!</span>")
return FALSE
Expand Down Expand Up @@ -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, "<span class='warning'>[parent] seems to be [locked_flavor]!</span>")
return FALSE
Expand Down Expand Up @@ -530,6 +542,8 @@
if(locked && !force)
to_chat(M, "<span class='warning'>[parent] seems to be [locked_flavor]!</span>")
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)
Expand All @@ -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)
Expand All @@ -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)
Expand Down Expand Up @@ -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
Expand Down Expand Up @@ -755,6 +772,8 @@

if(A.loc == user)
. = COMPONENT_NO_ATTACK_HAND
if(!access_check())
return FALSE
if(locked)
to_chat(user, "<span class='warning'>[parent] seems to be [locked_flavor]!</span>")
else
Expand All @@ -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

Expand All @@ -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, "<span class='warning'>[parent] seems to be [locked_flavor]!</span>")
return
Expand Down Expand Up @@ -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
8 changes: 8 additions & 0 deletions code/game/objects/items.dm
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
20 changes: 19 additions & 1 deletion code/game/objects/items/storage/backpack.dm
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -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"
Expand Down Expand Up @@ -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."
Expand Down Expand Up @@ -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"
Expand Down
2 changes: 1 addition & 1 deletion code/game/objects/items/storage/ration.dm
Original file line number Diff line number Diff line change
Expand Up @@ -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, "<span class='notice'>You tear open \the [src].</span>")
Expand Down
2 changes: 1 addition & 1 deletion code/modules/clothing/outfits/ert/roumain_ert.dm
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
3 changes: 1 addition & 2 deletions code/modules/clothing/outfits/factions/minutemen.dm
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
2 changes: 1 addition & 1 deletion code/modules/mob/living/carbon/human/species.dm
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
2 changes: 1 addition & 1 deletion code/modules/mob/living/carbon/inventory.dm
Original file line number Diff line number Diff line change
Expand Up @@ -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))
Expand Down

0 comments on commit 9e162aa

Please sign in to comment.