From 4146b973f083633c22516b96e121cf8e736d8343 Mon Sep 17 00:00:00 2001 From: warriorstar-orion Date: Thu, 5 Dec 2024 00:27:36 -0500 Subject: [PATCH] Attack Chain Migration: /obj/item/airlock_electronics/destroyed (#27538) * Attack Chain Migration: /obj/item/airlock_electronics/destroyed * don't register signals on global procs --- code/_onclick/item_attack.dm | 13 ++++++++ .../machinery/doors/airlock_electronics.dm | 7 +++-- docs/references/attack_chain.md | 31 +++++++++++++++++++ 3 files changed, 49 insertions(+), 2 deletions(-) diff --git a/code/_onclick/item_attack.dm b/code/_onclick/item_attack.dm index 94836bb8663e..afc536d096d5 100644 --- a/code/_onclick/item_attack.dm +++ b/code/_onclick/item_attack.dm @@ -274,3 +274,16 @@ "You hear someone being attacked with a weapon!" ) return TRUE + +/// Used for signal registrars who wish to completely ignore all behavior +/// in the attack chain from parent types. Should be used sparingly, as +/// subtypes are meant to build on behavior from the parent type. +/datum/proc/signal_cancel_activate_self(mob/user) + return COMPONENT_CANCEL_ATTACK_CHAIN + +/// Used for signal registrars who wish to completely ignore all behavior +/// in the attack chain from parent types calling `attack_by`. Should be +/// used sparingly, as subtypes are meant to build on behavior from the parent +/// type. +/datum/proc/signal_cancel_attack_by(datum/source, obj/item/attacking, mob/user, params) + return COMPONENT_SKIP_AFTERATTACK diff --git a/code/game/machinery/doors/airlock_electronics.dm b/code/game/machinery/doors/airlock_electronics.dm index 1cac4728de0d..044482c6d8d9 100644 --- a/code/game/machinery/doors/airlock_electronics.dm +++ b/code/game/machinery/doors/airlock_electronics.dm @@ -21,6 +21,8 @@ /// Is this electronic installed in a door? var/is_installed = FALSE + new_attack_chain = TRUE + /obj/item/airlock_electronics/Initialize(mapload) . = ..() if(!length(door_accesses_list)) @@ -108,8 +110,9 @@ name = "burned-out airlock electronics" icon_state = "door_electronics_smoked" -/obj/item/airlock_electronics/destroyed/attack_self__legacy__attackchain(mob/user) - return +/obj/item/airlock_electronics/destroyed/Initialize(mapload) + . = ..() + RegisterSignal(src, COMSIG_ACTIVATE_SELF, TYPE_PROC_REF(/datum, signal_cancel_activate_self)) /obj/item/airlock_electronics/destroyed/decompile_act(obj/item/matter_decompiler/C, mob/user) C.stored_comms["metal"] += 1 diff --git a/docs/references/attack_chain.md b/docs/references/attack_chain.md index 6c8bb35f61cb..5a159c2a00d7 100644 --- a/docs/references/attack_chain.md +++ b/docs/references/attack_chain.md @@ -595,6 +595,37 @@ sequence of events. Finally, because we constantly check the parent proc, all signals that are expected to be sent, are, so any other components or listeners can take appropriate action and cancel the attack chain themselves, if requested. +### Cancelling All Behavior + +Frequently, a subtype will want to completely prevent any of its parent type +behavior from running. Examples may be a holofloor, which should prevent any +attempts to deconstruct it, or a destroyed variant of an object, which cancels +out the existing functionality of the parent type. + +Attack chain methods must always call their parent procs, so this presents a +problem. + +In order to implement behavior such as this, the child type should register to +listen for the signal that applies to the attack chain proc, and respond by +calling one of the procs which return a signal preventing the rest of the attack +chain from running. + +For `attack_by` prevention, this proc is [/datum/proc/signal_cancel_attack_by][]. For +`activate_self` prevention, this proc is [/datum/proc/signal_cancel_activate_self][]. + +[/datum/proc/signal/cancel_attack_by]: https://codedocs.paradisestation.org/datum.html#proc/signal_cancel_attack_by +[/datum/proc/signal/cancel_activate_self]: https://codedocs.paradisestation.org/datum.html#proc/signal_cancel_activate_self + +For example, when we migrated the airlock electronics above, we neglected to +handle the `/destroyed` subtype, which prevents any interaction via +`activate_self`. To ensure this, we make the following change: + +```diff ++/obj/item/airlock_electronics/destroyed/Initialize(mapload) ++ . = ..() ++ RegisterSignal(src, COMSIG_ACTIVATE_SELF, TYPE_PROC_REF(/datum, signal_cancel_activate_self)) +``` + ## Migration Helpers There are two important tools which can help make the migration process easier: