diff --git a/code/game/objects/items.dm b/code/game/objects/items.dm
index 8624e047d9f..a14842fe341 100644
--- a/code/game/objects/items.dm
+++ b/code/game/objects/items.dm
@@ -338,26 +338,25 @@ GLOBAL_DATUM_INIT(welding_sparks, /mutable_appearance, mutable_appearance('icons
if(affecting && affecting.receive_damage(0, 5)) // 5 burn damage
H.UpdateDamageIcon()
- if(isstorage(src.loc))
- /// If the item is in a storage item, take it out
- var/obj/item/storage/S = src.loc
- S.remove_from_storage(src)
-
if(..())
return
if(throwing)
throwing.finalize(FALSE)
if(loc == user)
- if(HAS_TRAIT(user, TRAIT_I_WANT_BRAINS) || !user.unEquip(src, silent = TRUE))
+ if(HAS_TRAIT(user, TRAIT_I_WANT_BRAINS))
+ return FALSE
+ if(!user.canUnEquip(src, force = FALSE))
return FALSE
if(flags & ABSTRACT)
return FALSE
- else
- if(isliving(loc))
- return FALSE
+ if(user.is_in_inactive_hand(src))
+ return user.swap_item_between_hands()
+
+ if(isliving(loc))
+ return FALSE
pickup(user)
add_fingerprint(user)
diff --git a/code/game/objects/items/weapons/storage/storage_base.dm b/code/game/objects/items/weapons/storage/storage_base.dm
index 0b5236d0e31..4f751de8025 100644
--- a/code/game/objects/items/weapons/storage/storage_base.dm
+++ b/code/game/objects/items/weapons/storage/storage_base.dm
@@ -436,38 +436,42 @@
* * prevent_warning - Stop the insertion message being displayed. Intended for cases when you are inserting multiple items at once.
*/
/obj/item/storage/proc/handle_item_insertion(obj/item/I, mob/user, prevent_warning = FALSE)
- if(!istype(I))
- return FALSE
- if(user)
- if(!Adjacent(user) && !isnewplayer(user))
- return FALSE
- if(!user.unEquip(I, silent = TRUE))
- return FALSE
- user.update_icons() //update our overlays
- if(QDELING(I))
+ if(!istype(I) || QDELING(I))
return FALSE
if(silent || HAS_TRAIT(I, TRAIT_SILENT_INSERTION))
prevent_warning = TRUE
- I.forceMove(src)
- if(QDELING(I))
- return FALSE
- I.on_enter_storage(src)
-
- for(var/_M in mobs_viewing)
- var/mob/M = _M
- if((M.s_active == src) && M.client)
- M.client.screen += I
if(user)
+ if(!Adjacent(user) && !isnewplayer(user))
+ return FALSE
+ if(!user.unEquip(I, force = FALSE, silent = TRUE, destination = src))
+ return FALSE
if(user.client && user.s_active != src)
user.client.screen -= I
if(length(user.observers))
for(var/mob/observer in user.observers)
if(observer.client && observer.s_active != src)
observer.client.screen -= I
- I.dropped(user, TRUE)
- if(user)
+
add_fingerprint(user)
+ user.update_icons()
+
+ orient2hud(user)
+ if(user.s_active)
+ user.s_active.show_to(user)
+ else
+ I.forceMove(src)
+
+ I.on_enter_storage(src)
+ // So you can click on the area around the item to equip it, instead of having to pixel hunt
+ I.mouse_opacity = MOUSE_OPACITY_OPAQUE
+ I.in_inventory = TRUE
+
+ for(var/_M in mobs_viewing)
+ var/mob/M = _M
+ if((M.s_active == src) && M.client)
+ M.client.screen += I
+
if(!prevent_warning)
// the item's user will always get a notification
to_chat(user, "You put [I] into [src].")
@@ -481,13 +485,7 @@
// restrict player list to include only those in view
for(var/mob/M in oviewers(7, user))
M.show_message("[user] puts [I] into [src].")
- orient2hud(user)
- if(user)
- if(user.s_active)
- user.s_active.show_to(user)
- 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
- I.in_inventory = TRUE
update_icon()
return TRUE
diff --git a/code/modules/mob/inventory_procs.dm b/code/modules/mob/inventory_procs.dm
index c82b9bc39f0..5cb86fb1b29 100644
--- a/code/modules/mob/inventory_procs.dm
+++ b/code/modules/mob/inventory_procs.dm
@@ -66,6 +66,34 @@
if(ITEM_SLOT_RIGHT_HAND)
return put_in_r_hand(I)
+/**
+ * Swaps items between hands.
+ *
+ * A separate implementation is required for this because all of the
+ * pre-existing equip/unEquip procs perform forceMoves we don't want.
+ */
+/mob/proc/swap_item_between_hands()
+ var/obj/item/I = get_inactive_hand()
+ if(!put_in_hand_check(I))
+ return FALSE
+
+ if(I == r_hand && has_left_hand())
+ r_hand = null
+ l_hand = I
+ update_inv_r_hand()
+ update_inv_l_hand()
+ I.equipped(src, ITEM_SLOT_LEFT_HAND)
+ return TRUE
+ else if(I == l_hand && has_right_hand())
+ l_hand = null
+ r_hand = I
+ update_inv_l_hand()
+ update_inv_r_hand()
+ I.equipped(src, ITEM_SLOT_RIGHT_HAND)
+ return TRUE
+
+ return FALSE
+
//Puts the item into your l_hand if possible and calls all necessary triggers/updates. returns 1 on success.
/mob/proc/put_in_l_hand(obj/item/W, skip_blocked_hands_check = FALSE)
if(!put_in_hand_check(W, skip_blocked_hands_check))
@@ -166,13 +194,26 @@
return TRUE
-/mob/proc/unEquip(obj/item/I, force, silent = FALSE) //Force overrides NODROP for things like wizarditis and admin undress.
+/**
+ * Unequip an item from the hand that the item is found in.
+ *
+ * `force` overrides NODROP for things like wizarditis and admin undress.
+ *
+ * `destination` allows for items to be unequipped directly into storage and
+ * should only be used for that.
+ *
+ * Horrid stop-gap until we get atom storage or something.
+ */
+/mob/proc/unEquip(obj/item/I, force = FALSE, silent = FALSE, atom/destination)
if(!I) //If there's nothing to drop, the drop is automatically succesfull. If(unEquip) should generally be used to check for NODROP.
return 1
if(!canUnEquip(I, force))
return 0
+ if(isnull(destination))
+ destination = drop_location()
+
if(I == r_hand)
r_hand = null
update_inv_r_hand()
@@ -181,14 +222,13 @@
update_inv_l_hand()
else if(I in tkgrabbed_objects)
var/obj/item/tk_grab/tkgrab = tkgrabbed_objects[I]
- unEquip(tkgrab, force)
+ unEquip(tkgrab, force, silent, destination)
if(I)
if(client)
client.screen -= I
- var/turf/drop_loc = drop_location()
- if(drop_loc)
- I.forceMove(drop_loc)
+ if(destination)
+ I.forceMove(destination)
else
I.moveToNullspace()
I.dropped(src, silent)
diff --git a/code/modules/mob/living/carbon/alien/larva/larva_inventory.dm b/code/modules/mob/living/carbon/alien/larva/larva_inventory.dm
index 0c5df6d99e9..19222c379a9 100644
--- a/code/modules/mob/living/carbon/alien/larva/larva_inventory.dm
+++ b/code/modules/mob/living/carbon/alien/larva/larva_inventory.dm
@@ -1,3 +1,3 @@
//can't unequip since it can't equip anything // why the fuck is this it's own file
-/mob/living/carbon/alien/larva/unEquip(obj/item/I, force, silent = FALSE)
+/mob/living/carbon/alien/larva/unEquip(obj/item/I, force = FALSE, silent = FALSE, atom/destination)
return
diff --git a/code/modules/mob/living/carbon/carbon_procs.dm b/code/modules/mob/living/carbon/carbon_procs.dm
index 594e12a7963..7d9e4234a27 100644
--- a/code/modules/mob/living/carbon/carbon_procs.dm
+++ b/code/modules/mob/living/carbon/carbon_procs.dm
@@ -731,7 +731,7 @@ GLOBAL_LIST_INIT(ventcrawl_machinery, list(/obj/machinery/atmospherics/unary/ven
/mob/living/carbon/get_restraining_item()
return handcuffed
-/mob/living/carbon/unEquip(obj/item/I, force, silent = FALSE) //THIS PROC DID NOT CALL ..()
+/mob/living/carbon/unEquip(obj/item/I, force = FALSE, silent = FALSE, atom/destination)
. = ..() //Sets the default return value to what the parent returns.
if(!. || !I) //We don't want to set anything to null if the parent returned 0.
return
diff --git a/code/modules/mob/living/carbon/human/human_inventory.dm b/code/modules/mob/living/carbon/human/human_inventory.dm
index 4f87fe4ff7a..dfbe9004ff0 100644
--- a/code/modules/mob/living/carbon/human/human_inventory.dm
+++ b/code/modules/mob/living/carbon/human/human_inventory.dm
@@ -67,7 +67,7 @@
if(ITEM_SLOT_ACCESSORY)
return TRUE
-/mob/living/carbon/human/unEquip(obj/item/I, force, silent = FALSE)
+/mob/living/carbon/human/unEquip(obj/item/I, force = FALSE, silent = FALSE, atom/destination)
. = ..() //See mob.dm for an explanation on this and some rage about people copypasting instead of calling ..() like they should.
if(!. || !I)
return
diff --git a/code/modules/mob/living/silicon/robot/robot_inventory.dm b/code/modules/mob/living/silicon/robot/robot_inventory.dm
index e3201740d5a..bbb510ccf0f 100644
--- a/code/modules/mob/living/silicon/robot/robot_inventory.dm
+++ b/code/modules/mob/living/silicon/robot/robot_inventory.dm
@@ -239,7 +239,7 @@
while(slot_start != slot_num) //If we wrap around without finding any free slots, just give up.
return
-/mob/living/silicon/robot/unEquip(obj/item/I, force, silent = FALSE)
+/mob/living/silicon/robot/unEquip(obj/item/I, force = FALSE, silent = FALSE, atom/destination)
if(I == module_active)
uneq_active(I)
return ..()
diff --git a/code/modules/mob/living/simple_animal/simple_animal.dm b/code/modules/mob/living/simple_animal/simple_animal.dm
index daec7a7b43e..0d058adce0a 100644
--- a/code/modules/mob/living/simple_animal/simple_animal.dm
+++ b/code/modules/mob/living/simple_animal/simple_animal.dm
@@ -504,7 +504,7 @@
if(ITEM_SLOT_COLLAR)
add_collar(W)
-/mob/living/simple_animal/unEquip(obj/item/I, force, silent = FALSE)
+/mob/living/simple_animal/unEquip(obj/item/I, force = FALSE, silent = FALSE, atom/destination)
. = ..()
if(!. || !I)
return
diff --git a/code/modules/mob/living/simple_animal/slime/slime_mob.dm b/code/modules/mob/living/simple_animal/slime/slime_mob.dm
index ce0a5d3087a..bc2278127f4 100644
--- a/code/modules/mob/living/simple_animal/slime/slime_mob.dm
+++ b/code/modules/mob/living/simple_animal/slime/slime_mob.dm
@@ -266,7 +266,7 @@
return
return ..()
-/mob/living/simple_animal/slime/unEquip(obj/item/I, force, silent = FALSE)
+/mob/living/simple_animal/slime/unEquip(obj/item/I, force = FALSE, silent = FALSE, atom/destination)
return
/mob/living/simple_animal/slime/start_pulling(atom/movable/AM, state, force = pull_force, show_message = FALSE)