Tsu's Brand Spanking New Storage: or, How I Learned To Pass Github Copilot As My Own Code (#67478)

Currently, storage works as a subtype of /datum/component, utilizing GetComponent() and signals to operate. While this is a pretty good idea in theory, the execution was pretty trash, and we end up with alot of GetComponent() snowflake code (something that shouldn't even need to be used frankly), and a heaping load of scattered procs that lead into one another, and procs that don't get utilized properly.

Instead, this PR adds atom_storage and proc/create_storage(. . .) to every atom, allowing for the possibility of storage on quite frankly anything. Not only does this entirely remove the need for signals, but it heavily squashes down the number of needed procs in total (removing snowflake signal procs that just lead to one another), reducing overall proc overhead and improving performance.
This commit is contained in:
magatsuchi
2022-07-08 18:13:18 -07:00
committed by GitHub
parent 944eb14541
commit 7d0f393f5d
133 changed files with 2056 additions and 2358 deletions
@@ -1,32 +0,0 @@
// /datum/component/storage signals
///() - returns bool.
#define COMSIG_CONTAINS_STORAGE "is_storage"
///(obj/item/inserting, mob/user, silent, force) - returns bool
#define COMSIG_TRY_STORAGE_INSERT "storage_try_insert"
///(mob/show_to, force) - returns bool.
#define COMSIG_TRY_STORAGE_SHOW "storage_show_to"
///(mob/hide_from) - returns bool
#define COMSIG_TRY_STORAGE_HIDE_FROM "storage_hide_from"
///returns bool
#define COMSIG_TRY_STORAGE_HIDE_ALL "storage_hide_all"
///(newstate)
#define COMSIG_TRY_STORAGE_SET_LOCKSTATE "storage_lock_set_state"
///() - returns bool. MUST CHECK IF STORAGE IS THERE FIRST!
#define COMSIG_IS_STORAGE_LOCKED "storage_get_lockstate"
///(type, atom/destination, amount = INFINITY, check_adjacent, force, mob/user, list/inserted) - returns bool - type can be a list of types.
#define COMSIG_TRY_STORAGE_TAKE_TYPE "storage_take_type"
///(type, amount = INFINITY, force = FALSE). Force will ignore max_items, and amount is normally clamped to max_items.
#define COMSIG_TRY_STORAGE_FILL_TYPE "storage_fill_type"
///(obj, new_loc, force = FALSE) - returns bool
#define COMSIG_TRY_STORAGE_TAKE "storage_take_obj"
///(loc) - returns bool - if loc is null it will dump at parent location.
#define COMSIG_TRY_STORAGE_QUICK_EMPTY "storage_quick_empty"
///(list/list_to_inject_results_into, recursively_search_inside_storages = TRUE)
#define COMSIG_TRY_STORAGE_RETURN_INVENTORY "storage_return_inventory"
///(obj/item/insertion_candidate, mob/user, silent) - returns bool
#define COMSIG_TRY_STORAGE_CAN_INSERT "storage_can_equip"
//from base of atom/movable/on_enter_storage(): (datum/component/storage/concrete/master_storage)
#define COMSIG_STORAGE_ENTERED "storage_entered"
//from base of atom/movable/on_exit_storage(): (datum/component/storage/concrete/master_storage)
#define COMSIG_STORAGE_EXITED "storage_exited"
+2
View File
@@ -58,6 +58,8 @@ GLOBAL_LIST_INIT(bitflags, list(1, 2, 4, 8, 16, 32, 64, 128, 256, 512, 1024, 204
#define IS_PLAYER_COLORABLE_1 (1<<21)
/// Whether or not this atom has contextual screentips when hovered OVER
#define HAS_CONTEXTUAL_SCREENTIPS_1 (1<<22)
// Whether or not this atom is storing contents for a disassociated storage object
#define HAS_DISASSOCIATED_STORAGE_1 (1<<23)
// Update flags for [/atom/proc/update_appearance]
/// Update the atom's name
+5 -5
View File
@@ -2,15 +2,15 @@
//ITEM INVENTORY WEIGHT, FOR w_class
/// Usually items smaller then a human hand, (e.g. playing cards, lighter, scalpel, coins/holochips)
#define WEIGHT_CLASS_TINY 1
#define WEIGHT_CLASS_TINY 1
/// Pockets can hold small and tiny items, (e.g. flashlight, multitool, grenades, GPS device)
#define WEIGHT_CLASS_SMALL 2
#define WEIGHT_CLASS_SMALL 2
/// Standard backpacks can carry tiny, small & normal items, (e.g. fire extinguisher, stun baton, gas mask, metal sheets)
#define WEIGHT_CLASS_NORMAL 3
#define WEIGHT_CLASS_NORMAL 3
/// Items that can be weilded or equipped but not stored in an inventory, (e.g. defibrillator, backpack, space suits)
#define WEIGHT_CLASS_BULKY 4
#define WEIGHT_CLASS_BULKY 4
/// Usually represents objects that require two hands to operate, (e.g. shotgun, two-handed melee weapons)
#define WEIGHT_CLASS_HUGE 5
#define WEIGHT_CLASS_HUGE 5
/// Essentially means it cannot be picked up or placed in an inventory, (e.g. mech parts, safe)
#define WEIGHT_CLASS_GIGANTIC 6
+1 -5
View File
@@ -319,11 +319,7 @@ rough example of the "cone" made by the 3 dirs checked
. = list()
if(!istype(target) || !(target.item_flags & IN_STORAGE))
return
var/datum/component/storage/concrete/storage_datum = target.loc.GetComponent(/datum/component/storage/concrete)
var/datum/storage/storage_datum = target.loc.atom_storage
if(!storage_datum)
return
. += storage_datum.parent
for(var/datum/component/storage/slave as anything in storage_datum.slaves)
if(!isatom(slave.parent))
continue
. += slave.parent
+1
View File
@@ -116,6 +116,7 @@ DEFINE_BITFIELD(flags_1, list(
"CAN_BE_DIRTY_1" = CAN_BE_DIRTY_1,
"CONDUCT_1" = CONDUCT_1,
"HAS_CONTEXTUAL_SCREENTIPS_1" = HAS_CONTEXTUAL_SCREENTIPS_1,
"HAS_DISASSOCIATED_STORAGE_1" = HAS_DISASSOCIATED_STORAGE_1,
"HOLOGRAM_1" = HOLOGRAM_1,
"INITIALIZED_1" = INITIALIZED_1,
"IS_ONTOP_1" = IS_ONTOP_1,
+10 -3
View File
@@ -153,6 +153,12 @@
if(!loc.AllowClick())
return
// In a storage item with a disassociated storage parent
var/obj/item/item_atom = A
if(istype(item_atom))
if((item_atom.item_flags & IN_STORAGE) && (item_atom.loc.flags_1 & HAS_DISASSOCIATED_STORAGE_1))
UnarmedAttack(item_atom, TRUE, modifiers)
//Standard reach turf to turf or reaching inside storage
if(CanReach(A,W))
if(W)
@@ -206,6 +212,7 @@
var/list/closed = list()
var/list/checking = list(ultimate_target)
while (checking.len && depth > 0)
var/list/next = list()
--depth
@@ -214,7 +221,7 @@
if(closed[target] || isarea(target)) // avoid infinity situations
continue
if(isturf(target) || isturf(target.loc) || (target in direct_access) || (ismovable(target) && target.flags_1 & IS_ONTOP_1)) //Directly accessible atoms
if(isturf(target) || isturf(target.loc) || (target in direct_access) || (ismovable(target) && target.flags_1 & IS_ONTOP_1) || target.loc.atom_storage) //Directly accessible atoms
if(Adjacent(target) || (tool && CheckToolReach(src, target, tool.reach))) //Adjacent or reaching attacks
return TRUE
@@ -223,8 +230,7 @@
if (!target.loc)
continue
//Storage and things with reachable internal atoms need add to next here. Or return COMPONENT_ALLOW_REACH.
if(SEND_SIGNAL(target.loc, COMSIG_ATOM_CANREACH, next) & COMPONENT_ALLOW_REACH)
if(target.loc.atom_storage)
next += target.loc
checking = next
@@ -285,6 +291,7 @@
* modifiers is a lazy list of click modifiers this attack had,
* used for figuring out different properties of the click, mostly right vs left and such.
*/
/mob/proc/UnarmedAttack(atom/A, proximity_flag, list/modifiers)
if(ismob(A))
changeNext_move(CLICK_CD_MELEE)
+3 -3
View File
@@ -247,8 +247,8 @@
master = new_master
/atom/movable/screen/close/Click()
var/datum/component/storage/S = master
S.hide_from(usr)
var/datum/storage/storage = master
storage.hide_contents(usr)
return TRUE
/atom/movable/screen/drop
@@ -453,7 +453,7 @@
return TRUE
if(usr.incapacitated())
return TRUE
if (ismecha(usr.loc)) // stops inventory actions in a mech
if(ismecha(usr.loc)) // stops inventory actions in a mech
return TRUE
if(master)
var/obj/item/I = usr.get_active_held_item()
+1 -1
View File
@@ -161,7 +161,7 @@
var/list/present_qualities = list()
for(var/obj/item/contained_item in source.contents)
if(contained_item.GetComponent(/datum/component/storage))
if(contained_item.atom_storage)
for(var/obj/item/subcontained_item in contained_item.contents)
available_tools[subcontained_item.type] = TRUE
if(subcontained_item.tool_behaviour)
+8 -4
View File
@@ -34,8 +34,10 @@
if(isclothing(parent))
RegisterSignal(parent, COMSIG_ITEM_EQUIPPED, .proc/on_equip)
RegisterSignal(parent, COMSIG_ITEM_DROPPED, .proc/on_drop)
if(SEND_SIGNAL(parent, COMSIG_CONTAINS_STORAGE))
RegisterSignal(parent, COMSIG_TRY_STORAGE_INSERT, .proc/explodable_insert_item)
var/atom/atom_parent = parent
if(atom_parent.atom_storage)
RegisterSignal(parent, COMSIG_ATOM_ENTERED, .proc/explodable_insert_item)
if (devastation_range)
src.devastation_range = devastation_range
@@ -51,9 +53,11 @@
src.delete_after = delete_after
/// Explode if our parent is a storage place and something with high heat is inserted in.
/datum/component/explodable/proc/explodable_insert_item(datum/source, obj/item/I, mob/M, silent = FALSE, force = FALSE)
/datum/component/explodable/proc/explodable_insert_item(datum/source, obj/item/I)
SIGNAL_HANDLER
if(!(I.item_flags & IN_STORAGE))
return
check_if_detonate(I)
/datum/component/explodable/proc/explodable_impact(datum/source, atom/hit_atom, datum/thrownthing/throwingdatum)
+4 -4
View File
@@ -36,11 +36,11 @@
RegisterSignal(parent, COMSIG_MOVABLE_MOVED, .proc/handle_movement)
RegisterSignal(parent, list(
COMSIG_ITEM_PICKUP, //person picks up an item
COMSIG_STORAGE_ENTERED), //Object enters a storage object (boxes, etc.)
COMSIG_ATOM_ENTERED), //Object enters a storage object (boxes, etc.)
.proc/picked_up)
RegisterSignal(parent, list(
COMSIG_ITEM_DROPPED, //Object is dropped anywhere
COMSIG_STORAGE_EXITED), //Object exits a storage object (boxes, etc)
COMSIG_ATOM_EXITED), //Object exits a storage object (boxes, etc)
.proc/dropped)
RegisterSignal(parent, COMSIG_PARENT_EXAMINE, .proc/examine)
@@ -59,10 +59,10 @@
/datum/component/decomposition/UnregisterFromParent()
UnregisterSignal(parent, list(
COMSIG_ITEM_PICKUP,
COMSIG_STORAGE_ENTERED,
COMSIG_ATOM_ENTERED,
COMSIG_MOVABLE_MOVED,
COMSIG_ITEM_DROPPED,
COMSIG_STORAGE_EXITED,
COMSIG_ATOM_EXITED,
COMSIG_PARENT_EXAMINE))
/datum/component/decomposition/proc/handle_movement()
+4 -4
View File
@@ -35,8 +35,8 @@
RegisterSignal(parent, list(
COMSIG_ITEM_DROPPED,
COMSIG_ITEM_EQUIPPED,
COMSIG_STORAGE_ENTERED,
COMSIG_STORAGE_EXITED,
COMSIG_ATOM_ENTERED,
COMSIG_ATOM_EXITED,
), .proc/check_my_loc)
/datum/component/holderloving/UnregisterFromParent()
@@ -44,8 +44,8 @@
UnregisterSignal(parent, list(
COMSIG_ITEM_DROPPED,
COMSIG_ITEM_EQUIPPED,
COMSIG_STORAGE_ENTERED,
COMSIG_STORAGE_EXITED,
COMSIG_ATOM_ENTERED,
COMSIG_ATOM_EXITED,
))
/datum/component/holderloving/PostTransfer()
@@ -1,204 +0,0 @@
// External storage-related logic:
// /mob/proc/ClickOn() in /_onclick/click.dm - clicking items in storages
// /mob/living/Move() in /modules/mob/living/living.dm - hiding storage boxes on mob movement
/datum/component/storage/concrete
can_transfer = TRUE
var/drop_all_on_deconstruct = TRUE
var/drop_all_on_destroy = FALSE
var/transfer_contents_on_component_transfer = FALSE
var/list/datum/component/storage/slaves = list()
var/list/_contents_limbo // Where objects go to live mid transfer
var/list/_user_limbo // The last users before the component started moving
/datum/component/storage/concrete/Initialize()
. = ..()
RegisterSignal(parent, COMSIG_ATOM_CONTENTS_DEL, .proc/on_contents_del)
RegisterSignal(parent, COMSIG_OBJ_DECONSTRUCT, .proc/on_deconstruct)
/datum/component/storage/concrete/Destroy()
var/atom/real_location = real_location()
for(var/atom/_A in real_location)
_A.mouse_opacity = initial(_A.mouse_opacity)
if(drop_all_on_destroy)
do_quick_empty()
for(var/i in slaves)
var/datum/component/storage/slave = i
slave.change_master(null)
QDEL_LIST(_contents_limbo)
_user_limbo = null
return ..()
/datum/component/storage/concrete/master()
return src
/datum/component/storage/concrete/real_location()
return parent
/datum/component/storage/concrete/PreTransfer()
if(is_using)
_user_limbo = is_using.Copy()
close_all()
if(transfer_contents_on_component_transfer)
_contents_limbo = list()
for(var/atom/movable/AM in parent)
_contents_limbo += AM
AM.moveToNullspace()
/datum/component/storage/concrete/PostTransfer()
if(!isatom(parent))
return COMPONENT_INCOMPATIBLE
if(transfer_contents_on_component_transfer)
for(var/i in _contents_limbo)
var/atom/movable/AM = i
AM.forceMove(parent)
_contents_limbo = null
if(_user_limbo)
for(var/i in _user_limbo)
show_to(i)
_user_limbo = null
/datum/component/storage/concrete/_insert_physical_item(obj/item/I, override = FALSE)
. = TRUE
var/atom/real_location = real_location()
if(I.loc != real_location)
I.forceMove(real_location)
refresh_mob_views()
/datum/component/storage/concrete/refresh_mob_views()
. = ..()
for(var/i in slaves)
var/datum/component/storage/slave = i
slave.refresh_mob_views()
/datum/component/storage/concrete/emp_act(datum/source, severity)
if(emp_shielded)
return
var/atom/real_location = real_location()
for(var/i in real_location)
var/atom/A = i
A.emp_act(severity)
/datum/component/storage/concrete/proc/on_slave_link(datum/component/storage/S)
if(S == src)
return FALSE
slaves += S
return TRUE
/datum/component/storage/concrete/proc/on_slave_unlink(datum/component/storage/S)
slaves -= S
return FALSE
/datum/component/storage/concrete/proc/on_contents_del(datum/source, atom/A)
SIGNAL_HANDLER
var/atom/real_location = parent
if(A in real_location)
usr = null
remove_from_storage(A, null)
/datum/component/storage/concrete/proc/on_deconstruct(datum/source, disassembled)
SIGNAL_HANDLER
if(drop_all_on_deconstruct)
do_quick_empty()
/datum/component/storage/concrete/can_see_contents()
. = ..()
for(var/i in slaves)
var/datum/component/storage/slave = i
. |= slave.can_see_contents()
//Resets screen loc and other vars of something being removed from storage.
/datum/component/storage/concrete/_removal_reset(atom/movable/thing)
thing.layer = initial(thing.layer)
thing.plane = initial(thing.plane)
thing.mouse_opacity = initial(thing.mouse_opacity)
if(thing.maptext)
thing.maptext = ""
/datum/component/storage/concrete/remove_from_storage(atom/movable/AM, atom/new_location)
//Cache this as it should be reusable down the bottom, will not apply if anyone adds a sleep to dropped
//or moving objects, things that should never happen
var/atom/parent = src.parent
var/list/seeing_mobs = can_see_contents()
for(var/mob/M in seeing_mobs)
M.client.screen -= AM
if(isitem(AM))
var/obj/item/removed_item = AM
removed_item.item_flags &= ~IN_STORAGE
if(ismob(parent.loc))
var/mob/carrying_mob = parent.loc
removed_item.dropped(carrying_mob, TRUE)
if(new_location)
//Reset the items values
_removal_reset(AM)
AM.forceMove(new_location)
//We don't want to call this if the item is being destroyed
AM.on_exit_storage(src)
else
//Being destroyed, just move to nullspace now (so it's not in contents for the icon update)
AM.moveToNullspace()
refresh_mob_views()
if(isobj(parent))
var/obj/O = parent
O.update_appearance()
return TRUE
/datum/component/storage/concrete/proc/slave_can_insert_object(datum/component/storage/slave, obj/item/I, stop_messages = FALSE, mob/M)
return TRUE
/datum/component/storage/concrete/proc/handle_item_insertion_from_slave(datum/component/storage/slave, obj/item/I, prevent_warning = FALSE, M)
. = handle_item_insertion(I, prevent_warning, M, slave)
if(. && !prevent_warning)
slave.mob_item_insertion_feedback(usr, M, I)
/datum/component/storage/concrete/handle_item_insertion(obj/item/I, prevent_warning = FALSE, mob/M, datum/component/storage/remote) //Remote is null or the slave datum
var/datum/component/storage/concrete/master = master()
var/atom/parent = src.parent
var/moved = FALSE
if(!istype(I))
return FALSE
if(M)
if(!M.temporarilyRemoveItemFromInventory(I))
return FALSE
else
moved = TRUE //At this point if the proc fails we need to manually move the object back to the turf/mob/whatever.
if(I.pulledby)
I.pulledby.stop_pulling()
if(silent)
prevent_warning = TRUE
if(!_insert_physical_item(I))
if(moved)
if(M)
if(!M.put_in_active_hand(I))
I.forceMove(parent.drop_location())
else
I.forceMove(parent.drop_location())
return FALSE
I.on_enter_storage(master)
I.item_flags |= IN_STORAGE
refresh_mob_views()
I.mouse_opacity = MOUSE_OPACITY_OPAQUE //So you can click on the area around the item to equip it, instead of having to pixel hunt
if(M)
if(M.client && M.active_storage != src)
M.client.screen -= I
if(M.observers && M.observers.len)
for(var/i in M.observers)
var/mob/dead/observe = i
if(observe.client && observe.active_storage != src)
observe.client.screen -= I
if(!remote)
parent.add_fingerprint(M)
if(!prevent_warning)
mob_item_insertion_feedback(usr, M, I)
update_icon()
return TRUE
/datum/component/storage/concrete/update_icon()
if(isobj(parent))
var/obj/O = parent
O.update_appearance()
for(var/i in slaves)
var/datum/component/storage/slave = i
slave.update_icon()
@@ -1,27 +0,0 @@
/datum/component/storage/concrete/bluespace/bag_of_holding/handle_item_insertion(obj/item/W, prevent_warning = FALSE, mob/living/user)
var/atom/A = parent
if(A == W) //don't put yourself into yourself.
return
var/list/obj/item/storage/backpack/holding/matching = typecache_filter_list(W.get_all_contents(), typecacheof(/obj/item/storage/backpack/holding))
matching -= A
if(istype(W, /obj/item/storage/backpack/holding) || matching.len)
INVOKE_ASYNC(src, .proc/recursive_insertion, W, user)
return
. = ..()
/datum/component/storage/concrete/bluespace/bag_of_holding/proc/recursive_insertion(obj/item/W, mob/living/user)
var/atom/A = parent
var/safety = tgui_alert(user, "Doing this will have extremely dire consequences for the station and its crew. Be sure you know what you're doing.", "Put in [A.name]?", list("Proceed", "Abort"))
if(safety != "Proceed" || QDELETED(A) || QDELETED(W) || QDELETED(user) || !user.canUseTopic(A, BE_CLOSE, iscarbon(user)))
return
var/turf/loccheck = get_turf(A)
to_chat(user, span_danger("The Bluespace interfaces of the two devices catastrophically malfunction!"))
qdel(W)
playsound(loccheck,'sound/effects/supermatter.ogg', 200, TRUE)
message_admins("[ADMIN_LOOKUPFLW(user)] detonated a bag of holding at [ADMIN_VERBOSEJMP(loccheck)].")
log_game("[key_name(user)] detonated a bag of holding at [loc_name(loccheck)].")
user.gib(TRUE, TRUE, TRUE)
new/obj/boh_tear(loccheck)
qdel(A)
@@ -1,22 +0,0 @@
/datum/component/storage/concrete/bluespace
var/dumping_range = 8
var/dumping_sound = 'sound/items/pshoom.ogg'
var/alt_sound = 'sound/items/pshoom_2.ogg'
/datum/component/storage/concrete/bluespace/dump_content_at(atom/dest, mob/M)
var/atom/A = parent
if(A.Adjacent(M))
var/atom/dumping_location = dest.get_dumping_location()
var/turf/bagT = get_turf(parent)
var/turf/destT = get_turf(dumping_location)
if(destT && bagT && bagT.z == destT.z && get_dist(M, dumping_location) < dumping_range)
if(dumping_location.storage_contents_dump_act(src, M))
if(alt_sound && prob(1))
playsound(src, alt_sound, 40, TRUE)
else
playsound(src, dumping_sound, 40, TRUE)
M.Beam(dumping_location, icon_state="rped_upgrade", time=5)
return TRUE
to_chat(M, span_hear("The [A.name] buzzes."))
playsound(src, 'sound/machines/buzz-sigh.ogg', 50, FALSE)
return FALSE
@@ -1,37 +0,0 @@
/datum/component/storage/concrete/extract_inventory
max_combined_w_class = WEIGHT_CLASS_TINY * 3
max_items = 3
insert_preposition = "in"
//These need to be false in order for the extract's food to be unextractable
//from the inventory
attack_hand_interact = FALSE
quickdraw = FALSE
can_transfer = FALSE
drop_all_on_deconstruct = FALSE
locked = TRUE //True in order to prevent messing with the inventory in any way other than the specified ways on reproductive.dm
rustle_sound = FALSE
silent = TRUE
var/obj/item/slimecross/reproductive/parentSlimeExtract
/datum/component/storage/concrete/extract_inventory/Initialize()
. = ..()
set_holdable(/obj/item/food/monkeycube)
if(!istype(parent, /obj/item/slimecross/reproductive))
return COMPONENT_INCOMPATIBLE
parentSlimeExtract = parent
/datum/component/storage/concrete/extract_inventory/proc/processCubes(obj/item/slimecross/reproductive/parentSlimeExtract, mob/user)
if(length(parentSlimeExtract.contents) >= max_items)
QDEL_LIST(parentSlimeExtract.contents)
createExtracts(parentSlimeExtract,user)
/datum/component/storage/concrete/extract_inventory/proc/createExtracts(obj/item/slimecross/reproductive/parentSlimeExtract, mob/user)
var/cores = rand(1,4)
playsound(parentSlimeExtract, 'sound/effects/splat.ogg', 40, TRUE)
parentSlimeExtract.last_produce = world.time
to_chat(user, span_notice("[parentSlimeExtract] briefly swells to a massive size, and expels [cores] extract[cores > 1 ? "s":""]!"))
for(var/i in 1 to cores)
new parentSlimeExtract.extract_type(parentSlimeExtract.drop_location())
@@ -1,4 +0,0 @@
/datum/component/storage/concrete/fish_case
max_items = 1
can_hold_trait = TRAIT_FISH_CASE_COMPATIBILE
can_hold_description = "fish and aquarium equipment"
@@ -1,18 +0,0 @@
/datum/component/storage/concrete/implant
max_w_class = WEIGHT_CLASS_NORMAL
max_combined_w_class = 6
max_items = 2
drop_all_on_destroy = TRUE
drop_all_on_deconstruct = TRUE
silent = TRUE
allow_big_nesting = TRUE
/datum/component/storage/concrete/implant/Initialize()
. = ..()
set_holdable(null, list(/obj/item/disk/nuclear))
/datum/component/storage/concrete/implant/InheritComponent(datum/component/storage/concrete/implant/I, original)
if(!istype(I))
return ..()
max_combined_w_class += I.max_combined_w_class
max_items += I.max_items
@@ -1,33 +0,0 @@
/datum/component/storage/concrete/rped
collection_mode = COLLECT_EVERYTHING
allow_quick_gather = TRUE
allow_quick_empty = TRUE
click_gather = TRUE
max_w_class = WEIGHT_CLASS_NORMAL
max_combined_w_class = 100
max_items = 50
display_numerical_stacking = TRUE
/datum/component/storage/concrete/rped/can_be_inserted(obj/item/I, stop_messages, mob/M)
. = ..()
if(!I.get_part_rating())
if (!stop_messages)
to_chat(M, span_warning("[parent] only accepts machine parts!"))
return FALSE
/datum/component/storage/concrete/bluespace/rped
collection_mode = COLLECT_EVERYTHING
allow_quick_gather = TRUE
allow_quick_empty = TRUE
click_gather = TRUE
max_w_class = WEIGHT_CLASS_BULKY // can fit vending refills
max_combined_w_class = 800
max_items = 400
display_numerical_stacking = TRUE
/datum/component/storage/concrete/bluespace/rped/can_be_inserted(obj/item/I, stop_messages, mob/M)
. = ..()
if(!I.get_part_rating())
if (!stop_messages)
to_chat(M, span_warning("[parent] only accepts machine parts!"))
return FALSE
@@ -1,68 +0,0 @@
//Stack-only storage.
/datum/component/storage/concrete/stack
display_numerical_stacking = TRUE
var/max_combined_stack_amount = 300
max_w_class = WEIGHT_CLASS_NORMAL
max_combined_w_class = WEIGHT_CLASS_NORMAL * 14
/datum/component/storage/concrete/stack/proc/total_stack_amount()
. = 0
var/atom/real_location = real_location()
for(var/i in real_location)
var/obj/item/stack/S = i
if(!istype(S))
continue
. += S.amount
/datum/component/storage/concrete/stack/proc/remaining_space()
return max(0, max_combined_stack_amount - total_stack_amount())
//emptying procs do not need modification as stacks automatically merge.
/datum/component/storage/concrete/stack/_insert_physical_item(obj/item/I, override = FALSE)
if(!istype(I, /obj/item/stack))
if(override)
return ..()
return FALSE
var/atom/real_location = real_location()
var/obj/item/stack/S = I
var/can_insert = min(S.amount, remaining_space())
if(!can_insert)
return FALSE
for(var/i in real_location) //combine.
if(QDELETED(I))
return
var/obj/item/stack/_S = i
if(!istype(_S))
continue
if(_S.merge_type == S.merge_type)
_S.add(can_insert)
S.use(can_insert, TRUE)
return TRUE
I = S.split_stack(null, can_insert)
return ..()
/datum/component/storage/concrete/stack/remove_from_storage(obj/item/I, atom/new_location)
var/atom/real_location = real_location()
var/obj/item/stack/S = I
if(!istype(S))
return ..()
if(S.amount > S.max_amount)
var/overrun = S.amount - S.max_amount
S.amount = S.max_amount
var/obj/item/stack/temp = new S.type(real_location, overrun)
handle_item_insertion(temp)
return ..(S, new_location)
/datum/component/storage/concrete/stack/_process_numerical_display()
var/atom/real_location = real_location()
. = list()
for(var/i in real_location)
var/obj/item/stack/I = i
if(!istype(I) || QDELETED(I)) //We're specialized stack storage, just ignore non stacks.
continue
if(!.[I.merge_type])
.[I.merge_type] = new /datum/numbered_display(I, I.amount)
else
var/datum/numbered_display/ND = .[I.merge_type]
ND.number += I.amount
@@ -1,49 +0,0 @@
/**
*A storage component to be used on card piles, for use as hands/decks/discard piles. Don't use on something that's not a card pile!
*/
/datum/component/storage/concrete/tcg
display_numerical_stacking = FALSE
max_w_class = WEIGHT_CLASS_TINY
max_items = 30
max_combined_w_class = WEIGHT_CLASS_TINY * 30
///The deck that the card pile is using for FAIR PLAY.
/datum/component/storage/concrete/tcg/Initialize()
. = ..()
set_holdable(list(/obj/item/tcgcard))
/datum/component/storage/concrete/tcg/PostTransfer()
. = ..()
handle_empty_deck()
/datum/component/storage/concrete/tcg/remove_from_storage(atom/movable/AM, atom/new_location)
. = ..()
handle_empty_deck()
/datum/component/storage/concrete/tcg/show_to(mob/M)
. = ..()
M.visible_message(span_notice("[M] starts to look through the contents of \the [parent]!"), \
span_notice("You begin looking into the contents of \the [parent]!"))
/datum/component/storage/concrete/tcg/close(mob/M)
. = ..()
var/list/card_contents = contents()
var/obj/temp_parent = parent
temp_parent.visible_message(span_notice("\the [parent] is shuffled after looking through it."))
card_contents = shuffle(card_contents)
/datum/component/storage/concrete/tcg/mass_remove_from_storage(atom/target, list/things, datum/progressbar/progress, trigger_on_found)
. = ..()
if(!things.len)
qdel(parent)
/datum/component/storage/concrete/tcg/proc/handle_empty_deck()
var/list/contents = contents()
//You can't have a deck of one card!
if(contents.len == 1)
var/obj/item/tcgcard_deck/deck = parent
var/obj/item/tcgcard/card = contents[1]
remove_from_storage(card, card.drop_location())
card.flipped = deck.flipped
card.update_icon_state()
qdel(parent)
@@ -1,13 +0,0 @@
/datum/component/storage/concrete/wallet/open_storage(mob/user)
if(!isliving(user) || !user.CanReach(parent) || user.incapacitated())
return FALSE
if(locked)
to_chat(user, span_warning("[parent] seems to be locked!"))
return
var/obj/item/storage/wallet/A = parent
if(istype(A) && A.front_id && !issilicon(user) && !(A.item_flags & IN_STORAGE)) //if it's a wallet in storage seeing the full inventory is more useful
var/obj/item/I = A.front_id
INVOKE_ASYNC(src, .proc/attempt_put_in_hands, I, user)
return TRUE
return ..()
-960
View File
@@ -1,960 +0,0 @@
// External storage-related logic:
// /mob/proc/ClickOn() in /_onclick/click.dm - clicking items in storages
// /mob/living/Move() in /modules/mob/living/living.dm - hiding storage boxes on mob movement
/datum/component/storage
dupe_mode = COMPONENT_DUPE_UNIQUE
///If not null, all actions act on master and this is just an access point.
var/datum/component/storage/concrete/master
///if this is set, only items, and their children, will fit
var/list/can_hold
///if this is set, items, and their children, won't fit
var/list/cant_hold
///if set, these items will be the exception to the max size of object that can fit.
var/list/exception_hold
/// If set can only contain stuff with this single trait present.
var/list/can_hold_trait
var/can_hold_description
///lazy list of mobs looking at the contents of this storage.
var/list/mob/is_using
///when locked nothing can see inside or use it.
var/locked = FALSE
///max size of objects that will fit.
var/max_w_class = WEIGHT_CLASS_SMALL
///max combined sizes of objects that will fit.
var/max_combined_w_class = 14
///max number of objects that will fit.
var/max_items = 7
var/emp_shielded = FALSE
///whether this makes a message when things are put in.
var/silent = FALSE
///whether this can be clicked on items to pick it up rather than the other way around.
var/click_gather = FALSE
///play rustle sound on interact.
var/rustle_sound = TRUE
///allow empty verb which allows dumping on the floor of everything inside quickly.
var/allow_quick_empty = FALSE
///allow toggle mob verb which toggles collecting all items from a tile.
var/allow_quick_gather = FALSE
var/collection_mode = COLLECT_EVERYTHING
///you put things "in" a bag, but "on" a tray.
var/insert_preposition = "in"
///stack things of the same type and show as a single object with a number.
var/display_numerical_stacking = FALSE
///storage display object
var/atom/movable/screen/storage/boxes
///close button object
var/atom/movable/screen/close/closer
///allow storage objects of the same or greater size.
var/allow_big_nesting = FALSE
///interact on attack hand.
var/attack_hand_interact = TRUE
///altclick interact
var/quickdraw = FALSE
var/datum/weakref/modeswitch_action_ref
//Screen variables: Do not mess with these vars unless you know what you're doing. They're not defines so storage that isn't in the same location can be supported in the future.
var/screen_max_columns = 7 //These two determine maximum screen sizes.
var/screen_max_rows = INFINITY
var/screen_pixel_x = 16 //These two are pixel values for screen loc of boxes and closer
var/screen_pixel_y = 16
var/screen_start_x = 4 //These two are where the storage starts being rendered, screen_loc wise.
var/screen_start_y = 2
//End
/datum/component/storage/Initialize(datum/component/storage/concrete/master)
if(!isatom(parent))
return COMPONENT_INCOMPATIBLE
if(master)
change_master(master)
boxes = new(null, src)
closer = new(null, src)
orient2hud()
RegisterSignal(parent, COMSIG_CONTAINS_STORAGE, .proc/on_check)
RegisterSignal(parent, COMSIG_IS_STORAGE_LOCKED, .proc/check_locked)
RegisterSignal(parent, COMSIG_TRY_STORAGE_SHOW, .proc/signal_show_attempt)
RegisterSignal(parent, COMSIG_TRY_STORAGE_INSERT, .proc/signal_insertion_attempt)
RegisterSignal(parent, COMSIG_TRY_STORAGE_CAN_INSERT, .proc/signal_can_insert)
RegisterSignal(parent, COMSIG_TRY_STORAGE_TAKE_TYPE, .proc/signal_take_type)
RegisterSignal(parent, COMSIG_TRY_STORAGE_FILL_TYPE, .proc/signal_fill_type)
RegisterSignal(parent, COMSIG_TRY_STORAGE_SET_LOCKSTATE, .proc/set_locked)
RegisterSignal(parent, COMSIG_TRY_STORAGE_TAKE, .proc/signal_take_obj)
RegisterSignal(parent, COMSIG_TRY_STORAGE_QUICK_EMPTY, .proc/signal_quick_empty)
RegisterSignal(parent, COMSIG_TRY_STORAGE_HIDE_FROM, .proc/signal_hide_attempt)
RegisterSignal(parent, COMSIG_TRY_STORAGE_HIDE_ALL, .proc/close_all)
RegisterSignal(parent, COMSIG_TRY_STORAGE_RETURN_INVENTORY, .proc/signal_return_inv)
RegisterSignal(parent, COMSIG_TOPIC, .proc/topic_handle)
RegisterSignal(parent, COMSIG_PARENT_ATTACKBY, .proc/attackby)
RegisterSignal(parent, COMSIG_ATOM_ATTACK_HAND, .proc/on_attack_hand)
RegisterSignal(parent, COMSIG_ATOM_ATTACK_PAW, .proc/on_attack_hand)
RegisterSignal(parent, COMSIG_ATOM_EMP_ACT, .proc/emp_act)
RegisterSignal(parent, COMSIG_ATOM_ATTACK_GHOST, .proc/show_to_ghost)
RegisterSignal(parent, COMSIG_ATOM_ENTERED, .proc/refresh_mob_views)
RegisterSignal(parent, COMSIG_ATOM_EXITED, .proc/_remove_and_refresh)
RegisterSignal(parent, COMSIG_ATOM_CANREACH, .proc/canreach_react)
RegisterSignal(parent, COMSIG_ITEM_PRE_ATTACK, .proc/preattack_intercept)
RegisterSignal(parent, COMSIG_ITEM_ATTACK_SELF, .proc/attack_self)
RegisterSignal(parent, COMSIG_ITEM_PICKUP, .proc/signal_on_pickup)
RegisterSignal(parent, COMSIG_ITEM_EQUIPPED, .proc/update_actions)
RegisterSignal(parent, COMSIG_MOVABLE_POST_THROW, .proc/close_all)
RegisterSignal(parent, COMSIG_MOVABLE_MOVED, .proc/on_move)
RegisterSignal(parent, list(COMSIG_CLICK_ALT, COMSIG_ATOM_ATTACK_HAND_SECONDARY), .proc/on_open_storage_click)
RegisterSignal(parent, COMSIG_PARENT_ATTACKBY_SECONDARY, .proc/on_open_storage_attackby)
RegisterSignal(parent, COMSIG_MOUSEDROP_ONTO, .proc/mousedrop_onto)
RegisterSignal(parent, COMSIG_MOUSEDROPPED_ONTO, .proc/mousedrop_receive)
update_actions()
/datum/component/storage/Destroy()
close_all()
QDEL_NULL(boxes)
QDEL_NULL(closer)
LAZYCLEARLIST(is_using)
return ..()
/datum/component/storage/PreTransfer()
update_actions()
/// Almost 100% of the time the lists passed into set_holdable are reused for each instance of the component
/// Just fucking cache it 4head
/// Yes I could generalize this, but I don't want anyone else using it. in fact, DO NOT COPY THIS
/// If you find yourself needing this pattern, you're likely better off using static typecaches
/// I'm not because I do not trust implementers of the storage component to use them, BUT
/// IF I FIND YOU USING THIS PATTERN IN YOUR CODE I WILL BREAK YOU ACROSS MY KNEES
/// ~Lemon
GLOBAL_LIST_EMPTY(cached_storage_typecaches)
/datum/component/storage/proc/set_holdable(list/can_hold_list, list/cant_hold_list)
if(!islist(can_hold_list))
can_hold_list = list(can_hold_list)
if(!islist(cant_hold_list))
cant_hold_list = list(cant_hold_list)
can_hold_description = generate_hold_desc(can_hold_list)
if (can_hold_list)
var/unique_key = can_hold_list.Join("-")
if(!GLOB.cached_storage_typecaches[unique_key])
GLOB.cached_storage_typecaches[unique_key] = typecacheof(can_hold_list)
can_hold = GLOB.cached_storage_typecaches[unique_key]
if (cant_hold_list != null)
var/unique_key = cant_hold_list.Join("-")
if(!GLOB.cached_storage_typecaches[unique_key])
GLOB.cached_storage_typecaches[unique_key] = typecacheof(cant_hold_list)
cant_hold = GLOB.cached_storage_typecaches[unique_key]
/datum/component/storage/proc/generate_hold_desc(can_hold_list)
var/list/desc = list()
for(var/valid_type in can_hold_list)
var/obj/item/valid_item = valid_type
desc += "\a [initial(valid_item.name)]"
return "\n\t[span_notice("[desc.Join("\n\t")]")]"
/datum/component/storage/proc/update_actions()
SIGNAL_HANDLER
if(!isitem(parent) || !allow_quick_gather)
QDEL_NULL(modeswitch_action_ref)
return
var/datum/action/existing = modeswitch_action_ref?.resolve()
if(!QDELETED(existing))
return
var/obj/item/item_parent = parent
var/datum/action/modeswitch_action = item_parent.add_item_action(/datum/action/item_action/storage_gather_mode)
RegisterSignal(modeswitch_action, COMSIG_ACTION_TRIGGER, .proc/action_trigger)
modeswitch_action_ref = WEAKREF(modeswitch_action)
/datum/component/storage/proc/change_master(datum/component/storage/concrete/new_master)
if(new_master == src || (!isnull(new_master) && !istype(new_master)))
return FALSE
if(master)
master.on_slave_unlink(src)
master = new_master
if(master)
master.on_slave_link(src)
return TRUE
/datum/component/storage/proc/master()
if(master == src)
return //infinite loops yo.
return master
/datum/component/storage/proc/real_location()
var/datum/component/storage/concrete/master = master()
return master? master.real_location() : null
/datum/component/storage/proc/canreach_react(datum/source, list/next)
SIGNAL_HANDLER
var/datum/component/storage/concrete/master = master()
if(!master)
return
. = COMPONENT_ALLOW_REACH
next += master.parent
for(var/i in master.slaves)
var/datum/component/storage/slave = i
next += slave.parent
/datum/component/storage/proc/on_move()
SIGNAL_HANDLER
var/atom/A = parent
for(var/mob/living/L in can_see_contents())
if(!L.CanReach(A))
hide_from(L)
/datum/component/storage/proc/attack_self(datum/source, mob/M)
SIGNAL_HANDLER
if(locked)
to_chat(M, span_warning("[parent] seems to be locked!"))
return FALSE
if((M.get_active_held_item() == parent) && allow_quick_empty)
INVOKE_ASYNC(src, .proc/quick_empty, M)
/datum/component/storage/proc/preattack_intercept(datum/source, obj/O, mob/M, params)
SIGNAL_HANDLER
if(!isitem(O) || !click_gather || SEND_SIGNAL(O, COMSIG_CONTAINS_STORAGE))
return FALSE
. = COMPONENT_CANCEL_ATTACK_CHAIN
if(locked)
to_chat(M, span_warning("[parent] seems to be locked!"))
return FALSE
var/obj/item/I = O
if(collection_mode == COLLECT_ONE)
if(can_be_inserted(I, null, M))
handle_item_insertion(I, null, M)
return
if(!isturf(I.loc))
return
INVOKE_ASYNC(src, .proc/async_preattack_intercept, I, M)
///async functionality from preattack_intercept
/datum/component/storage/proc/async_preattack_intercept(obj/item/attack_item, mob/pre_attack_mob)
var/list/things = attack_item.loc.contents.Copy()
if(collection_mode == COLLECT_SAME)
things = typecache_filter_list(things, typecacheof(attack_item.type))
var/len = length(things)
if(!len)
to_chat(pre_attack_mob, span_warning("You failed to pick up anything with [parent]!"))
return
var/datum/progressbar/progress = new(pre_attack_mob, len, attack_item.loc)
var/list/rejections = list()
while(do_after(pre_attack_mob, 1 SECONDS, parent, NONE, FALSE, CALLBACK(src, .proc/handle_mass_pickup, things, attack_item.loc, rejections, progress)))
stoplag(1)
progress.end_progress()
to_chat(pre_attack_mob, span_notice("You put everything you could [insert_preposition] [parent]."))
/datum/component/storage/proc/handle_mass_item_insertion(list/things, datum/component/storage/src_object, mob/user, datum/progressbar/progress)
var/atom/source_real_location = src_object.real_location()
for(var/obj/item/I in things)
things -= I
if(I.loc != source_real_location)
continue
if(user.active_storage != src_object)
if(I.on_found(user))
break
if(can_be_inserted(I,FALSE,user))
handle_item_insertion(I, TRUE, user)
if (TICK_CHECK)
progress.update(progress.goal - things.len)
return TRUE
progress.update(progress.goal - things.len)
return FALSE
/datum/component/storage/proc/handle_mass_pickup(list/things, atom/thing_loc, list/rejections, datum/progressbar/progress)
var/atom/real_location = real_location()
for(var/obj/item/I in things)
things -= I
if(I.loc != thing_loc)
continue
if(I.type in rejections) // To limit bag spamming: any given type only complains once
continue
if(!can_be_inserted(I, stop_messages = TRUE)) // Note can_be_inserted still makes noise when the answer is no
if(real_location.contents.len >= max_items)
break
rejections += I.type // therefore full bags are still a little spammy
continue
handle_item_insertion(I, TRUE) //The TRUE stops the "You put the [parent] into [S]" insertion message from being displayed.
if (TICK_CHECK)
progress.update(progress.goal - things.len)
return TRUE
progress.update(progress.goal - things.len)
return FALSE
/datum/component/storage/proc/quick_empty(mob/M)
var/atom/A = parent
if(!M.canUseStorage() || !A.Adjacent(M) || M.incapacitated())
return
if(locked)
to_chat(M, span_warning("[parent] seems to be locked!"))
return FALSE
A.add_fingerprint(M)
to_chat(M, span_notice("You start dumping out [parent]."))
var/turf/T = get_turf(A)
var/list/things = contents()
var/datum/progressbar/progress = new(M, length(things), T)
while (do_after(M, 1 SECONDS, T, NONE, FALSE, CALLBACK(src, .proc/mass_remove_from_storage, T, things, progress)))
stoplag(1)
progress.end_progress()
/datum/component/storage/proc/mass_remove_from_storage(atom/target, list/things, datum/progressbar/progress, trigger_on_found = TRUE)
var/atom/real_location = real_location()
for(var/obj/item/I in things)
things -= I
if(I.loc != real_location)
continue
remove_from_storage(I, target)
I.pixel_x = rand(-10,10)
I.pixel_y = rand(-10,10)
if(trigger_on_found && I.on_found())
return FALSE
if(TICK_CHECK)
progress.update(progress.goal - length(things))
return TRUE
progress.update(progress.goal - length(things))
return FALSE
/datum/component/storage/proc/do_quick_empty(atom/_target)
if(!_target)
_target = get_turf(parent)
if(usr)
hide_from(usr)
var/list/contents = contents()
var/atom/real_location = real_location()
for(var/obj/item/I in contents)
if(I.loc != real_location)
continue
remove_from_storage(I, _target)
return TRUE
/datum/component/storage/proc/set_locked(datum/source, new_state)
SIGNAL_HANDLER
locked = new_state
if(locked)
close_all()
/datum/component/storage/proc/_process_numerical_display()
. = list()
var/atom/real_location = real_location()
for(var/obj/item/I in real_location.contents)
if(QDELETED(I))
continue
if(!.["[I.type]-[I.name]"])
.["[I.type]-[I.name]"] = new /datum/numbered_display(I, 1)
else
var/datum/numbered_display/ND = .["[I.type]-[I.name]"]
ND.number++
//This proc determines the size of the inventory to be displayed. Please touch it only if you know what you're doing.
/datum/component/storage/proc/orient2hud()
var/atom/real_location = real_location()
var/adjusted_contents = real_location.contents.len
//Numbered contents display
var/list/datum/numbered_display/numbered_contents
if(display_numerical_stacking)
numbered_contents = _process_numerical_display()
adjusted_contents = numbered_contents.len
var/columns = clamp(max_items, 1, screen_max_columns)
var/rows = clamp(CEILING(adjusted_contents / columns, 1), 1, screen_max_rows)
standard_orient_objs(rows, columns, numbered_contents)
//This proc draws out the inventory and places the items on it. It uses the standard position.
/datum/component/storage/proc/standard_orient_objs(rows, cols, list/obj/item/numerical_display_contents)
boxes.screen_loc = "[screen_start_x]:[screen_pixel_x],[screen_start_y]:[screen_pixel_y] to [screen_start_x+cols-1]:[screen_pixel_x],[screen_start_y+rows-1]:[screen_pixel_y]"
var/cx = screen_start_x
var/cy = screen_start_y
if(islist(numerical_display_contents))
for(var/type in numerical_display_contents)
var/datum/numbered_display/ND = numerical_display_contents[type]
ND.sample_object.mouse_opacity = MOUSE_OPACITY_OPAQUE
ND.sample_object.screen_loc = "[cx]:[screen_pixel_x],[cy]:[screen_pixel_y]"
ND.sample_object.maptext = MAPTEXT("<font color='white'>[(ND.number > 1)? "[ND.number]" : ""]</font>")
ND.sample_object.plane = ABOVE_HUD_PLANE
cx++
if(cx - screen_start_x >= cols)
cx = screen_start_x
cy++
if(cy - screen_start_y >= rows)
break
else
var/atom/real_location = real_location()
for(var/obj/O in real_location)
if(QDELETED(O))
continue
O.mouse_opacity = MOUSE_OPACITY_OPAQUE //This is here so storage items that spawn with contents correctly have the "click around item to equip"
O.screen_loc = "[cx]:[screen_pixel_x],[cy]:[screen_pixel_y]"
O.maptext = ""
O.plane = ABOVE_HUD_PLANE
cx++
if(cx - screen_start_x >= cols)
cx = screen_start_x
cy++
if(cy - screen_start_y >= rows)
break
closer.screen_loc = "[screen_start_x + cols]:[screen_pixel_x],[screen_start_y]:[screen_pixel_y]"
/datum/component/storage/proc/show_to(mob/M)
if(!M.client)
return FALSE
var/atom/real_location = real_location()
if(M.active_storage != src && (M.stat == CONSCIOUS))
for(var/obj/item/I in real_location)
if(I.on_found(M))
return FALSE
if(M.active_storage)
M.active_storage.hide_from(M)
orient2hud()
M.client.screen |= boxes
M.client.screen |= closer
M.client.screen |= real_location.contents
M.set_active_storage(src)
if(ismovable(real_location))
var/atom/movable/movable_loc = real_location
movable_loc.become_active_storage(src)
LAZYOR(is_using, M)
RegisterSignal(M, COMSIG_PARENT_QDELETING, .proc/mob_deleted)
return TRUE
/datum/component/storage/proc/mob_deleted(datum/source)
SIGNAL_HANDLER
hide_from(source)
/datum/component/storage/proc/hide_from(mob/M)
if(M.active_storage == src)
M.set_active_storage(null)
LAZYREMOVE(is_using, M)
UnregisterSignal(M, COMSIG_PARENT_QDELETING)
if(!M.client)
return TRUE
var/atom/real_location = real_location()
if(!length(is_using) && ismovable(real_location))
var/atom/movable/movable_loc = real_location
movable_loc.lose_active_storage(src)
M.client.screen -= boxes
M.client.screen -= closer
M.client.screen -= real_location.contents
return TRUE
/datum/component/storage/proc/close(mob/M)
hide_from(M)
/datum/component/storage/proc/close_all()
SIGNAL_HANDLER
. = FALSE
for(var/mob/M in can_see_contents())
close(M)
. = TRUE //returns TRUE if any mobs actually got a close(M) call
/datum/component/storage/proc/emp_act(datum/source, severity)
SIGNAL_HANDLER
if(emp_shielded)
return
var/datum/component/storage/concrete/master = master()
master.emp_act(source, severity)
//This proc draws out the inventory and places the items on it. tx and ty are the upper left tile and mx, my are the bottm right.
//The numbers are calculated from the bottom-left The bottom-left slot being 1,1.
/datum/component/storage/proc/orient_objs(tx, ty, mx, my)
var/atom/real_location = real_location()
var/cx = tx
var/cy = ty
boxes.screen_loc = "[tx]:,[ty] to [mx],[my]"
for(var/obj/O in real_location)
if(QDELETED(O))
continue
O.screen_loc = "[cx],[cy]"
O.plane = ABOVE_HUD_PLANE
cx++
if(cx > mx)
cx = tx
cy--
closer.screen_loc = "[mx+1],[my]"
//Resets something that is being removed from storage.
/datum/component/storage/proc/_removal_reset(atom/movable/thing)
if(!istype(thing))
return FALSE
var/datum/component/storage/concrete/master = master()
if(!istype(master))
return FALSE
return master._removal_reset(thing)
/datum/component/storage/proc/_remove_and_refresh(datum/source, atom/movable/gone, direction)
SIGNAL_HANDLER
_removal_reset(gone)
refresh_mob_views()
//Call this proc to handle the removal of an item from the storage item. The item will be moved to the new_location target, if that is null it's being deleted
/datum/component/storage/proc/remove_from_storage(atom/movable/AM, atom/new_location)
if(!istype(AM))
return FALSE
var/datum/component/storage/concrete/master = master()
if(!istype(master))
return FALSE
return master.remove_from_storage(AM, new_location)
/datum/component/storage/proc/refresh_mob_views()
SIGNAL_HANDLER
var/list/seeing = can_see_contents()
for(var/i in seeing)
show_to(i)
return TRUE
/datum/component/storage/proc/can_see_contents()
var/list/cansee = list()
for(var/mob/M in is_using)
if(M.active_storage == src && M.client)
cansee |= M
else
LAZYREMOVE(is_using, M)
UnregisterSignal(M, COMSIG_PARENT_QDELETING)
return cansee
//Tries to dump content
/datum/component/storage/proc/dump_content_at(atom/dest_object, mob/M)
var/atom/A = parent
var/atom/dump_destination = get_dumping_location(dest_object)
if(M.CanReach(A) && dump_destination && M.CanReach(dump_destination))
if(locked)
to_chat(M, span_warning("[parent] seems to be locked!"))
return FALSE
if(dump_destination.storage_contents_dump_act(src, M))
playsound(A, SFX_RUSTLE, 50, TRUE, -5)
return TRUE
return FALSE
/datum/component/storage/proc/get_dumping_location(atom/dest_object)
var/datum/component/storage/storage = dest_object.GetComponent(/datum/component/storage)
if(storage)
return storage.real_location()
return dest_object.get_dumping_location()
//This proc is called when you want to place an item into the storage item.
/datum/component/storage/proc/attackby(datum/source, obj/item/I, mob/M, params)
SIGNAL_HANDLER
if(!I.attackby_storage_insert(src, parent, M))
return FALSE
. = TRUE //no afterattack
if(iscyborg(M))
return
if(!can_be_inserted(I, FALSE, M))
var/atom/real_location = real_location()
if(real_location.contents.len >= max_items) //don't use items on the backpack if they don't fit
return TRUE
return FALSE
handle_item_insertion(I, FALSE, M)
/datum/component/storage/proc/return_inv(recursive)
var/list/ret = list()
ret |= contents()
if(recursive)
for(var/i in ret.Copy())
var/atom/A = i
SEND_SIGNAL(A, COMSIG_TRY_STORAGE_RETURN_INVENTORY, ret, TRUE)
return ret
/datum/component/storage/proc/contents() //ONLY USE IF YOU NEED TO COPY CONTENTS OF REAL LOCATION, COPYING IS NOT AS FAST AS DIRECT ACCESS!
var/atom/real_location = real_location()
return real_location.contents.Copy()
//Abuses the fact that lists are just references, or something like that.
/datum/component/storage/proc/signal_return_inv(datum/source, list/interface, recursive = TRUE)
SIGNAL_HANDLER
if(!islist(interface))
return FALSE
interface |= return_inv(recursive)
return TRUE
/datum/component/storage/proc/topic_handle(datum/source, user, href_list)
SIGNAL_HANDLER
if(href_list["show_valid_pocket_items"])
handle_show_valid_items(source, user)
/datum/component/storage/proc/handle_show_valid_items(datum/source, user)
to_chat(user, span_notice("[source] can hold: [can_hold_description]"))
/datum/component/storage/proc/mousedrop_onto(datum/source, atom/over_object, mob/M)
SIGNAL_HANDLER
set waitfor = FALSE
. = COMPONENT_NO_MOUSEDROP
if(!ismob(M))
return
if(!over_object)
return
if(ismecha(M.loc)) // stops inventory actions in a mech
return
if(M.incapacitated() || !M.canUseStorage())
return
var/atom/A = parent
A.add_fingerprint(M)
// this must come before the screen objects only block, dunno why it wasn't before
if(over_object == M)
user_show_to_mob(M)
if(!istype(over_object, /atom/movable/screen))
INVOKE_ASYNC(src, .proc/dump_content_at, over_object, M)
return
if(A.loc != M)
return
playsound(A, SFX_RUSTLE, 50, TRUE, -5)
if(istype(over_object, /atom/movable/screen/inventory/hand))
var/atom/movable/screen/inventory/hand/H = over_object
M.putItemFromInventoryInHandIfPossible(A, H.held_index)
return
A.add_fingerprint(M)
/datum/component/storage/proc/user_show_to_mob(mob/M, force = FALSE)
var/atom/A = parent
if(!istype(M))
return FALSE
A.add_fingerprint(M)
if(locked && !force)
to_chat(M, span_warning("[parent] seems to be locked!"))
return FALSE
if(force || M.CanReach(parent, view_only = TRUE))
show_to(M)
/datum/component/storage/proc/mousedrop_receive(datum/source, atom/movable/O, mob/M)
SIGNAL_HANDLER
if(isitem(O))
var/obj/item/I = O
if(iscarbon(M) || isdrone(M))
var/mob/living/L = M
if(!L.incapacitated() && I == L.get_active_held_item())
if(!SEND_SIGNAL(I, COMSIG_CONTAINS_STORAGE) && can_be_inserted(I, FALSE)) //If it has storage it should be trying to dump, not insert.
handle_item_insertion(I, FALSE, L)
//This proc return 1 if the item can be picked up and 0 if it can't.
//Set the stop_messages to stop it from printing messages
/datum/component/storage/proc/can_be_inserted(obj/item/I, stop_messages = FALSE, mob/M)
if(!istype(I) || (I.item_flags & ABSTRACT))
return FALSE //Not an item
if(I == parent)
return FALSE //no paradoxes for you
var/atom/real_location = real_location()
var/atom/host = parent
if(real_location == I.loc)
return FALSE //Means the item is already in the storage item
if(locked)
if(M && !stop_messages)
host.add_fingerprint(M)
to_chat(M, span_warning("[host] seems to be locked!"))
return FALSE
if(real_location.contents.len >= max_items)
if(!stop_messages)
to_chat(M, span_warning("[host] is full, make some space!"))
return FALSE //Storage item is full
if(length(can_hold))
if(!is_type_in_typecache(I, can_hold))
if(!stop_messages)
to_chat(M, span_warning("[host] cannot hold [I]!"))
return FALSE
if(is_type_in_typecache(I, cant_hold) || HAS_TRAIT(I, TRAIT_NO_STORAGE_INSERT) || (can_hold_trait && !HAS_TRAIT(I, can_hold_trait))) //Items which this container can't hold.
if(!stop_messages)
to_chat(M, span_warning("[host] cannot hold [I]!"))
return FALSE
if(I.w_class > max_w_class && !is_type_in_typecache(I, exception_hold))
if(!stop_messages)
to_chat(M, span_warning("[I] is too big for [host]!"))
return FALSE
var/datum/component/storage/biggerfish = real_location.loc.GetComponent(/datum/component/storage)
if(biggerfish && biggerfish.max_w_class < max_w_class) //return false if we are inside of another container, and that container has a smaller max_w_class than us (like if we're a bag in a box)
if(!stop_messages)
to_chat(M, span_warning("[I] can't fit in [host] while [real_location.loc] is in the way!"))
return FALSE
var/sum_w_class = I.w_class
for(var/obj/item/_I in real_location)
sum_w_class += _I.w_class //Adds up the combined w_classes which will be in the storage item if the item is added to it.
if(sum_w_class > max_combined_w_class)
if(!stop_messages)
to_chat(M, span_warning("[I] won't fit in [host], make some space!"))
return FALSE
if(isitem(host))
var/obj/item/IP = host
var/datum/component/storage/STR_I = I.GetComponent(/datum/component/storage)
if((I.w_class >= IP.w_class) && STR_I && !allow_big_nesting)
if(!stop_messages)
to_chat(M, span_warning("[IP] cannot hold [I] as it's a storage item of the same size!"))
return FALSE //To prevent the stacking of same sized storage items.
if(HAS_TRAIT(I, TRAIT_NODROP)) //SHOULD be handled in unEquip, but better safe than sorry.
if(!stop_messages)
to_chat(M, span_warning("\the [I] is stuck to your hand, you can't put it in \the [host]!"))
return FALSE
var/datum/component/storage/concrete/master = master()
if(!istype(master))
return FALSE
return master.slave_can_insert_object(src, I, stop_messages, M)
/datum/component/storage/proc/_insert_physical_item(obj/item/I, override = FALSE)
return FALSE
//This proc handles items being inserted. It does not perform any checks of whether an item can or can't be inserted. That's done by can_be_inserted()
//The prevent_warning parameter will stop the insertion message from being displayed. It is intended for cases where you are inserting multiple items at once,
//such as when picking up all the items on a tile with one click.
/datum/component/storage/proc/handle_item_insertion(obj/item/I, prevent_warning = FALSE, mob/M, datum/component/storage/remote)
var/atom/parent = src.parent
var/datum/component/storage/concrete/master = master()
if(!istype(master))
return FALSE
if(silent)
prevent_warning = TRUE
if(M)
parent.add_fingerprint(M)
. = master.handle_item_insertion_from_slave(src, I, prevent_warning, M)
/datum/component/storage/proc/mob_item_insertion_feedback(mob/user, mob/M, obj/item/I, override = FALSE)
if(silent && !override)
return
if(rustle_sound)
playsound(parent, SFX_RUSTLE, 50, TRUE, -5)
for(var/mob/viewing in viewers(user, null))
if(M == viewing)
to_chat(usr, span_notice("You put [I] [insert_preposition]to [parent]."))
else if(in_range(M, viewing)) //If someone is standing close enough, they can tell what it is...
viewing.show_message(span_notice("[M] puts [I] [insert_preposition]to [parent]."), MSG_VISUAL)
else if(I && I.w_class >= 3) //Otherwise they can only see large or normal items from a distance...
viewing.show_message(span_notice("[M] puts [I] [insert_preposition]to [parent]."), MSG_VISUAL)
/datum/component/storage/proc/update_icon()
if(isobj(parent))
var/obj/O = parent
O.update_appearance()
/datum/component/storage/proc/signal_insertion_attempt(datum/source, obj/item/I, mob/M, silent = FALSE, force = FALSE)
SIGNAL_HANDLER
if((!force && !can_be_inserted(I, TRUE, M)) || (I == parent))
return FALSE
return handle_item_insertion(I, silent, M)
/datum/component/storage/proc/signal_can_insert(datum/source, obj/item/I, mob/M, silent = FALSE)
SIGNAL_HANDLER
return can_be_inserted(I, silent, M)
/datum/component/storage/proc/show_to_ghost(datum/source, mob/dead/observer/M)
SIGNAL_HANDLER
return user_show_to_mob(M, TRUE)
/datum/component/storage/proc/signal_show_attempt(datum/source, mob/showto, force = FALSE)
SIGNAL_HANDLER
return user_show_to_mob(showto, force)
/datum/component/storage/proc/on_check()
SIGNAL_HANDLER
return TRUE
/datum/component/storage/proc/check_locked()
SIGNAL_HANDLER
return locked
/datum/component/storage/proc/signal_take_type(datum/source, type, atom/destination, amount = INFINITY, check_adjacent = FALSE, force = FALSE, mob/user, list/inserted)
SIGNAL_HANDLER
if(!force)
if(check_adjacent)
if(!user || !user.CanReach(destination) || !user.CanReach(parent))
return FALSE
var/list/taking = typecache_filter_list(contents(), typecacheof(type))
if(taking.len > amount)
taking.len = amount
if(inserted) //duplicated code for performance, don't bother checking retval/checking for list every item.
for(var/i in taking)
if(remove_from_storage(i, destination))
inserted |= i
else
for(var/i in taking)
remove_from_storage(i, destination)
return TRUE
/datum/component/storage/proc/remaining_space_items()
var/atom/real_location = real_location()
return max(0, max_items - real_location.contents.len)
/datum/component/storage/proc/signal_fill_type(datum/source, type, amount = 20, force = FALSE)
SIGNAL_HANDLER
var/atom/real_location = real_location()
if(!force)
amount = min(remaining_space_items(), amount)
for(var/i in 1 to amount)
if(!handle_item_insertion(new type(real_location), TRUE))
return i > 1 //return TRUE only if at least one insertion has been successful.
if(QDELETED(src))
return TRUE
return TRUE
/datum/component/storage/proc/on_attack_hand(datum/source, mob/user)
SIGNAL_HANDLER
var/atom/A = parent
if(!attack_hand_interact)
return
if(user.active_storage == src && A.loc == user) //if you're already looking inside the storage item
user.active_storage.close(user)
close(user)
. = COMPONENT_CANCEL_ATTACK_CHAIN
return
if(rustle_sound)
playsound(A, SFX_RUSTLE, 50, TRUE, -5)
if(ishuman(user))
var/mob/living/carbon/human/H = user
if(H.l_store == A && !H.get_active_held_item()) //Prevents opening if it's in a pocket.
. = COMPONENT_CANCEL_ATTACK_CHAIN
INVOKE_ASYNC(H, /mob.proc/put_in_hands, A)
H.l_store = null
return
if(H.r_store == A && !H.get_active_held_item())
. = COMPONENT_CANCEL_ATTACK_CHAIN
INVOKE_ASYNC(H, /mob.proc/put_in_hands, A)
H.r_store = null
return
if(A.loc == user)
. = COMPONENT_CANCEL_ATTACK_CHAIN
if(locked)
to_chat(user, span_warning("[parent] seems to be locked!"))
else
show_to(user)
/datum/component/storage/proc/signal_on_pickup(datum/source, mob/user)
SIGNAL_HANDLER
update_actions()
for(var/mob/M in can_see_contents() - user)
close(M)
/datum/component/storage/proc/signal_take_obj(datum/source, atom/movable/AM, new_loc, force = FALSE)
SIGNAL_HANDLER
if(!(AM in real_location()))
return FALSE
return remove_from_storage(AM, new_loc)
/datum/component/storage/proc/signal_quick_empty(datum/source, atom/loctarget)
SIGNAL_HANDLER
return do_quick_empty(loctarget)
/datum/component/storage/proc/signal_hide_attempt(datum/source, mob/target)
SIGNAL_HANDLER
return hide_from(target)
/datum/component/storage/proc/open_storage(mob/user)
if(!user.CanReach(parent))
user.balloon_alert(user, "can't reach!")
return FALSE
if(!isliving(user) || user.incapacitated())
return FALSE
if(locked)
to_chat(user, span_warning("[parent] seems to be locked!"))
return FALSE
. = TRUE
var/atom/A = parent
if(!quickdraw)
A.add_fingerprint(user)
user_show_to_mob(user)
playsound(A, SFX_RUSTLE, 50, TRUE, -5)
return
var/obj/item/to_remove = locate() in real_location()
if(!to_remove)
return
INVOKE_ASYNC(src, .proc/attempt_put_in_hands, to_remove, user)
/datum/component/storage/proc/on_open_storage_click(datum/source, mob/user, list/modifiers)
SIGNAL_HANDLER
if(open_storage(user))
return COMPONENT_CANCEL_ATTACK_CHAIN
if(LAZYACCESS(modifiers, RIGHT_CLICK))
return COMPONENT_SECONDARY_CANCEL_ATTACK_CHAIN
/datum/component/storage/proc/on_open_storage_attackby(datum/source, obj/item/weapon, mob/user, params)
SIGNAL_HANDLER
if(open_storage(user))
return COMPONENT_SECONDARY_CANCEL_ATTACK_CHAIN
///attempt to put an item from contents into the users hands
/datum/component/storage/proc/attempt_put_in_hands(obj/item/to_remove, mob/user)
var/atom/parent_as_atom = parent
parent_as_atom.add_fingerprint(user)
remove_from_storage(to_remove, get_turf(user))
if(!user.put_in_hands(to_remove))
to_chat(user, span_notice("You fumble for [to_remove] and it falls on the floor."))
return
user.visible_message(span_warning("[user] draws [to_remove] from [parent]!"), span_notice("You draw [to_remove] from [parent]."))
/datum/component/storage/proc/action_trigger(datum/signal_source, datum/action/source)
SIGNAL_HANDLER
gather_mode_switch(source.owner)
return COMPONENT_ACTION_BLOCK_TRIGGER
/datum/component/storage/proc/gather_mode_switch(mob/user)
collection_mode = (collection_mode+1)%3
switch(collection_mode)
if(COLLECT_SAME)
to_chat(user, span_notice("[parent] now picks up all items of a single type at once."))
if(COLLECT_EVERYTHING)
to_chat(user, span_notice("[parent] now picks up all items in a tile at once."))
if(COLLECT_ONE)
to_chat(user, span_notice("[parent] now picks up one item at a time."))
+7 -7
View File
@@ -42,10 +42,10 @@
// Make sure overlays also inherit the scaling.
ADD_KEEP_TOGETHER(target, ITEM_SCALING_TRAIT)
// Object scaled when dropped/thrown OR when exiting a storage component.
RegisterSignal(target, list(COMSIG_ITEM_DROPPED, COMSIG_STORAGE_EXITED), .proc/scale_overworld)
// Object scaled when dropped/thrown OR when exiting a storage object.
RegisterSignal(target, list(COMSIG_ITEM_DROPPED, COMSIG_ATOM_EXITED), .proc/scale_overworld)
// Object scaled when placed in an inventory slot OR when entering a storage component.
RegisterSignal(target, list(COMSIG_ITEM_EQUIPPED, COMSIG_STORAGE_ENTERED), .proc/scale_storage)
RegisterSignal(target, list(COMSIG_ITEM_EQUIPPED, COMSIG_ATOM_ENTERED), .proc/scale_storage)
/**
* Detach proc for the item_scaling element.
@@ -58,8 +58,8 @@
UnregisterSignal(target, list(
COMSIG_ITEM_PICKUP,
COMSIG_ITEM_DROPPED,
COMSIG_STORAGE_ENTERED,
COMSIG_STORAGE_EXITED,
COMSIG_ATOM_ENTERED,
COMSIG_ATOM_EXITED,
))
REMOVE_KEEP_TOGETHER(target, ITEM_SCALING_TRAIT)
@@ -82,7 +82,7 @@
scalable_object.transform = M.Scale(scaling)
/**
* Signal handler for COMSIG_ITEM_DROPPED or COMSIG_STORAGE_EXITED
* Signal handler for COMSIG_ITEM_DROPPED or COMSIG_ATOM_EXITED
*
* Longer detailed paragraph about the proc
* including any relevant detail
@@ -95,7 +95,7 @@
scale(source, overworld_scaling)
/**
* Signal handler for COMSIG_ITEM_EQUIPPED or COMSIG_STORAGE_ENTERED.
* Signal handler for COMSIG_ITEM_EQUIPPED or COMSIG_ATOM_ENTERED.
*
* Longer detailed paragraph about the proc
* including any relevant detail
+1 -1
View File
@@ -161,7 +161,7 @@
var/mob/living/carbon/human/human_holder = quirk_holder
// post_add() can be called via delayed callback. Check they still have a backpack equipped before trying to open it.
if(human_holder.back)
SEND_SIGNAL(human_holder.back, COMSIG_TRY_STORAGE_SHOW, human_holder)
human_holder.back.atom_storage.show_contents(human_holder)
for(var/chat_string in where_items_spawned)
to_chat(quirk_holder, chat_string)
File diff suppressed because it is too large Load Diff
@@ -0,0 +1,34 @@
/datum/storage/bag_of_holding/attempt_insert(datum/source, obj/item/to_insert, mob/user, override, force)
var/obj/item/resolve_parent = parent?.resolve()
if(!resolve_parent)
return
var/list/obj/item/storage/backpack/holding/matching = typecache_filter_list(to_insert.get_all_contents(), typecacheof(/obj/item/storage/backpack/holding))
matching -= resolve_parent
if(istype(to_insert, /obj/item/storage/backpack/holding) || matching.len)
INVOKE_ASYNC(src, .proc/recursive_insertion, to_insert, user)
return
return ..()
/datum/storage/bag_of_holding/proc/recursive_insertion(obj/item/to_insert, mob/living/user)
var/obj/item/resolve_parent = parent?.resolve()
if(!resolve_parent)
return
var/safety = tgui_alert(user, "Doing this will have extremely dire consequences for the station and its crew. Be sure you know what you're doing.", "Put in [to_insert.name]?", list("Proceed", "Abort"))
if(safety != "Proceed" || QDELETED(to_insert) || QDELETED(resolve_parent) || QDELETED(user) || !user.canUseTopic(resolve_parent, BE_CLOSE, iscarbon(user)))
return
var/turf/loccheck = get_turf(resolve_parent)
to_chat(user, span_danger("The Bluespace interfaces of the two devices catastrophically malfunction!"))
qdel(to_insert)
playsound(loccheck,'sound/effects/supermatter.ogg', 200, TRUE)
message_admins("[ADMIN_LOOKUPFLW(user)] detonated a bag of holding at [ADMIN_VERBOSEJMP(loccheck)].")
log_game("[key_name(user)] detonated a bag of holding at [loc_name(loccheck)].")
user.gib(TRUE, TRUE, TRUE)
new/obj/boh_tear(loccheck)
qdel(resolve_parent)
+66
View File
@@ -0,0 +1,66 @@
/**
*A storage component to be used on card piles, for use as hands/decks/discard piles. Don't use on something that's not a card pile!
*/
/datum/storage/tcg
max_specific_storage = WEIGHT_CLASS_TINY
max_slots = 30
max_total_storage = WEIGHT_CLASS_TINY * 30
/datum/storage/tcg/New()
. = ..()
set_holdable(list(/obj/item/tcgcard))
/datum/storage/tcg/attempt_remove(silent = FALSE)
. = ..()
handle_empty_deck()
/datum/storage/tcg/show_contents(mob/to_show)
. = ..()
var/obj/item/resolve_parent = parent?.resolve()
if(!resolve_parent)
return
to_show.visible_message(span_notice("[to_show] starts to look through the contents of \the [resolve_parent]!"), \
span_notice("You begin looking into the contents of \the [resolve_parent]!"))
/datum/storage/tcg/hide_contents()
. = ..()
var/obj/item/resolve_parent = parent?.resolve()
if(!resolve_parent)
return
var/obj/item/resolve_location = real_location?.resolve()
if(!resolve_location)
return
resolve_location.visible_message(span_notice("\the [resolve_parent] is shuffled after looking through it."))
resolve_location.contents = shuffle(resolve_location.contents)
/datum/storage/tcg/remove_all()
. = ..()
var/obj/item/resolve_parent = parent?.resolve()
if(!resolve_parent)
return
if(!resolve_parent.contents.len)
qdel(resolve_parent)
/datum/storage/tcg/proc/handle_empty_deck()
var/obj/item/resolve_parent = parent?.resolve()
if(!resolve_parent)
return
var/obj/item/resolve_location = real_location?.resolve()
if(!real_location)
return
//You can't have a deck of one card!
if(resolve_location.contents.len == 1)
var/obj/item/tcgcard_deck/deck = resolve_location
var/obj/item/tcgcard/card = resolve_location.contents[1]
attempt_remove(card, card.drop_location())
card.flipped = deck.flipped
card.update_icon_state()
qdel(resolve_parent)
@@ -0,0 +1,43 @@
/datum/storage/extract_inventory
max_total_storage = WEIGHT_CLASS_TINY * 3
max_slots = 3
insert_preposition = "in"
attack_hand_interact = FALSE
quickdraw = FALSE
locked = TRUE
rustle_sound = FALSE
silent = TRUE
/datum/storage/extract_inventory/New()
. = ..()
set_holdable(/obj/item/food/monkeycube)
var/obj/item/slimecross/reproductive/parentSlimeExtract = parent?.resolve()
if(!parentSlimeExtract)
return
if(!istype(parentSlimeExtract, /obj/item/slimecross/reproductive))
stack_trace("storage subtype extract_inventory incompatible with [parentSlimeExtract]")
qdel(src)
/datum/storage/extract_inventory/proc/processCubes(mob/user)
var/obj/item/slimecross/reproductive/parentSlimeExtract = parent?.resolve()
if(!parentSlimeExtract)
return
message_admins(parentSlimeExtract.contents.len)
if(parentSlimeExtract.contents.len >= max_slots)
QDEL_LIST(parentSlimeExtract.contents)
createExtracts(user)
/datum/storage/extract_inventory/proc/createExtracts(mob/user)
var/obj/item/slimecross/reproductive/parentSlimeExtract = parent?.resolve()
if(!parentSlimeExtract)
return
var/cores = rand(1,4)
playsound(parentSlimeExtract, 'sound/effects/splat.ogg', 40, TRUE)
parentSlimeExtract.last_produce = world.time
to_chat(user, span_notice("[parentSlimeExtract] briefly swells to a massive size, and expels [cores] extract[cores > 1 ? "s":""]!"))
for(var/i in 1 to cores)
new parentSlimeExtract.extract_type(parentSlimeExtract.drop_location())
+10
View File
@@ -0,0 +1,10 @@
/datum/storage/implant
max_specific_storage = WEIGHT_CLASS_NORMAL
max_total_storage = 6
max_slots = 2
silent = TRUE
allow_big_nesting = TRUE
/datum/storage/implant/New()
. = ..()
set_holdable(cant_hold_list = list(/obj/item/disk/nuclear))
@@ -1,28 +1,33 @@
/datum/component/storage/concrete/pockets
max_items = 2
max_w_class = WEIGHT_CLASS_SMALL
max_combined_w_class = 50
/datum/storage/pockets
max_slots = 2
max_specific_storage = WEIGHT_CLASS_SMALL
max_total_storage = 50
rustle_sound = FALSE
/datum/component/storage/concrete/pockets/handle_item_insertion(obj/item/I, prevent_warning, mob/user)
/datum/storage/pockets/attempt_insert(datum/source, obj/item/to_insert, mob/user, override, force)
. = ..()
if(. && silent && !prevent_warning)
var/obj/item/resolve_parent = parent?.resolve()
if(!resolve_parent)
return
if(. && silent && !override)
if(quickdraw)
to_chat(user, span_notice("You discreetly slip [I] into [parent]. Right-click [parent] to remove it."))
to_chat(user, span_notice("You discreetly slip [to_insert] into [resolve_parent]. Right-click [resolve_parent] to remove it."))
else
to_chat(user, span_notice("You discreetly slip [I] into [parent]."))
to_chat(user, span_notice("You discreetly slip [to_insert] into [resolve_parent]."))
/datum/component/storage/concrete/pockets/small
max_items = 1
max_w_class = WEIGHT_CLASS_SMALL
/datum/storage/pockets/small
max_slots = 1
max_specific_storage = WEIGHT_CLASS_SMALL
attack_hand_interact = FALSE
/datum/component/storage/concrete/pockets/tiny
max_items = 1
max_w_class = WEIGHT_CLASS_TINY
/datum/storage/pockets/tiny
max_slots = 1
max_specific_storage = WEIGHT_CLASS_TINY
attack_hand_interact = FALSE
/datum/component/storage/concrete/pockets/small/fedora/Initialize()
/datum/storage/pockets/small/fedora/New()
. = ..()
var/static/list/exception_cache = typecacheof(list(
/obj/item/katana,
@@ -33,35 +38,36 @@
))
exception_hold = exception_cache
/datum/component/storage/concrete/pockets/small/fedora/detective
/datum/storage/pockets/small/fedora/detective
attack_hand_interact = TRUE // so the detectives would discover pockets in their hats
/datum/component/storage/concrete/pockets/chefhat
/datum/storage/pockets/chefhat
attack_hand_interact = TRUE
max_items = 1
max_w_class = WEIGHT_CLASS_NORMAL
max_slots = 1
max_specific_storage = WEIGHT_CLASS_NORMAL
/datum/component/storage/concrete/pockets/chefhat/Initialize()
/datum/storage/pockets/chefhat/New()
. = ..()
set_holdable(list(
/obj/item/clothing/head/mob_holder,
/obj/item/food/deadmouse
))
/datum/component/storage/concrete/pockets/chefhat/can_be_inserted(obj/item/I, stop_messages, mob/M)
/datum/storage/pockets/chefhat/can_insert(obj/item/to_insert, mob/user, messages, force)
. = ..()
if(istype(I,/obj/item/clothing/head/mob_holder))
var/obj/item/clothing/head/mob_holder/mausholder = I
if(istype(to_insert, /obj/item/clothing/head/mob_holder))
var/obj/item/clothing/head/mob_holder/mausholder = to_insert
if(locate(/mob/living/simple_animal/mouse) in mausholder.contents)
return
return FALSE
/datum/component/storage/concrete/pockets/shoes
/datum/storage/pockets/shoes
max_slots = 2
attack_hand_interact = FALSE
quickdraw = TRUE
silent = TRUE
/datum/component/storage/concrete/pockets/shoes/Initialize()
/datum/storage/pockets/shoes/New()
. = ..()
set_holdable(list(
/obj/item/knife,
@@ -92,7 +98,7 @@
/obj/item/toy/crayon/spraycan)
)
/datum/component/storage/concrete/pockets/shoes/clown/Initialize()
/datum/storage/pockets/shoes/clown/New()
. = ..()
set_holdable(list(
/obj/item/knife,
@@ -124,13 +130,11 @@
/obj/item/toy/crayon/spraycan)
)
/datum/component/storage/concrete/pockets/pocketprotector
max_items = 3
max_w_class = WEIGHT_CLASS_TINY
var/atom/original_parent
/datum/storage/pockets/pocketprotector
max_slots = 3
max_specific_storage = WEIGHT_CLASS_TINY
/datum/component/storage/concrete/pockets/pocketprotector/Initialize()
original_parent = parent
/datum/storage/pockets/pocketprotector/New()
. = ..()
set_holdable(list( //Same items as a PDA
/obj/item/pen,
@@ -140,15 +144,12 @@
/obj/item/clothing/mask/cigarette)
)
/datum/component/storage/concrete/pockets/pocketprotector/real_location()
// if the component is reparented to a jumpsuit, the items still go in the protector
return original_parent
/datum/component/storage/concrete/pockets/helmet
/datum/storage/pockets/helmet
max_slots = 2
quickdraw = TRUE
max_combined_w_class = 6
max_total_storage = 6
/datum/component/storage/concrete/pockets/helmet/Initialize()
/datum/storage/pockets/helmet/New()
. = ..()
set_holdable(list(/obj/item/reagent_containers/food/drinks/bottle/vodka,
/obj/item/reagent_containers/food/drinks/bottle/molotov,
@@ -156,12 +157,12 @@
/obj/item/ammo_box/a762))
/datum/component/storage/concrete/pockets/void_cloak
/datum/storage/pockets/void_cloak
quickdraw = TRUE
max_combined_w_class = 5 // 2 small items + 1 tiny item, or 1 normal item + 1 small item
max_items = 3
max_total_storage = 5 // 2 small items + 1 tiny item, or 1 normal item + 1 small item
max_slots = 3
/datum/component/storage/concrete/pockets/void_cloak/Initialize()
/datum/storage/pockets/void_cloak/New()
. = ..()
set_holdable(list(
/obj/item/ammo_box/a762/lionhunter,
+52 -11
View File
@@ -162,6 +162,9 @@
/// forensics datum, contains fingerprints, fibres, blood_dna and hiddenprints on this atom
var/datum/forensics/forensics
/// the datum handler for our contents - see create_storage() for creation method
var/datum/storage/atom_storage
/**
* Called when an atom is created in byond (built in engine proc)
*
@@ -314,6 +317,9 @@
if(forensics)
QDEL_NULL(forensics)
if(atom_storage)
QDEL_NULL(atom_storage)
orbiters = null // The component is attached to us normaly and will be deleted elsewhere
LAZYCLEARLIST(overlays)
@@ -327,6 +333,43 @@
return ..()
/// A quick and easy way to create a storage datum for an atom
/atom/proc/create_storage(
max_slots,
max_specific_storage,
max_total_storage,
numerical_stacking = FALSE,
allow_quick_gather = FALSE,
allow_quick_empty = FALSE,
collection_mode = COLLECT_ONE,
attack_hand_interact = TRUE,
list/canhold,
list/canthold,
type = /datum/storage,
)
if(atom_storage)
QDEL_NULL(atom_storage)
atom_storage = new type(src, max_slots, max_specific_storage, max_total_storage, numerical_stacking, allow_quick_gather, collection_mode, attack_hand_interact)
if(canhold || canthold)
atom_storage.set_holdable(canhold, canthold)
return atom_storage
/// A quick and easy way to /clone/ a storage datum for an atom (does not copy over contents, only the datum details)
/atom/proc/clone_storage(datum/storage/cloning)
if(atom_storage)
QDEL_NULL(atom_storage)
atom_storage = new cloning.type(src, cloning.max_slots, cloning.max_specific_storage, cloning.max_total_storage, cloning.numerical_stacking, cloning.allow_quick_gather, cloning.collection_mode, cloning.attack_hand_interact)
if(cloning.can_hold || cloning.cant_hold)
atom_storage.set_holdable(cloning.can_hold, cloning.cant_hold)
return atom_storage
/atom/proc/handle_ricochet(obj/projectile/ricocheting_projectile)
var/turf/p_turf = get_turf(ricocheting_projectile)
var/face_direction = get_dir(src, p_turf)
@@ -991,8 +1034,8 @@
* TODO these should be purely component items that intercept the atom clicks higher in the
* call chain
*/
/atom/proc/storage_contents_dump_act(obj/item/storage/src_object, mob/user)
if(GetComponent(/datum/component/storage))
/atom/proc/storage_contents_dump_act(obj/item/src_object, mob/user)
if(atom_storage)
return component_storage_contents_dump_act(src_object, user)
return FALSE
@@ -1005,19 +1048,17 @@
* TODO these should be purely component items that intercept the atom clicks higher in the
* call chain
*/
/atom/proc/component_storage_contents_dump_act(datum/component/storage/src_object, mob/user)
var/list/things = src_object.contents()
/atom/proc/component_storage_contents_dump_act(obj/item/src_object, mob/user)
var/list/things = src_object.contents
var/datum/progressbar/progress = new(user, things.len, src)
var/datum/component/storage/STR = GetComponent(/datum/component/storage)
while (do_after(user, 1 SECONDS, src, NONE, FALSE, CALLBACK(STR, /datum/component/storage.proc/handle_mass_item_insertion, things, src_object, user, progress)))
while (do_after(user, 1 SECONDS, src, NONE, FALSE, CALLBACK(src_object.atom_storage, /datum/storage.proc/handle_mass_transfer, user, src)))
stoplag(1)
progress.end_progress()
to_chat(user, span_notice("You dump as much of [src_object.parent]'s contents [STR.insert_preposition]to [src] as you can."))
STR.orient2hud(user)
src_object.orient2hud(user)
to_chat(user, span_notice("You dump as much of [src_object]'s contents [atom_storage.insert_preposition]to [src] as you can."))
atom_storage.orient_to_hud(user)
src_object.atom_storage.orient_to_hud(user)
if(user.active_storage) //refresh the HUD to show the transfered contents
user.active_storage.close(user)
user.active_storage.show_to(user)
user.active_storage.refresh_views()
return TRUE
///Get the best place to dump the items contained in the source storage item?
+8 -8
View File
@@ -880,17 +880,17 @@
UNSETEMPTY(movable_loc.important_recursive_contents)
///called when this movable becomes the parent of a storage component that is currently being viewed by a player. uses important_recursive_contents
/atom/movable/proc/become_active_storage(datum/component/storage/component_source)
/atom/movable/proc/become_active_storage(datum/storage/source)
if(!HAS_TRAIT(src, TRAIT_ACTIVE_STORAGE))
for(var/atom/movable/location as anything in get_nested_locs(src) + src)
LAZYADDASSOCLIST(location.important_recursive_contents, RECURSIVE_CONTENTS_ACTIVE_STORAGE, src)
ADD_TRAIT(src, TRAIT_ACTIVE_STORAGE, component_source)
ADD_TRAIT(src, TRAIT_ACTIVE_STORAGE, REF(source))
///called when this movable's storage component is no longer viewed by any players, unsets important_recursive_contents
/atom/movable/proc/lose_active_storage(datum/component/storage/component_source)
/atom/movable/proc/lose_active_storage(datum/storage/source)
if(!HAS_TRAIT(src, TRAIT_ACTIVE_STORAGE))
return
REMOVE_TRAIT(src, TRAIT_ACTIVE_STORAGE, component_source)
REMOVE_TRAIT(src, TRAIT_ACTIVE_STORAGE, REF(source))
if(HAS_TRAIT(src, TRAIT_ACTIVE_STORAGE))
return
@@ -1198,12 +1198,12 @@
return blocker_opinion
/// called when this atom is removed from a storage item, which is passed on as S. The loc variable is already set to the new destination before this is called.
/atom/movable/proc/on_exit_storage(datum/component/storage/concrete/master_storage)
SEND_SIGNAL(src, COMSIG_STORAGE_EXITED, master_storage)
/atom/movable/proc/on_exit_storage(datum/storage/master_storage)
return
/// called when this atom is added into a storage item, which is passed on as S. The loc variable is already set to the storage item.
/atom/movable/proc/on_enter_storage(datum/component/storage/concrete/master_storage)
SEND_SIGNAL(src, COMSIG_STORAGE_ENTERED, master_storage)
/atom/movable/proc/on_enter_storage(datum/storage/master_storage)
return
/atom/movable/proc/get_spacemove_backup()
for(var/checked_range in orange(1, get_turf(src)))
+2 -2
View File
@@ -924,10 +924,10 @@
var/obj/item/stack/secondary_inserted = new secondary_stack.merge_type(null,used_amt)
component_parts += secondary_inserted
else
if(SEND_SIGNAL(replacer_tool, COMSIG_TRY_STORAGE_TAKE, secondary_part, src))
if(replacer_tool.atom_storage.attempt_remove(secondary_part, src))
component_parts += secondary_part
secondary_part.forceMove(src)
SEND_SIGNAL(replacer_tool, COMSIG_TRY_STORAGE_INSERT, primary_part, null, null, TRUE)
replacer_tool.atom_storage.attempt_insert(replacer_tool, primary_part, user, TRUE)
component_parts -= primary_part
to_chat(user, span_notice("[capitalize(primary_part.name)] replaced with [secondary_part.name]."))
shouldplaysound = 1 //Only play the sound when parts are actually replaced!
+1 -1
View File
@@ -255,7 +255,7 @@
req_components[path] -= used_amt
else
added_components[part] = path
if(SEND_SIGNAL(replacer, COMSIG_TRY_STORAGE_TAKE, part, src))
if(replacer.atom_storage.attempt_remove(part, src))
req_components[path]--
for(var/obj/item/part in added_components)
+1 -1
View File
@@ -309,7 +309,7 @@
pad.update_indicator()
pad.closed = FALSE
user.transferItemToLoc(src, pad, TRUE)
SEND_SIGNAL(src, COMSIG_TRY_STORAGE_HIDE_ALL)
atom_storage.close_all()
/obj/item/storage/briefcase/launchpad/attackby(obj/item/I, mob/user, params)
if(istype(I, /obj/item/launchpad_remote))
+13 -10
View File
@@ -544,7 +544,7 @@ GLOBAL_DATUM_INIT(welding_sparks, /mutable_appearance, mutable_appearance('icons
//If the item is in a storage item, take it out
SEND_SIGNAL(loc, COMSIG_TRY_STORAGE_TAKE, src, user.loc, TRUE)
loc.atom_storage?.attempt_remove(src, user.loc, silent = TRUE)
if(QDELETED(src)) //moving it out of the storage to the floor destroyed it.
return
@@ -579,7 +579,7 @@ GLOBAL_DATUM_INIT(welding_sparks, /mutable_appearance, mutable_appearance('icons
return
//If the item is in a storage item, take it out
SEND_SIGNAL(loc, COMSIG_TRY_STORAGE_TAKE, src, user.loc, TRUE)
loc.atom_storage?.attempt_remove(src, user.loc, silent = TRUE)
if(QDELETED(src)) //moving it out of the storage to the floor destroyed it.
return
@@ -768,9 +768,9 @@ GLOBAL_DATUM_INIT(welding_sparks, /mutable_appearance, mutable_appearance('icons
else
return
/obj/item/on_exit_storage(datum/component/storage/concrete/master_storage)
/obj/item/on_exit_storage(datum/storage/master_storage)
. = ..()
var/atom/location = master_storage.real_location()
var/atom/location = master_storage.real_location?.resolve()
do_drop_animation(location)
/obj/item/throw_impact(atom/hit_atom, datum/thrownthing/throwingdatum)
@@ -819,8 +819,8 @@ GLOBAL_DATUM_INIT(welding_sparks, /mutable_appearance, mutable_appearance('icons
/obj/item/proc/remove_item_from_storage(atom/newLoc) //please use this if you're going to snowflake an item out of a obj/item/storage
if(!newLoc)
return FALSE
if(SEND_SIGNAL(loc, COMSIG_CONTAINS_STORAGE))
return SEND_SIGNAL(loc, COMSIG_TRY_STORAGE_TAKE, src, newLoc, TRUE)
if(loc.atom_storage)
return loc.atom_storage.attempt_remove(src, newLoc, silent = TRUE)
return FALSE
/// Returns the icon used for overlaying the object on a belt
@@ -971,7 +971,7 @@ GLOBAL_DATUM_INIT(welding_sparks, /mutable_appearance, mutable_appearance('icons
/obj/item/MouseEntered(location, control, params)
. = ..()
if(get(src, /mob) == usr && !QDELETED(src))
if(((get(src, /mob) == usr) || src.loc.atom_storage || (src.item_flags & IN_STORAGE)) && !QDELETED(src))
var/mob/living/L = usr
if(usr.client.prefs.read_preference(/datum/preference/toggle/enable_tooltips))
var/timedelay = usr.client.prefs.read_preference(/datum/preference/numeric/tooltip_delay) / 100
@@ -992,8 +992,8 @@ GLOBAL_DATUM_INIT(welding_sparks, /mutable_appearance, mutable_appearance('icons
remove_filter("hover_outline")
/obj/item/proc/apply_outline(outline_color = null)
if(get(src, /mob) != usr || QDELETED(src) || isobserver(usr)) //cancel if the item isn't in an inventory, is being deleted, or if the person hovering is a ghost (so that people spectating you don't randomly make your items glow)
return
if(((get(src, /mob) != usr) && !src.loc.atom_storage && !(src.item_flags & IN_STORAGE)) || QDELETED(src) || isobserver(usr)) //cancel if the item isn't in an inventory, is being deleted, or if the person hovering is a ghost (so that people spectating you don't randomly make your items glow)
return FALSE
var/theme = lowertext(usr.client?.prefs?.read_preference(/datum/preference/choiced/ui_style))
if(!outline_color) //if we weren't provided with a color, take the theme's color
switch(theme) //yeah it kinda has to be this way
@@ -1345,7 +1345,7 @@ GLOBAL_DATUM_INIT(welding_sparks, /mutable_appearance, mutable_appearance('icons
return
/// Whether or not this item can be put into a storage item through attackby
/obj/item/proc/attackby_storage_insert(datum/component/storage, atom/storage_holder, mob/user)
/obj/item/proc/attackby_storage_insert(datum/storage, atom/storage_holder, mob/user)
return TRUE
/obj/item/proc/do_pickup_animation(atom/target)
@@ -1385,6 +1385,9 @@ GLOBAL_DATUM_INIT(welding_sparks, /mutable_appearance, mutable_appearance('icons
if(!istype(loc, /turf))
return
if(!istype(moving_from))
return
var/turf/current_turf = get_turf(src)
var/direction = get_dir(moving_from, current_turf)
var/from_x = moving_from.base_pixel_x
+2 -4
View File
@@ -599,9 +599,7 @@
/obj/item/storage/crayons/Initialize(mapload)
. = ..()
var/datum/component/storage/STR = GetComponent(/datum/component/storage)
STR.max_items = 7
STR.set_holdable(list(/obj/item/toy/crayon))
create_storage(canhold = list(/obj/item/toy/crayon))
/obj/item/storage/crayons/PopulateContents()
new /obj/item/toy/crayon/red(src)
@@ -822,7 +820,7 @@
return SECONDARY_ATTACK_CONTINUE_CHAIN
/obj/item/toy/crayon/spraycan/attackby_storage_insert(datum/component/storage, atom/storage_holder, mob/user)
/obj/item/toy/crayon/spraycan/attackby_storage_insert(datum/storage, atom/storage_holder, mob/user)
return is_capped
/obj/item/toy/crayon/spraycan/update_icon_state()
@@ -18,13 +18,11 @@
///If the UI has the pH meter shown
var/show_ph = TRUE
/obj/item/storage/portable_chem_mixer/ComponentInitialize()
/obj/item/storage/portable_chem_mixer/Initialize()
. = ..()
var/datum/component/storage/STR = GetComponent(/datum/component/storage)
STR.max_combined_w_class = 200
STR.max_items = 50
STR.insert_preposition = "in"
STR.set_holdable(list(
atom_storage.max_total_storage = 200
atom_storage.max_slots = 50
atom_storage.set_holdable(list(
/obj/item/reagent_containers/glass/beaker,
/obj/item/reagent_containers/glass/bottle,
/obj/item/reagent_containers/food/drinks/waterbottle,
@@ -40,8 +38,7 @@
return ..()
/obj/item/storage/portable_chem_mixer/attackby(obj/item/I, mob/user, params)
var/locked = SEND_SIGNAL(src, COMSIG_IS_STORAGE_LOCKED)
if (istype(I, /obj/item/reagent_containers) && !(I.item_flags & ABSTRACT) && I.is_open_container() && locked)
if (istype(I, /obj/item/reagent_containers) && !(I.item_flags & ABSTRACT) && I.is_open_container() && atom_storage.locked)
var/obj/item/reagent_containers/B = I
. = TRUE //no afterattack
if(!user.transferItemToLoc(B, src))
@@ -70,7 +67,7 @@
return
/obj/item/storage/portable_chem_mixer/update_icon_state()
if(!SEND_SIGNAL(src, COMSIG_IS_STORAGE_LOCKED))
if(!atom_storage.locked)
icon_state = "portablechemicalmixer_open"
return ..()
if(beaker)
@@ -81,8 +78,7 @@
/obj/item/storage/portable_chem_mixer/AltClick(mob/living/user)
var/locked = SEND_SIGNAL(src, COMSIG_IS_STORAGE_LOCKED)
if(!locked)
if(!atom_storage.locked)
return ..()
if(!can_interact(user) || !user.canUseTopic(src, BE_CLOSE, FALSE, NO_TK))
return
@@ -90,11 +86,10 @@
update_appearance()
/obj/item/storage/portable_chem_mixer/CtrlClick(mob/living/user)
var/locked = SEND_SIGNAL(src, COMSIG_IS_STORAGE_LOCKED)
SEND_SIGNAL(src, COMSIG_TRY_STORAGE_SET_LOCKSTATE, !locked)
if (!locked)
atom_storage.locked = !atom_storage.locked
if (!atom_storage.locked)
update_contents()
if (locked)
if (atom_storage.locked)
replace_beaker(user)
update_appearance()
playsound(src, 'sound/items/screwdriver2.ogg', 50)
@@ -122,17 +117,15 @@
if (loc != user)
return ..()
else
var/locked = SEND_SIGNAL(src, COMSIG_IS_STORAGE_LOCKED)
if (!locked)
if (!atom_storage.locked)
return ..()
if(SEND_SIGNAL(src, COMSIG_IS_STORAGE_LOCKED))
if(atom_storage?.locked)
ui_interact(user)
return
/obj/item/storage/portable_chem_mixer/attack_self(mob/user)
if(loc == user)
var/locked = SEND_SIGNAL(src, COMSIG_IS_STORAGE_LOCKED)
if (locked)
if (atom_storage.locked)
ui_interact(user)
return
else
+2 -4
View File
@@ -8,10 +8,8 @@
/obj/item/storage/dice/Initialize(mapload)
. = ..()
var/datum/component/storage/storage = GetComponent(/datum/component/storage)
storage.allow_quick_gather = TRUE
storage.click_gather = TRUE
storage.set_holdable(list(/obj/item/dice))
atom_storage.allow_quick_gather = TRUE
atom_storage.set_holdable(list(/obj/item/dice))
/obj/item/storage/dice/PopulateContents()
new /obj/item/dice/d4(src)
@@ -7,31 +7,34 @@
/obj/item/implant/storage/activate()
. = ..()
SEND_SIGNAL(src, COMSIG_TRY_STORAGE_SHOW, imp_in, TRUE)
atom_storage?.open_storage(src, imp_in)
/obj/item/implant/storage/removed(source, silent = FALSE, special = 0)
if(!special)
var/datum/component/storage/lostimplant = GetComponent(/datum/component/storage/concrete/implant)
var/mob/living/implantee = source
for (var/obj/item/I in lostimplant.contents())
var/atom/resolve_parent = atom_storage.parent?.resolve()
if(!resolve_parent)
return
for (var/obj/item/I in resolve_parent.contents)
I.add_mob_blood(implantee)
lostimplant.do_quick_empty()
atom_storage.remove_all(implantee)
implantee.visible_message(span_warning("A bluespace pocket opens around [src] as it exits [implantee], spewing out its contents and rupturing the surrounding tissue!"))
implantee.apply_damage(20, BRUTE, BODY_ZONE_CHEST)
qdel(lostimplant)
qdel(atom_storage)
return ..()
/obj/item/implant/storage/implant(mob/living/target, mob/user, silent = FALSE, force = FALSE)
for(var/X in target.implants)
if(istype(X, type))
var/obj/item/implant/storage/imp_e = X
var/datum/component/storage/STR = imp_e.GetComponent(/datum/component/storage)
if(!STR || (STR && STR.max_items < max_slot_stacking))
imp_e.AddComponent(/datum/component/storage/concrete/implant)
if(!imp_e.atom_storage || (imp_e.atom_storage && imp_e.atom_storage.max_slots < max_slot_stacking))
imp_e.create_storage(type = /datum/storage/implant)
qdel(src)
return TRUE
return FALSE
AddComponent(/datum/component/storage/concrete/implant)
create_storage(type = /datum/storage/implant)
return ..()
+6 -7
View File
@@ -268,14 +268,13 @@
worn_icon_state = "mailbag"
resistance_flags = FLAMMABLE
/obj/item/storage/bag/mail/ComponentInitialize()
/obj/item/storage/bag/mail/Initialize()
. = ..()
var/datum/component/storage/storage = GetComponent(/datum/component/storage)
storage.max_w_class = WEIGHT_CLASS_NORMAL
storage.max_combined_w_class = 42
storage.max_items = 21
storage.display_numerical_stacking = FALSE
storage.set_holdable(list(
atom_storage.max_specific_storage = WEIGHT_CLASS_NORMAL
atom_storage.max_total_storage = 42
atom_storage.max_slots = 21
atom_storage.numerical_stacking = FALSE
atom_storage.set_holdable(list(
/obj/item/mail,
/obj/item/delivery/small,
/obj/item/paper
+4 -4
View File
@@ -86,13 +86,13 @@
final_block_chance = 0 //Don't bring a sword to a gunfight
return ..()
/obj/item/melee/sabre/on_exit_storage(datum/component/storage/concrete/container)
var/obj/item/storage/belt/sabre/sabre = container.real_location()
/obj/item/melee/sabre/on_exit_storage(datum/storage/container)
var/obj/item/storage/belt/sabre/sabre = container.real_location?.resolve()
if(istype(sabre))
playsound(sabre, 'sound/items/unsheath.ogg', 25, TRUE)
/obj/item/melee/sabre/on_enter_storage(datum/component/storage/concrete/container)
var/obj/item/storage/belt/sabre/sabre = container.real_location()
/obj/item/melee/sabre/on_enter_storage(datum/storage/container)
var/obj/item/storage/belt/sabre/sabre = container.real_location?.resolve()
if(istype(sabre))
playsound(sabre, 'sound/items/sheath.ogg', 25, TRUE)
+1 -2
View File
@@ -254,8 +254,7 @@
/obj/item/storage/backpack/bannerpack/Initialize(mapload)
. = ..()
var/datum/component/storage/STR = GetComponent(/datum/component/storage)
STR.max_combined_w_class = 27 //6 more then normal, for the tradeoff of declaring yourself an antag at all times.
atom_storage.max_total_storage = 27 //6 more then normal, for the tradeoff of declaring yourself an antag at all times.
/obj/item/storage/backpack/bannerpack/red
name = "red banner backpack"
+1
View File
@@ -670,6 +670,7 @@
var/obj/item/stack/F = new type(user? user : drop_location(), amount, FALSE, mats_per_unit)
. = F
F.copy_evidences(src)
loc.atom_storage?.refresh_views()
if(user)
if(!user.put_in_hands(F, merge_stacks = FALSE))
F.forceMove(user.drop_location())
+25 -42
View File
@@ -21,21 +21,17 @@
resistance_flags = NONE
max_integrity = 300
/obj/item/storage/backpack/ComponentInitialize()
/obj/item/storage/backpack/Initialize()
. = ..()
var/datum/component/storage/STR = GetComponent(/datum/component/storage)
STR.max_combined_w_class = 21
STR.max_w_class = WEIGHT_CLASS_NORMAL
STR.max_items = 21
create_storage(max_slots = 21, max_total_storage = 21)
/*
* Backpack Types
*/
/obj/item/storage/backpack/old/ComponentInitialize()
/obj/item/storage/backpack/old/Initialize()
. = ..()
var/datum/component/storage/STR = GetComponent(/datum/component/storage)
STR.max_combined_w_class = 12
atom_storage.max_total_storage = 12
/obj/item/bag_of_holding_inert
name = "inert bag of holding"
@@ -57,14 +53,12 @@
resistance_flags = FIRE_PROOF
item_flags = NO_MAT_REDEMPTION
armor = list(MELEE = 0, BULLET = 0, LASER = 0, ENERGY = 0, BOMB = 0, BIO = 0, FIRE = 60, ACID = 50)
component_type = /datum/component/storage/concrete/bluespace/bag_of_holding
/obj/item/storage/backpack/holding/ComponentInitialize()
/obj/item/storage/backpack/holding/Initialize()
. = ..()
var/datum/component/storage/STR = GetComponent(/datum/component/storage)
STR.allow_big_nesting = TRUE
STR.max_w_class = WEIGHT_CLASS_GIGANTIC
STR.max_combined_w_class = 35
create_storage(max_specific_storage = WEIGHT_CLASS_GIGANTIC, max_total_storage = 35, max_slots = 30, type = /datum/storage/bag_of_holding)
atom_storage.allow_big_nesting = TRUE
/obj/item/storage/backpack/holding/suicide_act(mob/living/user)
user.visible_message(span_suicide("[user] is jumping into [src]! It looks like [user.p_theyre()] trying to commit suicide."))
@@ -85,11 +79,10 @@
. = ..()
regenerate_presents()
/obj/item/storage/backpack/santabag/ComponentInitialize()
/obj/item/storage/backpack/santabag/Initialize()
. = ..()
var/datum/component/storage/STR = GetComponent(/datum/component/storage)
STR.max_w_class = WEIGHT_CLASS_NORMAL
STR.max_combined_w_class = 60
atom_storage.max_specific_storage = WEIGHT_CLASS_NORMAL
atom_storage.max_total_storage = 60
/obj/item/storage/backpack/santabag/suicide_act(mob/user)
user.visible_message(span_suicide("[user] places [src] over [user.p_their()] head and pulls it tight! It looks like [user.p_they()] [user.p_are()]n't in the Christmas spirit..."))
@@ -98,17 +91,14 @@
/obj/item/storage/backpack/santabag/proc/regenerate_presents()
addtimer(CALLBACK(src, .proc/regenerate_presents), 30 SECONDS)
var/mob/M = get(loc, /mob)
if(!istype(M))
var/mob/user = get(loc, /mob)
if(!istype(user))
return
if(M.mind && HAS_TRAIT(M.mind, TRAIT_CANNOT_OPEN_PRESENTS))
var/datum/component/storage/STR = GetComponent(/datum/component/storage)
if(user.mind && HAS_TRAIT(user.mind, TRAIT_CANNOT_OPEN_PRESENTS))
var/turf/floor = get_turf(src)
var/obj/item/I = new /obj/item/a_gift/anything(floor)
if(STR.can_be_inserted(I, stop_messages=TRUE))
STR.handle_item_insertion(I, prevent_warning=TRUE)
else
qdel(I)
var/obj/item/thing = new /obj/item/a_gift/anything(floor)
if(!atom_storage.attempt_insert(src, thing, user, override = TRUE))
qdel(thing)
/obj/item/storage/backpack/cultpack
@@ -314,12 +304,8 @@
/obj/item/storage/backpack/satchel/flat/Initialize(mapload)
. = ..()
AddElement(/datum/element/undertile, TRAIT_T_RAY_VISIBLE, INVISIBILITY_OBSERVER, use_anchor = TRUE)
/obj/item/storage/backpack/satchel/flat/ComponentInitialize()
. = ..()
var/datum/component/storage/STR = GetComponent(/datum/component/storage)
STR.max_combined_w_class = 15
STR.set_holdable(null, list(/obj/item/storage/backpack/satchel/flat)) //muh recursive backpacks)
atom_storage.max_total_storage = 15
atom_storage.set_holdable(cant_hold_list = list(/obj/item/storage/backpack/satchel/flat)) //muh recursive backpacks)
/obj/item/storage/backpack/satchel/flat/PopulateContents()
var/datum/supply_pack/costumes_toys/randomised/contraband/C = new
@@ -345,10 +331,9 @@
inhand_icon_state = "duffel"
slowdown = 1
/obj/item/storage/backpack/duffelbag/ComponentInitialize()
/obj/item/storage/backpack/duffelbag/Initialize()
. = ..()
var/datum/component/storage/STR = GetComponent(/datum/component/storage)
STR.max_combined_w_class = 30
atom_storage.max_total_storage = 30
/obj/item/storage/backpack/duffelbag/cursed
name = "living duffel bag"
@@ -498,10 +483,9 @@
slowdown = 0
resistance_flags = FIRE_PROOF
/obj/item/storage/backpack/duffelbag/syndie/ComponentInitialize()
/obj/item/storage/backpack/duffelbag/syndie/Initialize()
. = ..()
var/datum/component/storage/STR = GetComponent(/datum/component/storage)
STR.silent = TRUE
atom_storage.silent = TRUE
/obj/item/storage/backpack/duffelbag/syndie/hitman
desc = "A large duffel bag for holding extra things. There is a Nanotrasen logo on the back."
@@ -655,11 +639,10 @@
new /obj/item/grenade/syndieminibomb(src)
// For ClownOps.
/obj/item/storage/backpack/duffelbag/clown/syndie/ComponentInitialize()
/obj/item/storage/backpack/duffelbag/clown/syndie/Initialize()
. = ..()
var/datum/component/storage/STR = GetComponent(/datum/component/storage)
slowdown = 0
STR.silent = TRUE
atom_storage.silent = TRUE
/obj/item/storage/backpack/duffelbag/clown/syndie/PopulateContents()
new /obj/item/modular_computer/tablet/pda/clown(src)
+86 -105
View File
@@ -20,13 +20,11 @@
slot_flags = ITEM_SLOT_BELT
w_class = WEIGHT_CLASS_BULKY
/obj/item/storage/bag/ComponentInitialize()
/obj/item/storage/bag/Initialize()
. = ..()
var/datum/component/storage/STR = GetComponent(/datum/component/storage)
STR.allow_quick_gather = TRUE
STR.allow_quick_empty = TRUE
STR.display_numerical_stacking = TRUE
STR.click_gather = TRUE
atom_storage.allow_quick_gather = TRUE
atom_storage.allow_quick_empty = TRUE
atom_storage.numerical_stacking = TRUE
// -----------------------------
// Trash bag
@@ -43,13 +41,12 @@
///If true, can be inserted into the janitor cart
var/insertable = TRUE
/obj/item/storage/bag/trash/ComponentInitialize()
/obj/item/storage/bag/trash/Initialize()
. = ..()
var/datum/component/storage/STR = GetComponent(/datum/component/storage)
STR.max_w_class = WEIGHT_CLASS_SMALL
STR.max_combined_w_class = 30
STR.max_items = 30
STR.set_holdable(null, list(/obj/item/disk/nuclear))
atom_storage.max_specific_storage = WEIGHT_CLASS_SMALL
atom_storage.max_total_storage = 30
atom_storage.max_slots = 30
atom_storage.set_holdable(cant_hold_list = list(/obj/item/disk/nuclear))
/obj/item/storage/bag/trash/suicide_act(mob/user)
user.visible_message(span_suicide("[user] puts [src] over [user.p_their()] head and starts chomping at the insides! Disgusting!"))
@@ -87,11 +84,10 @@
inhand_icon_state = "bluetrashbag"
item_flags = NO_MAT_REDEMPTION
/obj/item/storage/bag/trash/bluespace/ComponentInitialize()
/obj/item/storage/bag/trash/bluespace/Initialize()
. = ..()
var/datum/component/storage/STR = GetComponent(/datum/component/storage)
STR.max_combined_w_class = 60
STR.max_items = 60
atom_storage.max_total_storage = 60
atom_storage.max_slots = 60
/obj/item/storage/bag/trash/bluespace/cyborg
insertable = FALSE
@@ -108,17 +104,17 @@
worn_icon_state = "satchel"
slot_flags = ITEM_SLOT_BELT | ITEM_SLOT_POCKETS
w_class = WEIGHT_CLASS_NORMAL
component_type = /datum/component/storage/concrete/stack
var/spam_protection = FALSE //If this is TRUE, the holder won't receive any messages when they fail to pick up ore through crossing it
var/mob/listeningTo
/obj/item/storage/bag/ore/ComponentInitialize()
/obj/item/storage/bag/ore/Initialize(mapload)
. = ..()
var/datum/component/storage/concrete/stack/STR = GetComponent(/datum/component/storage/concrete/stack)
STR.allow_quick_empty = TRUE
STR.set_holdable(list(/obj/item/stack/ore))
STR.max_w_class = WEIGHT_CLASS_HUGE
STR.max_combined_stack_amount = 50
atom_storage.max_specific_storage = WEIGHT_CLASS_HUGE
atom_storage.max_total_storage = 50
atom_storage.numerical_stacking = TRUE
atom_storage.allow_quick_empty = TRUE
atom_storage.allow_quick_gather = TRUE
atom_storage.set_holdable(list(/obj/item/stack/ore))
/obj/item/storage/bag/ore/equipped(mob/user)
. = ..()
@@ -126,7 +122,7 @@
return
if(listeningTo)
UnregisterSignal(listeningTo, COMSIG_MOVABLE_MOVED)
RegisterSignal(user, COMSIG_MOVABLE_MOVED, .proc/Pickup_ores)
RegisterSignal(user, COMSIG_MOVABLE_MOVED, .proc/pickup_ores)
listeningTo = user
/obj/item/storage/bag/ore/dropped()
@@ -135,24 +131,27 @@
UnregisterSignal(listeningTo, COMSIG_MOVABLE_MOVED)
listeningTo = null
/obj/item/storage/bag/ore/proc/Pickup_ores(mob/living/user)
/obj/item/storage/bag/ore/proc/pickup_ores(mob/living/user)
SIGNAL_HANDLER
var/show_message = FALSE
var/obj/structure/ore_box/box
var/turf/tile = user.loc
if (!isturf(tile))
var/turf/tile = get_turf(user)
if(!isturf(tile))
return
if (istype(user.pulling, /obj/structure/ore_box))
if(istype(user.pulling, /obj/structure/ore_box))
box = user.pulling
var/datum/component/storage/STR = GetComponent(/datum/component/storage)
if(STR)
for(var/A in tile)
if (!is_type_in_typecache(A, STR.can_hold))
if(atom_storage)
for(var/thing in tile)
if(!is_type_in_typecache(thing, atom_storage.can_hold))
continue
if (box)
user.transferItemToLoc(A, box)
if(box)
user.transferItemToLoc(thing, box)
show_message = TRUE
else if(SEND_SIGNAL(src, COMSIG_TRY_STORAGE_INSERT, A, user, TRUE))
else if(atom_storage.attempt_insert(src, thing, user))
show_message = TRUE
else
if(!spam_protection)
@@ -161,12 +160,14 @@
continue
if(show_message)
playsound(user, SFX_RUSTLE, 50, TRUE)
if (box)
user.visible_message(span_notice("[user] offloads the ores beneath [user.p_them()] into [box]."), \
span_notice("You offload the ores beneath you into your [box]."))
span_notice("You offload the ores beneath you into your [box]."))
else
user.visible_message(span_notice("[user] scoops up the ores beneath [user.p_them()]."), \
span_notice("You scoop up the ores beneath you with your [name]."))
spam_protection = FALSE
/obj/item/storage/bag/ore/cyborg
@@ -177,12 +178,11 @@
desc = "A revolution in convenience, this satchel allows for huge amounts of ore storage. It's been outfitted with anti-malfunction safety measures."
icon_state = "satchel_bspace"
/obj/item/storage/bag/ore/holding/ComponentInitialize()
/obj/item/storage/bag/ore/holding/Initialize()
. = ..()
var/datum/component/storage/concrete/stack/STR = GetComponent(/datum/component/storage/concrete/stack)
STR.max_items = INFINITY
STR.max_combined_w_class = INFINITY
STR.max_combined_stack_amount = INFINITY
atom_storage.max_slots = INFINITY
atom_storage.max_specific_storage = INFINITY
atom_storage.max_total_storage = INFINITY
// -----------------------------
// Plant bag
@@ -195,13 +195,12 @@
worn_icon_state = "plantbag"
resistance_flags = FLAMMABLE
/obj/item/storage/bag/plants/ComponentInitialize()
/obj/item/storage/bag/plants/Initialize()
. = ..()
var/datum/component/storage/STR = GetComponent(/datum/component/storage)
STR.max_w_class = WEIGHT_CLASS_NORMAL
STR.max_combined_w_class = 100
STR.max_items = 100
STR.set_holdable(list(
atom_storage.max_specific_storage = WEIGHT_CLASS_NORMAL
atom_storage.max_total_storage = 100
atom_storage.max_slots = 100
atom_storage.set_holdable(list(
/obj/item/food/grown,
/obj/item/graft,
/obj/item/grown,
@@ -243,8 +242,7 @@
// -----------------------------
// Sheet Snatcher
// -----------------------------
// Because it stacks stacks, this doesn't operate normally.
// However, making it a storage/bag allows us to reuse existing code in some places. -Sayu
// sorry sayu your sheet snatcher is now OBSOLETE but i'm leaving it because idc
/obj/item/storage/bag/sheetsnatcher
name = "sheet snatcher"
@@ -254,20 +252,20 @@
worn_icon_state = "satchel"
var/capacity = 300; //the number of sheets it can carry.
component_type = /datum/component/storage/concrete/stack
/obj/item/storage/bag/sheetsnatcher/ComponentInitialize()
/obj/item/storage/bag/sheetsnatcher/Initialize()
. = ..()
var/datum/component/storage/concrete/stack/STR = GetComponent(/datum/component/storage/concrete/stack)
STR.allow_quick_empty = TRUE
STR.set_holdable(list(
atom_storage.allow_quick_empty = TRUE
atom_storage.allow_quick_gather = TRUE
atom_storage.numerical_stacking = TRUE
atom_storage.set_holdable(list(
/obj/item/stack/sheet
),
list(
/obj/item/stack/sheet/mineral/sandstone,
/obj/item/stack/sheet/mineral/wood,
))
STR.max_combined_stack_amount = 300
atom_storage.max_total_storage = capacity / 2
// -----------------------------
// Sheet Snatcher (Cyborg)
@@ -278,11 +276,6 @@
desc = ""
capacity = 500//Borgs get more because >specialization
/obj/item/storage/bag/sheetsnatcher/borg/ComponentInitialize()
. = ..()
var/datum/component/storage/concrete/stack/STR = GetComponent(/datum/component/storage/concrete/stack)
STR.max_combined_stack_amount = 500
// -----------------------------
// Book bag
// -----------------------------
@@ -295,14 +288,12 @@
worn_icon_state = "bookbag"
resistance_flags = FLAMMABLE
/obj/item/storage/bag/books/ComponentInitialize()
/obj/item/storage/bag/books/Initialize()
. = ..()
var/datum/component/storage/STR = GetComponent(/datum/component/storage)
STR.max_w_class = WEIGHT_CLASS_NORMAL
STR.max_combined_w_class = 21
STR.max_items = 7
STR.display_numerical_stacking = FALSE
STR.set_holdable(list(
atom_storage.max_specific_storage = WEIGHT_CLASS_NORMAL
atom_storage.max_total_storage = 21
atom_storage.max_slots = 7
atom_storage.set_holdable(list(
/obj/item/book,
/obj/item/spellbook,
/obj/item/storage/book,
@@ -326,11 +317,10 @@
custom_materials = list(/datum/material/iron=3000)
custom_price = PAYCHECK_CREW * 0.6
/obj/item/storage/bag/tray/ComponentInitialize()
/obj/item/storage/bag/tray/Initialize()
. = ..()
var/datum/component/storage/STR = GetComponent(/datum/component/storage)
STR.max_w_class = WEIGHT_CLASS_BULKY //Plates are required bulky to keep them out of backpacks
STR.set_holdable(list(
atom_storage.max_specific_storage = WEIGHT_CLASS_BULKY //Plates are required bulky to keep them out of backpacks
atom_storage.set_holdable(list(
/obj/item/clothing/mask/cigarette,
/obj/item/food,
/obj/item/kitchen,
@@ -345,14 +335,14 @@
/obj/item/storage/fancy,
/obj/item/trash,
)) //Should cover: Bottles, Beakers, Bowls, Booze, Glasses, Food, Food Containers, Food Trash, Organs, Tobacco Products, Lighters, and Kitchen Tools.
STR.insert_preposition = "on"
STR.max_items = 7
atom_storage.insert_preposition = "on"
atom_storage.max_slots = 7
/obj/item/storage/bag/tray/attack(mob/living/M, mob/living/user)
. = ..()
// Drop all the things. All of them.
var/list/obj/item/oldContents = contents.Copy()
SEND_SIGNAL(src, COMSIG_TRY_STORAGE_QUICK_EMPTY)
atom_storage.remove_all(user)
// Make each item scatter a bit
for(var/obj/item/tray_item in oldContents)
do_scatter(tray_item)
@@ -414,13 +404,11 @@
desc = "A bag for storing pills, patches, and bottles."
resistance_flags = FLAMMABLE
/obj/item/storage/bag/chemistry/ComponentInitialize()
/obj/item/storage/bag/chemistry/Initialize()
. = ..()
var/datum/component/storage/STR = GetComponent(/datum/component/storage)
STR.max_combined_w_class = 200
STR.max_items = 50
STR.insert_preposition = "in"
STR.set_holdable(list(
atom_storage.max_total_storage = 200
atom_storage.max_slots = 50
atom_storage.set_holdable(list(
/obj/item/reagent_containers/chem_pack,
/obj/item/reagent_containers/dropper,
/obj/item/reagent_containers/food/drinks/waterbottle,
@@ -443,13 +431,11 @@
desc = "A bag for the safe transportation and disposal of biowaste and other virulent materials."
resistance_flags = FLAMMABLE
/obj/item/storage/bag/bio/ComponentInitialize()
/obj/item/storage/bag/bio/Initialize()
. = ..()
var/datum/component/storage/STR = GetComponent(/datum/component/storage)
STR.max_combined_w_class = 200
STR.max_items = 25
STR.insert_preposition = "in"
STR.set_holdable(list(
atom_storage.max_total_storage = 200
atom_storage.max_slots = 25
atom_storage.set_holdable(list(
/obj/item/bodypart,
/obj/item/food/monkeycube,
/obj/item/healthanalyzer,
@@ -474,13 +460,11 @@
desc = "A bag for the storage and transport of anomalous materials."
resistance_flags = FLAMMABLE
/obj/item/storage/bag/xeno/ComponentInitialize()
/obj/item/storage/bag/xeno/Initialize()
. = ..()
var/datum/component/storage/STR = GetComponent(/datum/component/storage)
STR.max_combined_w_class = 200
STR.max_items = 25
STR.insert_preposition = "in"
STR.set_holdable(list(
atom_storage.max_total_storage = 200
atom_storage.max_slots = 25
atom_storage.set_holdable(list(
/obj/item/bodypart,
/obj/item/food/deadmouse,
/obj/item/food/monkeycube,
@@ -507,14 +491,12 @@
slot_flags = ITEM_SLOT_BELT | ITEM_SLOT_POCKETS
resistance_flags = FLAMMABLE
/obj/item/storage/bag/construction/ComponentInitialize()
/obj/item/storage/bag/construction/Initialize()
. = ..()
var/datum/component/storage/STR = GetComponent(/datum/component/storage)
STR.max_combined_w_class = 100
STR.max_items = 50
STR.max_w_class = WEIGHT_CLASS_SMALL
STR.insert_preposition = "in"
STR.set_holdable(list(
atom_storage.max_total_storage = 100
atom_storage.max_slots = 50
atom_storage.max_specific_storage = WEIGHT_CLASS_SMALL
atom_storage.set_holdable(list(
/obj/item/assembly,
/obj/item/circuitboard,
/obj/item/electronics,
@@ -532,13 +514,12 @@
inhand_icon_state = "quiver"
worn_icon_state = "harpoon_quiver"
/obj/item/storage/bag/harpoon_quiver/ComponentInitialize()
/obj/item/storage/bag/harpoon_quiver/Initialize()
. = ..()
var/datum/component/storage/STR = GetComponent(/datum/component/storage)
STR.max_w_class = WEIGHT_CLASS_TINY
STR.max_items = 40
STR.max_combined_w_class = 100
STR.set_holdable(list(
atom_storage.max_specific_storage = WEIGHT_CLASS_TINY
atom_storage.max_slots = 40
atom_storage.max_total_storage = 100
atom_storage.set_holdable(list(
/obj/item/ammo_casing/caseless/harpoon
))
+3 -4
View File
@@ -5,8 +5,7 @@
w_class = WEIGHT_CLASS_BULKY
resistance_flags = FLAMMABLE
/obj/item/storage/basket/ComponentInitialize()
/obj/item/storage/basket/Initialize()
. = ..()
var/datum/component/storage/STR = GetComponent(/datum/component/storage)
STR.max_w_class = WEIGHT_CLASS_NORMAL
STR.max_combined_w_class = 21
atom_storage.max_specific_storage = WEIGHT_CLASS_NORMAL
atom_storage.max_total_storage = 21
+66 -83
View File
@@ -41,12 +41,11 @@
drop_sound = 'sound/items/handling/toolbelt_drop.ogg'
pickup_sound = 'sound/items/handling/toolbelt_pickup.ogg'
/obj/item/storage/belt/utility/ComponentInitialize()
/obj/item/storage/belt/utility/Initialize()
. = ..()
var/datum/component/storage/STR = GetComponent(/datum/component/storage)
STR.max_w_class = WEIGHT_CLASS_NORMAL
STR.max_combined_w_class = 21
STR.set_holdable(list(
atom_storage.max_specific_storage = WEIGHT_CLASS_NORMAL
atom_storage.max_total_storage = 21
atom_storage.set_holdable(list(
/obj/item/airlock_painter,
/obj/item/analyzer,
/obj/item/assembly/signaler,
@@ -206,12 +205,11 @@
inhand_icon_state = "medical"
worn_icon_state = "medical"
/obj/item/storage/belt/medical/ComponentInitialize()
/obj/item/storage/belt/medical/Initialize()
. = ..()
var/datum/component/storage/STR = GetComponent(/datum/component/storage)
STR.max_w_class = WEIGHT_CLASS_NORMAL
STR.max_combined_w_class = 21
STR.set_holdable(list(
atom_storage.max_specific_storage = WEIGHT_CLASS_NORMAL
atom_storage.max_total_storage = 21
atom_storage.set_holdable(list(
/obj/item/bikehorn/rubberducky,
/obj/item/blood_filter,
/obj/item/bonesetter,
@@ -320,12 +318,11 @@
worn_icon_state = "security"
content_overlays = TRUE
/obj/item/storage/belt/security/ComponentInitialize()
/obj/item/storage/belt/security/Initialize()
. = ..()
var/datum/component/storage/STR = GetComponent(/datum/component/storage)
STR.max_items = 5
STR.max_w_class = WEIGHT_CLASS_NORMAL
STR.set_holdable(list(
atom_storage.max_slots = 5
atom_storage.max_specific_storage = WEIGHT_CLASS_NORMAL
atom_storage.set_holdable(list(
/obj/item/ammo_box,
/obj/item/ammo_casing/shotgun,
/obj/item/assembly/flash/handheld,
@@ -360,10 +357,9 @@
content_overlays = FALSE
custom_premium_price = PAYCHECK_COMMAND * 3
/obj/item/storage/belt/security/webbing/ComponentInitialize()
/obj/item/storage/belt/security/webbing/Initialize()
. = ..()
var/datum/component/storage/STR = GetComponent(/datum/component/storage)
STR.max_items = 6
atom_storage.max_slots = 6
/obj/item/storage/belt/mining
name = "explorer's webbing"
@@ -373,13 +369,12 @@
worn_icon_state = "explorer1"
w_class = WEIGHT_CLASS_BULKY
/obj/item/storage/belt/mining/ComponentInitialize()
/obj/item/storage/belt/mining/Initialize()
. = ..()
var/datum/component/storage/STR = GetComponent(/datum/component/storage)
STR.max_items = 6
STR.max_w_class = WEIGHT_CLASS_NORMAL
STR.max_combined_w_class = 20
STR.set_holdable(list(
atom_storage.max_slots = 6
atom_storage.max_specific_storage = WEIGHT_CLASS_NORMAL
atom_storage.max_total_storage = 20
atom_storage.set_holdable(list(
/obj/item/analyzer,
/obj/item/clothing/gloves,
/obj/item/crowbar,
@@ -435,10 +430,9 @@
inhand_icon_state = "ebelt"
worn_icon_state = "ebelt"
/obj/item/storage/belt/mining/primitive/ComponentInitialize()
/obj/item/storage/belt/mining/primitive/Initialize()
. = ..()
var/datum/component/storage/STR = GetComponent(/datum/component/storage)
STR.max_items = 5
atom_storage.max_slots = 5
/obj/item/storage/belt/soulstone
name = "soul stone belt"
@@ -447,11 +441,10 @@
inhand_icon_state = "soulstonebelt"
worn_icon_state = "soulstonebelt"
/obj/item/storage/belt/soulstone/ComponentInitialize()
/obj/item/storage/belt/soulstone/Initialize()
. = ..()
var/datum/component/storage/STR = GetComponent(/datum/component/storage)
STR.max_items = 6
STR.set_holdable(list(
atom_storage.max_slots = 6
atom_storage.set_holdable(list(
/obj/item/soulstone
))
@@ -471,11 +464,10 @@
worn_icon_state = "championbelt"
custom_materials = list(/datum/material/gold=400)
/obj/item/storage/belt/champion/ComponentInitialize()
/obj/item/storage/belt/champion/Initialize()
. = ..()
var/datum/component/storage/STR = GetComponent(/datum/component/storage)
STR.max_items = 1
STR.set_holdable(list(
atom_storage.max_slots = 1
atom_storage.set_holdable(list(
/obj/item/clothing/mask/luchador
))
@@ -494,10 +486,9 @@
worn_icon_state = "militarywebbing"
resistance_flags = FIRE_PROOF
/obj/item/storage/belt/military/ComponentInitialize()
/obj/item/storage/belt/military/Initialize()
. = ..()
var/datum/component/storage/STR = GetComponent(/datum/component/storage)
STR.max_w_class = WEIGHT_CLASS_SMALL
atom_storage.max_specific_storage = WEIGHT_CLASS_SMALL
/obj/item/storage/belt/military/snack
name = "tactical snack rig"
@@ -507,12 +498,11 @@
var/sponsor = pick("Donk Co.", "Waffle Co.", "Roffle Co.", "Gorlax Marauders", "Tiger Cooperative")
desc = "A set of snack-tical webbing worn by athletes of the [sponsor] VR sports division."
/obj/item/storage/belt/military/snack/ComponentInitialize()
/obj/item/storage/belt/military/snack/Initialize()
. = ..()
var/datum/component/storage/STR = GetComponent(/datum/component/storage)
STR.max_items = 6
STR.max_w_class = WEIGHT_CLASS_SMALL
STR.set_holdable(list(
atom_storage.max_slots = 6
atom_storage.max_specific_storage = WEIGHT_CLASS_SMALL
atom_storage.set_holdable(list(
/obj/item/food,
/obj/item/reagent_containers/food/drinks
))
@@ -578,10 +568,9 @@
inhand_icon_state = "security"
worn_icon_state = "assault"
/obj/item/storage/belt/military/assault/ComponentInitialize()
/obj/item/storage/belt/military/assault/Initialize()
. = ..()
var/datum/component/storage/STR = GetComponent(/datum/component/storage)
STR.max_items = 6
atom_storage.max_slots = 6
/obj/item/storage/belt/military/assault/full/PopulateContents()
generate_items_inside(list(
@@ -596,14 +585,13 @@
inhand_icon_state = "security"
worn_icon_state = "grenadebeltnew"
/obj/item/storage/belt/grenade/ComponentInitialize()
/obj/item/storage/belt/grenade/Initialize()
. = ..()
var/datum/component/storage/STR = GetComponent(/datum/component/storage)
STR.max_items = 30
STR.display_numerical_stacking = TRUE
STR.max_combined_w_class = 60
STR.max_w_class = WEIGHT_CLASS_BULKY
STR.set_holdable(list(
atom_storage.max_slots = 30
atom_storage.numerical_stacking = TRUE
atom_storage.max_total_storage = 60
atom_storage.max_specific_storage = WEIGHT_CLASS_BULKY
atom_storage.set_holdable(list(
/obj/item/food/grown/cherry_bomb,
/obj/item/food/grown/firelemon,
/obj/item/grenade,
@@ -636,11 +624,10 @@
inhand_icon_state = "soulstonebelt"
worn_icon_state = "soulstonebelt"
/obj/item/storage/belt/wands/ComponentInitialize()
/obj/item/storage/belt/wands/Initialize()
. = ..()
var/datum/component/storage/STR = GetComponent(/datum/component/storage)
STR.max_items = 6
STR.set_holdable(list(
atom_storage.max_slots = 6
atom_storage.set_holdable(list(
/obj/item/gun/magic/wand
))
@@ -663,12 +650,11 @@
inhand_icon_state = "janibelt"
worn_icon_state = "janibelt"
/obj/item/storage/belt/janitor/ComponentInitialize()
/obj/item/storage/belt/janitor/Initialize()
. = ..()
var/datum/component/storage/STR = GetComponent(/datum/component/storage)
STR.max_items = 6
STR.max_w_class = WEIGHT_CLASS_NORMAL // Set to this so the light replacer can fit.
STR.set_holdable(list(
atom_storage.max_slots = 6
atom_storage.max_specific_storage = WEIGHT_CLASS_NORMAL // Set to this so the light replacer can fit.
atom_storage.set_holdable(list(
/obj/item/assembly/mousetrap,
/obj/item/clothing/gloves,
/obj/item/flashlight,
@@ -699,13 +685,12 @@
inhand_icon_state = "bandolier"
worn_icon_state = "bandolier"
/obj/item/storage/belt/bandolier/ComponentInitialize()
/obj/item/storage/belt/bandolier/Initialize()
. = ..()
var/datum/component/storage/STR = GetComponent(/datum/component/storage)
STR.max_items = 18
STR.max_combined_w_class = 18
STR.display_numerical_stacking = TRUE
STR.set_holdable(list(
atom_storage.max_slots = 18
atom_storage.max_total_storage = 18
atom_storage.numerical_stacking = TRUE
atom_storage.set_holdable(list(
/obj/item/ammo_casing/a762,
/obj/item/ammo_casing/shotgun,
))
@@ -719,11 +704,10 @@
dying_key = DYE_REGISTRY_FANNYPACK
custom_price = PAYCHECK_CREW * 2
/obj/item/storage/belt/fannypack/ComponentInitialize()
/obj/item/storage/belt/fannypack/Initialize()
. = ..()
var/datum/component/storage/STR = GetComponent(/datum/component/storage)
STR.max_items = 3
STR.max_w_class = WEIGHT_CLASS_SMALL
atom_storage.max_slots = 3
atom_storage.max_specific_storage = WEIGHT_CLASS_SMALL
/obj/item/storage/belt/fannypack/black
name = "black fannypack"
@@ -793,14 +777,14 @@
worn_icon_state = "sheath"
w_class = WEIGHT_CLASS_BULKY
/obj/item/storage/belt/sabre/ComponentInitialize()
/obj/item/storage/belt/sabre/Initialize()
. = ..()
AddElement(/datum/element/update_icon_updates_onmob)
var/datum/component/storage/STR = GetComponent(/datum/component/storage)
STR.max_items = 1
STR.rustle_sound = FALSE
STR.max_w_class = WEIGHT_CLASS_BULKY
STR.set_holdable(list(
atom_storage.max_slots = 1
atom_storage.rustle_sound = FALSE
atom_storage.max_specific_storage = WEIGHT_CLASS_BULKY
atom_storage.set_holdable(list(
/obj/item/melee/sabre,
))
@@ -842,12 +826,11 @@
worn_icon_state = "plantbelt"
content_overlays = TRUE
/obj/item/storage/belt/plant/ComponentInitialize()
/obj/item/storage/belt/plant/Initialize()
. = ..()
var/datum/component/storage/STR = GetComponent(/datum/component/storage)
STR.max_items = 6
STR.max_w_class = WEIGHT_CLASS_NORMAL
STR.set_holdable(list(
atom_storage.max_slots = 6
atom_storage.max_specific_storage = WEIGHT_CLASS_NORMAL
atom_storage.set_holdable(list(
/obj/item/cultivator,
/obj/item/geneshears,
/obj/item/graft,
+2 -3
View File
@@ -10,10 +10,9 @@
resistance_flags = FLAMMABLE
var/title = "book"
/obj/item/storage/book/ComponentInitialize()
/obj/item/storage/book/Initialize()
. = ..()
var/datum/component/storage/STR = GetComponent(/datum/component/storage)
STR.max_items = 1
atom_storage.max_slots = 1
/obj/item/storage/book/attack_self(mob/user)
to_chat(user, span_notice("The pages of [title] have been cut out!"))
+27 -32
View File
@@ -462,10 +462,9 @@
for(var/i in 1 to 6)
new donktype(src)
/obj/item/storage/box/donkpockets/ComponentInitialize()
/obj/item/storage/box/donkpockets/Initialize()
. = ..()
var/datum/component/storage/STR = GetComponent(/datum/component/storage)
STR.set_holdable(list(/obj/item/food/donkpocket))
atom_storage.set_holdable(list(/obj/item/food/donkpocket))
/obj/item/storage/box/donkpockets/donkpocketspicy
name = "box of spicy-flavoured donk-pockets"
@@ -504,11 +503,10 @@
illustration = null
var/cube_type = /obj/item/food/monkeycube
/obj/item/storage/box/monkeycubes/ComponentInitialize()
/obj/item/storage/box/monkeycubes/Initialize()
. = ..()
var/datum/component/storage/STR = GetComponent(/datum/component/storage)
STR.max_items = 7
STR.set_holdable(list(/obj/item/food/monkeycube))
atom_storage.max_slots = 7
atom_storage.set_holdable(list(/obj/item/food/monkeycube))
/obj/item/storage/box/monkeycubes/PopulateContents()
for(var/i in 1 to 5)
@@ -524,11 +522,10 @@
icon_state = "monkeycubebox"
illustration = null
/obj/item/storage/box/gorillacubes/ComponentInitialize()
/obj/item/storage/box/gorillacubes/Initialize()
. = ..()
var/datum/component/storage/STR = GetComponent(/datum/component/storage)
STR.max_items = 3
STR.set_holdable(list(/obj/item/food/monkeycube))
atom_storage.max_slots = 3
atom_storage.set_holdable(list(/obj/item/food/monkeycube))
/obj/item/storage/box/gorillacubes/PopulateContents()
for(var/i in 1 to 3)
@@ -682,15 +679,15 @@
icon_state = "spbox"
illustration = ""
/obj/item/storage/box/snappops/ComponentInitialize()
/obj/item/storage/box/snappops/Initialize()
. = ..()
var/datum/component/storage/STR = GetComponent(/datum/component/storage)
STR.set_holdable(list(/obj/item/toy/snappop))
STR.max_items = 8
atom_storage.set_holdable(list(/obj/item/toy/snappop))
atom_storage.max_slots = 8
/obj/item/storage/box/snappops/PopulateContents()
SEND_SIGNAL(src, COMSIG_TRY_STORAGE_FILL_TYPE, /obj/item/toy/snappop)
for(var/i in 1 to 8)
new /obj/item/toy/snappop(src)
/obj/item/storage/box/matches
name = "matchbox"
desc = "A small box of Almost But Not Quite Plasma Premium Matches."
@@ -706,14 +703,14 @@
base_icon_state = "matchbox"
illustration = null
/obj/item/storage/box/matches/ComponentInitialize()
/obj/item/storage/box/matches/Initialize()
. = ..()
var/datum/component/storage/STR = GetComponent(/datum/component/storage)
STR.max_items = 10
STR.set_holdable(list(/obj/item/match))
atom_storage.max_slots = 10
atom_storage.set_holdable(list(/obj/item/match))
/obj/item/storage/box/matches/PopulateContents()
SEND_SIGNAL(src, COMSIG_TRY_STORAGE_FILL_TYPE, /obj/item/match)
for(var/i in 1 to 10)
new /obj/item/match(src)
/obj/item/storage/box/matches/attackby(obj/item/match/W as obj, mob/user as mob, params)
if(istype(W, /obj/item/match))
@@ -741,13 +738,12 @@
righthand_file = 'icons/mob/inhands/equipment/medical_righthand.dmi'
foldable = /obj/item/stack/sheet/cardboard //BubbleWrap
/obj/item/storage/box/lights/ComponentInitialize()
/obj/item/storage/box/lights/Initialize()
. = ..()
var/datum/component/storage/STR = GetComponent(/datum/component/storage)
STR.max_items = 21
STR.set_holdable(list(/obj/item/light/tube, /obj/item/light/bulb))
STR.max_combined_w_class = 21
STR.click_gather = FALSE //temp workaround to re-enable filling the light replacer with the box
atom_storage.max_slots = 21
atom_storage.set_holdable(list(/obj/item/light/tube, /obj/item/light/bulb))
atom_storage.max_total_storage = 21
atom_storage.allow_quick_gather = FALSE //temp workaround to re-enable filling the light replacer with the box
/obj/item/storage/box/lights/bulbs/PopulateContents()
for(var/i in 1 to 21)
@@ -1239,11 +1235,10 @@
foldable = null
custom_price = PAYCHECK_CREW
/obj/item/storage/box/gum/ComponentInitialize()
/obj/item/storage/box/gum/Initialize()
. = ..()
var/datum/component/storage/STR = GetComponent(/datum/component/storage)
STR.set_holdable(list(/obj/item/food/bubblegum))
STR.max_items = 4
atom_storage.set_holdable(list(/obj/item/food/bubblegum))
atom_storage.max_slots = 4
/obj/item/storage/box/gum/PopulateContents()
for(var/i in 1 to 4)
+3 -4
View File
@@ -16,11 +16,10 @@
max_integrity = 150
var/folder_path = /obj/item/folder //this is the path of the folder that gets spawned in New()
/obj/item/storage/briefcase/ComponentInitialize()
/obj/item/storage/briefcase/Initialize()
. = ..()
var/datum/component/storage/STR = GetComponent(/datum/component/storage)
STR.max_w_class = WEIGHT_CLASS_NORMAL
STR.max_combined_w_class = 21
atom_storage.max_specific_storage = WEIGHT_CLASS_NORMAL
atom_storage.max_total_storage = 21
/obj/item/storage/briefcase/PopulateContents()
new /obj/item/pen(src)
+32 -67
View File
@@ -21,16 +21,22 @@
var/contents_tag = "errors"
/// What type of thing to fill this storage with.
var/spawn_type = null
/// How many of the things to fill this storage with.
var/spawn_count = 0
/// Whether the container is open or not
var/is_open = FALSE
/// What this container folds up into when it's empty.
var/obj/fold_result = /obj/item/stack/sheet/cardboard
/obj/item/storage/fancy/Initialize()
. = ..()
atom_storage.max_slots = spawn_count
/obj/item/storage/fancy/PopulateContents()
if(!spawn_type)
return
var/datum/component/storage/STR = GetComponent(/datum/component/storage)
for(var/i = 1 to STR.max_items)
for(var/i = 1 to spawn_count)
new spawn_type(src)
/obj/item/storage/fancy/update_icon_state()
@@ -80,16 +86,15 @@
icon_state = "donutbox_open" //composite image used for mapping
base_icon_state = "donutbox"
spawn_type = /obj/item/food/donut/plain
spawn_count = 6
is_open = TRUE
appearance_flags = KEEP_TOGETHER|LONG_GLIDE
custom_premium_price = PAYCHECK_COMMAND * 1.75
contents_tag = "donut"
/obj/item/storage/fancy/donut_box/ComponentInitialize()
/obj/item/storage/fancy/donut_box/Initialize()
. = ..()
var/datum/component/storage/STR = GetComponent(/datum/component/storage)
STR.max_items = 6
STR.set_holdable(list(/obj/item/food/donut))
atom_storage.set_holdable(list(/obj/item/food/donut))
/obj/item/storage/fancy/donut_box/PopulateContents()
. = ..()
@@ -131,13 +136,12 @@
name = "egg box"
desc = "A carton for containing eggs."
spawn_type = /obj/item/food/egg
spawn_count = 12
contents_tag = "egg"
/obj/item/storage/fancy/egg_box/ComponentInitialize()
/obj/item/storage/fancy/egg_box/Initialize()
. = ..()
var/datum/component/storage/STR = GetComponent(/datum/component/storage)
STR.max_items = 12
STR.set_holdable(list(/obj/item/food/egg))
atom_storage.set_holdable(list(/obj/item/food/egg))
/*
* Candle Box
@@ -154,14 +158,10 @@
throwforce = 2
slot_flags = ITEM_SLOT_BELT
spawn_type = /obj/item/candle
spawn_count = 5
is_open = TRUE
contents_tag = "candle"
/obj/item/storage/fancy/candle_box/ComponentInitialize()
. = ..()
var/datum/component/storage/STR = GetComponent(/datum/component/storage)
STR.max_items = 5
/obj/item/storage/fancy/candle_box/attack_self(mob/user)
if(!contents.len)
new fold_result(user.drop_location())
@@ -184,6 +184,7 @@
throwforce = 0
slot_flags = ITEM_SLOT_BELT
spawn_type = /obj/item/clothing/mask/cigarette/space_cigarette
spawn_count = 6
custom_price = PAYCHECK_CREW
age_restricted = TRUE
contents_tag = "cigarette"
@@ -208,15 +209,13 @@
spawn_coupon = FALSE
name = "discarded cigarette packet"
desc = "An old cigarette packet with the back torn off, worth less than nothing now."
var/datum/component/storage/STR = GetComponent(/datum/component/storage)
STR.max_items = 0
atom_storage.max_slots = 0
return
/obj/item/storage/fancy/cigarettes/ComponentInitialize()
/obj/item/storage/fancy/cigarettes/Initialize()
. = ..()
var/datum/component/storage/STR = GetComponent(/datum/component/storage)
STR.max_items = 6
STR.set_holdable(list(/obj/item/clothing/mask/cigarette, /obj/item/lighter))
atom_storage.quickdraw = TRUE
atom_storage.set_holdable(list(/obj/item/clothing/mask/cigarette, /obj/item/lighter))
/obj/item/storage/fancy/cigarettes/examine(mob/user)
. = ..()
@@ -225,18 +224,6 @@
if(spawn_coupon)
. += span_notice("There's a coupon on the back of the pack! You can tear it off once it's empty.")
/obj/item/storage/fancy/cigarettes/AltClick(mob/user)
if(!user.canUseTopic(src, BE_CLOSE, NO_DEXTERITY, FALSE, TRUE))
return
var/obj/item/clothing/mask/cigarette/W = locate(/obj/item/clothing/mask/cigarette) in contents
if(W && contents.len > 0)
SEND_SIGNAL(src, COMSIG_TRY_STORAGE_TAKE, W, user)
user.put_in_hands(W)
contents -= W
to_chat(user, span_notice("You take \a [W] out of the pack."))
else
to_chat(user, span_notice("There are no [contents_tag]s left in the pack."))
/obj/item/storage/fancy/cigarettes/update_icon_state()
. = ..()
icon_state = "[base_icon_state][contents.len ? null : "_empty"]"
@@ -267,24 +254,6 @@
. += "[use_icon_state]_[cig_position]"
cig_position++
/obj/item/storage/fancy/cigarettes/attack(mob/living/carbon/target, mob/living/carbon/user)
if(!istype(target))
return
var/obj/item/clothing/mask/cigarette/cig = locate() in contents
if(!cig)
to_chat(user, span_notice("There are no [contents_tag]s left in the pack."))
return
if(target != user || !contents.len || user.wear_mask)
return ..()
SEND_SIGNAL(src, COMSIG_TRY_STORAGE_TAKE, cig, target)
target.equip_to_slot_if_possible(cig, ITEM_SLOT_MASK)
contents -= cig
to_chat(user, span_notice("You take \a [cig] out of the pack."))
return
/obj/item/storage/fancy/cigarettes/dromedaryco
name = "\improper DromedaryCo packet"
desc = "A packet of six imported DromedaryCo cancer sticks. A label on the packaging reads, \"Wouldn't a slow death make a change?\""
@@ -388,11 +357,10 @@
spawn_type = /obj/item/rollingpaper
custom_price = PAYCHECK_LOWER
/obj/item/storage/fancy/rollingpapers/ComponentInitialize()
/obj/item/storage/fancy/rollingpapers/Initialize()
. = ..()
var/datum/component/storage/STR = GetComponent(/datum/component/storage)
STR.max_items = 10
STR.set_holdable(list(/obj/item/rollingpaper))
atom_storage.max_slots = 10
atom_storage.set_holdable(list(/obj/item/rollingpaper))
///Overrides to do nothing because fancy boxes are fucking insane.
/obj/item/storage/fancy/rollingpapers/update_icon_state()
@@ -417,14 +385,13 @@
w_class = WEIGHT_CLASS_NORMAL
contents_tag = "premium cigar"
spawn_type = /obj/item/clothing/mask/cigarette/cigar
spawn_count = 5
spawn_coupon = FALSE
display_cigs = FALSE
/obj/item/storage/fancy/cigarettes/cigars/ComponentInitialize()
/obj/item/storage/fancy/cigarettes/cigars/Initialize()
. = ..()
var/datum/component/storage/STR = GetComponent(/datum/component/storage)
STR.max_items = 5
STR.set_holdable(list(/obj/item/clothing/mask/cigarette/cigar))
atom_storage.set_holdable(list(/obj/item/clothing/mask/cigarette/cigar))
/obj/item/storage/fancy/cigarettes/cigars/update_icon_state()
. = ..()
@@ -469,12 +436,11 @@
righthand_file = 'icons/mob/inhands/misc/food_righthand.dmi'
contents_tag = "chocolate"
spawn_type = /obj/item/food/tinychocolate
spawn_count = 8
/obj/item/storage/fancy/heart_box/ComponentInitialize()
/obj/item/storage/fancy/heart_box/Initialize()
. = ..()
var/datum/component/storage/STR = GetComponent(/datum/component/storage)
STR.max_items = 8
STR.set_holdable(list(/obj/item/food/tinychocolate))
atom_storage.set_holdable(list(/obj/item/food/tinychocolate))
/obj/item/storage/fancy/nugget_box
@@ -485,9 +451,8 @@
base_icon_state = "nuggetbox"
contents_tag = "nugget"
spawn_type = /obj/item/food/nugget
spawn_count = 6
/obj/item/storage/fancy/nugget_box/ComponentInitialize()
/obj/item/storage/fancy/nugget_box/Initialize()
. = ..()
var/datum/component/storage/STR = GetComponent(/datum/component/storage)
STR.max_items = 6
STR.set_holdable(list(/obj/item/food/nugget))
atom_storage.set_holdable(list(/obj/item/food/nugget))
+7 -8
View File
@@ -30,15 +30,14 @@
name = "chief engineer's garment bag"
desc = "A bag for storing extra clothes and shoes. This one belongs to the chief engineer."
/obj/item/storage/bag/garment/ComponentInitialize()
/obj/item/storage/bag/garment/Initialize()
. = ..()
var/datum/component/storage/STR = GetComponent(/datum/component/storage)
STR.max_w_class = WEIGHT_CLASS_NORMAL
STR.display_numerical_stacking = FALSE
STR.max_combined_w_class = 200
STR.max_items = 15
STR.insert_preposition = "in"
STR.set_holdable(list(
atom_storage.max_specific_storage = WEIGHT_CLASS_NORMAL
atom_storage.numerical_stacking = FALSE
atom_storage.max_total_storage = 200
atom_storage.max_slots = 15
atom_storage.insert_preposition = "in"
atom_storage.set_holdable(list(
/obj/item/clothing,
))
+22 -28
View File
@@ -17,12 +17,11 @@
. = ..()
REMOVE_TRAIT(user, TRAIT_GUNFLIP, CLOTHING_TRAIT)
/obj/item/storage/belt/holster/ComponentInitialize()
/obj/item/storage/belt/holster/Initialize()
. = ..()
var/datum/component/storage/STR = GetComponent(/datum/component/storage)
STR.max_items = 1
STR.max_w_class = WEIGHT_CLASS_NORMAL
STR.set_holdable(list(
atom_storage.max_slots = 1
atom_storage.max_total_storage = 16
atom_storage.set_holdable(list(
/obj/item/gun/ballistic/automatic/pistol,
/obj/item/gun/ballistic/revolver,
/obj/item/gun/energy/e_gun/mini,
@@ -36,12 +35,11 @@
name = "thermal shoulder holsters"
desc = "A rather plain pair of shoulder holsters with a bit of insulated padding inside. Meant to hold a twinned pair of thermal pistols, but can fit several kinds of energy handguns as well."
/obj/item/storage/belt/holster/thermal/ComponentInitialize()
/obj/item/storage/belt/holster/thermal/Initialize()
. = ..()
var/datum/component/storage/STR = GetComponent(/datum/component/storage)
STR.max_items = 2
STR.max_w_class = WEIGHT_CLASS_NORMAL
STR.set_holdable(list(
atom_storage.max_slots = 2
atom_storage.max_specific_storage = WEIGHT_CLASS_NORMAL
atom_storage.set_holdable(list(
/obj/item/gun/energy/e_gun/mini,
/obj/item/gun/energy/disabler,
/obj/item/gun/energy/dueling,
@@ -60,12 +58,11 @@
desc = "A holster able to carry handguns and some ammo. WARNING: Badasses only."
w_class = WEIGHT_CLASS_BULKY
/obj/item/storage/belt/holster/detective/ComponentInitialize()
/obj/item/storage/belt/holster/detective/Initialize()
. = ..()
var/datum/component/storage/STR = GetComponent(/datum/component/storage)
STR.max_items = 3
STR.max_w_class = WEIGHT_CLASS_NORMAL
STR.set_holdable(list(
atom_storage.max_slots = 3
atom_storage.max_specific_storage = WEIGHT_CLASS_NORMAL
atom_storage.set_holdable(list(
/obj/item/gun/ballistic/automatic/pistol,
/obj/item/ammo_box/magazine/m9mm, // Pistol magazines.
/obj/item/ammo_box/magazine/m9mm_aps,
@@ -119,10 +116,9 @@
chameleon_action.initialize_disguises()
add_item_action(chameleon_action)
/obj/item/storage/belt/holster/chameleon/ComponentInitialize()
/obj/item/storage/belt/holster/chameleon/Initialize()
. = ..()
var/datum/component/storage/STR = GetComponent(/datum/component/storage)
STR.silent = TRUE
atom_storage.silent = TRUE
/obj/item/storage/belt/holster/chameleon/emp_act(severity)
. = ..()
@@ -134,12 +130,11 @@
. = ..()
chameleon_action.emp_randomise(INFINITY)
/obj/item/storage/belt/holster/chameleon/ComponentInitialize()
/obj/item/storage/belt/holster/chameleon/Initialize()
. = ..()
var/datum/component/storage/STR = GetComponent(/datum/component/storage)
STR.max_items = 2
STR.max_w_class = WEIGHT_CLASS_NORMAL
STR.set_holdable(list(
atom_storage.max_slots = 2
atom_storage.max_total_storage = WEIGHT_CLASS_NORMAL
atom_storage.set_holdable(list(
/obj/item/gun/ballistic/automatic/pistol,
/obj/item/ammo_box/magazine/m9mm,
/obj/item/ammo_box/magazine/m9mm_aps,
@@ -164,12 +159,11 @@
worn_icon_state = "syndicate_holster"
w_class = WEIGHT_CLASS_BULKY
/obj/item/storage/belt/holster/nukie/ComponentInitialize()
/obj/item/storage/belt/holster/nukie/Initialize()
. = ..()
var/datum/component/storage/STR = GetComponent(/datum/component/storage)
STR.max_items = 2
STR.max_w_class = WEIGHT_CLASS_BULKY
STR.set_holdable(list(
atom_storage.max_slots = 2
atom_storage.max_specific_storage = WEIGHT_CLASS_BULKY
atom_storage.set_holdable(list(
/obj/item/gun, // ALL guns.
/obj/item/ammo_box/magazine, // ALL magazines.
/obj/item/ammo_box/c38, //There isn't a speedloader parent type, so I just put these three here by hand.
+21 -25
View File
@@ -13,27 +13,26 @@
var/icon_closed = "lockbox"
var/icon_broken = "lockbox+b"
/obj/item/storage/lockbox/ComponentInitialize()
/obj/item/storage/lockbox/Initialize()
. = ..()
var/datum/component/storage/STR = GetComponent(/datum/component/storage)
STR.max_w_class = WEIGHT_CLASS_NORMAL
STR.max_combined_w_class = 14
STR.max_items = 4
STR.locked = TRUE
atom_storage.max_specific_storage = WEIGHT_CLASS_NORMAL
atom_storage.max_total_storage = 14
atom_storage.max_slots = 4
atom_storage.locked = TRUE
/obj/item/storage/lockbox/attackby(obj/item/W, mob/user, params)
var/locked = SEND_SIGNAL(src, COMSIG_IS_STORAGE_LOCKED)
var/locked = atom_storage.locked
if(W.GetID())
if(broken)
to_chat(user, span_danger("It appears to be broken."))
return
if(allowed(user))
SEND_SIGNAL(src, COMSIG_TRY_STORAGE_SET_LOCKSTATE, !locked)
locked = SEND_SIGNAL(src, COMSIG_IS_STORAGE_LOCKED)
atom_storage.locked = !locked
locked = atom_storage.locked
if(locked)
icon_state = icon_locked
to_chat(user, span_danger("You lock the [src.name]!"))
SEND_SIGNAL(src, COMSIG_TRY_STORAGE_HIDE_ALL)
atom_storage.close_all()
return
else
icon_state = icon_closed
@@ -50,7 +49,7 @@
/obj/item/storage/lockbox/emag_act(mob/user)
if(!broken)
broken = TRUE
SEND_SIGNAL(src, COMSIG_TRY_STORAGE_SET_LOCKSTATE, FALSE)
atom_storage.locked = FALSE
desc += "It appears to be broken."
icon_state = src.icon_broken
if(user)
@@ -97,22 +96,21 @@
icon_closed = "medalbox"
icon_broken = "medalbox+b"
/obj/item/storage/lockbox/medal/ComponentInitialize()
/obj/item/storage/lockbox/medal/Initialize()
. = ..()
var/datum/component/storage/STR = GetComponent(/datum/component/storage)
STR.max_w_class = WEIGHT_CLASS_SMALL
STR.max_items = 10
STR.max_combined_w_class = 20
STR.set_holdable(list(/obj/item/clothing/accessory/medal))
atom_storage.max_specific_storage = WEIGHT_CLASS_SMALL
atom_storage.max_slots = 10
atom_storage.max_total_storage = 20
atom_storage.set_holdable(list(/obj/item/clothing/accessory/medal))
/obj/item/storage/lockbox/medal/examine(mob/user)
. = ..()
if(!SEND_SIGNAL(src, COMSIG_IS_STORAGE_LOCKED))
if(!atom_storage.locked)
. += span_notice("Alt-click to [open ? "close":"open"] it.")
/obj/item/storage/lockbox/medal/AltClick(mob/user)
if(user.canUseTopic(src, BE_CLOSE))
if(!SEND_SIGNAL(src, COMSIG_IS_STORAGE_LOCKED))
if(!atom_storage.locked)
open = (open ? FALSE : TRUE)
update_appearance()
..()
@@ -129,8 +127,7 @@
new /obj/item/clothing/accessory/medal/conduct(src)
/obj/item/storage/lockbox/medal/update_icon_state()
var/locked = SEND_SIGNAL(src, COMSIG_IS_STORAGE_LOCKED)
if(locked)
if(atom_storage?.locked)
icon_state = "medalbox+l"
return ..()
@@ -145,8 +142,7 @@
. = ..()
if(!contents || !open)
return
var/locked = SEND_SIGNAL(src, COMSIG_IS_STORAGE_LOCKED)
if(locked)
if(atom_storage?.locked)
return
for(var/i in 1 to contents.len)
var/obj/item/clothing/accessory/medal/M = contents[i]
@@ -240,8 +236,8 @@
to_chat(user, span_warning("Bank account does not match with buyer!"))
return
SEND_SIGNAL(src, COMSIG_TRY_STORAGE_SET_LOCKSTATE, !privacy_lock)
privacy_lock = SEND_SIGNAL(src, COMSIG_IS_STORAGE_LOCKED)
atom_storage.locked = !privacy_lock
privacy_lock = atom_storage.locked
user.visible_message(span_notice("[user] [privacy_lock ? "" : "un"]locks [src]'s privacy lock."),
span_notice("You [privacy_lock ? "" : "un"]lock [src]'s privacy lock."))
+15 -20
View File
@@ -60,13 +60,12 @@
inhand_icon_state = "medkit"
desc = "A high capacity aid kit for doctors, full of medical supplies and basic surgical equipment"
/obj/item/storage/medkit/surgery/ComponentInitialize()
/obj/item/storage/medkit/surgery/Initialize()
. = ..()
var/datum/component/storage/STR = GetComponent(/datum/component/storage)
STR.max_w_class = WEIGHT_CLASS_NORMAL //holds the same equipment as a medibelt
STR.max_items = 12
STR.max_combined_w_class = 24
STR.set_holdable(list(
atom_storage.max_specific_storage = WEIGHT_CLASS_NORMAL //holds the same equipment as a medibelt
atom_storage.max_slots = 12
atom_storage.max_total_storage = 24
atom_storage.set_holdable(list(
/obj/item/healthanalyzer,
/obj/item/dnainjector,
/obj/item/reagent_containers/dropper,
@@ -259,10 +258,9 @@
icon_state = "medkit_tactical"
damagetype_healed = "all"
/obj/item/storage/medkit/tactical/ComponentInitialize()
/obj/item/storage/medkit/tactical/Initialize()
. = ..()
var/datum/component/storage/STR = GetComponent(/datum/component/storage)
STR.max_w_class = WEIGHT_CLASS_NORMAL
atom_storage.max_specific_storage = WEIGHT_CLASS_NORMAL
/obj/item/storage/medkit/tactical/PopulateContents()
if(empty)
@@ -318,12 +316,10 @@
righthand_file = 'icons/mob/inhands/equipment/medical_righthand.dmi'
w_class = WEIGHT_CLASS_SMALL
/obj/item/storage/pill_bottle/ComponentInitialize()
/obj/item/storage/pill_bottle/Initialize()
. = ..()
var/datum/component/storage/STR = GetComponent(/datum/component/storage)
STR.allow_quick_gather = TRUE
STR.click_gather = TRUE
STR.set_holdable(list(/obj/item/reagent_containers/pill))
atom_storage.allow_quick_gather = TRUE
atom_storage.set_holdable(list(/obj/item/reagent_containers/pill))
/obj/item/storage/pill_bottle/suicide_act(mob/user)
user.visible_message(span_suicide("[user] is trying to get the cap off [src]! It looks like [user.p_theyre()] trying to commit suicide!"))
@@ -528,12 +524,11 @@
/// var to prevent it freezing the same things over and over
var/cooling = FALSE
/obj/item/storage/organbox/ComponentInitialize()
/obj/item/storage/organbox/Initialize()
. = ..()
var/datum/component/storage/STR = GetComponent(/datum/component/storage)
STR.max_w_class = WEIGHT_CLASS_BULKY /// you have to remove it from your bag before opening it but I think that's fine
STR.max_combined_w_class = 21
STR.set_holdable(list(
atom_storage.max_specific_storage = WEIGHT_CLASS_BULKY /// you have to remove it from your bag before opening it but I think that's fine
atom_storage.max_total_storage = 21
atom_storage.set_holdable(list(
/obj/item/organ,
/obj/item/bodypart,
/obj/item/food/icecream
@@ -543,7 +538,7 @@
. = ..()
create_reagents(100, TRANSPARENT)
RegisterSignal(src, COMSIG_ATOM_ENTERED, .proc/freeze)
RegisterSignal(src, COMSIG_TRY_STORAGE_TAKE, .proc/unfreeze)
RegisterSignal(src, COMSIG_ATOM_EXITED, .proc/unfreeze)
START_PROCESSING(SSobj, src)
/obj/item/storage/organbox/process(delta_time)
+15 -18
View File
@@ -33,11 +33,10 @@
var/can_hack_open = TRUE
/obj/item/storage/secure/ComponentInitialize()
/obj/item/storage/secure/Initialize()
. = ..()
var/datum/component/storage/STR = GetComponent(/datum/component/storage)
STR.max_w_class = WEIGHT_CLASS_SMALL
STR.max_combined_w_class = 14
atom_storage.max_specific_storage = WEIGHT_CLASS_SMALL
atom_storage.max_total_storage = 14
/obj/item/storage/secure/examine(mob/user)
. = ..()
@@ -45,7 +44,7 @@
. += "The service panel is currently <b>[panel_open ? "unscrewed" : "screwed shut"]</b>."
/obj/item/storage/secure/tool_act(mob/living/user, obj/item/tool)
if(can_hack_open && SEND_SIGNAL(src, COMSIG_IS_STORAGE_LOCKED))
if(can_hack_open && atom_storage.locked)
return ..()
else
return FALSE
@@ -78,7 +77,7 @@
to_chat(user, span_warning("You must <b>unscrew</b> the service panel before you can pulse the wiring!"))
/obj/item/storage/secure/attack_self(mob/user)
var/locked = SEND_SIGNAL(src, COMSIG_IS_STORAGE_LOCKED)
var/locked = atom_storage.locked
user.set_machine(src)
var/dat = text("<TT><B>[]</B><BR>\n\nLock Status: []",src, (locked ? "LOCKED" : "UNLOCKED"))
var/message = "Code"
@@ -100,7 +99,7 @@
lock_code = entered_code
lock_set = TRUE
else if ((entered_code == lock_code) && lock_set)
SEND_SIGNAL(src, COMSIG_TRY_STORAGE_SET_LOCKSTATE, FALSE)
atom_storage.locked = TRUE
cut_overlays()
add_overlay(icon_opened)
entered_code = null
@@ -108,10 +107,10 @@
entered_code = "ERROR"
else
if (href_list["type"] == "R")
SEND_SIGNAL(src, COMSIG_TRY_STORAGE_SET_LOCKSTATE, TRUE)
atom_storage.locked = FALSE
cut_overlays()
entered_code = null
SEND_SIGNAL(src, COMSIG_TRY_STORAGE_HIDE_FROM, usr)
atom_storage.hide_contents(usr)
else
entered_code += text("[]", sanitize_text(href_list["type"]))
if (length(entered_code) > 5)
@@ -144,11 +143,10 @@
new /obj/item/paper(src)
new /obj/item/pen(src)
/obj/item/storage/secure/briefcase/ComponentInitialize()
/obj/item/storage/secure/briefcase/Initialize()
. = ..()
var/datum/component/storage/STR = GetComponent(/datum/component/storage)
STR.max_combined_w_class = 21
STR.max_w_class = WEIGHT_CLASS_NORMAL
atom_storage.max_total_storage = 21
atom_storage.max_specific_storage = WEIGHT_CLASS_NORMAL
///Syndie variant of Secure Briefcase. Contains space cash, slightly more robust.
/obj/item/storage/secure/briefcase/syndie
@@ -174,11 +172,10 @@
MAPPING_DIRECTIONAL_HELPERS(/obj/item/storage/secure/safe, 32)
/obj/item/storage/secure/safe/ComponentInitialize()
/obj/item/storage/secure/safe/Initialize()
. = ..()
var/datum/component/storage/STR = GetComponent(/datum/component/storage)
STR.set_holdable(null, list(/obj/item/storage/secure/briefcase))
STR.max_w_class = 8 //??
atom_storage.set_holdable(cant_hold_list = list(/obj/item/storage/secure/briefcase))
atom_storage.max_specific_storage = WEIGHT_CLASS_GIGANTIC
/obj/item/storage/secure/safe/PopulateContents()
new /obj/item/paper(src)
@@ -219,7 +216,7 @@ MAPPING_DIRECTIONAL_HELPERS(/obj/item/storage/secure/safe/caps_spare, 32)
lock_code = SSid_access.spare_id_safe_code
lock_set = TRUE
SEND_SIGNAL(src, COMSIG_TRY_STORAGE_SET_LOCKSTATE, TRUE)
atom_storage.locked = TRUE
/obj/item/storage/secure/safe/caps_spare/PopulateContents()
new /obj/item/card/id/advanced/gold/captains_spare(src)
+5 -6
View File
@@ -21,13 +21,12 @@
. = ..()
update_appearance()
/obj/item/storage/cans/ComponentInitialize()
/obj/item/storage/cans/Initialize()
. = ..()
var/datum/component/storage/STR = GetComponent(/datum/component/storage)
STR.max_w_class = WEIGHT_CLASS_SMALL
STR.max_combined_w_class = 12
STR.max_items = 6
STR.set_holdable(list(
atom_storage.max_specific_storage = WEIGHT_CLASS_SMALL
atom_storage.max_total_storage = 12
atom_storage.max_slots = 6
atom_storage.set_holdable(list(
/obj/item/reagent_containers/food/drinks/soda_cans,
/obj/item/reagent_containers/food/drinks/bottle/beer,
/obj/item/reagent_containers/food/drinks/bottle/ale,
+6 -8
View File
@@ -3,7 +3,6 @@
icon = 'icons/obj/storage.dmi'
w_class = WEIGHT_CLASS_NORMAL
var/rummage_if_nodrop = TRUE
var/component_type = /datum/component/storage/concrete
/// Should we preload the contents of this type?
/// BE CAREFUL, THERE'S SOME REALLY NASTY SHIT IN THIS TYPEPATH
/// SANTA IS EVIL
@@ -11,13 +10,14 @@
/obj/item/storage/Initialize(mapload)
. = ..()
create_storage()
PopulateContents()
for (var/obj/item/item in src)
item.item_flags |= IN_STORAGE
/obj/item/storage/ComponentInitialize()
AddComponent(component_type)
/obj/item/storage/AllowDrop()
return FALSE
@@ -37,8 +37,7 @@
/obj/item/storage/doStrip(mob/who)
if(HAS_TRAIT(src, TRAIT_NODROP) && rummage_if_nodrop)
var/datum/component/storage/CP = GetComponent(/datum/component/storage)
CP.do_quick_empty()
atom_storage.remove_all()
return TRUE
return ..()
@@ -48,8 +47,7 @@
/obj/item/storage/proc/PopulateContents()
/obj/item/storage/proc/emptyStorage()
var/datum/component/storage/ST = GetComponent(/datum/component/storage)
ST.do_quick_empty()
atom_storage.remove_all()
/obj/item/storage/Destroy()
for(var/obj/important_thing in contents)
+14 -19
View File
@@ -38,10 +38,9 @@
if(has_latches)
. += latches
/obj/item/storage/toolbox/ComponentInitialize()
/obj/item/storage/toolbox/Initialize()
. = ..()
var/datum/component/storage/STR = GetComponent(/datum/component/storage)
STR.max_w_class = WEIGHT_CLASS_NORMAL
atom_storage.max_specific_storage = WEIGHT_CLASS_NORMAL
/obj/item/storage/toolbox/suicide_act(mob/user)
user.visible_message(span_suicide("[user] robusts [user.p_them()]self with [src]! It looks like [user.p_theyre()] trying to commit suicide!"))
@@ -102,10 +101,9 @@
force = 5
w_class = WEIGHT_CLASS_NORMAL
/obj/item/storage/toolbox/mechanical/old/heirloom/ComponentInitialize()
/obj/item/storage/toolbox/mechanical/old/heirloom/Initialize()
. = ..()
var/datum/component/storage/STR = GetComponent(/datum/component/storage)
STR.max_w_class = WEIGHT_CLASS_SMALL
atom_storage.max_specific_storage = WEIGHT_CLASS_SMALL
/obj/item/storage/toolbox/mechanical/old/heirloom/PopulateContents()
return
@@ -170,10 +168,9 @@
throwforce = 18
material_flags = NONE
/obj/item/storage/toolbox/syndicate/ComponentInitialize()
/obj/item/storage/toolbox/syndicate/Initialize()
. = ..()
var/datum/component/storage/STR = GetComponent(/datum/component/storage)
STR.silent = TRUE
atom_storage.silent = TRUE
/obj/item/storage/toolbox/syndicate/PopulateContents()
new /obj/item/screwdriver/nuke(src)
@@ -208,11 +205,10 @@
w_class = WEIGHT_CLASS_GIGANTIC //Holds more than a regular toolbox!
material_flags = NONE
/obj/item/storage/toolbox/artistic/ComponentInitialize()
/obj/item/storage/toolbox/artistic/Initialize()
. = ..()
var/datum/component/storage/STR = GetComponent(/datum/component/storage)
STR.max_combined_w_class = 20
STR.max_items = 10
atom_storage.max_total_storage = 20
atom_storage.max_slots = 10
/obj/item/storage/toolbox/artistic/PopulateContents()
new /obj/item/storage/crayons(src)
@@ -275,13 +271,12 @@
w_class = WEIGHT_CLASS_NORMAL
has_latches = FALSE
/obj/item/storage/toolbox/infiltrator/ComponentInitialize()
/obj/item/storage/toolbox/infiltrator/Initialize()
. = ..()
var/datum/component/storage/STR = GetComponent(/datum/component/storage)
STR.max_items = 10
STR.max_w_class = WEIGHT_CLASS_NORMAL
STR.max_combined_w_class = 24
STR.set_holdable(list(
atom_storage.max_slots = 10
atom_storage.max_specific_storage = WEIGHT_CLASS_NORMAL
atom_storage.max_total_storage = 24
atom_storage.set_holdable(list(
/obj/item/clothing/head/helmet/infiltrator,
/obj/item/clothing/suit/armor/vest/infiltrator,
/obj/item/clothing/under/syndicate/bloodred,
@@ -385,11 +385,10 @@
/obj/item/storage/box/syndie_kit/space
name = "boxed space suit and helmet"
/obj/item/storage/box/syndie_kit/space/ComponentInitialize()
/obj/item/storage/box/syndie_kit/space/Initialize()
. = ..()
var/datum/component/storage/STR = GetComponent(/datum/component/storage)
STR.max_w_class = WEIGHT_CLASS_NORMAL
STR.set_holdable(list(/obj/item/clothing/suit/space/syndicate, /obj/item/clothing/head/helmet/space/syndicate))
atom_storage.max_specific_storage = WEIGHT_CLASS_NORMAL
atom_storage.set_holdable(list(/obj/item/clothing/suit/space/syndicate, /obj/item/clothing/head/helmet/space/syndicate))
/obj/item/storage/box/syndie_kit/space/PopulateContents()
if(prob(50))
@@ -411,10 +410,9 @@
/obj/item/storage/box/syndie_kit/chemical
name = "chemical kit"
/obj/item/storage/box/syndie_kit/chemical/ComponentInitialize()
/obj/item/storage/box/syndie_kit/chemical/Initialize()
. = ..()
var/datum/component/storage/STR = GetComponent(/datum/component/storage)
STR.max_items = 14
atom_storage.max_slots = 14
/obj/item/storage/box/syndie_kit/chemical/PopulateContents()
new /obj/item/reagent_containers/glass/bottle/polonium(src)
+3 -5
View File
@@ -5,17 +5,15 @@
w_class = WEIGHT_CLASS_SMALL
resistance_flags = FLAMMABLE
slot_flags = ITEM_SLOT_ID
component_type = /datum/component/storage/concrete/wallet
var/obj/item/card/id/front_id = null
var/list/combined_access
var/cached_flat_icon
/obj/item/storage/wallet/ComponentInitialize()
/obj/item/storage/wallet/Initialize()
. = ..()
var/datum/component/storage/STR = GetComponent(/datum/component/storage/concrete/wallet)
STR.max_items = 4
STR.set_holdable(list(
atom_storage.max_slots = 4
atom_storage.set_holdable(list(
/obj/item/stack/spacecash,
/obj/item/holochip,
/obj/item/card,
+5 -6
View File
@@ -184,7 +184,7 @@ GLOBAL_LIST_EMPTY(tcgcard_radial_choices)
/obj/item/tcgcard_deck/Initialize(mapload)
. = ..()
LoadComponent(/datum/component/storage/concrete/tcg)
create_storage(type = /datum/storage/tcg)
/obj/item/tcgcard_deck/update_icon_state()
if(!flipped)
@@ -284,7 +284,7 @@ GLOBAL_LIST_EMPTY(tcgcard_radial_choices)
return
contents = shuffle(contents)
if(user.active_storage)
user.active_storage.close(user)
user.active_storage.hide_contents(user)
if(visable)
user.visible_message(span_notice("[user] shuffles \the [src]!"), \
span_notice("You shuffle \the [src]!"))
@@ -396,10 +396,9 @@ GLOBAL_LIST_EMPTY(tcgcard_radial_choices)
/obj/item/storage/card_binder/Initialize(mapload)
. = ..()
var/datum/component/storage/STR = GetComponent(/datum/component/storage)
STR.set_holdable(list(/obj/item/tcgcard))
STR.max_combined_w_class = 120
STR.max_items = 60
atom_storage.set_holdable(list(/obj/item/tcgcard))
atom_storage.max_total_storage = 120
atom_storage.max_slots = 60
///Returns a list of cards ids of card_cnt weighted by rarity from the pack's tables that have matching series, with gnt_cnt of the guarenteed table.
/obj/item/cardpack/proc/buildCardListWithRarity(card_cnt, rarity_cnt)
@@ -248,7 +248,7 @@
break
for(var/i in reverse_range(location.get_all_contents()))
var/atom/movable/thing = i
SEND_SIGNAL(thing, COMSIG_TRY_STORAGE_HIDE_ALL)
thing.atom_storage?.close_all()
/obj/structure/closet/proc/open(mob/living/user, force = FALSE)
if(!can_open(user, force))
@@ -28,7 +28,7 @@
var/obj/item/storage/bag/trash/T = W
to_chat(user, span_notice("You fill the bag."))
for(var/obj/item/O in src)
SEND_SIGNAL(T, COMSIG_TRY_STORAGE_INSERT, O, user, TRUE)
T.atom_storage?.attempt_insert(T, O, user, TRUE)
T.update_appearance()
do_animate()
return TRUE
+1 -1
View File
@@ -209,7 +209,7 @@
for(var/x in T.contents)
var/obj/item/item = x
AfterPutItemOnTable(item, user)
SEND_SIGNAL(I, COMSIG_TRY_STORAGE_QUICK_EMPTY, drop_location())
I.atom_storage.remove_all(drop_location())
user.visible_message(span_notice("[user] empties [I] on [src]."))
return
// If the tray IS empty, continue on (tray will be placed on the table like other items)
+10 -9
View File
@@ -452,20 +452,21 @@ GLOBAL_LIST_EMPTY(station_turfs)
/turf/proc/Bless()
new /obj/effect/blessing(src)
/turf/storage_contents_dump_act(datum/component/storage/src_object, mob/user)
/turf/storage_contents_dump_act(atom/src_object, mob/user)
. = ..()
if(.)
return
if(length(src_object.contents()))
to_chat(usr, span_notice("You start dumping out the contents..."))
if(!do_after(usr,20,target=src_object.parent))
if(!src_object.atom_storage)
return
var/atom/resolve_parent = src_object.atom_storage.real_location?.resolve()
if(!resolve_parent)
return FALSE
if(length(resolve_parent.contents))
to_chat(user, span_notice("You start dumping out the contents of [src_object]..."))
if(!do_after(user, 20, target=resolve_parent))
return FALSE
var/list/things = src_object.contents()
var/datum/progressbar/progress = new(user, things.len, src)
while (do_after(usr, 1 SECONDS, src, NONE, FALSE, CALLBACK(src_object, /datum/component/storage.proc/mass_remove_from_storage, src, things, progress)))
stoplag(1)
progress.end_progress()
src_object.atom_storage.remove_all(src)
return TRUE
@@ -20,7 +20,11 @@
armor = list(MELEE = 25, BULLET = 25, LASER = 25, ENERGY = 25, BOMB = 50, BIO = 90, FIRE = 70, ACID = 50)
strip_delay = 70
resistance_flags = NONE
pocket_storage_component_path = /datum/component/storage/concrete/pockets/shoes
/obj/item/clothing/shoes/clown_shoes/combat/Initialize(mapload)
. = ..()
create_storage(type = /datum/storage/pockets/shoes)
/// Recharging rate in PPS (peels per second)
#define BANANA_SHOES_RECHARGE_RATE 17
@@ -34,11 +38,13 @@
armor = list(MELEE = 25, BULLET = 25, LASER = 25, ENERGY = 25, BOMB = 50, BIO = 50, FIRE = 90, ACID = 50)
strip_delay = 70
resistance_flags = NONE
pocket_storage_component_path = /datum/component/storage/concrete/pockets/shoes
always_noslip = TRUE
/obj/item/clothing/shoes/clown_shoes/banana_shoes/combat/Initialize(mapload)
. = ..()
create_storage(type = /datum/storage/pockets/shoes)
var/datum/component/material_container/bananium = GetComponent(/datum/component/material_container)
bananium.insert_amount_mat(BANANA_SHOES_MAX_CHARGE, /datum/material/bananium)
START_PROCESSING(SSobj, src)
+1 -1
View File
@@ -126,7 +126,7 @@
else
to_chat(mob, span_danger("You have a [item_name] in your [where]."))
if(where == "backpack")
SEND_SIGNAL(mob.back, COMSIG_TRY_STORAGE_SHOW, mob)
mob.back.atom_storage?.show_contents(mob)
return TRUE
/datum/antagonist/cult/apply_innate_effects(mob/living/mob_override)
@@ -60,8 +60,12 @@
body_parts_covered = CHEST|GROIN|ARMS
// slightly worse than normal cult robes
armor = list(MELEE = 30, BULLET = 30, LASER = 30,ENERGY = 30, BOMB = 15, BIO = 0, FIRE = 0, ACID = 0)
pocket_storage_component_path = /datum/component/storage/concrete/pockets/void_cloak
alternative_mode = TRUE
/obj/item/clothing/suit/hooded/cultrobes/void/Initialize(mapload)
. = ..()
create_storage(type = /datum/storage/pockets/void_cloak)
/obj/item/clothing/suit/hooded/cultrobes/void/Initialize(mapload)
. = ..()
+4 -5
View File
@@ -602,12 +602,14 @@
desc = "A pair of black shoes."
resistance_flags = NONE
armor = list(MELEE = 10, BULLET = 10, LASER = 10, ENERGY = 0, BOMB = 0, BIO = 90, FIRE = 50, ACID = 50)
pocket_storage_component_path = /datum/component/storage/concrete/pockets/shoes
var/datum/action/item_action/chameleon/change/chameleon_action
/obj/item/clothing/shoes/chameleon/Initialize(mapload)
. = ..()
create_storage(type = /datum/storage/pockets/shoes)
chameleon_action = new(src)
chameleon_action.chameleon_type = /obj/item/clothing/shoes
chameleon_action.chameleon_name = "Shoes"
@@ -665,10 +667,7 @@
chameleon_action.initialize_disguises()
add_item_action(chameleon_action)
/obj/item/storage/belt/chameleon/ComponentInitialize()
. = ..()
var/datum/component/storage/STR = GetComponent(/datum/component/storage)
STR.silent = TRUE
atom_storage.silent = TRUE
/obj/item/storage/belt/chameleon/emp_act(severity)
. = ..()
+7 -8
View File
@@ -287,20 +287,19 @@
if(30 to 59)
. += span_danger("The [zone_name] is partially shredded.")
var/datum/component/storage/pockets = GetComponent(/datum/component/storage)
if(pockets)
if(atom_storage)
var/list/how_cool_are_your_threads = list("<span class='notice'>")
if(pockets.attack_hand_interact)
if(atom_storage.attack_hand_interact)
how_cool_are_your_threads += "[src]'s storage opens when clicked.\n"
else
how_cool_are_your_threads += "[src]'s storage opens when dragged to yourself.\n"
if (pockets.can_hold?.len) // If pocket type can hold anything, vs only specific items
how_cool_are_your_threads += "[src] can store [pockets.max_items] <a href='?src=[REF(src)];show_valid_pocket_items=1'>item\s</a>.\n"
if (atom_storage.can_hold?.len) // If pocket type can hold anything, vs only specific items
how_cool_are_your_threads += "[src] can store [atom_storage.max_slots] <a href='?src=[REF(src)];show_valid_pocket_items=1'>item\s</a>.\n"
else
how_cool_are_your_threads += "[src] can store [pockets.max_items] item\s that are [weight_class_to_text(pockets.max_w_class)] or smaller.\n"
if(pockets.quickdraw)
how_cool_are_your_threads += "[src] can store [atom_storage.max_slots] item\s that are [weight_class_to_text(atom_storage.max_specific_storage)] or smaller.\n"
if(atom_storage.quickdraw)
how_cool_are_your_threads += "You can quickly remove an item from [src] using Right-Click.\n"
if(pockets.silent)
if(atom_storage.silent)
how_cool_are_your_threads += "Adding or removing items from [src] makes no noise.\n"
how_cool_are_your_threads += "</span>"
. += how_cool_are_your_threads.Join()
+5 -1
View File
@@ -3,7 +3,11 @@
icon_state = "fedora"
inhand_icon_state = "fedora"
desc = "A really cool hat if you're a mobster. A really lame hat if you're not."
pocket_storage_component_path = /datum/component/storage/concrete/pockets/small/fedora
/obj/item/clothing/head/fedora/Initialize(mapload)
. = ..()
create_storage(type = /datum/storage/pockets/small/fedora)
/obj/item/clothing/head/fedora/white
name = "white fedora"
+5 -1
View File
@@ -340,7 +340,11 @@
icon_state = "rus_helmet"
inhand_icon_state = "rus_helmet"
armor = list(MELEE = 25, BULLET = 30, LASER = 0, ENERGY = 10, BOMB = 10, BIO = 0, FIRE = 20, ACID = 50, WOUND = 5)
pocket_storage_component_path = /datum/component/storage/concrete/pockets/helmet
/obj/item/clothing/head/helmet/rus_helmet/Initialize(mapload)
. = ..()
create_storage(type = /datum/storage/pockets/helmet)
/obj/item/clothing/head/helmet/rus_ushanka
name = "battle ushanka"
+8 -2
View File
@@ -13,11 +13,15 @@
strip_delay = 10
equip_delay_other = 10
pocket_storage_component_path = /datum/component/storage/concrete/pockets/chefhat
dog_fashion = /datum/dog_fashion/head/chef
///the chance that the movements of a mouse inside of this hat get relayed to the human wearing the hat
var/mouse_control_probability = 20
/obj/item/clothing/head/chefhat/Initialize(mapload)
. = ..()
create_storage(type = /datum/storage/pockets/chefhat)
/obj/item/clothing/head/chefhat/i_am_assuming_direct_control
desc = "The commander in chef's head wear. Upon closer inspection, there seem to be dozens of tiny levers, buttons, dials, and screens inside of this hat. What the hell...?"
mouse_control_probability = 100
@@ -94,11 +98,13 @@
armor = list(MELEE = 25, BULLET = 5, LASER = 25, ENERGY = 35, BOMB = 0, BIO = 0, FIRE = 30, ACID = 50, WOUND = 5)
icon_state = "detective"
var/candy_cooldown = 0
pocket_storage_component_path = /datum/component/storage/concrete/pockets/small/fedora/detective
dog_fashion = /datum/dog_fashion/head/detective
/obj/item/clothing/head/fedora/det_hat/Initialize(mapload)
. = ..()
create_storage(type = /datum/storage/pockets/small/fedora/detective)
new /obj/item/reagent_containers/food/drinks/flask/det(src)
/obj/item/clothing/head/fedora/det_hat/examine(mob/user)
+10 -2
View File
@@ -17,10 +17,18 @@
name = "white taqiyah"
desc = "An extra-mustahabb way of showing your devotion to Allah."
icon_state = "taqiyahwhite"
pocket_storage_component_path = /datum/component/storage/concrete/pockets/small
/obj/item/clothing/head/taqiyahwhite/Initialize(mapload)
. = ..()
create_storage(type = /datum/storage/pockets/small)
/obj/item/clothing/head/taqiyahred
name = "red taqiyah"
desc = "An extra-mustahabb way of showing your devotion to Allah."
icon_state = "taqiyahred"
pocket_storage_component_path = /datum/component/storage/concrete/pockets/small
/obj/item/clothing/head/taqiyahred/Initialize(mapload)
. = ..()
create_storage(type = /datum/storage/pockets/small)
+5 -5
View File
@@ -252,11 +252,11 @@
for(var/obj/item/briefcase_item in sec_briefcase)
qdel(briefcase_item)
for(var/i = 3 to 0 step -1)
SEND_SIGNAL(sec_briefcase, COMSIG_TRY_STORAGE_INSERT, new /obj/item/stack/spacecash/c1000, null, TRUE, TRUE)
SEND_SIGNAL(sec_briefcase, COMSIG_TRY_STORAGE_INSERT, new /obj/item/gun/energy/recharge/ebow, null, TRUE, TRUE)
SEND_SIGNAL(sec_briefcase, COMSIG_TRY_STORAGE_INSERT, new /obj/item/gun/ballistic/revolver/mateba, null, TRUE, TRUE)
SEND_SIGNAL(sec_briefcase, COMSIG_TRY_STORAGE_INSERT, new /obj/item/ammo_box/a357, null, TRUE, TRUE)
SEND_SIGNAL(sec_briefcase, COMSIG_TRY_STORAGE_INSERT, new /obj/item/grenade/c4/x4, null, TRUE, TRUE)
sec_briefcase.contents += new /obj/item/stack/spacecash/c1000
sec_briefcase.contents += new /obj/item/gun/energy/recharge/ebow
sec_briefcase.contents += new /obj/item/gun/ballistic/revolver/mateba
sec_briefcase.contents += new /obj/item/ammo_box/a357
sec_briefcase.contents += new /obj/item/grenade/c4/x4
var/obj/item/modular_computer/tablet/pda/heads/pda = H.belt
pda.saved_identification = H.real_name
+2 -2
View File
@@ -107,10 +107,10 @@
O.vv_values = result
//Copy backpack contents if exist.
var/obj/item/backpack = get_item_by_slot(ITEM_SLOT_BACK)
if(istype(backpack) && SEND_SIGNAL(backpack, COMSIG_CONTAINS_STORAGE))
if(istype(backpack) && backpack.atom_storage)
var/list/bp_stuff = list()
var/list/typecounts = list()
SEND_SIGNAL(backpack, COMSIG_TRY_STORAGE_RETURN_INVENTORY, bp_stuff, FALSE)
backpack.atom_storage.return_inv(bp_stuff, FALSE)
for(var/obj/item/I in bp_stuff)
if(typecounts[I.type])
typecounts[I.type] += 1
+25 -5
View File
@@ -8,9 +8,13 @@
armor = list(MELEE = 25, BULLET = 25, LASER = 25, ENERGY = 25, BOMB = 50, BIO = 90, FIRE = 70, ACID = 50)
strip_delay = 40
resistance_flags = NONE
pocket_storage_component_path = /datum/component/storage/concrete/pockets/shoes
lace_time = 12 SECONDS
/obj/item/clothing/shoes/combat/Initialize(mapload)
. = ..()
create_storage(type = /datum/storage/pockets/shoes)
/obj/item/clothing/shoes/combat/sneakboots
name = "sneakboots"
desc = "These boots have special noise cancelling soles. Perfect for stealth, if it wasn't for the color scheme."
@@ -37,9 +41,13 @@
equip_delay_other = 50
resistance_flags = NONE
armor = list(MELEE = 0, BULLET = 0, LASER = 0, ENERGY = 0, BOMB = 0, BIO = 90, FIRE = 0, ACID = 0)
pocket_storage_component_path = /datum/component/storage/concrete/pockets/shoes
can_be_tied = FALSE
/obj/item/clothing/shoes/jackboots/Initialize(mapload)
. = ..()
create_storage(type = /datum/storage/pockets/shoes)
/obj/item/clothing/shoes/jackboots/fast
slowdown = -1
@@ -53,9 +61,13 @@
min_cold_protection_temperature = SHOES_MIN_TEMP_PROTECT
heat_protection = FEET|LEGS
max_heat_protection_temperature = SHOES_MAX_TEMP_PROTECT
pocket_storage_component_path = /datum/component/storage/concrete/pockets/shoes
lace_time = 8 SECONDS
/obj/item/clothing/shoes/winterboots/Initialize(mapload)
. = ..()
create_storage(type = /datum/storage/pockets/shoes)
/obj/item/clothing/shoes/winterboots/ice_boots
name = "ice hiking boots"
desc = "A pair of winter boots with special grips on the bottom, designed to prevent slipping on frozen surfaces."
@@ -73,10 +85,14 @@
armor = list(MELEE = 0, BULLET = 0, LASER = 0, ENERGY = 0, BOMB = 0, BIO = 80, FIRE = 0, ACID = 0)
strip_delay = 20
equip_delay_other = 40
pocket_storage_component_path = /datum/component/storage/concrete/pockets/shoes
lace_time = 8 SECONDS
species_exception = list(/datum/species/golem/uranium)
/obj/item/clothing/shoes/workboots/Initialize(mapload)
. = ..()
create_storage(type = /datum/storage/pockets/shoes)
/obj/item/clothing/shoes/workboots/mining
name = "mining boots"
desc = "Steel-toed mining boots for mining in hazardous environments. Very good at keeping toes uncrushed."
@@ -88,9 +104,13 @@
desc = "Comfy shoes."
icon_state = "rus_shoes"
inhand_icon_state = "rus_shoes"
pocket_storage_component_path = /datum/component/storage/concrete/pockets/shoes
lace_time = 8 SECONDS
/obj/item/clothing/shoes/russian/Initialize(mapload)
. = ..()
create_storage(type = /datum/storage/pockets/shoes)
/obj/item/clothing/shoes/discoshoes
name = "green lizardskin shoes"
desc = "They may have lost some of their lustre over the years, but these green lizardskin shoes fit you perfectly."
+2 -1
View File
@@ -4,13 +4,14 @@
icon_state = "clown"
inhand_icon_state = "clown_shoes"
slowdown = SHOES_SLOWDOWN+1
pocket_storage_component_path = /datum/component/storage/concrete/pockets/shoes/clown
var/enabled_waddle = TRUE
lace_time = 20 SECONDS // how the hell do these laces even work??
species_exception = list(/datum/species/golem/bananium)
/obj/item/clothing/shoes/clown_shoes/Initialize(mapload)
. = ..()
create_storage(type = /datum/storage/pockets/shoes/clown)
LoadComponent(/datum/component/squeak, list('sound/effects/clownstep1.ogg'=1,'sound/effects/clownstep2.ogg'=1), 50, falloff_exponent = 20) //die off quick please
AddElement(/datum/element/swabable, CELL_LINE_TABLE_CLOWN, CELL_VIRUS_TABLE_GENERIC, rand(2,3), 0)
+5 -1
View File
@@ -13,9 +13,13 @@
desc = "A pair of costume boots fashioned after bird talons."
icon_state = "griffinboots"
inhand_icon_state = "griffinboots"
pocket_storage_component_path = /datum/component/storage/concrete/pockets/shoes
lace_time = 8 SECONDS
/obj/item/clothing/shoes/griffin/Initialize(mapload)
. = ..()
create_storage(type = /datum/storage/pockets/shoes)
/obj/item/clothing/shoes/singery
name = "yellow performer's boots"
desc = "These boots were made for dancing."
+3 -1
View File
@@ -3,13 +3,15 @@
desc = "A small sticker lets you know they've been inspected for snakes, It is unclear how long ago the inspection took place..."
icon_state = "cowboy_brown"
armor = list(MELEE = 0, BULLET = 0, LASER = 0, ENERGY = 0, BOMB = 0, BIO = 90, FIRE = 0, ACID = 0) //these are quite tall
pocket_storage_component_path = /datum/component/storage/concrete/pockets/shoes
custom_price = PAYCHECK_CREW
var/max_occupants = 4
can_be_tied = FALSE
/obj/item/clothing/shoes/cowboy/Initialize(mapload)
. = ..()
create_storage(type = /datum/storage/pockets/shoes)
if(prob(2))
//There's a snake in my boot
new /mob/living/simple_animal/hostile/retaliate/snake(src)
+3 -1
View File
@@ -5,7 +5,6 @@
inhand_icon_state = "jackboots"
lefthand_file = 'icons/mob/inhands/equipment/security_lefthand.dmi'
righthand_file = 'icons/mob/inhands/equipment/security_righthand.dmi'
pocket_storage_component_path = /datum/component/storage/concrete/pockets/shoes
/// What projectile do we shoot?
var/projectile_type = /obj/projectile/bullet/c10mm
/// Each step, this is the chance we fire a shot
@@ -13,6 +12,9 @@
/obj/item/clothing/shoes/gunboots/Initialize(mapload)
. = ..()
create_storage(type = /datum/storage/pockets/shoes)
RegisterSignal(src, COMSIG_SHOES_STEP_ACTION, .proc/check_step)
/obj/item/clothing/shoes/gunboots/equipped(mob/user, slot)
+5 -1
View File
@@ -4,7 +4,6 @@
icon_state = "jetboots"
inhand_icon_state = "jetboots"
resistance_flags = FIRE_PROOF
pocket_storage_component_path = /datum/component/storage/concrete/pockets/shoes
actions_types = list(/datum/action/item_action/bhop)
armor = list(MELEE = 0, BULLET = 0, LASER = 0, ENERGY = 0, BOMB = 0, BIO = 90, FIRE = 0, ACID = 0)
strip_delay = 30
@@ -13,6 +12,11 @@
var/recharging_rate = 60 //default 6 seconds between each dash
var/recharging_time = 0 //time until next dash
/obj/item/clothing/shoes/bhop/Initialize(mapload)
. = ..()
create_storage(type = /datum/storage/pockets/shoes)
/obj/item/clothing/shoes/bhop/ui_action_click(mob/user, action)
if(!isliving(user))
return
+5 -1
View File
@@ -13,7 +13,11 @@
/obj/item/clothing/suit/mothcoat/original
desc = "An old-school flightsuit from the moth fleet. A perfect token of mothic survivalistic and adaptable attitude, yet a bitter reminder that with the loss of their home planet and institution of the fleet, their beloved wings remain as a burden to bear, condemned to never fly again."
greyscale_colors = "#dfa409"
pocket_storage_component_path = /datum/component/storage/concrete/pockets
/obj/item/clothing/suit/mothcoat/original/Initialize(mapload)
. = ..()
create_storage(type = /datum/storage/pockets)
/obj/item/clothing/suit/mothcoat/winter
name = "mothic mantella"
+9 -24
View File
@@ -11,15 +11,9 @@
var/above_suit = TRUE
/// TRUE if shown as a small icon in corner, FALSE if overlayed
var/minimize_when_attached = TRUE
/// Whether the accessory has any storage to apply to the clothing it's attached to.
var/datum/component/storage/detached_pockets
/// What equipment slot the accessory attaches to.
var/attachment_slot = CHEST
/obj/item/clothing/accessory/Destroy()
set_detached_pockets(null)
return ..()
/obj/item/clothing/accessory/proc/can_attach_accessory(obj/item/clothing/U, mob/user)
if(!attachment_slot || (U && U.body_parts_covered & attachment_slot))
return TRUE
@@ -27,12 +21,11 @@
to_chat(user, span_warning("There doesn't seem to be anywhere to put [src]..."))
/obj/item/clothing/accessory/proc/attach(obj/item/clothing/under/U, user)
var/datum/component/storage/storage = GetComponent(/datum/component/storage)
if(storage)
if(SEND_SIGNAL(U, COMSIG_CONTAINS_STORAGE))
if(atom_storage)
if(U.atom_storage)
return FALSE
U.TakeComponent(storage)
set_detached_pockets(storage)
U.clone_storage(atom_storage)
U.atom_storage.set_real_location(src)
U.attached_accessory = src
forceMove(U)
layer = FLOAT_LAYER
@@ -57,8 +50,8 @@
return TRUE
/obj/item/clothing/accessory/proc/detach(obj/item/clothing/under/U, user)
if(detached_pockets && detached_pockets.parent == U)
TakeComponent(detached_pockets)
if(U.atom_storage && U.atom_storage.real_location?.resolve() == src)
QDEL_NULL(U.atom_storage)
U.armor = U.armor.detachArmor(armor)
@@ -75,16 +68,6 @@
U.attached_accessory = null
U.accessory_overlay = null
/obj/item/clothing/accessory/proc/set_detached_pockets(new_pocket)
if(detached_pockets)
UnregisterSignal(detached_pockets, COMSIG_PARENT_QDELETING)
detached_pockets = new_pocket
if(detached_pockets)
RegisterSignal(detached_pockets, COMSIG_PARENT_QDELETING, .proc/handle_pockets_del)
/obj/item/clothing/accessory/proc/handle_pockets_del(datum/source)
SIGNAL_HANDLER
set_detached_pockets(null)
/obj/item/clothing/accessory/proc/on_uniform_equip(obj/item/clothing/under/U, user)
return
@@ -356,10 +339,12 @@
name = "pocket protector"
desc = "Can protect your clothing from ink stains, but you'll look like a nerd if you're using one."
icon_state = "pocketprotector"
pocket_storage_component_path = /datum/component/storage/concrete/pockets/pocketprotector
/obj/item/clothing/accessory/pocketprotector/full/Initialize(mapload)
. = ..()
create_storage(type = /datum/storage/pockets/pocketprotector)
new /obj/item/pen/red(src)
new /obj/item/pen(src)
new /obj/item/pen/blue(src)
+3 -3
View File
@@ -28,7 +28,7 @@
if(!istype(I) || I.anchored)
return
if(SEND_SIGNAL(loc, COMSIG_CONTAINS_STORAGE) && SEND_SIGNAL(I, COMSIG_CONTAINS_STORAGE))
if(loc.atom_storage && I.atom_storage)
to_chat(user, span_warning("No matter what way you try, you can't get [I] to fit inside [src]."))
return TRUE //begone infinite storage ghosts, begone from me
@@ -53,8 +53,8 @@
return
if(!isturf(I.loc)) //If it isn't on the floor. Do some checks to see if it's in our hands or a box. Otherwise give up.
if(SEND_SIGNAL(I.loc, COMSIG_CONTAINS_STORAGE)) //in a container.
SEND_SIGNAL(I.loc, COMSIG_TRY_STORAGE_TAKE, I, src)
if(I.loc.atom_storage) //in a container.
I.loc.atom_storage.attempt_remove(I, src)
if(!user.dropItemToGround(I))
return
+3 -3
View File
@@ -86,10 +86,10 @@ GLOBAL_DATUM(rpgloot_controller, /datum/rpgloot_controller)
if(istype(fantasy_item, /obj/item/storage))
var/obj/item/storage/storage_item = fantasy_item
var/datum/component/storage/storage_component = storage_item.GetComponent(/datum/component/storage)
if(prob(upgrade_scroll_chance) && storage_item.contents.len < storage_component.max_items && !storage_item.invisibility)
var/datum/storage/storage_component = storage_item.atom_storage
if(prob(upgrade_scroll_chance) && storage_item.contents.len < storage_component.max_slots && !storage_item.invisibility)
var/obj/item/upgradescroll/scroll = new(get_turf(storage_item))
SEND_SIGNAL(storage_item, COMSIG_TRY_STORAGE_INSERT, scroll, null, TRUE, TRUE)
storage_item.atom_storage?.attempt_insert(storage_item, scroll, null, TRUE)
upgrade_scroll_chance = max(0,upgrade_scroll_chance-100)
if(isturf(scroll.loc))
qdel(scroll)
+3 -6
View File
@@ -71,10 +71,8 @@ GLOBAL_LIST_EMPTY(exodrone_launchers)
name_counter[name] = 1
GLOB.exodrones += src
/// Cargo storage
var/datum/component/storage/storage = AddComponent(/datum/component/storage/concrete)
storage.cant_hold = GLOB.blacklisted_cargo_types
storage.max_w_class = WEIGHT_CLASS_NORMAL
storage.max_items = EXODRONE_CARGO_SLOTS
create_storage(max_slots = EXODRONE_CARGO_SLOTS)
atom_storage.set_holdable(cant_hold_list = GLOB.blacklisted_cargo_types)
/obj/item/exodrone/Destroy()
. = ..()
@@ -148,8 +146,7 @@ GLOBAL_LIST_EMPTY(exodrone_launchers)
/// Resizes storage component depending on slots used by tools.
/obj/item/exodrone/proc/update_storage_size()
var/datum/component/storage/storage = GetComponent(/datum/component/storage/concrete)
storage.max_items = EXODRONE_CARGO_SLOTS - length(tools)
atom_storage.max_slots = EXODRONE_CARGO_SLOTS - length(tools)
/// Builds ui data for drone storage.
/obj/item/exodrone/proc/get_cargo_data()
@@ -21,12 +21,14 @@
lefthand_file = 'icons/mob/inhands/equipment/medical_lefthand.dmi'
righthand_file = 'icons/mob/inhands/equipment/medical_righthand.dmi'
component_type = /datum/component/storage/concrete/fish_case
/obj/item/storage/fish_case/Initialize(mapload)
ADD_TRAIT(src, TRAIT_FISH_SAFE_STORAGE, TRAIT_GENERIC) // Before populate so fish instatiates in ready container already
. = ..()
create_storage(max_slots = 1)
atom_storage.can_hold_trait = TRAIT_FISH_CASE_COMPATIBILE
atom_storage.can_hold_description = "fish and aquarium equipment"
///Fish case with single random fish inside.
/obj/item/storage/fish_case/random/PopulateContents()
. = ..()
+2 -3
View File
@@ -70,12 +70,11 @@
inhand_icon_state = "artistic_toolbox"
material_flags = NONE
/obj/item/storage/toolbox/ComponentInitialize()
/obj/item/storage/toolbox/Initialize()
. = ..()
// Can hold fishing rod despite the size
var/static/list/exception_cache = typecacheof(/obj/item/fishing_rod)
var/datum/component/storage/STR = GetComponent(/datum/component/storage)
STR.exception_hold = exception_cache
atom_storage.exception_hold = exception_cache
/obj/item/storage/toolbox/fishing/PopulateContents()
new /obj/item/bait_can/worm(src)
@@ -86,7 +86,7 @@ GLOBAL_LIST_INIT(oilfry_blacklisted_items, typecacheof(list(
if(default_deconstruction_screwdriver(user, "fryer_off", "fryer_off", weapon)) //where's the open maint panel icon?!
return
else
if(is_type_in_typecache(weapon, deepfry_blacklisted_items) || is_type_in_typecache(weapon, GLOB.oilfry_blacklisted_items) || SEND_SIGNAL(weapon, COMSIG_CONTAINS_STORAGE) || HAS_TRAIT(weapon, TRAIT_NODROP) || (weapon.item_flags & (ABSTRACT | DROPDEL)))
if(is_type_in_typecache(weapon, deepfry_blacklisted_items) || is_type_in_typecache(weapon, GLOB.oilfry_blacklisted_items) || weapon.atom_storage || HAS_TRAIT(weapon, TRAIT_NODROP) || (weapon.item_flags & (ABSTRACT | DROPDEL)))
return ..()
else if(!frying && user.transferItemToLoc(weapon, src))
fry(weapon, user)
@@ -183,7 +183,7 @@
if(ingredients.len >= max_n_of_items)
to_chat(user, span_warning("\The [src] is full, you can't put anything in!"))
return TRUE
if(SEND_SIGNAL(T, COMSIG_TRY_STORAGE_TAKE, S, src))
if(T.atom_storage.attempt_remove(S, src))
loaded++
ingredients += S
if(loaded)
@@ -93,7 +93,7 @@
continue
var/datum/food_processor_process/P = PROCESSOR_SELECT_RECIPE(S)
if(P)
if(SEND_SIGNAL(T, COMSIG_TRY_STORAGE_TAKE, S, src))
if(T.atom_storage.attempt_remove(S, src))
LAZYADD(processor_contents, S)
loaded++
@@ -155,8 +155,8 @@
else
return TRUE
else
if(SEND_SIGNAL(O.loc, COMSIG_CONTAINS_STORAGE))
return SEND_SIGNAL(O.loc, COMSIG_TRY_STORAGE_TAKE, O, src)
if(O.loc.atom_storage)
return O.loc.atom_storage.attempt_remove(O, src)
else
O.forceMove(src)
return TRUE
+1 -2
View File
@@ -36,8 +36,7 @@
/obj/item/storage/basket/easter/Initialize(mapload)
. = ..()
var/datum/component/storage/STR = GetComponent(/datum/component/storage)
STR.set_holdable(list(/obj/item/food/egg, /obj/item/food/chocolateegg, /obj/item/food/boiledegg, /obj/item/surprise_egg))
atom_storage.set_holdable(list(/obj/item/food/egg, /obj/item/food/chocolateegg, /obj/item/food/boiledegg, /obj/item/surprise_egg))
/obj/item/storage/basket/easter/proc/countEggs()
cut_overlays()
+1 -1
View File
@@ -113,7 +113,7 @@
for(var/obj/item/food/grown/G in PB.contents)
if(i >= max_items)
break
if(SEND_SIGNAL(PB, COMSIG_TRY_STORAGE_TAKE, G, src))
if(PB.atom_storage.attempt_remove(G, src))
i++
if(i<max_items)
to_chat(user, span_info("You empty the plant bag into the biogenerator."))
+1 -1
View File
@@ -891,7 +891,7 @@
else if(istype(O, /obj/item/storage/bag/plants))
attack_hand(user)
for(var/obj/item/food/grown/G in locate(user.x,user.y,user.z))
SEND_SIGNAL(O, COMSIG_TRY_STORAGE_INSERT, G, user, TRUE)
O.atom_storage?.attempt_insert(O, G, user, TRUE)
return
else if(istype(O, /obj/item/shovel/spade))
+2 -3
View File
@@ -167,9 +167,8 @@
to_chat(usr, span_notice("\The [src] is full."))
return FALSE
var/datum/component/storage/STR = O.loc.GetComponent(/datum/component/storage)
if(STR)
if(!STR.remove_from_storage(O,src))
if(atom_storage)
if(!atom_storage.attempt_remove(O, src, silent = TRUE))
return FALSE
else if(ismob(O.loc))
var/mob/M = O.loc

Some files were not shown because too many files have changed in this diff Show More