mirror of
https://github.com/Bubberstation/Bubberstation.git
synced 2025-12-11 10:11:09 +00:00
## About The Pull Request and also Why It's Good For The Game Lately I noticed that watchers display the do_after "working" cog while channeling their "look away" ability, which looks silly because it already has its own indicator. That should be hidden.  Actually now I look at this gif again the offset on the cog is fucked up, probably need to update that for larger-than-usual mobs... While I was at it I also added "hidden" to mob basic attack forecasts. I can't think it's _likely_ that anyone will add a mob with a > 1 second forecast (they are only displayed if the length is at least one second) but it's not totally impossible. ## Changelog 🆑 image: Watchers won't display an animated cog at the same time as using their gaze attack. /🆑
108 lines
4.1 KiB
Plaintext
108 lines
4.1 KiB
Plaintext
/**
|
|
* Delays outgoing attacks which are directed at mobs to give players time to get out of the way
|
|
*/
|
|
/datum/component/basic_mob_attack_telegraph
|
|
/// Time to wait before attack can complete
|
|
var/telegraph_duration
|
|
/// Overlay which we display over targets
|
|
var/mutable_appearance/target_overlay
|
|
/// Our current target, if we have one
|
|
var/mob/living/current_target
|
|
/// Callback executed when we start aiming at something
|
|
var/datum/callback/on_began_forecast
|
|
|
|
/datum/component/basic_mob_attack_telegraph/Initialize(
|
|
telegraph_icon = 'icons/mob/telegraphing/telegraph.dmi',
|
|
telegraph_state = ATTACK_EFFECT_BITE,
|
|
display_telegraph_overlay = TRUE,
|
|
telegraph_duration = 0.4 SECONDS,
|
|
datum/callback/on_began_forecast,
|
|
)
|
|
. = ..()
|
|
if (!isbasicmob(parent) && !ishostile(parent))
|
|
return ELEMENT_INCOMPATIBLE
|
|
|
|
if(display_telegraph_overlay)
|
|
target_overlay = mutable_appearance(telegraph_icon, telegraph_state)
|
|
|
|
src.telegraph_duration = telegraph_duration
|
|
src.on_began_forecast = on_began_forecast
|
|
|
|
/datum/component/basic_mob_attack_telegraph/Destroy(force)
|
|
if(current_target)
|
|
forget_target(current_target)
|
|
target_overlay = null
|
|
on_began_forecast = null
|
|
return ..()
|
|
|
|
/datum/component/basic_mob_attack_telegraph/RegisterWithParent()
|
|
. = ..()
|
|
RegisterSignal(parent, COMSIG_HOSTILE_PRE_ATTACKINGTARGET, PROC_REF(on_attack))
|
|
|
|
/datum/component/basic_mob_attack_telegraph/UnregisterFromParent()
|
|
if (current_target)
|
|
forget_target(current_target)
|
|
QDEL_NULL(target_overlay)
|
|
REMOVE_TRAIT(parent, TRAIT_BASIC_ATTACK_FORECAST, REF(src))
|
|
UnregisterSignal(parent, COMSIG_HOSTILE_PRE_ATTACKINGTARGET)
|
|
return ..()
|
|
|
|
/// When we attempt to attack, check if it is allowed
|
|
/datum/component/basic_mob_attack_telegraph/proc/on_attack(mob/living/basic/source, atom/target)
|
|
SIGNAL_HANDLER
|
|
if (!(isliving(target) || ismecha(target))) // Curse you CLARKE
|
|
return
|
|
if (HAS_TRAIT_FROM(source, TRAIT_BASIC_ATTACK_FORECAST, REF(src)))
|
|
REMOVE_TRAIT(source, TRAIT_BASIC_ATTACK_FORECAST, REF(src))
|
|
return
|
|
|
|
if (!DOING_INTERACTION(source, INTERACTION_BASIC_ATTACK_FORCEAST))
|
|
INVOKE_ASYNC(src, PROC_REF(delayed_attack), source, target)
|
|
return COMPONENT_HOSTILE_NO_ATTACK
|
|
|
|
/// Perform an attack after a delay
|
|
/datum/component/basic_mob_attack_telegraph/proc/delayed_attack(mob/living/source, atom/target)
|
|
current_target = target
|
|
|
|
if(target_overlay)
|
|
RegisterSignal(target, COMSIG_ATOM_UPDATE_OVERLAYS, PROC_REF(on_target_overlays_update))
|
|
target.update_appearance()
|
|
|
|
RegisterSignal(target, COMSIG_QDELETING, PROC_REF(forget_target))
|
|
RegisterSignal(target, COMSIG_MOVABLE_MOVED, PROC_REF(target_moved))
|
|
|
|
on_began_forecast?.Invoke(target)
|
|
//we stop the do_after if the target moves out of neighboring turfs but if they dance around us they get their face smashed
|
|
if (!do_after(source, delay = telegraph_duration, target = target, timed_action_flags = IGNORE_TARGET_LOC_CHANGE, extra_checks = CALLBACK(source, TYPE_PROC_REF(/atom/movable, Adjacent), target), interaction_key = INTERACTION_BASIC_ATTACK_FORCEAST, hidden = TRUE))
|
|
forget_target(target)
|
|
return
|
|
if (isnull(target)) // They got out of the way :(
|
|
return
|
|
ADD_TRAIT(source, TRAIT_BASIC_ATTACK_FORECAST, REF(src))
|
|
forget_target(target)
|
|
if(isbasicmob(source))
|
|
var/mob/living/basic/basic_source = source
|
|
basic_source.melee_attack(target, ignore_cooldown = TRUE) // We already started the cooldown when we triggered the forecast
|
|
return
|
|
var/mob/living/simple_animal/hostile/hostile_source = source
|
|
hostile_source.AttackingTarget(target)
|
|
|
|
/// The guy we're trying to attack moved, is he still in range?
|
|
/datum/component/basic_mob_attack_telegraph/proc/target_moved(atom/target)
|
|
SIGNAL_HANDLER
|
|
if (in_range(parent, target))
|
|
return
|
|
forget_target(target)
|
|
|
|
/// The guy we're trying to attack isn't a valid target any more
|
|
/datum/component/basic_mob_attack_telegraph/proc/forget_target(atom/target)
|
|
SIGNAL_HANDLER
|
|
current_target = null
|
|
target.update_appearance()
|
|
UnregisterSignal(target, list(COMSIG_QDELETING, COMSIG_MOVABLE_MOVED, COMSIG_ATOM_UPDATE_OVERLAYS))
|
|
|
|
/datum/component/basic_mob_attack_telegraph/proc/on_target_overlays_update(atom/parent_atom, list/overlays)
|
|
SIGNAL_HANDLER
|
|
if(parent_atom == current_target)
|
|
overlays += target_overlay
|