Duiffel Spotfix (#76442)

## About The Pull Request

Gives duffelbags their proper slot count
They inherited this from backpacks, but I sorta just forgot about that

[Creates "levels" of locked objects, uses that to make locked duffels
work](https://github.com/tgstation/tgstation/pull/76442/commits/c613c00f62fa3ff03bb33737d24da9acbf2050e3)

[c613c00](https://github.com/tgstation/tgstation/pull/76442/commits/c613c00f62fa3ff03bb33737d24da9acbf2050e3)

Turns locked into something that holds defines, this makes life a lot
easier.
Requires a lot of boilerplate because of how many uses of these procs
there are and all the passthrough and shit.

Adds a few outfit subtypes to avoid this class of failure in future.

Renames the args in a few but not all touched procs, one thing at a time

Closes #76407
Closes #76430 Had the lock check in the wrong place
Closes #76441 GOD I HATE TK SO MUCH

Wrote half the pr without glasses so if it's weird gimme some grace
yeah?

## Changelog
🆑
fix: Fixes some fuck with duffelbags, them not holding enough + issues
with spawning gear in them (job shit and all)
/🆑
This commit is contained in:
LemonInTheDark
2023-07-01 15:36:26 +01:00
committed by GitHub
parent 5ac30929e4
commit 8c2c72b0ed
38 changed files with 193 additions and 147 deletions
+7
View File
@@ -15,3 +15,10 @@
#define FANCY_CONTAINER_CLOSED 0
#define FANCY_CONTAINER_OPEN 1
#define FANCY_CONTAINER_ALWAYS_OPEN 2
// Defines for levels of storage locking
// Also used fort the force param of can_insert
// Higher values are "more" locked then lower ones
#define STORAGE_NOT_LOCKED 0
#define STORAGE_SOFT_LOCKED 1
#define STORAGE_FULLY_LOCKED 2
+2 -2
View File
@@ -1035,7 +1035,7 @@ SUBSYSTEM_DEF(job)
LOCATION_BACKPACK = ITEM_SLOT_BACKPACK,
LOCATION_HANDS = ITEM_SLOT_HANDS
)
var/where = new_captain.equip_in_one_of_slots(paper, slots, FALSE) || "at your feet"
var/where = new_captain.equip_in_one_of_slots(paper, slots, FALSE, indirect_action = TRUE) || "at your feet"
if(acting_captain)
to_chat(new_captain, span_notice("Due to your position in the chain of command, you have been promoted to Acting Captain. You can find in important note about this [where]."))
@@ -1106,7 +1106,7 @@ SUBSYSTEM_DEF(job)
if(is_banned_from(player.ckey, possible_job.title))
JobDebug("[debug_prefix] Error: [get_job_unavailable_error_message(JOB_UNAVAILABLE_BANNED, possible_job.title)], Player: [player][add_job_to_log ? ", Job: [possible_job]" : ""]")
return JOB_UNAVAILABLE_BANNED
// Check for character age
if(possible_job.required_character_age > player.client.prefs.read_preference(/datum/preference/numeric/age) && possible_job.required_character_age != null)
JobDebug("[debug_prefix] Error: [get_job_unavailable_error_message(JOB_UNAVAILABLE_AGE)], Player: [player][add_job_to_log ? ", Job: [possible_job]" : ""]")
+1 -1
View File
@@ -153,7 +153,7 @@
return
#define EQUIP_OUTFIT_ITEM(item_path, slot_name) if(##item_path) { \
user.equip_to_slot_or_del(SSwardrobe.provide_type(##item_path, user), ##slot_name, TRUE); \
user.equip_to_slot_or_del(SSwardrobe.provide_type(##item_path, user), ##slot_name, TRUE, indirect_action = TRUE); \
var/obj/item/outfit_item = user.get_item_by_slot(##slot_name); \
if (outfit_item && outfit_item.type == ##item_path) { \
outfit_item.on_outfit_equip(user, visualsOnly, ##slot_name); \
+1 -1
View File
@@ -173,7 +173,7 @@
var/mob/living/carbon/human/human_holder = quirk_holder
var/where = human_holder.equip_in_one_of_slots(quirk_item, valid_slots, qdel_on_fail = FALSE) || default_location
var/where = human_holder.equip_in_one_of_slots(quirk_item, valid_slots, qdel_on_fail = FALSE, indirect_action = TRUE) || default_location
if(where == LOCATION_BACKPACK)
open_backpack = TRUE
+2 -2
View File
@@ -271,7 +271,7 @@
))
hat = new hat(spawned_mob)
if(!spawned_mob.equip_to_slot_if_possible(hat, ITEM_SLOT_HEAD, disable_warning = TRUE))
spawned_mob.equip_to_slot_or_del(hat, ITEM_SLOT_BACKPACK)
spawned_mob.equip_to_slot_or_del(hat, ITEM_SLOT_BACKPACK, indirect_action = TRUE)
var/obj/item/toy = pick_weight(list(
/obj/item/reagent_containers/spray/chemsprayer/party = 4,
/obj/item/toy/balloon = 2,
@@ -283,7 +283,7 @@
if(istype(toy, /obj/item/toy/balloon))
spawned_mob.equip_to_slot_or_del(toy, ITEM_SLOT_HANDS) //Balloons do not fit inside of backpacks.
else
spawned_mob.equip_to_slot_or_del(toy, ITEM_SLOT_BACKPACK)
spawned_mob.equip_to_slot_or_del(toy, ITEM_SLOT_BACKPACK, indirect_action = TRUE)
if(birthday_person_name) //Anyone who joins after the annoucement gets one of these.
var/obj/item/birthday_invite/birthday_invite = new(spawned_mob)
birthday_invite.setup_card(birthday_person_name)
+6 -6
View File
@@ -33,7 +33,7 @@
/// list of all the mobs currently viewing the contents
var/list/is_using = list()
var/locked = FALSE
var/locked = STORAGE_NOT_LOCKED
/// whether or not we should open when clicked
var/attack_hand_interact = TRUE
/// whether or not we allow storage objects of the same size inside
@@ -310,9 +310,9 @@ GLOBAL_LIST_EMPTY(cached_storage_typecaches)
*
* @param obj/item/to_insert the item we're checking
* @param messages if TRUE, will print out a message if the item is not valid
* @param force bypass locked storage
* @param force bypass locked storage up to a certain level. See [code/__DEFINES/storage.dm]
*/
/datum/storage/proc/can_insert(obj/item/to_insert, mob/user, messages = TRUE, force = FALSE)
/datum/storage/proc/can_insert(obj/item/to_insert, mob/user, messages = TRUE, force = STORAGE_NOT_LOCKED)
var/obj/item/resolve_parent = parent?.resolve()
if(!resolve_parent)
return
@@ -327,7 +327,7 @@ GLOBAL_LIST_EMPTY(cached_storage_typecaches)
if(!isitem(to_insert))
return FALSE
if(locked && !force)
if(locked > force)
return FALSE
if((to_insert == resolve_parent) || (to_insert == real_location))
@@ -406,9 +406,9 @@ GLOBAL_LIST_EMPTY(cached_storage_typecaches)
* @param obj/item/to_insert the item we're inserting
* @param mob/user the user who is inserting the item
* @param override see item_insertion_feedback()
* @param force bypass locked storage
* @param force bypass locked storage up to a certain level. See [code/__DEFINES/storage.dm]
*/
/datum/storage/proc/attempt_insert(obj/item/to_insert, mob/user, override = FALSE, force = FALSE)
/datum/storage/proc/attempt_insert(obj/item/to_insert, mob/user, override = FALSE, force = STORAGE_NOT_LOCKED)
var/obj/item/resolve_location = real_location?.resolve()
if(!resolve_location)
return FALSE
+5
View File
@@ -1,3 +1,8 @@
/datum/storage/backpack
max_total_storage = 21
max_slots = 21
/datum/storage/backpack/santabag
max_total_storage = 60
max_slots = 21
max_specific_storage = WEIGHT_CLASS_NORMAL
@@ -1,5 +1,6 @@
/datum/storage/duffel
max_total_storage = 30
max_slots = 21
// Syndi bags get some FUN extras
// You can fit any 3 bulky objects (assuming they're in the whitelist)
@@ -4,7 +4,7 @@
insert_preposition = "in"
attack_hand_interact = FALSE
quickdraw = FALSE
locked = TRUE
locked = STORAGE_FULLY_LOCKED
rustle_sound = FALSE
silent = TRUE
+1 -1
View File
@@ -170,7 +170,7 @@ GLOBAL_LIST(admin_objective_list) //Prefilled admin assignable objective list
var/list/slots = list("backpack" = ITEM_SLOT_BACKPACK)
for(var/obj/equipment_path as anything in special_equipment)
var/obj/equipment_object = new equipment_path
if(!receiver_current.equip_in_one_of_slots(equipment_object, slots))
if(!receiver_current.equip_in_one_of_slots(equipment_object, slots, indirect_action = TRUE))
LAZYINITLIST(receiver.failed_special_equipment)
receiver.failed_special_equipment += equipment_path
receiver.try_give_equipment_fallback()
+1 -1
View File
@@ -1005,7 +1005,7 @@
else
physical_part = primary_part_base
replacer_tool.atom_storage.attempt_insert(physical_part, user, TRUE)
replacer_tool.atom_storage.attempt_insert(physical_part, user, TRUE, force = STORAGE_SOFT_LOCKED)
to_chat(user, span_notice("[capitalize(physical_part.name)] replaced with [secondary_part_name]."))
shouldplaysound = TRUE //Only play the sound when parts are actually replaced!
break
+4 -2
View File
@@ -704,12 +704,14 @@
* * disable_warning to TRUE if you wish it to not give you text outputs.
* * slot is the slot we are trying to equip to
* * bypass_equip_delay_self for whether we want to bypass the equip delay
* * ignore_equipped ignores any already equipped items in that slot
* * indirect_action allows inserting into "soft locked" bags, things that can be easily opened by the owner
*/
/obj/item/proc/mob_can_equip(mob/living/M, slot, disable_warning = FALSE, bypass_equip_delay_self = FALSE, ignore_equipped = FALSE)
/obj/item/proc/mob_can_equip(mob/living/M, slot, disable_warning = FALSE, bypass_equip_delay_self = FALSE, ignore_equipped = FALSE, indirect_action = FALSE)
if(!M)
return FALSE
return M.can_equip(src, slot, disable_warning, bypass_equip_delay_self, ignore_equipped)
return M.can_equip(src, slot, disable_warning, bypass_equip_delay_self, ignore_equipped, indirect_action = indirect_action)
/obj/item/verb/verb_pickup()
set src in oview(1)
@@ -89,7 +89,10 @@
update_appearance()
/obj/item/storage/portable_chem_mixer/CtrlClick(mob/living/user)
atom_storage.locked = !atom_storage.locked
if(atom_storage.locked)
atom_storage.locked = STORAGE_NOT_LOCKED
else
atom_storage.locked = STORAGE_FULLY_LOCKED
if (!atom_storage.locked)
update_contents()
if (atom_storage.locked)
+14 -14
View File
@@ -78,16 +78,12 @@
icon_state = "giftbag0"
inhand_icon_state = "giftbag"
w_class = WEIGHT_CLASS_BULKY
storage_type = /datum/storage/backpack/santabag
/obj/item/storage/backpack/santabag/Initialize(mapload)
. = ..()
regenerate_presents()
/obj/item/storage/backpack/santabag/Initialize(mapload)
. = ..()
atom_storage.max_specific_storage = WEIGHT_CLASS_NORMAL
atom_storage.max_total_storage = 60
/obj/item/storage/backpack/santabag/suicide_act(mob/living/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..."))
return OXYLOSS
@@ -101,7 +97,7 @@
if(user.mind && HAS_TRAIT(user.mind, TRAIT_CANNOT_OPEN_PRESENTS))
var/turf/floor = get_turf(src)
var/obj/item/thing = new /obj/item/a_gift/anything(floor)
if(!atom_storage.attempt_insert(thing, user, override = TRUE))
if(!atom_storage.attempt_insert(thing, user, override = TRUE, force = STORAGE_SOFT_LOCKED))
qdel(thing)
@@ -395,8 +391,10 @@
inhand_icon_state = "duffel"
actions_types = list(/datum/action/item_action/zipper)
storage_type = /datum/storage/duffel
// How much to slow you down if your bag isn't zipped up
var/zip_slowdown = 1
/// If this bag is zipped (contents hidden) up or not
/// Starts enabled so people need to figure it out to use the thing
/// Starts enabled so you're forced to interact with it to "get" it
var/zipped_up = TRUE
/obj/item/storage/backpack/duffelbag/Initialize(mapload)
@@ -408,6 +406,8 @@
desc = "[initial(desc)]<br>[zipped_up ? "It's zipped up, preventing you from accessing its contents." : "It's unzipped, and harder to move in."]"
/obj/item/storage/backpack/duffelbag/attack_self(mob/user, modifiers)
if(loc != user) // God fuck TK
return ..()
if(zipped_up)
return attack_hand(user, modifiers)
else
@@ -439,9 +439,9 @@
// Vis versa
/obj/item/storage/backpack/duffelbag/attack_hand_secondary(mob/user, list/modifiers)
if(loc != user)
return ..()
if(zipped_up)
if(loc != user)
return ..()
return SECONDARY_ATTACK_CALL_NORMAL
balloon_alert(user, "zipping...")
@@ -462,13 +462,13 @@
zipped_up = new_zip
SEND_SIGNAL(src, COMSIG_DUFFEL_ZIP_CHANGE, new_zip)
if(zipped_up)
slowdown = 0
atom_storage.locked = TRUE
slowdown = initial(slowdown)
atom_storage.locked = STORAGE_SOFT_LOCKED
atom_storage.display_contents = FALSE
atom_storage.close_all()
else
slowdown = 1
atom_storage.locked = FALSE
slowdown = zip_slowdown
atom_storage.locked = STORAGE_NOT_LOCKED
atom_storage.display_contents = TRUE
if(isliving(loc))
@@ -483,7 +483,7 @@
then it might have negative effects on the bag..."
icon_state = "duffel-curse"
inhand_icon_state = "duffel-curse"
slowdown = 2
zip_slowdown = 2
max_integrity = 100
/obj/item/storage/backpack/duffelbag/cursed/Initialize(mapload)
+15 -8
View File
@@ -30,7 +30,10 @@
balloon_alert(user, "broken!")
return
if(allowed(user))
atom_storage.locked = !locked
if(atom_storage.locked)
atom_storage.locked = STORAGE_NOT_LOCKED
else
atom_storage.locked = STORAGE_FULLY_LOCKED
locked = atom_storage.locked
if(locked)
icon_state = icon_locked
@@ -52,7 +55,7 @@
/obj/item/storage/lockbox/emag_act(mob/user)
if(!broken)
broken = TRUE
atom_storage.locked = FALSE
atom_storage.locked = STORAGE_NOT_LOCKED
icon_state = src.icon_broken
if(user)
visible_message(span_warning("\The [src] is broken by [user] with an electromagnetic card!"))
@@ -116,11 +119,12 @@
. += span_notice("Alt-click to [open ? "close":"open"] it.")
/obj/item/storage/lockbox/medal/AltClick(mob/user)
if(user.can_perform_action(src))
if(!atom_storage.locked)
open = (open ? FALSE : TRUE)
update_appearance()
..()
if(!user.can_perform_action(src))
return
if(!atom_storage.locked)
open = (open ? FALSE : TRUE)
update_appearance()
..()
/obj/item/storage/lockbox/medal/PopulateContents()
new /obj/item/clothing/accessory/medal/gold/captain(src)
@@ -244,7 +248,10 @@
balloon_alert(user, "incorrect bank account!")
return
atom_storage.locked = !privacy_lock
if(privacy_lock)
atom_storage.locked = STORAGE_NOT_LOCKED
else
atom_storage.locked = STORAGE_FULLY_LOCKED
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."))
+3 -3
View File
@@ -96,14 +96,14 @@
lock_code = entered_code
lock_set = TRUE
else if ((entered_code == lock_code) && lock_set)
atom_storage.locked = FALSE
atom_storage.locked = STORAGE_NOT_LOCKED
update_appearance()
entered_code = null
else
entered_code = "ERROR"
else
if (href_list["type"] == "R")
atom_storage.locked = TRUE
atom_storage.locked = STORAGE_FULLY_LOCKED
update_appearance()
entered_code = null
atom_storage.hide_contents(usr)
@@ -231,7 +231,7 @@ MAPPING_DIRECTIONAL_HELPERS(/obj/item/storage/secure/safe/caps_spare, 32)
atom_storage.set_holdable(can_hold_list = list(/obj/item/card/id))
lock_code = SSid_access.spare_id_safe_code
lock_set = TRUE
atom_storage.locked = TRUE
atom_storage.locked = STORAGE_FULLY_LOCKED
update_appearance()
/obj/item/storage/secure/safe/caps_spare/PopulateContents()
+1 -1
View File
@@ -177,7 +177,7 @@
id.forceMove(W)
W.update_icon()
else
H.equip_to_slot(id,ITEM_SLOT_ID)
H.equip_to_slot(id, ITEM_SLOT_ID)
else
tgui_alert(usr,"Invalid mob")
@@ -848,7 +848,7 @@
flesh_id.hud_icon = chosen_profile.id_icon
if(equip)
user.equip_to_slot_or_del(new_flesh_item, slot2slot[slot])
user.equip_to_slot_or_del(new_flesh_item, slot2slot[slot], indirect_action = TRUE)
if(!QDELETED(new_flesh_item))
ADD_TRAIT(new_flesh_item, TRAIT_NODROP, CHANGELING_TRAIT)
+1 -1
View File
@@ -119,7 +119,7 @@
var/T = new item_path(mob)
var/item_name = initial(item_path.name)
var/where = mob.equip_in_one_of_slots(T, slots)
var/where = mob.equip_in_one_of_slots(T, slots, indirect_action = TRUE)
if(!where)
to_chat(mob, span_userdanger("Unfortunately, you weren't able to get a [item_name]. This is very bad and you should adminhelp immediately (press F1)."))
return FALSE
+1 -1
View File
@@ -40,7 +40,7 @@
if(ispath(uplink_type, /obj/item/uplink/nuclear) || tc) // /obj/item/uplink/nuclear understands 0 tc
var/obj/item/uplink = new uplink_type(nukie, nukie.key, tc)
nukie.equip_to_slot_or_del(uplink, ITEM_SLOT_BACKPACK)
nukie.equip_to_slot_or_del(uplink, ITEM_SLOT_BACKPACK, indirect_action = TRUE)
var/obj/item/implant/weapons_auth/weapons_implant = new/obj/item/implant/weapons_auth(nukie)
weapons_implant.implant(nukie)
@@ -397,7 +397,7 @@
"left pocket" = ITEM_SLOT_LPOCKET,
"right pocket" = ITEM_SLOT_RPOCKET
)
var/where = C.equip_in_one_of_slots(T, slots)
var/where = C.equip_in_one_of_slots(T, slots, indirect_action = TRUE)
if (!where)
to_chat(C, "The Syndicate were unfortunately unable to get you a flash.")
else
+1 -1
View File
@@ -315,7 +315,7 @@
fire = 50
acid = 40
/obj/item/clothing/neck/petcollar/mob_can_equip(mob/M, slot, disable_warning = FALSE, bypass_equip_delay_self = FALSE, ignore_equipped = FALSE)
/obj/item/clothing/neck/petcollar/mob_can_equip(mob/M, slot, disable_warning = FALSE, bypass_equip_delay_self = FALSE, ignore_equipped = FALSE, indirect_action = FALSE)
if(!ismonkey(M))
return FALSE
return ..()
+1 -1
View File
@@ -27,7 +27,7 @@
/datum/outfit/vr/syndicate/post_equip(mob/living/carbon/human/H)
. = ..()
var/obj/item/uplink/U = new /obj/item/uplink/nuclear_restricted(H, H.key, 80)
H.equip_to_slot_or_del(U, ITEM_SLOT_BACKPACK)
H.equip_to_slot_or_del(U, ITEM_SLOT_BACKPACK, indirect_action = TRUE)
var/obj/item/implant/weapons_auth/W = new/obj/item/implant/weapons_auth(H)
W.implant(H)
var/obj/item/implant/explosive/E = new/obj/item/implant/explosive(H)
+1 -1
View File
@@ -50,7 +50,7 @@
var/obj/item/J = loadout[i]
var/obj/item/I = new J //dumb but required because of byond throwing a fit anytime new gets too close to a list
H.dropItemToGround(H.get_item_by_slot(i), TRUE)
H.equip_to_slot_or_del(I, i)
H.equip_to_slot_or_del(I, i, indirect_action = TRUE)
ADD_TRAIT(I, TRAIT_NODROP, CURSED_ITEM_TRAIT(I))
I.item_flags |= DROPDEL
I.name = "cursed " + I.name
+1 -1
View File
@@ -96,7 +96,7 @@ GLOBAL_DATUM(rpgloot_controller, /datum/rpgloot_controller)
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))
storage_item.atom_storage?.attempt_insert(scroll, override = TRUE)
storage_item.atom_storage?.attempt_insert(scroll, override = TRUE, force = STORAGE_SOFT_LOCKED)
upgrade_scroll_chance = max(0,upgrade_scroll_chance-100)
if(isturf(scroll.loc))
qdel(scroll)
@@ -55,7 +55,7 @@
if(GLOB.bible_inhand_icon_state)
holy_bible.inhand_icon_state = GLOB.bible_inhand_icon_state
to_chat(human_spawned, span_boldnotice("There is already an established religion onboard the station. You are an acolyte of [GLOB.deity]. Defer to the Chaplain."))
human_spawned.equip_to_slot_or_del(holy_bible, ITEM_SLOT_BACKPACK)
human_spawned.equip_to_slot_or_del(holy_bible, ITEM_SLOT_BACKPACK, indirect_action = TRUE)
var/nrt = GLOB.holy_weapon_type || /obj/item/nullrod
var/obj/item/nullrod/nullrod = new nrt(human_spawned)
human_spawned.put_in_hands(nullrod)
@@ -104,7 +104,7 @@
GLOB.bible_name = new_bible
GLOB.deity = holy_bible.deity_name
human_spawned.equip_to_slot_or_del(holy_bible, ITEM_SLOT_BACKPACK)
human_spawned.equip_to_slot_or_del(holy_bible, ITEM_SLOT_BACKPACK, indirect_action = TRUE)
SSblackbox.record_feedback("text", "religion_name", 1, "[new_religion]", 1)
SSblackbox.record_feedback("text", "religion_deity", 1, "[new_deity]", 1)
+1 -1
View File
@@ -63,7 +63,7 @@ GLOBAL_LIST_EMPTY(total_extraction_beacons)
if(do_after(user,50,target=A))
to_chat(user, span_notice("You attach the pack to [A] and activate it."))
if(loc == user)
user.back?.atom_storage?.attempt_insert(src, user)
user.back?.atom_storage?.attempt_insert(src, user, force = STORAGE_SOFT_LOCKED)
uses_left--
if(uses_left <= 0)
user.transferItemToLoc(src, A, TRUE)
+1 -1
View File
@@ -140,7 +140,7 @@
//Returns if a certain item can be equipped to a certain slot.
// Currently invalid for two-handed items - call obj/item/mob_can_equip() instead.
/mob/proc/can_equip(obj/item/I, slot, disable_warning = FALSE, bypass_equip_delay_self = FALSE)
/mob/proc/can_equip(obj/item/I, slot, disable_warning = FALSE, bypass_equip_delay_self = FALSE, ignore_equipped = FALSE, indirect_action = FALSE)
return FALSE
/mob/proc/can_put_in_hand(I, hand_index)
@@ -818,7 +818,7 @@ GLOBAL_LIST_EMPTY(features_by_species)
/datum/species/proc/spec_death(gibbed, mob/living/carbon/human/H)
return
/datum/species/proc/can_equip(obj/item/I, slot, disable_warning, mob/living/carbon/human/H, bypass_equip_delay_self = FALSE, ignore_equipped = FALSE)
/datum/species/proc/can_equip(obj/item/I, slot, disable_warning, mob/living/carbon/human/H, bypass_equip_delay_self = FALSE, ignore_equipped = FALSE, indirect_action = FALSE)
if(no_equip_flags & slot)
if(!I.species_exception || !is_type_in_list(src, I.species_exception))
return FALSE
@@ -963,7 +963,7 @@ GLOBAL_LIST_EMPTY(features_by_species)
return FALSE
return TRUE
if(ITEM_SLOT_BACKPACK)
if(H.back && H.back.atom_storage?.can_insert(I, H, messages = TRUE))
if(H.back && H.back.atom_storage?.can_insert(I, H, messages = TRUE, force = indirect_action ? STORAGE_SOFT_LOCKED : STORAGE_NOT_LOCKED))
return TRUE
return FALSE
return FALSE //Unsupported slot
@@ -1,8 +1,8 @@
/mob/living/carbon/human/can_equip(obj/item/equip_target, slot, disable_warning = FALSE, bypass_equip_delay_self = FALSE, ignore_equipped = FALSE)
/mob/living/carbon/human/can_equip(obj/item/equip_target, slot, disable_warning = FALSE, bypass_equip_delay_self = FALSE, ignore_equipped = FALSE, indirect_action = FALSE)
if(SEND_SIGNAL(src, COMSIG_HUMAN_EQUIPPING_ITEM, equip_target, slot) == COMPONENT_BLOCK_EQUIP)
return FALSE
return dna.species.can_equip(equip_target, slot, disable_warning, src, bypass_equip_delay_self, ignore_equipped)
return dna.species.can_equip(equip_target, slot, disable_warning, src, bypass_equip_delay_self, ignore_equipped, indirect_action)
/mob/living/carbon/human/get_item_by_slot(slot_id)
switch(slot_id)
@@ -142,7 +142,7 @@
//This is an UNSAFE proc. Use mob_can_equip() before calling this one! Or rather use equip_to_slot_if_possible() or advanced_equip_to_slot_if_possible()
// Initial is used to indicate whether or not this is the initial equipment (job datums etc) or just a player doing it
/mob/living/carbon/human/equip_to_slot(obj/item/I, slot, initial = FALSE, redraw_mob = FALSE)
/mob/living/carbon/human/equip_to_slot(obj/item/equipping, slot, initial = FALSE, redraw_mob = FALSE, indirect_action = FALSE)
if(!..()) //a check failed or the item has already found its slot
return
@@ -151,48 +151,47 @@
if(ITEM_SLOT_BELT)
if(belt)
return
belt = I
belt = equipping
update_worn_belt()
if(ITEM_SLOT_ID)
if(wear_id)
return
wear_id = I
wear_id = equipping
sec_hud_set_ID()
update_worn_id()
if(ITEM_SLOT_EARS)
if(ears)
return
ears = I
ears = equipping
update_inv_ears()
if(ITEM_SLOT_EYES)
if(glasses)
return
glasses = I
var/obj/item/clothing/glasses/G = I
if(G.glass_colour_type)
update_glasses_color(G, 1)
if(G.tint)
glasses = equipping
if(glasses.glass_colour_type)
update_glasses_color(glasses, 1)
if(glasses.tint)
update_tint()
if(G.vision_flags || G.invis_override || G.invis_view || !isnull(G.lighting_cutoff))
if(glasses.vision_flags || glasses.invis_override || glasses.invis_view || !isnull(glasses.lighting_cutoff))
update_sight()
update_worn_glasses()
if(ITEM_SLOT_GLOVES)
if(gloves)
return
gloves = I
gloves = equipping
update_worn_gloves()
if(ITEM_SLOT_FEET)
if(shoes)
return
shoes = I
shoes = equipping
update_worn_shoes()
if(ITEM_SLOT_OCLOTHING)
if(wear_suit)
return
wear_suit = I
wear_suit = equipping
if(I.flags_inv & HIDEJUMPSUIT)
if(equipping.flags_inv & HIDEJUMPSUIT)
update_worn_undersuit()
if(wear_suit.breakouttime) //when equipping a straightjacket
ADD_TRAIT(src, TRAIT_RESTRAINED, SUIT_TRAIT)
@@ -202,30 +201,30 @@
if(ITEM_SLOT_ICLOTHING)
if(w_uniform)
return
w_uniform = I
w_uniform = equipping
update_suit_sensors()
update_worn_undersuit()
if(ITEM_SLOT_LPOCKET)
l_store = I
l_store = equipping
update_pockets()
if(ITEM_SLOT_RPOCKET)
r_store = I
r_store = equipping
update_pockets()
if(ITEM_SLOT_SUITSTORE)
if(s_store)
return
s_store = I
s_store = equipping
update_suit_storage()
else
to_chat(src, span_danger("You are trying to equip this item to an unsupported inventory slot. Report this to a coder!"))
//Item is handled and in slot, valid to call callback, for this proc should always be true
if(!not_handled)
has_equipped(I, slot, initial)
has_equipped(equipping, slot, initial)
// Send a signal for when we equip an item that used to cover our feet/shoes. Used for bloody feet
if((I.body_parts_covered & FEET) || (I.flags_inv | I.transparent_protection) & HIDESHOES)
SEND_SIGNAL(src, COMSIG_CARBON_EQUIP_SHOECOVER, I, slot, initial, redraw_mob)
if(equipping.body_parts_covered & FEET || (equipping.flags_inv | equipping.transparent_protection) & HIDESHOES)
SEND_SIGNAL(src, COMSIG_CARBON_EQUIP_SHOECOVER, equipping, slot, initial, redraw_mob)
return not_handled //For future deeper overrides
+28 -29
View File
@@ -49,74 +49,73 @@
legcuffed,
)
/mob/living/carbon/proc/equip_in_one_of_slots(obj/item/I, list/slots, qdel_on_fail = 1)
/mob/living/carbon/proc/equip_in_one_of_slots(obj/item/equipping, list/slots, qdel_on_fail = TRUE, indirect_action = FALSE)
for(var/slot in slots)
if(equip_to_slot_if_possible(I, slots[slot], qdel_on_fail = 0, disable_warning = TRUE))
if(equip_to_slot_if_possible(equipping, slots[slot], disable_warning = TRUE, indirect_action = indirect_action))
return slot
if(qdel_on_fail)
qdel(I)
qdel(equipping)
return null
//This is an UNSAFE proc. Use mob_can_equip() before calling this one! Or rather use equip_to_slot_if_possible() or advanced_equip_to_slot_if_possible()
/mob/living/carbon/equip_to_slot(obj/item/I, slot, initial = FALSE, redraw_mob = FALSE)
/mob/living/carbon/equip_to_slot(obj/item/equipping, slot, initial = FALSE, redraw_mob = FALSE, indirect_action = FALSE)
if(!slot)
return
if(!istype(I))
if(!istype(equipping))
return
var/index = get_held_index_of_item(I)
var/index = get_held_index_of_item(equipping)
if(index)
held_items[index] = null
if(I.pulledby)
I.pulledby.stop_pulling()
if(equipping.pulledby)
equipping.pulledby.stop_pulling()
I.screen_loc = null
equipping.screen_loc = null
if(client)
client.screen -= I
client.screen -= equipping
if(observers?.len)
for(var/M in observers)
var/mob/dead/observe = M
for(var/mob/dead/observe as anything in observers)
if(observe.client)
observe.client.screen -= I
I.forceMove(src)
SET_PLANE_EXPLICIT(I, ABOVE_HUD_PLANE, src)
I.appearance_flags |= NO_CLIENT_COLOR
observe.client.screen -= equipping
equipping.forceMove(src)
SET_PLANE_EXPLICIT(equipping, ABOVE_HUD_PLANE, src)
equipping.appearance_flags |= NO_CLIENT_COLOR
var/not_handled = FALSE
switch(slot)
if(ITEM_SLOT_BACK)
if(back)
return
back = I
back = equipping
update_worn_back()
if(ITEM_SLOT_MASK)
if(wear_mask)
return
wear_mask = I
wear_mask_update(I, toggle_off = 0)
wear_mask = equipping
wear_mask_update(equipping, toggle_off = 0)
if(ITEM_SLOT_HEAD)
if(head)
return
head = I
SEND_SIGNAL(src, COMSIG_CARBON_EQUIP_HAT, I)
head_update(I)
head = equipping
SEND_SIGNAL(src, COMSIG_CARBON_EQUIP_HAT, equipping)
head_update(equipping)
if(ITEM_SLOT_NECK)
if(wear_neck)
return
wear_neck = I
update_worn_neck(I)
wear_neck = equipping
update_worn_neck(equipping)
if(ITEM_SLOT_HANDCUFFED)
set_handcuffed(I)
set_handcuffed(equipping)
update_handcuffed()
if(ITEM_SLOT_LEGCUFFED)
legcuffed = I
legcuffed = equipping
update_worn_legcuffs()
if(ITEM_SLOT_HANDS)
put_in_hands(I)
put_in_hands(equipping)
update_held_items()
if(ITEM_SLOT_BACKPACK)
if(!back || !back.atom_storage?.attempt_insert(I, src, override = TRUE))
if(!back || !back.atom_storage?.attempt_insert(equipping, src, override = TRUE, force = indirect_action ? STORAGE_SOFT_LOCKED : STORAGE_NOT_LOCKED))
not_handled = TRUE
else
not_handled = TRUE
@@ -125,7 +124,7 @@
//We cannot call it for items that have not been handled as they are not yet correctly
//in a slot (handled further down inheritance chain, probably living/carbon/human/equip_to_slot
if(!not_handled)
has_equipped(I, slot, initial)
has_equipped(equipping, slot, initial)
return not_handled
@@ -19,7 +19,7 @@
return FALSE
/mob/living/simple_animal/drone/can_equip(obj/item/I, slot, disable_warning = FALSE, bypass_equip_delay_self = FALSE)
/mob/living/simple_animal/drone/can_equip(obj/item/I, slot, disable_warning = FALSE, bypass_equip_delay_self = FALSE, ignore_equipped = FALSE, indirect_action = FALSE)
switch(slot)
if(ITEM_SLOT_HEAD)
if(head)
@@ -50,37 +50,37 @@
return ITEM_SLOT_HEAD
return ..()
/mob/living/simple_animal/drone/equip_to_slot(obj/item/I, slot)
/mob/living/simple_animal/drone/equip_to_slot(obj/item/equipping, slot, initial = FALSE, redraw_mob = FALSE, indirect_action = FALSE)
if(!slot)
return
if(!istype(I))
if(!istype(equipping))
return
var/index = get_held_index_of_item(I)
var/index = get_held_index_of_item(equipping)
if(index)
held_items[index] = null
update_held_items()
if(I.pulledby)
I.pulledby.stop_pulling()
if(equipping.pulledby)
equipping.pulledby.stop_pulling()
I.screen_loc = null // will get moved if inventory is visible
I.forceMove(src)
SET_PLANE_EXPLICIT(I, ABOVE_HUD_PLANE, src)
equipping.screen_loc = null // will get moved if inventory is visible
equipping.forceMove(src)
SET_PLANE_EXPLICIT(equipping, ABOVE_HUD_PLANE, src)
switch(slot)
if(ITEM_SLOT_HEAD)
head = I
head = equipping
update_worn_head()
if(ITEM_SLOT_DEX_STORAGE)
internal_storage = I
internal_storage = equipping
update_inv_internal_storage()
else
to_chat(src, span_danger("You are trying to equip this item to an unsupported inventory slot. Report this to a coder!"))
return
//Call back for item being equipped to drone
I.equipped(src, slot)
equipping.equipped(src, slot)
/mob/living/simple_animal/drone/getBackSlot()
return ITEM_SLOT_DEX_STORAGE
@@ -434,25 +434,25 @@ GLOBAL_LIST_EMPTY(parasites) //all currently existing/living guardians
//HAND HANDLING
/mob/living/simple_animal/hostile/guardian/equip_to_slot(obj/item/equipped_item, slot)
/mob/living/simple_animal/hostile/guardian/equip_to_slot(obj/item/equipping, slot, initial = FALSE, redraw_mob = FALSE, indirect_action = FALSE)
if(!slot)
return FALSE
if(!istype(equipped_item))
if(!istype(equipping))
return FALSE
. = TRUE
var/index = get_held_index_of_item(equipped_item)
var/index = get_held_index_of_item(equipping)
if(index)
held_items[index] = null
update_held_items()
if(equipped_item.pulledby)
equipped_item.pulledby.stop_pulling()
if(equipping.pulledby)
equipping.pulledby.stop_pulling()
equipped_item.screen_loc = null // will get moved if inventory is visible
equipped_item.forceMove(src)
equipped_item.equipped(src, slot)
SET_PLANE_EXPLICIT(equipped_item, ABOVE_HUD_PLANE, src)
equipping.screen_loc = null // will get moved if inventory is visible
equipping.forceMove(src)
equipping.equipped(src, slot)
SET_PLANE_EXPLICIT(equipping, ABOVE_HUD_PLANE, src)
/mob/living/simple_animal/hostile/guardian/proc/apply_overlay(cache_index)
if((. = guardian_overlays[cache_index]))
@@ -52,7 +52,7 @@
return TRUE
return FALSE
/mob/living/simple_animal/hostile/guardian/dextrous/can_equip(obj/item/equipped_item, slot, disable_warning = FALSE, bypass_equip_delay_self = FALSE)
/mob/living/simple_animal/hostile/guardian/dextrous/can_equip(obj/item/equipped_item, slot, disable_warning = FALSE, bypass_equip_delay_self = FALSE, ignore_equipped = FALSE)
switch(slot)
if(ITEM_SLOT_DEX_STORAGE)
if(internal_storage)
@@ -70,13 +70,13 @@
return ITEM_SLOT_DEX_STORAGE
return ..()
/mob/living/simple_animal/hostile/guardian/dextrous/equip_to_slot(obj/item/equipped_item, slot)
/mob/living/simple_animal/hostile/guardian/dextrous/equip_to_slot(obj/item/equipping, slot, initial = FALSE, redraw_mob = FALSE, indirect_action = FALSE)
if(!..())
return
switch(slot)
if(ITEM_SLOT_DEX_STORAGE)
internal_storage = equipped_item
internal_storage = equipping
update_inv_internal_storage()
else
to_chat(src, span_danger("You are trying to equip this item to an unsupported inventory slot. Report this to a coder!"))
+11 -8
View File
@@ -424,17 +424,19 @@
* unset redraw_mob to prevent the mob icons from being redrawn at the end.
*
* Initial is used to indicate whether or not this is the initial equipment (job datums etc) or just a player doing it
*
* set indirect_action to allow insertions into "soft" locked objects, things that are easily opened by the owning mob
*/
/mob/proc/equip_to_slot_if_possible(obj/item/W, slot, qdel_on_fail = FALSE, disable_warning = FALSE, redraw_mob = TRUE, bypass_equip_delay_self = FALSE, initial = FALSE)
/mob/proc/equip_to_slot_if_possible(obj/item/W, slot, qdel_on_fail = FALSE, disable_warning = FALSE, redraw_mob = TRUE, bypass_equip_delay_self = FALSE, initial = FALSE, indirect_action = FALSE)
if(!istype(W) || QDELETED(W)) //This qdeleted is to prevent stupid behavior with things that qdel during init, like say stacks
return FALSE
if(!W.mob_can_equip(src, slot, disable_warning, bypass_equip_delay_self))
if(!W.mob_can_equip(src, slot, disable_warning, bypass_equip_delay_self, indirect_action = indirect_action))
if(qdel_on_fail)
qdel(W)
else if(!disable_warning)
to_chat(src, span_warning("You are unable to equip that!"))
return FALSE
equip_to_slot(W, slot, initial, redraw_mob) //This proc should not ever fail.
equip_to_slot(W, slot, initial, redraw_mob, indirect_action = indirect_action) //This proc should not ever fail.
return TRUE
/**
@@ -445,7 +447,7 @@
*
*In most cases you will want to use equip_to_slot_if_possible()
*/
/mob/proc/equip_to_slot(obj/item/W, slot)
/mob/proc/equip_to_slot(obj/item/equipping, slot, initial = FALSE, redraw_mob = FALSE, indirect_action = FALSE)
return
/**
@@ -456,9 +458,10 @@
*
* Also bypasses equip delay checks, since the mob isn't actually putting it on.
* Initial is used to indicate whether or not this is the initial equipment (job datums etc) or just a player doing it
* set indirect_action to allow insertions into "soft" locked objects, things that are easily opened by the owning mob
*/
/mob/proc/equip_to_slot_or_del(obj/item/W, slot, initial = FALSE)
return equip_to_slot_if_possible(W, slot, TRUE, TRUE, FALSE, TRUE, initial)
/mob/proc/equip_to_slot_or_del(obj/item/W, slot, initial = FALSE, indirect_action = FALSE)
return equip_to_slot_if_possible(W, slot, TRUE, TRUE, FALSE, TRUE, initial, indirect_action)
/**
* Auto equip the passed in item the appropriate slot based on equipment priority
@@ -467,7 +470,7 @@
*
* returns 0 if it cannot, 1 if successful
*/
/mob/proc/equip_to_appropriate_slot(obj/item/W, qdel_on_fail = FALSE)
/mob/proc/equip_to_appropriate_slot(obj/item/W, qdel_on_fail = FALSE, indirect_action = FALSE)
if(!istype(W))
return FALSE
var/slot_priority = W.slot_equipment_priority
@@ -485,7 +488,7 @@
)
for(var/slot in slot_priority)
if(equip_to_slot_if_possible(W, slot, FALSE, TRUE, TRUE, FALSE, FALSE)) //qdel_on_fail = FALSE; disable_warning = TRUE; redraw_mob = TRUE;
if(equip_to_slot_if_possible(W, slot, disable_warning = TRUE, redraw_mob = TRUE, indirect_action = indirect_action))
return TRUE
if(qdel_on_fail)
+3 -3
View File
@@ -19,17 +19,17 @@
. = ..()
create_storage(max_specific_storage = max_w_class, max_total_storage = max_combined_w_class, max_slots = max_items)
atom_storage.allow_big_nesting = TRUE
atom_storage.locked = TRUE
atom_storage.locked = STORAGE_FULLY_LOCKED
/obj/item/mod/module/storage/on_install()
var/datum/storage/modstorage = mod.create_storage(max_specific_storage = max_w_class, max_total_storage = max_combined_w_class, max_slots = max_items)
modstorage.set_real_location(src)
atom_storage.locked = FALSE
atom_storage.locked = STORAGE_NOT_LOCKED
RegisterSignal(mod.chestplate, COMSIG_ITEM_PRE_UNEQUIP, PROC_REF(on_chestplate_unequip))
/obj/item/mod/module/storage/on_uninstall(deleting = FALSE)
var/datum/storage/modstorage = mod.atom_storage
atom_storage.locked = TRUE
atom_storage.locked = STORAGE_FULLY_LOCKED
qdel(modstorage)
if(!deleting)
atom_storage.remove_all(get_turf(src))
@@ -50,7 +50,7 @@ Reproductive extracts:
return
else if(istype(O, /obj/item/food/monkeycube))
if(atom_storage?.attempt_insert(O, user, override = TRUE, force = TRUE))
if(atom_storage?.attempt_insert(O, user, override = TRUE, force = STORAGE_FULLY_LOCKED))
to_chat(user, span_notice("You feed 1 Monkey Cube to [src], and it pulses gently."))
slime_storage?.processCubes(user)
playsound(src, 'sound/items/eatfood.ogg', 20, TRUE)
+21 -1
View File
@@ -19,6 +19,26 @@
l_hand = /obj/item/stack/spacecash/c1000
r_hand = /obj/item/stack/spacecash/c1000
/// outfit_sanity needs to cover insertions into duffelbags
/datum/outfit/duffel_user
name = "Mr. Runtime"
back = /obj/item/storage/backpack/duffelbag
backpack_contents = list(/obj/item/clothing/mask/cigarette/cigar/havana)
/// Satchels too
/datum/outfit/stachel_user
name = "Mr. Runtime"
back = /obj/item/storage/backpack/satchel
backpack_contents = list(/obj/item/clothing/mask/cigarette/cigar/havana)
/// And just in case we'll check backpacks
/datum/outfit/backpack_user
name = "Mr. Runtime"
back = /obj/item/storage/backpack
backpack_contents = list(/obj/item/clothing/mask/cigarette/cigar/havana)
/datum/unit_test/outfit_sanity/Run()
var/datum/outfit/prototype_outfit = /datum/outfit
var/prototype_name = initial(prototype_outfit.name)
@@ -61,7 +81,7 @@
for (var/path in backpack_contents)
var/number = backpack_contents[path] || 1
for (var/_ in 1 to number)
if (!H.equip_to_slot_or_del(new path(H), ITEM_SLOT_BACKPACK, TRUE))
if (!H.equip_to_slot_or_del(new path(H), ITEM_SLOT_BACKPACK, TRUE, indirect_action = TRUE))
TEST_FAIL("[outfit.name]'s backpack_contents are invalid! Couldn't add [path] to backpack.")
#undef CHECK_OUTFIT_SLOT