From 0a61cce996d3087e540838564e0534a3b330b4c3 Mon Sep 17 00:00:00 2001 From: MrMelbert <51863163+MrMelbert@users.noreply.github.com> Date: Sun, 15 Mar 2026 15:24:20 -0500 Subject: [PATCH] Refactor revenant abilities / they now indicate if they are unlocked (#95380) ## About The Pull Request Refactors Revenant abilities into a component Revenant abilities now indicate if they are locked image image They also more accurately update if they are un/usable (ie, if you enter a wall, they turn red.) Also, Revenants are no longer affected by gravity. They already weren't affected by gravity (as far as I could tell) this just prevents them from getting the no-grav alert. ## Why It's Good For The Game - Not all future Revenant abilities need to be an AOE spell - It makes them easier to parse at a glance (what powers you have / don't have / can use) ## Changelog :cl: Melbert qol: Revenant abilities indicate if they are locked, and better indicate if they are currently usable qol: Revenants are no longer alerted that they have no gravity (they always have gravity) refactor: Refactored Revenant abilities, report any oddities with them. /:cl: --- code/__DEFINES/dcs/signals/signals_spell.dm | 4 + .../antagonists/revenant/revenant_skill.dm | 124 ++++++++++++++++++ .../basic/space_fauna/revenant/_revenant.dm | 39 +++++- .../revenant/revenant_abilities.dm | 72 +++------- code/modules/spells/spell.dm | 3 + icons/mob/actions/actions_revenant.dmi | Bin 10664 -> 10942 bytes tgstation.dme | 1 + 7 files changed, 181 insertions(+), 62 deletions(-) create mode 100644 code/modules/antagonists/revenant/revenant_skill.dm diff --git a/code/__DEFINES/dcs/signals/signals_spell.dm b/code/__DEFINES/dcs/signals/signals_spell.dm index ebbdcc4e2be..1154eba338f 100644 --- a/code/__DEFINES/dcs/signals/signals_spell.dm +++ b/code/__DEFINES/dcs/signals/signals_spell.dm @@ -14,6 +14,10 @@ /// Return from before cast signals to prevent the spell from going on cooldown before aftercast. #define SPELL_NO_IMMEDIATE_COOLDOWN (1 << 2) +/// Sent from /datum/action/cooldown/spell/can_cast_check() to the spell: (feedback) +#define COMSIG_SPELL_CAN_CAST_CHECK "can_cast_spell" + // Return SPELL_CANCEL_CAST to prevent the spell from being cast + /// Sent to an mob when a [/datum/action/cooldown/spell] calls try_invoke() to the caster: (datum/action/cooldown/spell/spell, feedback) #define COMSIG_MOB_TRY_INVOKE_SPELL "try_invoke_spell" /// The spell gets canceled diff --git a/code/modules/antagonists/revenant/revenant_skill.dm b/code/modules/antagonists/revenant/revenant_skill.dm new file mode 100644 index 00000000000..e3259ba9143 --- /dev/null +++ b/code/modules/antagonists/revenant/revenant_skill.dm @@ -0,0 +1,124 @@ +/// Attach to revenant spells to make them cost essence to cast +/datum/component/revenant_ability + /// If it's locked, and needs to be unlocked before use + VAR_FINAL/locked = TRUE + /// How much essence it costs to unlock + var/unlock_amount = 100 + /// How much essence it costs to use + var/cast_amount = 50 + + /// How long it reveals the revenant + var/reveal_duration = 8 SECONDS + // How long it stuns the revenant + var/stun_duration = 2 SECONDS + + VAR_FINAL/image/locked_overlay + +/datum/component/revenant_ability/Initialize( + unlock_amount = 100, + cast_amount = 50, + reveal_duration = 8 SECONDS, + stun_duration = 2 SECONDS, +) + + if(!istype(parent, /datum/action/cooldown/spell)) + return COMPONENT_INCOMPATIBLE + + set_unlock_amount(unlock_amount) + set_cast_amount(cast_amount) + set_durations(reveal_duration, stun_duration) + + RegisterSignal(parent, COMSIG_SPELL_CAN_CAST_CHECK, PROC_REF(can_cast)) + RegisterSignal(parent, COMSIG_SPELL_BEFORE_CAST, PROC_REF(before_cast)) + RegisterSignal(parent, COMSIG_SPELL_AFTER_CAST, PROC_REF(after_cast)) + RegisterSignal(parent, COMSIG_ACTION_OVERLAY_APPLY, PROC_REF(add_locked_overlay)) + + locked_overlay = image('icons/mob/actions/actions_revenant.dmi', "locked") + +/datum/component/revenant_ability/vv_edit_var(var_name, var_value) + . = ..() + switch(var_name) + if(NAMEOF(src, unlock_amount)) + set_unlock_amount(var_value) + if(NAMEOF(src, cast_amount)) + set_cast_amount(var_value) + if(NAMEOF(src, reveal_duration), NAMEOF(src, stun_duration)) + set_durations(reveal_duration, stun_duration) + if(NAMEOF(src, locked)) + update_spell_name() + +/datum/component/revenant_ability/proc/update_spell_name() + var/datum/action/cooldown/spell/spell = parent + if(locked) + spell.name = "[initial(spell.name)] ([unlock_amount]SE)" + else + spell.name = "[initial(spell.name)] ([cast_amount]E)" + spell.build_all_button_icons() + +/datum/component/revenant_ability/proc/set_unlock_amount(new_value) + unlock_amount = new_value + update_spell_name() + +/datum/component/revenant_ability/proc/set_cast_amount(new_value) + cast_amount = new_value + update_spell_name() + +/datum/component/revenant_ability/proc/set_durations(new_reveal_duration, new_stun_duration) + reveal_duration = new_reveal_duration + stun_duration = new_stun_duration + +/datum/component/revenant_ability/proc/can_cast(datum/action/cooldown/spell/source, feedback) + SIGNAL_HANDLER + + var/mob/living/basic/revenant/ghost = source.owner + if(!istype(ghost)) + return NONE // just allow it anyways + + if(locked) + if(ghost.essence_excess >= unlock_amount) + return NONE + if(feedback) + to_chat(ghost, span_revenwarning("You don't have enough essence to unlock [initial(source.name)]!")) + return SPELL_CANCEL_CAST + + if(!ghost.cast_check(cast_amount, deduct_essence = FALSE, silent = !feedback)) + return SPELL_CANCEL_CAST + + return NONE + +/datum/component/revenant_ability/proc/before_cast(datum/action/cooldown/spell/source, atom/cast_on) + SIGNAL_HANDLER + + var/mob/living/basic/revenant/ghost = source.owner + if(!istype(ghost)) + return NONE // just allow it anyways + + if(locked) + if(ghost.unlock(unlock_amount)) + to_chat(ghost, span_revennotice("You have unlocked [initial(source.name)]!")) + locked = FALSE + update_spell_name() + else + to_chat(ghost, span_revenwarning("You don't have enough essence to unlock [initial(source.name)]!")) + return SPELL_CANCEL_CAST + + if(!ghost.cast_check(cast_amount, deduct_essence = TRUE, silent = FALSE)) + return SPELL_CANCEL_CAST + + return NONE + +/datum/component/revenant_ability/proc/after_cast(datum/action/cooldown/spell/source, atom/cast_on) + SIGNAL_HANDLER + + var/mob/living/caster = source.owner + if(reveal_duration > 0 SECONDS) + caster.apply_status_effect(/datum/status_effect/revenant/revealed, reveal_duration) + if(stun_duration > 0 SECONDS) + caster.apply_status_effect(/datum/status_effect/incapacitating/paralyzed/revenant, stun_duration) + +/datum/component/revenant_ability/proc/add_locked_overlay(datum/action/cooldown/spell/source, atom/movable/screen/movable/action_button/current_button, ...) + SIGNAL_HANDLER + + current_button.cut_overlay(locked_overlay) + if(locked) + current_button.add_overlay(locked_overlay) diff --git a/code/modules/mob/living/basic/space_fauna/revenant/_revenant.dm b/code/modules/mob/living/basic/space_fauna/revenant/_revenant.dm index 4aae0ffa2d7..436f8e27c89 100644 --- a/code/modules/mob/living/basic/space_fauna/revenant/_revenant.dm +++ b/code/modules/mob/living/basic/space_fauna/revenant/_revenant.dm @@ -160,6 +160,7 @@ /mob/living/basic/revenant/proc/update_revenant_appearance() SIGNAL_HANDLER update_appearance(UPDATE_ICON) + update_mob_action_buttons() /mob/living/basic/revenant/AltClickOn(atom/target) if(CAN_I_SEE(target)) @@ -321,6 +322,7 @@ return ADD_TRAIT(src, TRAIT_NO_TRANSFORM, REVENANT_STUNNED_TRAIT) dormant = TRUE + update_mob_action_buttons() visible_message( span_warning("[src] lets out a waning screech as violet mist swirls around its dissolving body!"), @@ -410,28 +412,39 @@ return TRUE -/mob/living/basic/revenant/proc/cast_check(essence_cost) +/mob/living/basic/revenant/proc/cast_check(essence_cost, deduct_essence = TRUE, silent = FALSE) if(QDELETED(src)) return var/turf/current = get_turf(src) if(isclosedturf(current)) - to_chat(src, span_revenwarning("You cannot use abilities from inside of a wall.")) + if(!silent) + to_chat(src, span_revenwarning("You cannot use abilities from inside of a wall.")) return FALSE for(var/obj/thing in current) if(!thing.density || thing.CanPass(src, get_dir(current, src))) continue - to_chat(src, span_revenwarning("You cannot use abilities inside of a dense object.")) + if(!silent) + to_chat(src, span_revenwarning("You cannot use abilities inside of a dense object.")) return FALSE + if(dormant) + if(!silent) + to_chat(src, span_revenwarning("Your powers lie dormant right now!")) + return SPELL_CANCEL_CAST + if(HAS_TRAIT(src, TRAIT_REVENANT_INHIBITED)) - to_chat(src, span_revenwarning("Your powers have been suppressed by a nullifying energy!")) + if(!silent) + to_chat(src, span_revenwarning("Your powers have been suppressed by a nullifying energy!")) return FALSE - if(!change_essence_amount(essence_cost, TRUE)) - to_chat(src, span_revenwarning("You lack the essence to use that ability.")) + essence_cost = abs(essence_cost) * -1 + var/has_essence = deduct_essence ? change_essence_amount(essence_cost, silent = TRUE) : (essence + essence_cost >= 0) + if(!has_essence) + if(!silent) + to_chat(src, span_revenwarning("You lack the essence to use that ability!")) return FALSE return TRUE @@ -455,6 +468,7 @@ incorporeal_move = INCORPOREAL_MOVE_JAUNT RemoveInvisibility(type) alpha = 255 + update_mob_action_buttons() /mob/living/basic/revenant/proc/change_essence_amount(essence_to_change_by, silent = FALSE, source = null) if(QDELETED(src)) @@ -478,6 +492,19 @@ to_chat(src, span_revenminor("Lost [essence_to_change_by]E [source ? "from [source]":""].")) return TRUE +/mob/living/basic/revenant/mob_negates_gravity() + return TRUE // i don't gotta explain shit + +/mob/living/basic/revenant/vv_edit_var(vname, vval) + . = ..() + if(vname == NAMEOF(src, essence) || vname == NAMEOF(src, max_essence) || vname == NAMEOF(src, essence_excess)) + update_health_hud() + update_mob_action_buttons() + +/mob/living/basic/revenant/Moved(atom/old_loc, movement_dir, forced, list/old_locs, momentum_change) + . = ..() + update_mob_action_buttons() + /mob/living/basic/revenant/proc/on_reflect(datum/source, atom/movable/reflecting_in, obj/effect/abstract/reflection) SIGNAL_HANDLER // powers are inhibited and we're not revealed so we can't project a reflect diff --git a/code/modules/mob/living/basic/space_fauna/revenant/revenant_abilities.dm b/code/modules/mob/living/basic/space_fauna/revenant/revenant_abilities.dm index d456f104218..2030315410c 100644 --- a/code/modules/mob/living/basic/space_fauna/revenant/revenant_abilities.dm +++ b/code/modules/mob/living/basic/space_fauna/revenant/revenant_abilities.dm @@ -20,13 +20,10 @@ antimagic_flags = MAGIC_RESISTANCE_HOLY spell_requirements = NONE - /// If it's locked, and needs to be unlocked before use - var/locked = TRUE /// How much essence it costs to unlock var/unlock_amount = 100 /// How much essence it costs to use var/cast_amount = 50 - /// How long it reveals the revenant var/reveal_duration = 8 SECONDS // How long it stuns the revenant @@ -34,64 +31,27 @@ /datum/action/cooldown/spell/aoe/revenant/New(Target) . = ..() - if(!isrevenant(target)) - stack_trace("[type] was given to a non-revenant mob, please don't.") - qdel(src) - return - - if(locked) - name = "[initial(name)] ([unlock_amount]SE)" - else - name = "[initial(name)] ([cast_amount]E)" - -/datum/action/cooldown/spell/aoe/revenant/can_cast_spell(feedback = TRUE) - . = ..() - if(!.) - return FALSE - if(!isrevenant(owner)) - stack_trace("[type] was owned by a non-revenant mob, please don't.") - return FALSE - - var/mob/living/basic/revenant/ghost = owner - if(ghost.dormant || HAS_TRAIT(ghost, TRAIT_REVENANT_INHIBITED)) - return FALSE - if(locked && ghost.essence_excess <= unlock_amount) - return FALSE - if(ghost.essence <= cast_amount) - return FALSE - - return TRUE + AddComponent(/datum/component/revenant_ability, \ + unlock_amount = unlock_amount, \ + cast_amount = cast_amount, \ + reveal_duration = reveal_duration, \ + stun_duration = stun_duration, \ + ) /datum/action/cooldown/spell/aoe/revenant/get_things_to_cast_on(atom/center) return RANGE_TURFS(aoe_radius, center) -/datum/action/cooldown/spell/aoe/revenant/before_cast(mob/living/basic/revenant/cast_on) +/datum/action/cooldown/spell/aoe/revenant/vv_edit_var(var_name, var_value) . = ..() - if(. & SPELL_CANCEL_CAST) - return - - if(locked) - if(!cast_on.unlock(unlock_amount)) - to_chat(cast_on, span_revenwarning("You don't have enough essence to unlock [initial(name)]!")) - reset_spell_cooldown() - return . | SPELL_CANCEL_CAST - - name = "[initial(name)] ([cast_amount]E)" - to_chat(cast_on, span_revennotice("You have unlocked [initial(name)]!")) - locked = FALSE - reset_spell_cooldown() - return . | SPELL_CANCEL_CAST - - if(!cast_on.cast_check(-cast_amount)) - reset_spell_cooldown() - return . | SPELL_CANCEL_CAST - -/datum/action/cooldown/spell/aoe/revenant/after_cast(mob/living/basic/revenant/cast_on) - . = ..() - if(reveal_duration > 0 SECONDS) - cast_on.apply_status_effect(/datum/status_effect/revenant/revealed, reveal_duration) - if(stun_duration > 0 SECONDS) - cast_on.apply_status_effect(/datum/status_effect/incapacitating/paralyzed/revenant, stun_duration) + // gross getcomp, but this is solely to make life easier for badmins/debug. sue me + var/datum/component/revenant_ability/rev_comp = GetComponent(/datum/component/revenant_ability) + switch(var_name) + if(NAMEOF(src, unlock_amount)) + rev_comp.set_unlock_amount(var_value) + if(NAMEOF(src, cast_amount)) + rev_comp.set_cast_amount(var_value) + if(NAMEOF(src, reveal_duration), NAMEOF(src, stun_duration)) + rev_comp.set_durations(reveal_duration, stun_duration) //Overload Light: Breaks a light that's online and sends out lightning bolts to all nearby people. /datum/action/cooldown/spell/aoe/revenant/overload diff --git a/code/modules/spells/spell.dm b/code/modules/spells/spell.dm index 5bdf8014769..ccbf0097cda 100644 --- a/code/modules/spells/spell.dm +++ b/code/modules/spells/spell.dm @@ -153,6 +153,9 @@ if(!owner) CRASH("[type] - can_cast_spell called on a spell without an owner!") + if(SEND_SIGNAL(src, COMSIG_SPELL_CAN_CAST_CHECK, feedback) & SPELL_CANCEL_CAST) + return FALSE + // Certain spells are not allowed on the centcom zlevel var/turf/caster_turf = get_turf(owner) // Spells which require being on the station diff --git a/icons/mob/actions/actions_revenant.dmi b/icons/mob/actions/actions_revenant.dmi index d657e8a3daebb3160ff2b85791e5e55b8db5b305..3b75c4c1d30c6f9d998b8accd53201e455378e7f 100644 GIT binary patch literal 10942 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 HzlHoCG+pS9 diff --git a/tgstation.dme b/tgstation.dme index f4ae7c525a4..da8503ddcfc 100644 --- a/tgstation.dme +++ b/tgstation.dme @@ -3563,6 +3563,7 @@ #include "code\modules\antagonists\revenant\haunted_item.dm" #include "code\modules\antagonists\revenant\revenant_antag.dm" #include "code\modules\antagonists\revenant\revenant_blight.dm" +#include "code\modules\antagonists\revenant\revenant_skill.dm" #include "code\modules\antagonists\revolution\enemy_of_the_state.dm" #include "code\modules\antagonists\revolution\revolution.dm" #include "code\modules\antagonists\revolution\revolution_handler.dm"