[MIRROR] Fixes quickswap letting you keep clothing traits (#542)

* Fixes quickswap letting you keep clothing traits (#52790)

Unequipping clothing via quickswap now properly calls dropped(), so you lose any traits you get for wearing them. This fixes being able to use the quickswap hotkey to keep traits and other properties like krav maga, sec/med/diagnostic hud's, and whatever else without actually wearing the clothing.

Fixes: #52788
Fixes: #50798

Why It's Good For The Game

Honestly for my money, a quickswap hotkey is lame and overly gamey, which is funny because the kind of player who would be into that is exactly the kind of player I'd suspect of quietly abusing a bug like this bug for the last several months, but I digress.
Changelog

cl Ryll/Shaps
fix: Quickswapping clothing now properly unequips the swapped-out clothing, removing any traits they granted while worn
/cl

* Fixes quickswap letting you keep clothing traits

Co-authored-by: Ryll Ryll <3589655+Ryll-Ryll@users.noreply.github.com>
This commit is contained in:
SkyratBot
2020-08-27 09:38:21 -04:00
committed by GitHub
co-authored by Ryll Ryll
parent 2f7c3fbf08
commit 2cd8f8c083
4 changed files with 40 additions and 70 deletions
@@ -83,27 +83,31 @@
if(!..()) //a check failed or the item has already found its slot
return
var/current_equip
var/obj/item/current_equip
var/not_handled = FALSE //Added in case we make this type path deeper one day
switch(slot)
if(ITEM_SLOT_BELT)
if (belt && swap)
belt.dropped(src, TRUE)
current_equip = belt
belt = I
update_inv_belt()
if(ITEM_SLOT_ID)
if (wear_id && swap)
wear_id.dropped(src, TRUE)
current_equip = wear_id
wear_id = I
sec_hud_set_ID()
update_inv_wear_id()
if(ITEM_SLOT_EARS)
if (ears && swap)
ears.dropped(src, TRUE)
current_equip = ears
ears = I
update_inv_ears()
if(ITEM_SLOT_EYES)
if (glasses && swap)
glasses.dropped(src, TRUE)
current_equip = glasses
glasses = I
var/obj/item/clothing/glasses/G = I
@@ -118,16 +122,19 @@
update_inv_glasses()
if(ITEM_SLOT_GLOVES)
if (gloves && swap)
gloves.dropped(src, TRUE)
current_equip = gloves
gloves = I
update_inv_gloves()
if(ITEM_SLOT_FEET)
if (shoes && swap)
shoes.dropped(src, TRUE)
current_equip = shoes
shoes = I
update_inv_shoes()
if(ITEM_SLOT_OCLOTHING)
if (wear_suit && swap)
wear_suit.dropped(src, TRUE)
current_equip = wear_suit
wear_suit = I
if(I.flags_inv & HIDEJUMPSUIT)
@@ -138,6 +145,7 @@
update_inv_wear_suit()
if(ITEM_SLOT_ICLOTHING)
if (w_uniform && swap)
w_uniform.dropped(src, TRUE)
current_equip = w_uniform
w_uniform = I
update_suit_sensors()
@@ -150,6 +158,7 @@
update_inv_pockets()
if(ITEM_SLOT_SUITSTORE)
if (s_store && swap)
s_store.dropped(src, TRUE)
current_equip = s_store
s_store = I
update_inv_s_store()
+23 -65
View File
@@ -920,50 +920,44 @@ GLOBAL_LIST_EMPTY(roundstart_races)
if(!I.species_exception || !is_type_in_list(src, I.species_exception))
return FALSE
var/obj/item/replaced_item = H.get_item_by_slot(slot)
// if there's an item in the slot we want, only allow past this if we're trying to swap and the item being replaced isn't NODROP or ABSTRACT
if(replaced_item && (!swap || (HAS_TRAIT(replaced_item, TRAIT_NODROP) || (replaced_item.item_flags & ABSTRACT))))
return FALSE
// this check prevents us from equipping something to a slot it doesn't support, WITH the exceptions of storage slots (pockets, suit storage, and backpacks)
// we don't require having those slots defined in the item's slot_flags, so we'll rely on their own checks further down
if(!(I.slot_flags & slot))
var/excused = FALSE
// Anything that's small or smaller can fit into a pocket by default
if((slot == ITEM_SLOT_RPOCKET || slot == ITEM_SLOT_LPOCKET) && I.w_class <= WEIGHT_CLASS_SMALL)
excused = TRUE
else if(slot == ITEM_SLOT_SUITSTORE || slot == ITEM_SLOT_BACKPACK)
excused = TRUE
if(!excused)
return FALSE
switch(slot)
if(ITEM_SLOT_HANDS)
if(H.get_empty_held_indexes())
return TRUE
return FALSE
if(ITEM_SLOT_MASK)
if(H.wear_mask && !swap)
return FALSE
if(!(I.slot_flags & ITEM_SLOT_MASK))
return FALSE
if(!H.get_bodypart(BODY_ZONE_HEAD))
return FALSE
return equip_delay_self_check(I, H, bypass_equip_delay_self)
if(ITEM_SLOT_NECK)
if(H.wear_neck && !swap)
return FALSE
if( !(I.slot_flags & ITEM_SLOT_NECK) )
return FALSE
return TRUE
if(ITEM_SLOT_BACK)
if(H.back && !swap)
return FALSE
if( !(I.slot_flags & ITEM_SLOT_BACK) )
return FALSE
return equip_delay_self_check(I, H, bypass_equip_delay_self)
if(ITEM_SLOT_OCLOTHING)
if(H.wear_suit && !swap)
return FALSE
if( !(I.slot_flags & ITEM_SLOT_OCLOTHING) )
return FALSE
return equip_delay_self_check(I, H, bypass_equip_delay_self)
if(ITEM_SLOT_GLOVES)
if(H.gloves && !swap)
return FALSE
if( !(I.slot_flags & ITEM_SLOT_GLOVES) )
return FALSE
if(H.num_hands < 2)
return FALSE
return equip_delay_self_check(I, H, bypass_equip_delay_self)
if(ITEM_SLOT_FEET)
if(H.shoes && !swap)
return FALSE
if( !(I.slot_flags & ITEM_SLOT_FEET) )
return FALSE
if(H.num_legs < 2)
return FALSE
if(DIGITIGRADE in species_traits)
@@ -972,23 +966,14 @@ GLOBAL_LIST_EMPTY(roundstart_races)
return FALSE
return equip_delay_self_check(I, H, bypass_equip_delay_self)
if(ITEM_SLOT_BELT)
if(H.belt && !swap)
return FALSE
var/obj/item/bodypart/O = H.get_bodypart(BODY_ZONE_CHEST)
if(!H.w_uniform && !nojumpsuit && (!O || O.status != BODYPART_ROBOTIC))
if(!disable_warning)
to_chat(H, "<span class='warning'>You need a jumpsuit before you can attach this [I.name]!</span>")
return FALSE
if(!(I.slot_flags & ITEM_SLOT_BELT))
return
return equip_delay_self_check(I, H, bypass_equip_delay_self)
if(ITEM_SLOT_EYES)
if(H.glasses && !swap)
return FALSE
if(!(I.slot_flags & ITEM_SLOT_EYES))
return FALSE
if(!H.get_bodypart(BODY_ZONE_HEAD))
return FALSE
var/obj/item/organ/eyes/E = H.getorganslot(ORGAN_SLOT_EYES)
@@ -996,43 +981,26 @@ GLOBAL_LIST_EMPTY(roundstart_races)
return FALSE
return equip_delay_self_check(I, H, bypass_equip_delay_self)
if(ITEM_SLOT_HEAD)
if(H.head && !swap)
return FALSE
if(!(I.slot_flags & ITEM_SLOT_HEAD))
return FALSE
if(!H.get_bodypart(BODY_ZONE_HEAD))
return FALSE
return equip_delay_self_check(I, H, bypass_equip_delay_self)
if(ITEM_SLOT_EARS)
if(H.ears && !swap)
return FALSE
if(!(I.slot_flags & ITEM_SLOT_EARS))
return FALSE
if(!H.get_bodypart(BODY_ZONE_HEAD))
return FALSE
return equip_delay_self_check(I, H, bypass_equip_delay_self)
if(ITEM_SLOT_ICLOTHING)
if(H.w_uniform && !swap)
return FALSE
if( !(I.slot_flags & ITEM_SLOT_ICLOTHING) )
return FALSE
return equip_delay_self_check(I, H, bypass_equip_delay_self)
if(ITEM_SLOT_ID)
if(H.wear_id && !swap)
return FALSE
var/obj/item/bodypart/O = H.get_bodypart(BODY_ZONE_CHEST)
if(!H.w_uniform && !nojumpsuit && (!O || O.status != BODYPART_ROBOTIC))
if(!disable_warning)
to_chat(H, "<span class='warning'>You need a jumpsuit before you can attach this [I.name]!</span>")
return FALSE
if( !(I.slot_flags & ITEM_SLOT_ID) )
return FALSE
return equip_delay_self_check(I, H, bypass_equip_delay_self)
if(ITEM_SLOT_LPOCKET)
if(HAS_TRAIT(I, TRAIT_NODROP)) //Pockets aren't visible, so you can't move TRAIT_NODROP items into them.
return FALSE
if(H.l_store)
if(H.l_store) // no pocket swaps at all
return FALSE
var/obj/item/bodypart/O = H.get_bodypart(BODY_ZONE_L_LEG)
@@ -1041,8 +1009,7 @@ GLOBAL_LIST_EMPTY(roundstart_races)
if(!disable_warning)
to_chat(H, "<span class='warning'>You need a jumpsuit before you can attach this [I.name]!</span>")
return FALSE
if( I.w_class <= WEIGHT_CLASS_SMALL || (I.slot_flags & ITEM_SLOT_LPOCKET) )
return TRUE
return TRUE
if(ITEM_SLOT_RPOCKET)
if(HAS_TRAIT(I, TRAIT_NODROP))
return FALSE
@@ -1055,14 +1022,10 @@ GLOBAL_LIST_EMPTY(roundstart_races)
if(!disable_warning)
to_chat(H, "<span class='warning'>You need a jumpsuit before you can attach this [I.name]!</span>")
return FALSE
if( I.w_class <= WEIGHT_CLASS_SMALL || (I.slot_flags & ITEM_SLOT_RPOCKET) )
return TRUE
return FALSE
return TRUE
if(ITEM_SLOT_SUITSTORE)
if(HAS_TRAIT(I, TRAIT_NODROP))
return FALSE
if(H.s_store && !swap)
return FALSE
if(!H.wear_suit)
if(!disable_warning)
to_chat(H, "<span class='warning'>You need a suit before you can attach this [I.name]!</span>")
@@ -1079,25 +1042,20 @@ GLOBAL_LIST_EMPTY(roundstart_races)
return TRUE
return FALSE
if(ITEM_SLOT_HANDCUFFED)
if(H.handcuffed)
return FALSE
if(!istype(I, /obj/item/restraints/handcuffs))
return FALSE
if(H.num_hands < 2)
return FALSE
return TRUE
if(ITEM_SLOT_LEGCUFFED)
if(H.legcuffed)
return FALSE
if(!istype(I, /obj/item/restraints/legcuffs))
return FALSE
if(H.num_legs < 2)
return FALSE
return TRUE
if(ITEM_SLOT_BACKPACK)
if(H.back)
if(SEND_SIGNAL(H.back, COMSIG_TRY_STORAGE_CAN_INSERT, I, H, TRUE))
return TRUE
if(H.back && SEND_SIGNAL(H.back, COMSIG_TRY_STORAGE_CAN_INSERT, I, H, TRUE))
return TRUE
return FALSE
return FALSE //Unsupported slot
+5 -1
View File
@@ -49,26 +49,30 @@
I.plane = ABOVE_HUD_PLANE
I.appearance_flags |= NO_CLIENT_COLOR
var/not_handled = FALSE
var/current_equip
var/obj/item/current_equip
switch(slot)
if(ITEM_SLOT_BACK)
if (back && swap)
back.dropped(src, TRUE)
current_equip = back
back = I
update_inv_back()
if(ITEM_SLOT_MASK)
if (wear_mask && swap)
wear_mask.dropped(src, TRUE)
current_equip = wear_mask
wear_mask = I
wear_mask_update(I, toggle_off = 0)
if(ITEM_SLOT_HEAD)
if (head && swap)
head.dropped(src, TRUE)
current_equip = head
head = I
SEND_SIGNAL(src, COMSIG_CARBON_EQUIP_HAT, I)
head_update(I)
if(ITEM_SLOT_NECK)
if (wear_neck && swap)
wear_neck.dropped(src, TRUE)
current_equip = wear_neck
wear_neck = I
update_inv_neck(I)
+2 -3
View File
@@ -336,9 +336,8 @@
if(!W.mob_can_equip(src, null, slot, disable_warning, bypass_equip_delay_self, swap))
if(qdel_on_fail)
qdel(W)
else
if(!disable_warning)
to_chat(src, "<span class='warning'>You are unable to equip that!</span>")
else if(!disable_warning)
to_chat(src, "<span class='warning'>You are unable to equip that!</span>")
return FALSE
equip_to_slot(W, slot, initial, redraw_mob, swap) //This proc should not ever fail.
return TRUE