Files
Aurora.3/code/modules/vision_cone/vision_cone.dm
mikomyazaki 16485289d6 Vision cones (#9624)
aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
2020-09-21 22:44:32 +03:00

222 lines
5.8 KiB
Plaintext

/////////////VISION CONE///////////////
// Vision cone code by Honkertron (for Otuska), Matt and Myazaki.
// This vision cone code allows for mobs and/or items to be blocked out from a player's field of vision.
// This code makes use of the "cone of effect" proc created by Lummox, contributed by Jtgibson.
//
// More info on that here:
// http://www.byond.com/forum/?post=195138
///////////////////////////////////////
/client
var/list/hidden_atoms = list()
var/list/hidden_mobs = list()
/proc/cone(turf/center, dir, list/list)
. = list()
for(var/turf/T in list)
if(T.InConeDirection(center, dir))
for(var/mob/M in T.contents)
if(!istype(M, /mob/abstract))
. += M.InCone(center, dir)
/turf/proc/InConeDirection(turf/center, dir)
if(get_dist(center, src) == 0 || src == center) return 0
var/d = get_dir(center, src)
if(!d || d == dir) return 1
if(dir & (dir-1))
return (d & ~dir) ? 0 : 1
if(!(d & dir)) return 0
var/dx = abs(x - center.x)
var/dy = abs(y - center.y)
if(dx == dy) return 1
if(dy > dx)
return (dir & (NORTH|SOUTH)) ? 1 : 0
return (dir & (EAST|WEST)) ? 1 : 0
/mob/living/proc/toggle_vision_cone()
set name = "Toggle Vision Cone"
set category = "OOC"
set desc = "Toggle the ability to have a vision cone"
can_have_vision_cone = !can_have_vision_cone
check_fov()
// Should return atoms that are in the cone.
/atom/proc/InCone(turf/center, dir)
SHOULD_CALL_PARENT(TRUE)
return list()
/mob/dead/InCone(turf/center, dir)
. = ..()
/mob/InCone(turf/center, dir)
. = ..() | src
/mob/living/InCone(turf/center, dir)
. = ..()
if(pulling)
. += pulling
/mob/proc/update_vision_cone()
return
/mob/living/update_vision_cone()
if(!can_have_vision_cone)
if(vision_cone_overlay)
remove_cone()
return
for(var/obj/item/item in src)
if(item.zoom)
remove_cone()
return
var/delay = 1 SECONDS
if(client)
var/image/I = null
for(I in client.hidden_atoms)
I.override = FALSE
QDEL_IN(I, delay)
delay += 1 SECONDS
check_fov()
client.hidden_atoms.Cut()
client.hidden_mobs.Cut()
if(resting || lying)
hide_cone()
return
vision_cone_overlay.dir = dir
if(vision_cone_overlay.alpha)
var/turf/T = get_turf(src)
for(var/cone_atom in cone(T, reverse_direction(dir), get_rectangle_in_dir(T, client.view + 1, reverse_direction(dir)) & oview(client.view + 1, T)))
add_to_mobs_hidden_atoms(cone_atom)
/mob/living/proc/add_to_mobs_hidden_atoms(atom/A)
var/image/I
I = image("split", A)
I.override = TRUE
client.images += I
client.hidden_atoms += I
if(ismob(A))
var/mob/hidden_mob = A
client.hidden_mobs += hidden_mob
if(pulling && (pulling == hidden_mob || pulling == hidden_mob.buckled))//If we're pulling them we don't want them to be invisible, too hard to play like that.
I.override = FALSE
return
for(var/obj/item/grab/G in src)
if(A == G.affecting)
I.override = FALSE
return
for(var/obj/item/grab/G in A)
if(src == G.affecting)
I.override = FALSE
return
/mob/living/proc/SetFov(var/n)
if(!can_have_vision_cone)
return
if(!n)
hide_cone()
else
show_cone()
/mob/living/proc/check_fov()
if(!can_have_vision_cone)
if(client)
for(var/hidden in client.hidden_atoms)
var/image/I = hidden
client.images -= I
client.hidden_atoms.Cut()
client.hidden_mobs.Cut()
remove_cone()
return
if(isnull(vision_cone_overlay))
vision_cone_overlay = new /obj/screen/fov()
client.screen |= vision_cone_overlay
if(resting || lying || client.eye != client.mob)
vision_cone_overlay.alpha = 0
return
else if(vision_cone_overlay)
show_cone()
else
hide_cone()
//Making these generic procs so you can call them anywhere.
/mob/living/proc/show_cone()
if(!can_have_vision_cone)
return
if(vision_cone_overlay)
vision_cone_overlay.alpha = client.prefs.fov_cone_alpha
/mob/living/proc/hide_cone()
if(vision_cone_overlay)
vision_cone_overlay.alpha = 0
/mob/living/proc/remove_cone()
if(vision_cone_overlay)
client.screen -= vision_cone_overlay
/mob/living/set_dir(var/new_dir, ignore_facing_dir = FALSE)
. = ..()
if(.)
update_vision_cone()
// Rotates a rectangle around a center turf
/proc/get_rectangle_in_dir(var/turf/T, var/length, var/dir)
var/matrix/M = new
var/matrix/N = new
M.Turn(dir2angle(dir))
N.Turn((dir2angle(dir)+180) % 360)
. = block(\
locate(T.x + (M.a+M.b) * length + 0.5*(M.a + M.b - 1), T.y + (M.d+M.e) * length + 0.5*(M.d + M.e - 1), T.z),\
locate(T.x + N.a * length + 0.5*(M.a + M.b - 1), T.y + N.d * length + 0.5*(M.d + M.e - 1), T.z)\
)
#define ALWAYS_FOOTSTEP_DISTANCE 2
#define MAX_FOOTSTEP_DISTANCE 5
#define RIPPLE_POSITION_BOUNDS 8
#define RIPPLE_START_RADIUS 10
#define RIPPLE_END_RADIUS 2
#define RIPPLE_START_SIZE 0
#define RIPPLE_END_SIZE 16
/turf/proc/show_footsteps(var/mob/viewer, var/turf/Tviewer, var/mob/M)
var/dist = get_dist(src, Tviewer)
if(src == Tviewer)
return
if(dist > MAX_FOOTSTEP_DISTANCE || prob(100*max(dist-ALWAYS_FOOTSTEP_DISTANCE,0) / MAX_FOOTSTEP_DISTANCE))
return
if(isdeaf(viewer))
return
if(viewer.stat || M.stat || M.lying)
return
if(ishuman(M))
var/mob/living/carbon/human/H = M
if(!H.is_noisy)
return
var/image/marker = image(icon, src, icon_state, layer = layer)
marker.overlays = overlays.Copy()
marker.override = TRUE
marker.filters += filter(type = "ripple", x=rand(-RIPPLE_POSITION_BOUNDS, RIPPLE_POSITION_BOUNDS), y=rand(-RIPPLE_POSITION_BOUNDS, RIPPLE_POSITION_BOUNDS), radius = RIPPLE_START_RADIUS, size = RIPPLE_START_SIZE, falloff = 0)
viewer.client.images += marker
QDEL_IN(marker, 1.5 SECONDS)
animate(marker.filters[marker.filters.len], time = 1.5 SECONDS, radius = RIPPLE_END_RADIUS, size = RIPPLE_END_SIZE)
#undef ALWAYS_FOOTSTEP_DISTANCE
#undef MAX_FOOTSTEP_DISTANCE
#undef RIPPLE_POSITION_BOUNDS
#undef RIPPLE_START_RADIUS
#undef RIPPLE_END_RADIUS
#undef RIPPLE_START_SIZE
#undef RIPPLE_END_SIZE