Skip to content

Commit

Permalink
Cleanup ITEM_INTERACT_ flags. (ParadiseSS13#27640)
Browse files Browse the repository at this point in the history
* Cleanup `ITEM_INTERACT_` flags.

* replace new uses of old flags
  • Loading branch information
warriorstar-orion authored Dec 17, 2024
1 parent f37038e commit bd6450d
Show file tree
Hide file tree
Showing 11 changed files with 297 additions and 285 deletions.
8 changes: 2 additions & 6 deletions code/__DEFINES/dcs/attack_chain_signals.dm
Original file line number Diff line number Diff line change
@@ -1,12 +1,8 @@
// MARK: Item Interactions

// Return values for non-attack interactions.
#define ITEM_INTERACT_SUCCESS (1<<0) //! Cancel the rest of the attack chain, indicating success.
#define ITEM_INTERACT_BLOCKING (1<<1) //! Cancel the rest of the attack chain, without indicating success.
#define ITEM_INTERACT_SKIP_TO_ATTACK (1<<2) //! Skip the rest of the interaction chain, going straight to the attack phase.

/// Combination return value for any item interaction that cancels the rest of the attack chain.
#define ITEM_INTERACT_ANY_BLOCKER (ITEM_INTERACT_SUCCESS | ITEM_INTERACT_BLOCKING)
#define ITEM_INTERACT_COMPLETE 1 //! Cancel the rest of the attack chain, indicating success.
#define ITEM_INTERACT_SKIP_TO_AFTER_ATTACK 2 //! Skip pre-attack and attack/attack_by, going straight to after_attack.

/// Sent when this atom is clicked on by a mob with an item.
///
Expand Down
33 changes: 20 additions & 13 deletions code/_onclick/item_attack.dm
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,8 @@
* This is the proc that handles the order of an item_attack.
*
* The order of procs called is:
* * [/atom/proc/base_item_interaction] on the target. If it returns ITEM_INTERACT_SUCCESS or ITEM_INTERACT_BLOCKING, the chain will be stopped.
* * [/atom/proc/base_item_interaction] on the target. If it returns ITEM_INTERACT_COMPLETE, the chain will be stopped.
* If it returns ITEM_INTERACT_SKIP_TO_AFTER_ATTACK, all attack chain steps except after-attack will be skipped.
* * [/obj/item/proc/pre_attack] on `src`. If this returns FINISH_ATTACK, the chain will be stopped.
* * [/atom/proc/attack_by] on the target. If it returns FINISH_ATTACK, the chain will be stopped.
* * [/obj/item/proc/after_attack]. The return value does not matter.
Expand All @@ -14,13 +15,14 @@
var/list/modifiers = params2list(params)

var/item_interact_result = target.base_item_interaction(user, src, modifiers)
if(item_interact_result & ITEM_INTERACT_SUCCESS)
return
if(item_interact_result & ITEM_INTERACT_BLOCKING)
return
switch(item_interact_result)
if(ITEM_INTERACT_COMPLETE)
return
if(ITEM_INTERACT_SKIP_TO_AFTER_ATTACK)
__after_attack_core(user, target, params, proximity_flag)
return

// Attack phase

if(pre_attack(target, user, params))
return

Expand All @@ -35,14 +37,8 @@
// At this point it means the attack was "successful", or at least
// handled, in some way. This can mean nothing happened, this can mean the
// target took damage, etc.
__after_attack_core(user, target, params, proximity_flag)

// TODO: `target` here should probably be another `!QDELETED` check.
// Preserved for backwards compatibility, may be fixed post-migration.
if(target && !QDELETED(src))
if(new_attack_chain)
after_attack(target, user, proximity_flag, params)
else
afterattack__legacy__attackchain(target, user, proximity_flag, params)

/// Called when the item is in the active hand, and clicked; alternately, there
/// is an 'activate held object' verb or you can hit pagedown.
Expand Down Expand Up @@ -137,6 +133,17 @@
if(!target.new_attack_chain)
return target.attacked_by__legacy__attackchain(src, user, /* def_zone */ null)

/obj/item/proc/__after_attack_core(mob/user, atom/target, params, proximity_flag = 1)
PRIVATE_PROC(TRUE)

// TODO: `target` here should probably be another `!QDELETED` check.
// Preserved for backwards compatibility, may be fixed post-migration.
if(target && !QDELETED(src))
if(new_attack_chain)
after_attack(target, user, proximity_flag, params)
else
afterattack__legacy__attackchain(target, user, proximity_flag, params)

/obj/item/proc/__attack_core(mob/living/target, mob/living/user)
PRIVATE_PROC(TRUE)

Expand Down
4 changes: 2 additions & 2 deletions code/game/objects/items/weapons/agent_id.dm
Original file line number Diff line number Diff line change
Expand Up @@ -59,7 +59,7 @@
if(isliving(user) && user?.mind?.special_role)
to_chat(usr, "<span class='notice'>The card's microscanners activate as you pass it over [I], copying its access.</span>")
access |= I.access //Don't copy access if user isn't an antag -- to prevent metagaming
return ITEM_INTERACT_SUCCESS
return ITEM_INTERACT_COMPLETE

/obj/item/card/id/syndicate/ui_act(action, list/params, datum/tgui/ui, datum/ui_state/state)
if(..())
Expand Down Expand Up @@ -296,4 +296,4 @@
if(user.mind.special_role)
to_chat(user, "<span class='notice'>The card's microscanners activate as you pass it over [I], copying its access.</span>")
access |= I.access // Don't copy access if user isn't an antag -- to prevent metagaming
return ITEM_INTERACT_SUCCESS
return ITEM_INTERACT_COMPLETE
20 changes: 10 additions & 10 deletions code/game/objects/items/weapons/cards_ids.dm
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,7 @@

/obj/item/card/emag/interact_with_atom(atom/target, mob/living/user, list/modifiers)
if(target.emag_act(user))
return ITEM_INTERACT_SUCCESS
return ITEM_INTERACT_COMPLETE

/obj/item/card/emag/magic_key
name = "magic key"
Expand All @@ -55,13 +55,13 @@

/obj/item/card/emag/magic_key/interact_with_atom(atom/target, mob/living/user, list/modifiers)
if(!isairlock(target))
return ITEM_INTERACT_BLOCKING
return ITEM_INTERACT_COMPLETE
var/obj/machinery/door/D = target
D.locked = FALSE
D.update_icon()
D.emag_act(user)
qdel(src)
return ITEM_INTERACT_SUCCESS
return ITEM_INTERACT_COMPLETE

/obj/item/card/cmag
desc = "It's a card coated in a slurry of electromagnetic bananium."
Expand All @@ -82,7 +82,7 @@

/obj/item/card/cmag/interact_with_atom(atom/target, mob/living/user, list/modifiers)
if(target.cmag_act(user))
return ITEM_INTERACT_SUCCESS
return ITEM_INTERACT_COMPLETE

/obj/item/card/id
name = "identification card"
Expand Down Expand Up @@ -264,31 +264,31 @@
item_state = decal.decal_item_state
qdel(decal)
qdel(used)
return ITEM_INTERACT_SUCCESS
return ITEM_INTERACT_COMPLETE

else if(istype(used, /obj/item/barcodescanner))
var/obj/item/barcodescanner/B = used
B.scanID(src, user)
return ITEM_INTERACT_SUCCESS
return ITEM_INTERACT_COMPLETE

else if(istype(used, /obj/item/stamp))
if(!stamped)
dat+="<img src=large_[used.icon_state].png>"
stamped = 1
to_chat(user, "You stamp the ID card!")
playsound(user, 'sound/items/handling/standard_stamp.ogg', 50, vary = TRUE)
return ITEM_INTERACT_SUCCESS
return ITEM_INTERACT_COMPLETE
to_chat(user, "This ID has already been stamped!")
return ITEM_INTERACT_BLOCKING
return ITEM_INTERACT_COMPLETE


else if(istype(used, /obj/item/card/id/guest))
attach_guest_pass(used, user)
return ITEM_INTERACT_SUCCESS
return ITEM_INTERACT_COMPLETE

else if(istype(used, /obj/item/storage/wallet))
used.attackby__legacy__attackchain(src, user)
return ITEM_INTERACT_SUCCESS
return ITEM_INTERACT_COMPLETE

/obj/item/card/id/AltClick(mob/user)
if(user.stat || HAS_TRAIT(user, TRAIT_HANDS_BLOCKED) || !Adjacent(user))
Expand Down
2 changes: 1 addition & 1 deletion code/game/objects/structures/curtains.dm
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,7 @@
/obj/structure/curtain/item_interaction(mob/living/user, obj/item/used, list/modifiers)
if(istype(used, /obj/item/toy/crayon))
color = tgui_input_color(user,"Please choose a color.", "Curtain Color")
return ITEM_INTERACT_SUCCESS
return ITEM_INTERACT_COMPLETE

/obj/structure/curtain/screwdriver_act(mob/user, obj/item/I)
. = TRUE
Expand Down
2 changes: 1 addition & 1 deletion code/modules/mining/machine_vending.dm
Original file line number Diff line number Diff line change
Expand Up @@ -510,7 +510,7 @@
points = 0
else
to_chat(user, "<span class='notice'>There's no points left on [src].</span>")
return ITEM_INTERACT_SUCCESS
return ITEM_INTERACT_COMPLETE

/obj/item/card/mining_point_card/examine(mob/user)
. = ..()
Expand Down
12 changes: 6 additions & 6 deletions code/modules/vehicle/janivehicle.dm
Original file line number Diff line number Diff line change
Expand Up @@ -96,28 +96,28 @@
if(istype(used, /obj/item/storage/bag/trash))
if(mybag)
to_chat(user, fail_msg)
return ITEM_INTERACT_BLOCKING
return ITEM_INTERACT_COMPLETE
if(!user.drop_item())
return ITEM_INTERACT_BLOCKING
return ITEM_INTERACT_COMPLETE
to_chat(user, "<span class='notice'>You hook [used] onto [src].</span>")
used.forceMove(src)
mybag = used
update_icon(UPDATE_OVERLAYS)
return ITEM_INTERACT_SUCCESS
return ITEM_INTERACT_COMPLETE

if(istype(used, /obj/item/borg/upgrade/floorbuffer))
if(buffer_installed)
to_chat(user, fail_msg)
return ITEM_INTERACT_BLOCKING
return ITEM_INTERACT_COMPLETE
buffer_installed = TRUE
qdel(used)
to_chat(user,"<span class='notice'>You upgrade [src] with [used].</span>")
update_icon(UPDATE_OVERLAYS)
return ITEM_INTERACT_SUCCESS
return ITEM_INTERACT_COMPLETE

if(mybag && user.a_intent == INTENT_HELP && !is_key(used))
mybag.attackby__legacy__attackchain(used, user)
return ITEM_INTERACT_ANY_BLOCKER
return ITEM_INTERACT_COMPLETE

return ..()

Expand Down
4 changes: 2 additions & 2 deletions code/modules/vehicle/vehicle.dm
Original file line number Diff line number Diff line change
Expand Up @@ -78,10 +78,10 @@
inserted_key = used
else
to_chat(user, "<span class='warning'>[used] seems to be stuck to your hand!</span>")
return ITEM_INTERACT_ANY_BLOCKER
return ITEM_INTERACT_COMPLETE

if(istype(used, /obj/item/borg/upgrade/vtec) && install_vtec(used, user))
return ITEM_INTERACT_ANY_BLOCKER
return ITEM_INTERACT_COMPLETE

/obj/vehicle/AltClick(mob/user)
if(inserted_key && user.Adjacent(user))
Expand Down
35 changes: 21 additions & 14 deletions docs/references/attack_chain.md
Original file line number Diff line number Diff line change
Expand Up @@ -32,10 +32,13 @@ The core of the attack chain commences:
`COMSIG_INTERACT_USER`. If any listeners request it (usually by returning a
non-null value), the attack chain may end here.
5. If the target implements `item_interaction()`, it is called here, and can
return one of the `ITEM_INTERACT_` flags to end the attack chain.
either return `ITEM_INTERACT_COMPLETE` to end the attack chain, or
`ITEM_INTERACT_SKIP_TO_AFTER_ATTACK` to skip all phases of the attack chain
except for after-attack.
6. If the item being used on the target implements `interact_with_atom()`, it is
called here, and can return one of the `ITEM_INTERACT_` flags to end the
attack chain.
called here, and can either return `ITEM_INTERACT_COMPLETE` to end the attack
chain, or `ITEM_INTERACT_SKIP_TO_AFTER_ATTACK` to skip all phases of the
attack chain except for after-attack.

The above steps can generally be considered the "item interaction phase", when
the action is not meant to cause in-game harm to the target. If the attack chain
Expand Down Expand Up @@ -89,12 +92,16 @@ into the attack chain.

### ITEM_INTERACT flags

One may also ask why there are several `ITEM_INTERACT_` flags if returning any
of them always results in the end of the attack chain. This is for two reasons:
One may also ask why the `ITEM_INTERACT_SKIP_TO_AFTER_ATTACK` flag is necessary.
Pre-migration, a common pattern was for an object to skip certain items in its
`attackby`, and let those items handle the interaction in their `afterattack`.
Some examples of this include:

1. To make it clear at the call site what the intent of the code is, and
2. So that in the future, if we do wish to separate the behavior of these flags,
we do not need to refactor all of the call sites.
- Mountable frames being "ignored" in `/turf/attackby`, in order to let
`/obj/item/mounted/frame/afterattack` handle its specific behavior.
- Reagent containers being "ignored" in various machines' `attackby`, in order
to let the container's `afterattack` handle reagent transfer or other specific
behavior.

## Attack Chain Refactor

Expand Down Expand Up @@ -257,33 +264,33 @@ at each junction whenever we have handled the item interaction.
if(mybag)
to_chat(user, fail_msg)
- return
+ return ITEM_INTERACT_BLOCKING
+ return ITEM_INTERACT_COMPLETE
if(!user.drop_item())
- return
+ return ITEM_INTERACT_BLOCKING
+ return ITEM_INTERACT_COMPLETE
to_chat(user, "<span class='notice'>You hook [I] onto [src].</span>")
I.forceMove(src)
mybag = I
update_icon(UPDATE_OVERLAYS)
- return
+ return ITEM_INTERACT_SUCCESS
+ return ITEM_INTERACT_COMPLETE
+
if(istype(I, /obj/item/borg/upgrade/floorbuffer))
if(buffer_installed)
to_chat(user, fail_msg)
- return
+ return ITEM_INTERACT_BLOCKING
+ return ITEM_INTERACT_COMPLETE
buffer_installed = TRUE
qdel(I)
to_chat(user,"<span class='notice'>You upgrade [src] with [I].</span>")
update_icon(UPDATE_OVERLAYS)
- return
- if(istype(I, /obj/item/borg/upgrade/vtec) && floorbuffer)
+ return ITEM_INTERACT_SUCCESS
+ return ITEM_INTERACT_COMPLETE
+
+ if(mybag && user.a_intent == INTENT_HELP && !is_key(I))
+ mybag.attackby__legacy__attackchain(I, user)
+ return ITEM_INTERACT_ANY_BLOCKER
+ return ITEM_INTERACT_COMPLETE
+
+ return ..()
```
Expand Down
Loading

0 comments on commit bd6450d

Please sign in to comment.