From 2cd8f8c08347db121f10caa28a9f49453bfd1dfa Mon Sep 17 00:00:00 2001 From: SkyratBot <59378654+SkyratBot@users.noreply.github.com> Date: Thu, 27 Aug 2020 15:38:21 +0200 Subject: [PATCH] [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> --- .../mob/living/carbon/human/inventory.dm | 11 ++- .../mob/living/carbon/human/species.dm | 88 +++++-------------- code/modules/mob/living/carbon/inventory.dm | 6 +- code/modules/mob/mob.dm | 5 +- 4 files changed, 40 insertions(+), 70 deletions(-) diff --git a/code/modules/mob/living/carbon/human/inventory.dm b/code/modules/mob/living/carbon/human/inventory.dm index 1c8f252ed41..e717b93623a 100644 --- a/code/modules/mob/living/carbon/human/inventory.dm +++ b/code/modules/mob/living/carbon/human/inventory.dm @@ -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() diff --git a/code/modules/mob/living/carbon/human/species.dm b/code/modules/mob/living/carbon/human/species.dm index df83aea6a9b..1a235723b76 100644 --- a/code/modules/mob/living/carbon/human/species.dm +++ b/code/modules/mob/living/carbon/human/species.dm @@ -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, "You need a jumpsuit before you can attach this [I.name]!") 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, "You need a jumpsuit before you can attach this [I.name]!") 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, "You need a jumpsuit before you can attach this [I.name]!") 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, "You need a jumpsuit before you can attach this [I.name]!") 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, "You need a suit before you can attach this [I.name]!") @@ -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 diff --git a/code/modules/mob/living/carbon/inventory.dm b/code/modules/mob/living/carbon/inventory.dm index dfcd3a826ee..2248c225816 100644 --- a/code/modules/mob/living/carbon/inventory.dm +++ b/code/modules/mob/living/carbon/inventory.dm @@ -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) diff --git a/code/modules/mob/mob.dm b/code/modules/mob/mob.dm index d5df002705c..bd5e4ffe28c 100644 --- a/code/modules/mob/mob.dm +++ b/code/modules/mob/mob.dm @@ -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, "You are unable to equip that!") + else if(!disable_warning) + to_chat(src, "You are unable to equip that!") return FALSE equip_to_slot(W, slot, initial, redraw_mob, swap) //This proc should not ever fail. return TRUE