From bd96f4221aa882d15d4dfccaf812fa2ff31fb0bf Mon Sep 17 00:00:00 2001 From: SkyratBot <59378654+SkyratBot@users.noreply.github.com> Date: Wed, 24 Jul 2024 19:07:21 +0200 Subject: [PATCH] [MIRROR] Refactored the on_hit_effect into an element. (#29028) * Refactored the on_hit_effect into an element. (#85034) ## About The Pull Request on_hit_effect is now an element, which uses signals instead of callbacks. ## Why It's Good For The Game Easy peasy almost lemon squeezy. It's a good thing that I had made the AddElementTrait proc so we can manage multiple sources of a common element. It's much better to use signals than callbacks for components and datums with several possible sources, kinda like how it's been donw with the relay_attackers element. ## Changelog N/A * Refactored the on_hit_effect into an element. --------- Co-authored-by: Ghom <42542238+Ghommie@users.noreply.github.com> --- code/__DEFINES/dcs/signals/signals_datum.dm | 3 + code/__DEFINES/traits/declarations.dm | 2 + code/_globalvars/traits/_traits.dm | 1 + code/datums/components/on_hit_effect.dm | 93 --------------------- code/datums/elements/bane.dm | 55 ++++++------ code/datums/elements/lifesteal.dm | 11 ++- code/datums/elements/on_hit_effect.dm | 65 ++++++++++++++ code/datums/elements/venomous.dm | 19 +++-- tgstation.dme | 2 +- 9 files changed, 116 insertions(+), 135 deletions(-) delete mode 100644 code/datums/components/on_hit_effect.dm create mode 100644 code/datums/elements/on_hit_effect.dm diff --git a/code/__DEFINES/dcs/signals/signals_datum.dm b/code/__DEFINES/dcs/signals/signals_datum.dm index 0c998be1921..81224e7a58d 100644 --- a/code/__DEFINES/dcs/signals/signals_datum.dm +++ b/code/__DEFINES/dcs/signals/signals_datum.dm @@ -45,3 +45,6 @@ ///from /datum/bank_account/pay_debt(), after a portion or all the debt has been paid. #define COMSIG_BANK_ACCOUNT_DEBT_PAID "bank_account_debt_paid" + +///from /datum/component/on_hit_effect/send_signal(): (user, target, hit_zone) +#define COMSIG_ON_HIT_EFFECT "comsig_on_hit_effect" diff --git a/code/__DEFINES/traits/declarations.dm b/code/__DEFINES/traits/declarations.dm index c13d96922f7..d3a95aeb27e 100644 --- a/code/__DEFINES/traits/declarations.dm +++ b/code/__DEFINES/traits/declarations.dm @@ -701,6 +701,8 @@ Remember to update _globalvars/traits.dm if you're adding/removing/renaming trai #define TRAIT_HONKSPAMMING "trait_honkspamming" /// Required by the waddling element since there are multiple sources of it. #define TRAIT_WADDLING "trait_waddling" +/// Required by the on_hit_effect element, which is in turn added by other elements. +#define TRAIT_ON_HIT_EFFECT "trait_on_hit_effect" ///Used for managing KEEP_TOGETHER in [/atom/var/appearance_flags] #define TRAIT_KEEP_TOGETHER "keep-together" diff --git a/code/_globalvars/traits/_traits.dm b/code/_globalvars/traits/_traits.dm index 2b0186301fd..f61da4a70b3 100644 --- a/code/_globalvars/traits/_traits.dm +++ b/code/_globalvars/traits/_traits.dm @@ -59,6 +59,7 @@ GLOBAL_LIST_INIT(traits_by_type, list( "TRAIT_NOT_ENGRAVABLE" = TRAIT_NOT_ENGRAVABLE, "TRAIT_SPELLS_TRANSFER_TO_LOC" = TRAIT_SPELLS_TRANSFER_TO_LOC, "TRAIT_ODD_CUSTOMIZABLE_FOOD_INGREDIENT" = TRAIT_ODD_CUSTOMIZABLE_FOOD_INGREDIENT, + "TRAIT_ON_HIT_EFFECT" = TRAIT_ON_HIT_EFFECT, "TRAIT_RUNECHAT_HIDDEN" = TRAIT_RUNECHAT_HIDDEN, "TRAIT_SECLUDED_LOCATION" = TRAIT_SECLUDED_LOCATION, "TRAIT_SNOWSTORM_IMMUNE" = TRAIT_SNOWSTORM_IMMUNE, diff --git a/code/datums/components/on_hit_effect.dm b/code/datums/components/on_hit_effect.dm deleted file mode 100644 index 9d1d0474290..00000000000 --- a/code/datums/components/on_hit_effect.dm +++ /dev/null @@ -1,93 +0,0 @@ -/** - * ## On Hit Effect Component! - * - * Component for other elements/components to rely on for on-hit effects without duplicating the on-hit code. - * See Lifesteal, or bane for examples. - * - * THIS COULD EASILY SUPPORT COMPONENT_DUPE_ALLOWED but the getcomponent makes it throw errors. if you can figure that out feel free to readd the dupe types - */ -/datum/component/on_hit_effect - ///callback used by other components to apply effects - var/datum/callback/on_hit_callback - ///callback optionally used for more checks - var/datum/callback/extra_check_callback - ///optionally should we also apply the effect if thrown at something? - var/thrown_effect - -/datum/component/on_hit_effect/Initialize(on_hit_callback, extra_check_callback, thrown_effect = FALSE) - src.on_hit_callback = on_hit_callback - src.extra_check_callback = extra_check_callback - if(!(ismachinery(parent) || isstructure(parent) || isgun(parent) || isprojectilespell(parent) || isitem(parent) || isanimal_or_basicmob(parent) || isprojectile(parent))) - return ELEMENT_INCOMPATIBLE - src.thrown_effect = thrown_effect - -/datum/component/on_hit_effect/Destroy(force) - on_hit_callback = null - extra_check_callback = null - return ..() - -/datum/component/on_hit_effect/RegisterWithParent() - if(ismachinery(parent) || isstructure(parent) || isgun(parent) || isprojectilespell(parent)) - RegisterSignal(parent, COMSIG_PROJECTILE_ON_HIT, PROC_REF(on_projectile_hit)) - else if(isitem(parent)) - RegisterSignal(parent, COMSIG_ITEM_AFTERATTACK, PROC_REF(item_afterattack)) - else if(isanimal_or_basicmob(parent)) - RegisterSignal(parent, COMSIG_HOSTILE_POST_ATTACKINGTARGET, PROC_REF(hostile_attackingtarget)) - else if(isprojectile(parent)) - RegisterSignal(parent, COMSIG_PROJECTILE_SELF_ON_HIT, PROC_REF(on_projectile_self_hit)) - - if(thrown_effect) - RegisterSignal(parent, COMSIG_MOVABLE_IMPACT, PROC_REF(on_thrown_hit)) - -/datum/component/on_hit_effect/UnregisterFromParent() - UnregisterSignal(parent, list( - COMSIG_PROJECTILE_ON_HIT, - COMSIG_ITEM_AFTERATTACK, - COMSIG_HOSTILE_POST_ATTACKINGTARGET, - COMSIG_PROJECTILE_SELF_ON_HIT, - COMSIG_MOVABLE_IMPACT, - )) - -/datum/component/on_hit_effect/proc/item_afterattack(obj/item/source, atom/target, mob/user, proximity_flag, click_parameters) - SIGNAL_HANDLER - - if(!proximity_flag) - return - - if(extra_check_callback) - if(!extra_check_callback.Invoke(user, target, source)) - return - on_hit_callback.Invoke(source, user, target, user.zone_selected) - -/datum/component/on_hit_effect/proc/hostile_attackingtarget(mob/living/attacker, atom/target, success) - SIGNAL_HANDLER - - if(!success) - return - - if(extra_check_callback) - if(!extra_check_callback.Invoke(attacker, target)) - return - on_hit_callback.Invoke(attacker, attacker, target, attacker.zone_selected) - -/datum/component/on_hit_effect/proc/on_projectile_hit(datum/fired_from, atom/movable/firer, atom/target, angle, body_zone) - SIGNAL_HANDLER - - if(extra_check_callback) - if(!extra_check_callback.Invoke(firer, target)) - return - on_hit_callback.Invoke(fired_from, firer, target, body_zone) - -/datum/component/on_hit_effect/proc/on_projectile_self_hit(datum/source, mob/firer, atom/target, angle, body_zone) - SIGNAL_HANDLER - - if(extra_check_callback) - if(!extra_check_callback.Invoke(firer, target)) - return - on_hit_callback.Invoke(source, firer, target, body_zone) - -/datum/component/on_hit_effect/proc/on_thrown_hit(datum/source, atom/hit_atom, datum/thrownthing/throwingdatum) - SIGNAL_HANDLER - if(extra_check_callback && !extra_check_callback.Invoke(source, hit_atom)) - return - on_hit_callback.Invoke(source, source, hit_atom, null) diff --git a/code/datums/elements/bane.dm b/code/datums/elements/bane.dm index 3c37c327412..95e21251657 100644 --- a/code/datums/elements/bane.dm +++ b/code/datums/elements/bane.dm @@ -27,40 +27,20 @@ src.added_damage = added_damage src.requires_combat_mode = requires_combat_mode src.mob_biotypes = mob_biotypes - target.AddComponent(/datum/component/on_hit_effect, CALLBACK(src, PROC_REF(do_bane)), CALLBACK(src, PROC_REF(check_bane))) + target.AddElementTrait(TRAIT_ON_HIT_EFFECT, REF(src), /datum/element/on_hit_effect) + RegisterSignal(target, COMSIG_ON_HIT_EFFECT, PROC_REF(do_bane)) -/datum/element/bane/Detach(datum/target) - qdel(target.GetComponent(/datum/component/on_hit_effect)) +/datum/element/bane/Detach(datum/source) + UnregisterSignal(source, COMSIG_ON_HIT_EFFECT) + REMOVE_TRAIT(source, TRAIT_ON_HIT_EFFECT, REF(src)) return ..() -/datum/element/bane/proc/check_bane(bane_applier, target, bane_weapon) - if(!check_biotype_path(bane_applier, target)) +/datum/element/bane/proc/do_bane(datum/element_owner, mob/living/bane_applier, mob/living/baned_target, hit_zone, throw_hit) + if(!check_biotype_path(bane_applier, baned_target)) return - var/atom/movable/atom_owner = bane_weapon - if(SEND_SIGNAL(atom_owner, COMSIG_OBJECT_PRE_BANING, target) & COMPONENT_CANCEL_BANING) + if(SEND_SIGNAL(element_owner, COMSIG_OBJECT_PRE_BANING, baned_target) & COMPONENT_CANCEL_BANING) return - return TRUE -/** - * Checks typepaths and the mob's biotype, returning TRUE if correct and FALSE if wrong. - * Additionally checks if combat mode is required, and if so whether it's enabled or not. - */ -/datum/element/bane/proc/check_biotype_path(mob/living/bane_applier, atom/target) - if(!isliving(target)) - return FALSE - var/mob/living/living_target = target - if(bane_applier) - if(requires_combat_mode && !bane_applier.combat_mode) - return FALSE - var/is_correct_biotype = living_target.mob_biotypes & mob_biotypes - if(mob_biotypes && !(is_correct_biotype)) - return FALSE - if(ispath(target_type, /mob/living)) - return istype(living_target, target_type) - else //species type - return is_species(living_target, target_type) - -/datum/element/bane/proc/do_bane(datum/element_owner, mob/living/bane_applier, mob/living/baned_target, hit_zone) var/force_boosted var/applied_dam_type @@ -91,3 +71,22 @@ baned_target.apply_damage(extra_damage, applied_dam_type, hit_zone) SEND_SIGNAL(baned_target, COMSIG_LIVING_BANED, bane_applier, baned_target) // for extra effects when baned. SEND_SIGNAL(element_owner, COMSIG_OBJECT_ON_BANING, baned_target) + +/** + * Checks typepaths and the mob's biotype, returning TRUE if correct and FALSE if wrong. + * Additionally checks if combat mode is required, and if so whether it's enabled or not. + */ +/datum/element/bane/proc/check_biotype_path(mob/living/bane_applier, atom/target) + if(!isliving(target)) + return FALSE + var/mob/living/living_target = target + if(bane_applier) + if(requires_combat_mode && !bane_applier.combat_mode) + return FALSE + var/is_correct_biotype = living_target.mob_biotypes & mob_biotypes + if(mob_biotypes && !(is_correct_biotype)) + return FALSE + if(ispath(target_type, /mob/living)) + return istype(living_target, target_type) + else //species type + return is_species(living_target, target_type) diff --git a/code/datums/elements/lifesteal.dm b/code/datums/elements/lifesteal.dm index 48f812fc1f1..ed607c34976 100644 --- a/code/datums/elements/lifesteal.dm +++ b/code/datums/elements/lifesteal.dm @@ -13,13 +13,16 @@ /datum/element/lifesteal/Attach(datum/target, flat_heal = 10) . = ..() src.flat_heal = flat_heal - target.AddComponent(/datum/component/on_hit_effect, CALLBACK(src, PROC_REF(do_lifesteal))) + target.AddElementTrait(TRAIT_ON_HIT_EFFECT, REF(src), /datum/element/on_hit_effect) + RegisterSignal(target, COMSIG_ON_HIT_EFFECT, PROC_REF(do_lifesteal)) -/datum/element/lifesteal/Detach(datum/target) - qdel(target.GetComponent(/datum/component/on_hit_effect)) +/datum/element/lifesteal/Detach(datum/source) + UnregisterSignal(source, COMSIG_ON_HIT_EFFECT) + REMOVE_TRAIT(source, TRAIT_ON_HIT_EFFECT, REF(src)) return ..() -/datum/element/lifesteal/proc/do_lifesteal(datum/element_owner, atom/heal_target, atom/damage_target, hit_zone) +/datum/element/lifesteal/proc/do_lifesteal(datum/source, atom/heal_target, atom/damage_target, hit_zone, throw_hit) + SIGNAL_HANDLER if(isliving(heal_target) && isliving(damage_target)) var/mob/living/healing = heal_target var/mob/living/damaging = damage_target diff --git a/code/datums/elements/on_hit_effect.dm b/code/datums/elements/on_hit_effect.dm new file mode 100644 index 00000000000..f84a6cafa6f --- /dev/null +++ b/code/datums/elements/on_hit_effect.dm @@ -0,0 +1,65 @@ +/** + * ## On Hit Effect Component! + * + * Component for other elements/components to rely on for on-hit effects without duplicating the on-hit code. + * See Lifesteal, or bane for examples. + */ +/datum/element/on_hit_effect + +/datum/element/on_hit_effect/Attach(datum/target) + . = ..() + if(!HAS_TRAIT(target, TRAIT_ON_HIT_EFFECT)) + stack_trace("[type] added to [target] without adding TRAIT_ON_HIT_EFFECT first. Please use AddElementTrait instead.") + if(ismachinery(target) || isstructure(target) || isgun(target) || isprojectilespell(target)) + RegisterSignal(target, COMSIG_PROJECTILE_ON_HIT, PROC_REF(on_projectile_hit)) + else if(isitem(target)) + RegisterSignal(target, COMSIG_ITEM_AFTERATTACK, PROC_REF(item_afterattack)) + else if(isanimal_or_basicmob(target)) + RegisterSignal(target, COMSIG_HOSTILE_POST_ATTACKINGTARGET, PROC_REF(hostile_attackingtarget)) + else if(isprojectile(target)) + RegisterSignal(target, COMSIG_PROJECTILE_SELF_ON_HIT, PROC_REF(on_projectile_self_hit)) + else + return ELEMENT_INCOMPATIBLE + + RegisterSignal(target, COMSIG_MOVABLE_IMPACT, PROC_REF(on_thrown_hit)) + +/datum/element/on_hit_effect/Detach(datum/source) + UnregisterSignal(source, list( + COMSIG_PROJECTILE_ON_HIT, + COMSIG_ITEM_AFTERATTACK, + COMSIG_HOSTILE_POST_ATTACKINGTARGET, + COMSIG_PROJECTILE_SELF_ON_HIT, + COMSIG_MOVABLE_IMPACT, + )) + return ..() + +/datum/element/on_hit_effect/proc/item_afterattack(obj/item/source, atom/target, mob/user, proximity_flag, click_parameters) + SIGNAL_HANDLER + + if(!proximity_flag) + return + + on_hit(source, user, target, user.zone_selected) + +/datum/element/on_hit_effect/proc/hostile_attackingtarget(mob/living/attacker, atom/target, success) + SIGNAL_HANDLER + + if(!success) + return + + on_hit(attacker, attacker, target, attacker.zone_selected) + +/datum/element/on_hit_effect/proc/on_projectile_hit(datum/fired_from, atom/movable/firer, atom/target, angle, body_zone) + SIGNAL_HANDLER + on_hit(fired_from, firer, target, body_zone) + +/datum/element/on_hit_effect/proc/on_projectile_self_hit(datum/source, mob/firer, atom/target, angle, body_zone) + SIGNAL_HANDLER + on_hit(source, firer, target, body_zone) + +/datum/element/on_hit_effect/proc/on_thrown_hit(datum/source, atom/hit_atom, datum/thrownthing/throwingdatum) + SIGNAL_HANDLER + on_hit(source, source, hit_atom, null, TRUE) + +/datum/element/on_hit_effect/proc/on_hit(atom/source, atom/movable/attacker, atom/target, body_zone, throw_hit = FALSE) + SEND_SIGNAL(source, COMSIG_ON_HIT_EFFECT, attacker, target, body_zone, throw_hit) diff --git a/code/datums/elements/venomous.dm b/code/datums/elements/venomous.dm index ba4e088750c..9f9e4940df1 100644 --- a/code/datums/elements/venomous.dm +++ b/code/datums/elements/venomous.dm @@ -12,24 +12,25 @@ var/injection_flags ///How much of the reagent added. if it's a list, it'll pick a range with the range being list(lower_value, upper_value) var/list/amount_added + ///Does this trigger when thrown? + var/thrown_effect = FALSE /datum/element/venomous/Attach(datum/target, poison_type, amount_added, injection_flags = NONE, thrown_effect = FALSE) . = ..() src.poison_type = poison_type src.amount_added = amount_added src.injection_flags = injection_flags - target.AddComponent(\ - /datum/component/on_hit_effect,\ - on_hit_callback = CALLBACK(src, PROC_REF(do_venom)),\ - thrown_effect = thrown_effect,\ - ) + src.thrown_effect = thrown_effect + target.AddElementTrait(TRAIT_ON_HIT_EFFECT, REF(src), /datum/element/on_hit_effect) + RegisterSignal(target, COMSIG_ON_HIT_EFFECT, PROC_REF(do_venom)) -/datum/element/venomous/Detach(datum/target) - qdel(target.GetComponent(/datum/component/on_hit_effect)) +/datum/element/venomous/Detach(datum/source) + UnregisterSignal(source, COMSIG_ON_HIT_EFFECT) + REMOVE_TRAIT(source, TRAIT_ON_HIT_EFFECT, REF(src)) return ..() -/datum/element/venomous/proc/do_venom(datum/element_owner, atom/venom_source, mob/living/target, hit_zone) - if(!istype(target)) +/datum/element/venomous/proc/do_venom(datum/element_owner, atom/venom_source, mob/living/target, hit_zone, throw_hit) + if((throw_hit && !thrown_effect) || !istype(target)) return if(target.stat == DEAD) return diff --git a/tgstation.dme b/tgstation.dme index 0e64fd92852..523cc8d8b4f 100644 --- a/tgstation.dme +++ b/tgstation.dme @@ -1249,7 +1249,6 @@ #include "code\datums\components\nuclear_bomb_operator.dm" #include "code\datums\components\object_possession.dm" #include "code\datums\components\omen.dm" -#include "code\datums\components\on_hit_effect.dm" #include "code\datums\components\onwear_mood.dm" #include "code\datums\components\orbiter.dm" #include "code\datums\components\overlay_lighting.dm" @@ -1594,6 +1593,7 @@ #include "code\datums\elements\noisy_movement.dm" #include "code\datums\elements\noticable_organ.dm" #include "code\datums\elements\obj_regen.dm" +#include "code\datums\elements\on_hit_effect.dm" #include "code\datums\elements\only_pull_living.dm" #include "code\datums\elements\openspace_item_click_handler.dm" #include "code\datums\elements\ore_collecting.dm"