Files
Bubberstation/code/datums/elements/attack_equip.dm
Sealed101 2a9de94463 Fixes attack-equipping others triggering a self-equip timer with clothing that have equip_delay_self (#91661)
## About The Pull Request

The element wasn't making use of the flag in the
`equip_to_slot_if_possible()` proc, which meant that you would spend
time on a `do_after()` to attack-equip an item onto someone else just so
the recipient would have to spend time equal to `equip_delay_self` to
equip the item. This is weird, and it led to stuff like #73225 where you
could magically make a jacket disappear into the recipient's contents.
In theory this calls for a closer inspection of the equip pipeline's
safety checks? but I might be a tad bit lazy to that. Funny how there
are exactly 3 instances of an item with `equip_delay_self` in the entire
game.

## Why It's Good For The Game

Closes #73225

## Changelog

🆑
fix: fixed equipping straight jackets onto people with attack-equip then
equipping another jacket through the equip window causing magical jacket
consumption into the recipient's contents
/🆑
2025-06-21 22:36:00 -04:00

56 lines
2.0 KiB
Plaintext

/**
* Attached to an item, when the item is used to attack a human, and the attacker isn't in combat mode, attempts to equip the item to the target after the normal delay.
*
* Uses the compare_zone_to_item_slot() proc to see if the attacker is targeting a valid slot.
*/
/datum/element/attack_equip
/datum/element/attack_equip/Attach(datum/target)
. = ..()
if(!isitem(target))
return ELEMENT_INCOMPATIBLE
RegisterSignal(target, COMSIG_ITEM_ATTACK, PROC_REF(on_item_attack))
/datum/element/attack_equip/Detach(datum/source, ...)
. = ..()
UnregisterSignal(source, COMSIG_ITEM_ATTACK)
/datum/element/attack_equip/proc/on_item_attack(obj/item/attire, mob/living/target, mob/living/user)
SIGNAL_HANDLER
if(user.combat_mode || !ishuman(target) || target == user)
return
var/mob/living/carbon/human/sharp_dresser = target
var/targeted_zone = user.zone_selected
if(!attire.compare_zone_to_item_slot(targeted_zone))
return
if(attire.mob_can_equip(target, attire.slot_flags, disable_warning = TRUE, bypass_equip_delay_self = TRUE))
INVOKE_ASYNC(src, PROC_REF(equip), attire, sharp_dresser, user)
return COMPONENT_CANCEL_ATTACK_CHAIN
/datum/element/attack_equip/proc/equip(obj/item/attire, mob/living/carbon/human/sharp_dresser, mob/living/user)
if(HAS_TRAIT(attire, TRAIT_NODROP))
to_chat(user, span_warning("You can't put [attire] on [sharp_dresser], it's stuck to your hand!"))
return
var/equip_time = attire.equip_delay_other
attire.item_start_equip(sharp_dresser, attire, user)
if(!do_after(user, equip_time, sharp_dresser))
return
if(!user.Adjacent(sharp_dresser)) // Due to teleporting shenanigans
user.put_in_hands(attire)
return
user.temporarilyRemoveItemFromInventory(attire)
//we've spent time based on the item's equip_delay_other already, so we don't need to wait more on a self-equip timer
sharp_dresser.equip_to_slot_if_possible(attire, attire.slot_flags, bypass_equip_delay_self = TRUE)
return finish_equip_mob(attire, sharp_dresser, user)