Files
Bubberstation/code/datums/components/revenge_ability.dm
Jacquerel 2aeeed086f Basic Dark Wizards (#89147)
## About The Pull Request

Simple animal Dark Wizard => Basic mob Dark Wizard.
This mob is I think used in literally one ruin, and very occasionally
spawned in deathmatch.
They don't really do anything except shoot you with slowing projectiles
and hit you with sticks.

I gave them a version of blink with a longer cooldown that they use when
attacked in melee range purely to make them very marginally more
wizard-like, and they will also now try to back away from you while
shooting you instead of running towards you.

They will also retaliate against anyone who attacks them including as a
response to friendly fire from other Dark Wizards, because I think it is
funny if they have very little loyalty to each other and that's a fun
thing to trigger when you are playing Doom.

Finally, we have a component called "revenge ability" which is mostly a
standin for AI responses to getting attacked. I made all existing uses
of it turn off if you're controlled by a sapient player who can hit
those buttons themselves, because they can choose when they want to use
those abilities themselves.

## Why It's Good For The Game

The march of progress is almost complete

## Changelog

🆑
refactor: refactored some code
balance: Dark Wizards now teleport when attacked, but are more likely to
turn on their allies
/🆑
2025-01-22 20:50:07 -07:00

61 lines
2.3 KiB
Plaintext

/**
* Automatically triggers a linked ability at a target who attacks us.
* The ability might not necessarily be on our mob.
* Make sure that /datum/element/relay_attackers is also present or you'll never receive the triggering signal.
*/
/datum/component/revenge_ability
dupe_mode = COMPONENT_DUPE_ALLOWED
/// The ability to use when we are attacked
var/datum/action/cooldown/ability
/// Optional datum for validating targets
var/datum/targeting_strategy/targeting
/// Trigger only if target is at least this far away
var/min_range
/// Trigger only if target is at least this close
var/max_range
/// Target the ability at ourself instead of at the offender
var/target_self
/// Should this behavoid continue if our mob is sapient?
var/activate_with_mind
/datum/component/revenge_ability/Initialize(datum/action/cooldown/ability, datum/targeting_strategy/targeting, min_range = 0, max_range = INFINITY, target_self = FALSE, activate_with_mind = FALSE)
. = ..()
if (!isliving(parent))
return COMPONENT_INCOMPATIBLE
src.ability = ability
src.targeting = targeting
src.min_range = min_range
src.max_range = max_range
src.target_self = target_self
src.activate_with_mind = activate_with_mind
RegisterSignal(ability, COMSIG_QDELETING, PROC_REF(ability_destroyed))
/datum/component/revenge_ability/RegisterWithParent()
. = ..()
RegisterSignal(parent, COMSIG_ATOM_WAS_ATTACKED, PROC_REF(on_attacked))
/datum/component/revenge_ability/UnregisterFromParent()
UnregisterSignal(parent, COMSIG_ATOM_WAS_ATTACKED)
if (ability)
UnregisterSignal(ability, COMSIG_QDELETING)
return ..()
/// If we were attacked, get revenge
/datum/component/revenge_ability/proc/on_attacked(mob/living/victim, atom/attacker)
SIGNAL_HANDLER
if (victim.mind && !activate_with_mind)
return // This is mostly a component for the use of AI
var/atom/ability_user = ability.owner
var/distance = get_dist(ability_user, attacker)
if (distance < min_range || distance > max_range)
return
if (targeting && !targeting.can_attack(victim, attacker))
return
INVOKE_ASYNC(ability, TYPE_PROC_REF(/datum/action/cooldown, InterceptClickOn), ability_user, null, (target_self) ? ability_user : attacker)
/// For whatever reason we lost our linked ability so we can drop this behaviour
/datum/component/revenge_ability/proc/ability_destroyed(datum/source)
SIGNAL_HANDLER
qdel(src)