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

<img width="419" height="185" alt="image"
src="https://github.com/user-attachments/assets/7223f025-d99c-4c09-883b-b53f29947c36"
/>

<img width="337" height="97" alt="image"
src="https://github.com/user-attachments/assets/321bf64f-df57-4da5-9951-a2795637cea3"
/>

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

🆑 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.
/🆑
This commit is contained in:
MrMelbert
2026-03-15 20:24:20 +00:00
committed by GitHub
parent 682f24be45
commit 0a61cce996
7 changed files with 181 additions and 62 deletions
@@ -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
@@ -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