mirror of
https://github.com/Bubberstation/Bubberstation.git
synced 2026-08-23 05:00:55 +01:00
Adds a visual hint to watcher gaze ability showing if you're going to be affected or not (#96636)
This commit is contained in:
@@ -17,12 +17,22 @@
|
||||
var/animation_time = 0.8 SECONDS
|
||||
/// How long after pressing the button do we give people to turn around?
|
||||
var/wait_delay = 1.6 SECONDS
|
||||
/// What are we currently displaying?
|
||||
/// What are we currently displaying to all mobs?
|
||||
var/image/current_overlay
|
||||
/// Image displayed for to-be-blinded victims
|
||||
var/image/danger_overlay
|
||||
/// Timer until we go to the next stage
|
||||
var/stage_timer
|
||||
/// Proximity monitor we use to keep track of possible targets
|
||||
var/datum/proximity_monitor/watcher_gaze/proximity_monitor
|
||||
/// List of textrefs to mobs in range we're currently displaying warnings to -> are they currently under threat or not
|
||||
var/list/tracked_mobs = list()
|
||||
|
||||
/datum/action/cooldown/mob_cooldown/watcher_gaze/Activate(mob/living/target)
|
||||
proximity_monitor = new(owner, effect_radius, ability = src)
|
||||
// Start tracking all potential victims in range as proxmon won't trigger on them
|
||||
for (var/mob/living/victim in viewers(effect_radius, owner))
|
||||
on_entered(victim)
|
||||
show_indicator_overlay("eye_open")
|
||||
stage_timer = addtimer(CALLBACK(src, PROC_REF(show_indicator_overlay), "eye_pulse"), animation_time, TIMER_STOPPABLE)
|
||||
StartCooldown(360 SECONDS, 360 SECONDS)
|
||||
@@ -33,14 +43,20 @@
|
||||
deltimer(stage_timer)
|
||||
clear_current_overlay()
|
||||
StartCooldown()
|
||||
tracked_mobs.Cut()
|
||||
QDEL_NULL(proximity_monitor)
|
||||
return TRUE
|
||||
|
||||
/datum/action/cooldown/mob_cooldown/watcher_gaze/Destroy()
|
||||
tracked_mobs.Cut()
|
||||
QDEL_NULL(proximity_monitor)
|
||||
deltimer(stage_timer)
|
||||
clear_current_overlay()
|
||||
return ..()
|
||||
|
||||
/datum/action/cooldown/mob_cooldown/watcher_gaze/Remove(mob/removed_from)
|
||||
tracked_mobs.Cut()
|
||||
QDEL_NULL(proximity_monitor)
|
||||
deltimer(stage_timer)
|
||||
clear_current_overlay()
|
||||
return ..()
|
||||
@@ -50,8 +66,7 @@
|
||||
deltimer(stage_timer)
|
||||
show_indicator_overlay("eye_flash")
|
||||
for (var/mob/living/viewer in viewers(effect_radius, owner))
|
||||
var/view_dir = get_dir(viewer, owner)
|
||||
if (!(viewer.dir & view_dir) || viewer.stat != CONSCIOUS)
|
||||
if (!valid_target(viewer))
|
||||
continue
|
||||
if (!apply_effect(viewer))
|
||||
continue
|
||||
@@ -67,6 +82,13 @@
|
||||
var/mob/living/living_owner = owner
|
||||
living_owner.Stun(1.5 SECONDS, ignore_canstun = TRUE)
|
||||
|
||||
/datum/action/cooldown/mob_cooldown/watcher_gaze/proc/valid_target(mob/living/viewer)
|
||||
if (!istype(viewer) || viewer.stat || viewer == owner)
|
||||
return FALSE
|
||||
if (!(viewer.dir & get_dir(viewer, owner)))
|
||||
return FALSE
|
||||
return TRUE
|
||||
|
||||
/// Do something bad to someone who was looking at us
|
||||
/datum/action/cooldown/mob_cooldown/watcher_gaze/proc/apply_effect(mob/living/viewer)
|
||||
if (!viewer.flash_act(intensity = 4, affect_silicon = TRUE, visual = TRUE, length = 3 SECONDS))
|
||||
@@ -83,18 +105,88 @@
|
||||
/// Display an animated overlay over our head to indicate what's going on
|
||||
/datum/action/cooldown/mob_cooldown/watcher_gaze/proc/show_indicator_overlay(overlay_state)
|
||||
clear_current_overlay()
|
||||
current_overlay = image(icon = 'icons/effects/eldritch.dmi', loc = owner, icon_state = overlay_state, layer = ABOVE_ALL_MOB_LAYER)
|
||||
current_overlay = image(icon = 'icons/effects/eldritch.dmi', loc = owner, icon_state = "[overlay_state]_y", layer = ABOVE_ALL_MOB_LAYER)
|
||||
current_overlay.pixel_w = -owner.pixel_x
|
||||
current_overlay.pixel_z = 28
|
||||
SET_PLANE_EXPLICIT(current_overlay, ABOVE_LIGHTING_PLANE, owner)
|
||||
// This will cause turning to reset the animation *but* this is the best option
|
||||
// as modifying alpha requires readding the image to client.images for it to actually update
|
||||
danger_overlay = image(icon = 'icons/effects/eldritch.dmi', loc = owner, icon_state = overlay_state, layer = ABOVE_ALL_MOB_LAYER)
|
||||
danger_overlay.pixel_w = -owner.pixel_x
|
||||
danger_overlay.pixel_z = 28
|
||||
SET_PLANE_EXPLICIT(danger_overlay, ABOVE_LIGHTING_PLANE, owner)
|
||||
|
||||
for(var/client/add_to in GLOB.clients)
|
||||
add_to.images += current_overlay
|
||||
var/mob/living/victim = add_to.mob
|
||||
if (istype(victim) && tracked_mobs[REF(victim)])
|
||||
add_to.images += danger_overlay
|
||||
else
|
||||
add_to.images += current_overlay
|
||||
|
||||
/// Hide whatever overlay we are showing
|
||||
/datum/action/cooldown/mob_cooldown/watcher_gaze/proc/clear_current_overlay()
|
||||
if (!isnull(current_overlay))
|
||||
remove_image_from_clients(current_overlay, GLOB.clients)
|
||||
remove_image_from_clients(danger_overlay, GLOB.clients)
|
||||
current_overlay = null
|
||||
danger_overlay = null
|
||||
|
||||
/datum/action/cooldown/mob_cooldown/watcher_gaze/proc/on_entered(mob/living/arrived)
|
||||
if (arrived == owner)
|
||||
return
|
||||
// Already tracked
|
||||
if (isnull(tracked_mobs[REF(arrived)]))
|
||||
RegisterSignals(arrived, list(COMSIG_ATOM_POST_DIR_CHANGE, COMSIG_MOB_STATCHANGE), PROC_REF(update_state))
|
||||
update_state(arrived)
|
||||
|
||||
/datum/action/cooldown/mob_cooldown/watcher_gaze/proc/on_exited(mob/living/exited)
|
||||
if (exited == owner)
|
||||
return
|
||||
UnregisterSignal(exited, list(COMSIG_ATOM_POST_DIR_CHANGE, COMSIG_MOB_STATCHANGE))
|
||||
tracked_mobs -= REF(exited)
|
||||
if (current_overlay && exited.client)
|
||||
exited.client.images += current_overlay
|
||||
exited.client.images -= danger_overlay
|
||||
|
||||
/datum/action/cooldown/mob_cooldown/watcher_gaze/proc/update_state(mob/living/target)
|
||||
SIGNAL_HANDLER
|
||||
// Don't do viewers(), too costly and only applies for thermals anyways
|
||||
if (valid_target(target))
|
||||
if (!tracked_mobs[REF(target)])
|
||||
tracked_mobs[REF(target)] = TRUE
|
||||
if (current_overlay && target.client)
|
||||
target.client.images -= current_overlay
|
||||
target.client.images += danger_overlay
|
||||
else if (tracked_mobs[REF(target)] != FALSE) // Can be null
|
||||
tracked_mobs[REF(target)] = FALSE
|
||||
if (current_overlay && target.client)
|
||||
target.client.images += current_overlay
|
||||
target.client.images -= danger_overlay
|
||||
|
||||
// No need to refresh targets when the owner moves as the ability uses a do_after and will stop if the owner moves anyways
|
||||
/datum/proximity_monitor/watcher_gaze
|
||||
/// Ability we're linked to
|
||||
var/datum/action/cooldown/mob_cooldown/watcher_gaze/gaze = null
|
||||
|
||||
/datum/proximity_monitor/watcher_gaze/Destroy()
|
||||
gaze = null
|
||||
return ..()
|
||||
|
||||
/datum/proximity_monitor/watcher_gaze/New(atom/_host, range, _ignore_if_not_on_turf = TRUE, datum/action/cooldown/mob_cooldown/watcher_gaze/ability = null)
|
||||
. = ..()
|
||||
gaze = ability
|
||||
|
||||
/datum/proximity_monitor/watcher_gaze/on_entered(atom/source, atom/movable/arrived, turf/old_loc)
|
||||
if (source != host && arrived != host && isliving(arrived))
|
||||
gaze.on_entered(arrived)
|
||||
|
||||
/datum/proximity_monitor/watcher_gaze/on_uncrossed(atom/source, atom/movable/gone, direction)
|
||||
if (source != host && gone != host && isliving(gone))
|
||||
gaze.on_exited(gone)
|
||||
|
||||
/datum/proximity_monitor/watcher_gaze/on_initialized(turf/location, atom/created, init_flags)
|
||||
if (isliving(created))
|
||||
gaze.on_entered(created)
|
||||
|
||||
/// Magmawing glare burns you
|
||||
/datum/action/cooldown/mob_cooldown/watcher_gaze/fire
|
||||
|
||||
Reference in New Issue
Block a user