mirror of
https://github.com/Aurorastation/Aurora.3.git
synced 2026-08-30 16:38:22 +01:00
Ports BS12 fixes / refactor of visualnets. (#7572)
Ports (and adjusts) Baystation12/Baystation12#12521 et al. Essentially brings our visualnet code up to the standard of three years ago, rather than five. Side effects of merging may include but are not limited to loss of AI vision, helmet camera failure, garbage collection implosion, infinite turf loops, and unintended layer shenanigans. High-level changes: Overall, visualnet/chunk procs have been renamed and refactored to be clear as to their function. Fix some layering issues related to magic numbers, these have been set to constants. Visualnets now track source movement rather than overriding individual mob/obj procs. Adds obfuscation underlay to complicate memory fudging to remove camera static. Cameras now only add themselves to the cameranet if they're on open (non-restricted) networks. Helmet cameras now use cameras themselves rather than network defines. Adds a sorted object list insertion helper. The Camera MIU (presently unused) should now function properly. Unused cultnet / cult mask deleted because refactoring that would likely kill the few brain cells I have left
This commit is contained in:
@@ -3,42 +3,37 @@
|
||||
// The datum containing all the chunks.
|
||||
|
||||
/datum/visualnet/camera
|
||||
// The cameras on the map, no matter if they work or not. Updated in obj/machinery/camera.dm by New() and Destroy().
|
||||
var/list/cameras = list()
|
||||
var/cameras_unsorted = 1
|
||||
// The cameras on the map, no matter if they work or not.
|
||||
var/list/cameras
|
||||
chunk_type = /datum/chunk/camera
|
||||
valid_source_types = list(/obj/machinery/camera, /mob/living/silicon/ai)
|
||||
|
||||
/datum/visualnet/camera/proc/process_sort()
|
||||
if(cameras_unsorted)
|
||||
sortTim(cameras, /proc/cmp_camera, FALSE)
|
||||
cameras_unsorted = 0
|
||||
/datum/visualnet/camera/New()
|
||||
cameras = list()
|
||||
..()
|
||||
|
||||
// Removes a camera from a chunk.
|
||||
/datum/visualnet/camera/Destroy()
|
||||
cameras.Cut()
|
||||
. = ..()
|
||||
|
||||
/datum/visualnet/camera/proc/removeCamera(obj/machinery/camera/c)
|
||||
if(c.can_use())
|
||||
majorChunkChange(c, 0)
|
||||
/datum/visualnet/camera/add_source(obj/machinery/camera/c)
|
||||
if(istype(c))
|
||||
if(c in cameras)
|
||||
return FALSE
|
||||
. = ..(c, c.can_use())
|
||||
if(.)
|
||||
dd_binaryInsertSorted(cameras, c)
|
||||
else if(isAI(c))
|
||||
var/mob/living/silicon/AI = c
|
||||
return ..(AI, AI.stat != DEAD)
|
||||
else
|
||||
..()
|
||||
|
||||
// Add a camera to a chunk.
|
||||
|
||||
/datum/visualnet/camera/proc/addCamera(obj/machinery/camera/c)
|
||||
if(c.can_use())
|
||||
majorChunkChange(c, 1)
|
||||
|
||||
// Used for Cyborg cameras. Since portable cameras can be in ANY chunk.
|
||||
|
||||
/datum/visualnet/camera/proc/updatePortableCamera(obj/machinery/camera/c)
|
||||
if(c.can_use())
|
||||
majorChunkChange(c, 1)
|
||||
//else
|
||||
// majorChunkChange(c, 0)
|
||||
|
||||
/datum/visualnet/camera/onMajorChunkChange(atom/c, var/choice, var/datum/chunk/camera/chunk)
|
||||
// Only add actual cameras to the list of cameras
|
||||
if(istype(c, /obj/machinery/camera))
|
||||
if(choice == 0)
|
||||
// Remove the camera.
|
||||
chunk.cameras -= c
|
||||
else if(choice == 1)
|
||||
// You can't have the same camera in the list twice.
|
||||
chunk.cameras |= c
|
||||
/datum/visualnet/camera/remove_source(obj/machinery/camera/c)
|
||||
if(istype(c) && cameras.Remove(c))
|
||||
. = ..(c, c.can_use())
|
||||
if(isAI(c))
|
||||
var/mob/living/silicon/AI = c
|
||||
return ..(AI, AI.stat != DEAD)
|
||||
else
|
||||
..()
|
||||
@@ -3,50 +3,21 @@
|
||||
// A 16x16 grid of the map with a list of turfs that can be seen, are visible and are dimmed.
|
||||
// Allows the Eye to stream these chunks and know what it can and cannot see.
|
||||
|
||||
/datum/chunk/camera
|
||||
var/list/cameras = list()
|
||||
|
||||
/datum/chunk/camera/acquireVisibleTurfs(var/list/visible)
|
||||
var/turf/point = locate(src.x + 8, src.y + 8, src.z)
|
||||
for(var/camera in cameras)
|
||||
var/obj/machinery/camera/c = camera
|
||||
|
||||
if(!istype(c))
|
||||
cameras -= c
|
||||
continue
|
||||
|
||||
if(!c.can_use())
|
||||
continue
|
||||
|
||||
if(get_dist(point, c) > 24)
|
||||
cameras -= c
|
||||
continue
|
||||
|
||||
for(var/turf/t in c.can_see())
|
||||
visible[t] = t
|
||||
|
||||
for(var/mob/living/silicon/ai/AI in living_mob_list)
|
||||
if (get_dist(point, AI) > world.view)
|
||||
continue
|
||||
for(var/turf/t in AI.seen_camera_turfs())
|
||||
visible[t] = t
|
||||
|
||||
// Create a new camera chunk, since the chunks are made as they are needed.
|
||||
|
||||
/datum/chunk/camera/New(loc, x, y, z)
|
||||
for(var/obj/machinery/camera/c in range(16, locate(x + 8, y + 8, z)))
|
||||
if(c.can_use())
|
||||
cameras += c
|
||||
..()
|
||||
|
||||
/mob/living/silicon/proc/provides_camera_vision()
|
||||
return 0
|
||||
|
||||
/mob/living/silicon/ai/provides_camera_vision()
|
||||
return stat != DEAD
|
||||
|
||||
/mob/living/silicon/robot/provides_camera_vision()
|
||||
return src.camera && src.camera.network.len
|
||||
|
||||
/mob/living/silicon/ai/proc/seen_camera_turfs()
|
||||
return seen_turfs_in_range(src, world.view)
|
||||
/datum/chunk/camera/acquire_visible_turfs(var/list/visible)
|
||||
for(var/source in sources)
|
||||
if(istype(source, /obj/machinery/camera))
|
||||
var/obj/machinery/camera/c = source
|
||||
if(!c.can_use())
|
||||
continue
|
||||
|
||||
for(var/turf/t in c.can_see())
|
||||
visible[t] = t
|
||||
else if(isAI(source))
|
||||
var/mob/living/silicon/ai/AI = source
|
||||
if (AI.stat == DEAD)
|
||||
continue
|
||||
for(var/turf/t in seen_turfs_in_range(AI, world.view))
|
||||
visible[t] = t
|
||||
else
|
||||
log_visualnet("Contained an unhandled source", source)
|
||||
sources -= source
|
||||
@@ -3,16 +3,27 @@
|
||||
// A mob that the AI controls to look around the station with.
|
||||
// It streams chunks as it moves around, which will show it what the AI can and cannot see.
|
||||
|
||||
/mob/abstract/eye/cameranet
|
||||
// Generic version of the AI eye without the AI-specific handling, for things like the Camera MIU mask.
|
||||
name = "Inactive Camera Eye"
|
||||
name_suffix = "Camera Eye"
|
||||
|
||||
/mob/abstract/eye/cameranet/Initialize()
|
||||
. = ..()
|
||||
visualnet = cameranet
|
||||
|
||||
/mob/abstract/eye/aiEye
|
||||
name = "Inactive AI Eye"
|
||||
name_suffix = "AI Eye"
|
||||
icon_state = "AI-eye"
|
||||
|
||||
/mob/abstract/eye/aiEye/New()
|
||||
..()
|
||||
/mob/abstract/eye/aiEye/Initialize()
|
||||
. = ..()
|
||||
visualnet = cameranet
|
||||
|
||||
/mob/abstract/eye/aiEye/setLoc(var/T, var/cancel_tracking = 1)
|
||||
if(..())
|
||||
. = ..()
|
||||
if(. && isAI(owner))
|
||||
var/mob/living/silicon/ai/ai = owner
|
||||
if(cancel_tracking)
|
||||
ai.ai_cancel_tracking()
|
||||
@@ -33,7 +44,6 @@
|
||||
if(!eyeobj) return
|
||||
if(!new_eye)
|
||||
new_eye = src
|
||||
eyeobj.owner = null
|
||||
qdel(eyeobj) // No AI, no Eye
|
||||
eyeobj = null
|
||||
if(client)
|
||||
@@ -41,26 +51,18 @@
|
||||
|
||||
/mob/living/silicon/ai/proc/create_eyeobj(var/newloc)
|
||||
if(eyeobj) destroy_eyeobj()
|
||||
if(!newloc) newloc = src.loc
|
||||
if(!newloc) newloc = get_turf(src)
|
||||
eyeobj = new /mob/abstract/eye/aiEye(newloc)
|
||||
eyeobj.owner = src
|
||||
eyeobj.name = "[src.name] (AI Eye)" // Give it a name
|
||||
if(client) client.eye = eyeobj
|
||||
SetName(src.name)
|
||||
eyeobj.possess(src)
|
||||
|
||||
// Intiliaze the eye by assigning it's "ai" variable to us. Then set it's loc to us.
|
||||
/mob/living/silicon/ai/Initialize()
|
||||
. = ..()
|
||||
create_eyeobj()
|
||||
addtimer(CALLBACK(src, .proc/init_move_eyeobj), 5)
|
||||
|
||||
/mob/living/silicon/ai/proc/init_move_eyeobj()
|
||||
if (eyeobj)
|
||||
eyeobj.forceMove(loc)
|
||||
|
||||
/mob/living/silicon/ai/Destroy()
|
||||
destroy_eyeobj()
|
||||
return ..()
|
||||
. = ..()
|
||||
|
||||
/atom/proc/move_camera_by_click()
|
||||
if(istype(usr, /mob/living/silicon/ai))
|
||||
@@ -82,11 +84,7 @@
|
||||
if(!src.eyeobj)
|
||||
return
|
||||
|
||||
if(client && client.eye)
|
||||
client.eye = src
|
||||
for(var/datum/chunk/c in eyeobj.visibleChunks)
|
||||
c.remove(eyeobj)
|
||||
src.eyeobj.setLoc(src)
|
||||
eyeobj.possess(src)
|
||||
|
||||
/mob/living/silicon/ai/proc/toggle_acceleration()
|
||||
set category = "AI Commands"
|
||||
|
||||
@@ -1,39 +1,3 @@
|
||||
#define BORG_CAMERA_BUFFER 30
|
||||
|
||||
// ROBOT MOVEMENT
|
||||
|
||||
// Update the portable camera everytime the Robot moves.
|
||||
// This might be laggy, comment it out if there are problems.
|
||||
/mob/living/silicon/var/updating = 0
|
||||
|
||||
/mob/living/silicon/robot/Move()
|
||||
var/oldLoc = src.loc
|
||||
. = ..()
|
||||
if (.)
|
||||
if(provides_camera_vision())
|
||||
if(!updating)
|
||||
updating = 1
|
||||
addtimer(CALLBACK(src, .proc/camera_post_move, oldLoc), BORG_CAMERA_BUFFER)
|
||||
|
||||
/mob/living/silicon/robot/proc/camera_post_move(oldLoc)
|
||||
if (oldLoc != loc)
|
||||
cameranet.updatePortableCamera(camera)
|
||||
|
||||
updating = 0
|
||||
|
||||
/mob/living/silicon/ai/Move()
|
||||
var/oldLoc = src.loc
|
||||
. = ..()
|
||||
if (.)
|
||||
if(provides_camera_vision())
|
||||
addtimer(CALLBACK(src, .proc/camera_post_move, oldLoc), BORG_CAMERA_BUFFER, TIMER_UNIQUE)
|
||||
|
||||
/mob/living/silicon/ai/proc/camera_post_move(oldLoc)
|
||||
if(oldLoc != src.loc)
|
||||
cameranet.updateVisibility(oldLoc, 0)
|
||||
cameranet.updateVisibility(loc, 0)
|
||||
#undef BORG_CAMERA_BUFFER
|
||||
|
||||
// CAMERA
|
||||
|
||||
// An addition to deactivate which removes/adds the camera from the chunk list based on if it works or not.
|
||||
@@ -41,33 +5,55 @@
|
||||
/obj/machinery/camera/deactivate(user as mob, var/choice = 1)
|
||||
..(user, choice)
|
||||
invalidateCameraCache()
|
||||
if(src.can_use())
|
||||
cameranet.addCamera(src)
|
||||
else
|
||||
src.set_light(0)
|
||||
cameranet.removeCamera(src)
|
||||
if(!can_use())
|
||||
set_light(0)
|
||||
cameranet.update_visibility(src)
|
||||
|
||||
/obj/machinery/camera/Initialize()
|
||||
. = ..()
|
||||
//Camera must be added to global list of all cameras no matter what...
|
||||
cameranet.cameras += src
|
||||
cameranet.cameras_unsorted = TRUE
|
||||
update_coverage(1)
|
||||
var/list/open_networks = difflist(network, restricted_camera_networks)
|
||||
on_open_network = open_networks.len
|
||||
if(on_open_network)
|
||||
cameranet.add_source(src)
|
||||
|
||||
/obj/machinery/camera/Destroy()
|
||||
clear_all_networks()
|
||||
cameranet.cameras -= src
|
||||
return ..()
|
||||
if(on_open_network)
|
||||
cameranet.remove_source(src)
|
||||
. = ..()
|
||||
|
||||
/obj/machinery/camera/proc/update_coverage(var/network_change = 0)
|
||||
if(network_change)
|
||||
var/list/open_networks = difflist(network, restricted_camera_networks)
|
||||
// Add or remove camera from the camera net as necessary
|
||||
if(on_open_network && !open_networks.len)
|
||||
on_open_network = FALSE
|
||||
cameranet.remove_source(src)
|
||||
else if(!on_open_network && open_networks.len)
|
||||
on_open_network = TRUE
|
||||
cameranet.add_source(src)
|
||||
else
|
||||
cameranet.update_visibility(src)
|
||||
|
||||
invalidateCameraCache()
|
||||
|
||||
// Mobs
|
||||
/mob/living/silicon/ai/Initialize()
|
||||
. = ..()
|
||||
cameranet.add_source(src)
|
||||
|
||||
/mob/living/silicon/ai/Destroy()
|
||||
cameranet.remove_source(src)
|
||||
. = ..()
|
||||
|
||||
/mob/living/silicon/ai/rejuvenate()
|
||||
var/was_dead = stat == DEAD
|
||||
..()
|
||||
if(was_dead && stat != DEAD)
|
||||
// Arise!
|
||||
cameranet.updateVisibility(src, 0)
|
||||
cameranet.update_visibility(src, FALSE)
|
||||
|
||||
/mob/living/silicon/ai/death(gibbed)
|
||||
if(..())
|
||||
. = ..()
|
||||
if(.)
|
||||
// If true, the mob went from living to dead (assuming everyone has been overriding as they should...)
|
||||
cameranet.updateVisibility(src, 0)
|
||||
cameranet.update_visibility(src, FALSE)
|
||||
|
||||
@@ -8,120 +8,51 @@
|
||||
/datum/obfuscation
|
||||
var/icon = 'icons/effects/cameravis.dmi'
|
||||
var/icon_state = "black"
|
||||
var/list/obfuscation_images = list()
|
||||
var/static/icon/obfuscation_underlay
|
||||
// There is an exploit were clients can memory-edit their local version of the static images, allowing them to see everything. This is a minor attempt to make that more difficult.
|
||||
|
||||
/datum/obfuscation/Destroy()
|
||||
obfuscation_images.Cut()
|
||||
. = ..()
|
||||
|
||||
/datum/obfuscation/proc/has_obfuscation(var/turf/T)
|
||||
return !isnull(obfuscation_images[T])
|
||||
|
||||
/datum/obfuscation/proc/get_obfuscation(var/turf/T)
|
||||
var/image/obfuscation = obfuscation_images[T]
|
||||
if(!obfuscation)
|
||||
obfuscation = image(icon, T, icon_state)
|
||||
obfuscation.layer = OBFUSCATION_LAYER
|
||||
if(!obfuscation_underlay)
|
||||
// Creating a new icon of a fairly common icon state, adding some random color to prevent address searching, and hoping being static kills memory locality
|
||||
var/turf/floor = /turf/simulated/floor/tiled
|
||||
obfuscation_underlay = icon(initial(floor.icon), initial(floor.icon_state))
|
||||
obfuscation_underlay.Blend(rgb(rand(0,255),rand(0,255),rand(0,255)))
|
||||
obfuscation.underlays += obfuscation_underlay
|
||||
obfuscation_images[T] = obfuscation
|
||||
return obfuscation
|
||||
|
||||
/datum/chunk
|
||||
var/datum/visualnet/visualnet
|
||||
var/list/obscuredTurfs = list()
|
||||
var/list/visibleTurfs = list()
|
||||
var/list/obscured = list()
|
||||
var/list/turfs = list()
|
||||
var/list/seenby = list()
|
||||
var/visible = 0
|
||||
var/changed = 0
|
||||
var/updating = 0
|
||||
var/list/sources = list()
|
||||
var/dirty = FALSE
|
||||
var/updating = FALSE
|
||||
var/x = 0
|
||||
var/y = 0
|
||||
var/z = 0
|
||||
var/datum/obfuscation/obfuscation = new()
|
||||
|
||||
// Add an eye to the chunk, then update if changed.
|
||||
|
||||
/datum/chunk/proc/add(mob/abstract/eye/eye)
|
||||
if(!eye.owner)
|
||||
return
|
||||
eye.visibleChunks += src
|
||||
if(eye.owner.client)
|
||||
eye.owner.client.images += obscured
|
||||
visible++
|
||||
seenby += eye
|
||||
if(changed && !updating)
|
||||
update()
|
||||
|
||||
// Remove an eye from the chunk, then update if changed.
|
||||
|
||||
/datum/chunk/proc/remove(mob/abstract/eye/eye)
|
||||
if(!eye.owner)
|
||||
return
|
||||
eye.visibleChunks -= src
|
||||
if(eye.owner.client)
|
||||
eye.owner.client.images -= obscured
|
||||
seenby -= eye
|
||||
if(visible > 0)
|
||||
visible--
|
||||
|
||||
// Called when a chunk has changed. I.E: A wall was deleted.
|
||||
|
||||
/datum/chunk/proc/visibilityChanged(turf/loc)
|
||||
if(!visibleTurfs[loc])
|
||||
return
|
||||
hasChanged()
|
||||
|
||||
// Updates the chunk, makes sure that it doesn't update too much. If the chunk isn't being watched it will
|
||||
// instead be flagged to update the next time an AI Eye moves near it.
|
||||
|
||||
/datum/chunk/proc/hasChanged(var/update_now = 0)
|
||||
if(visible || update_now)
|
||||
if(!updating)
|
||||
updating = 1
|
||||
addtimer(CALLBACK(src, .proc/doUpdate), UPDATE_BUFFER)
|
||||
else
|
||||
changed = 1
|
||||
|
||||
/datum/chunk/proc/doUpdate()
|
||||
update()
|
||||
updating = 0
|
||||
|
||||
// The actual updating.
|
||||
|
||||
/datum/chunk/proc/update()
|
||||
set waitfor = FALSE
|
||||
|
||||
var/list/newVisibleTurfs = new()
|
||||
acquireVisibleTurfs(newVisibleTurfs)
|
||||
|
||||
// Removes turf that isn't in turfs.
|
||||
newVisibleTurfs &= turfs
|
||||
|
||||
var/list/visAdded = newVisibleTurfs - visibleTurfs
|
||||
var/list/visRemoved = visibleTurfs - newVisibleTurfs
|
||||
|
||||
visibleTurfs = newVisibleTurfs
|
||||
obscuredTurfs = turfs - newVisibleTurfs
|
||||
|
||||
for(var/turf in visAdded)
|
||||
var/turf/t = turf
|
||||
if(LAZYACCESS(t.obfuscations, obfuscation.type))
|
||||
obscured -= t.obfuscations[obfuscation.type]
|
||||
for(var/eye in seenby)
|
||||
var/mob/abstract/eye/m = eye
|
||||
if(!m || !m.owner)
|
||||
continue
|
||||
if(m.owner.client)
|
||||
m.owner.client.images -= t.obfuscations[obfuscation.type]
|
||||
|
||||
for(var/turf in visRemoved)
|
||||
var/turf/t = turf
|
||||
if(obscuredTurfs[t])
|
||||
if(!LAZYACCESS(t.obfuscations, obfuscation.type))
|
||||
LAZYINITLIST(t.obfuscations)
|
||||
var/image/obfuscation_static = image(obfuscation.icon, t, obfuscation.icon_state, OBFUSCATION_LAYER)
|
||||
obfuscation_static.plane = 0
|
||||
t.obfuscations[obfuscation.type] = obfuscation_static
|
||||
|
||||
obscured += LAZYACCESS(t.obfuscations, obfuscation.type)
|
||||
for(var/eye in seenby)
|
||||
var/mob/abstract/eye/m = eye
|
||||
if(!m || !m.owner)
|
||||
seenby -= m
|
||||
continue
|
||||
if(m.owner.client)
|
||||
m.owner.client.images += LAZYACCESS(t.obfuscations, obfuscation.type)
|
||||
|
||||
/datum/chunk/proc/acquireVisibleTurfs(var/list/visible)
|
||||
|
||||
// Create a new camera chunk, since the chunks are made as they are needed.
|
||||
|
||||
/datum/chunk/New(loc, x, y, z)
|
||||
|
||||
/datum/chunk/New(var/datum/visualnet/visualnet, x, y, z)
|
||||
..()
|
||||
src.visualnet = visualnet
|
||||
// 0xf = 15
|
||||
x &= ~0xf
|
||||
y &= ~0xf
|
||||
@@ -136,7 +67,8 @@
|
||||
if(t.x >= x && t.y >= y && t.x < x + 16 && t.y < y + 16)
|
||||
turfs[t] = t
|
||||
|
||||
acquireVisibleTurfs(visibleTurfs)
|
||||
add_sources(visualnet.sources)
|
||||
acquire_visible_turfs(visibleTurfs)
|
||||
|
||||
// Removes turf that isn't in turfs.
|
||||
visibleTurfs &= turfs
|
||||
@@ -145,12 +77,116 @@
|
||||
|
||||
for(var/turf in obscuredTurfs)
|
||||
var/turf/t = turf
|
||||
if(!LAZYACCESS(t.obfuscations, obfuscation.type))
|
||||
LAZYINITLIST(t.obfuscations)
|
||||
var/image/obfuscation_static = image(obfuscation.icon, t, obfuscation.icon_state, OBFUSCATION_LAYER)
|
||||
obfuscation_static.plane = 0
|
||||
t.obfuscations[obfuscation.type] = obfuscation_static
|
||||
obscured += obfuscation.get_obfuscation(t)
|
||||
|
||||
obscured += LAZYACCESS(t.obfuscations, obfuscation.type)
|
||||
|
||||
#undef UPDATE_BUFFER
|
||||
/datum/chunk/Destroy()
|
||||
visualnet = null
|
||||
. = ..()
|
||||
|
||||
/datum/chunk/proc/add_sources(var/list/sources)
|
||||
var/turf/center = locate(x + 8, y + 8, z)
|
||||
for(var/entry in sources)
|
||||
var/atom/A = entry
|
||||
if(get_dist(get_turf(A), center) > 16)
|
||||
continue
|
||||
add_source(A)
|
||||
|
||||
// The visualnet checks if a source already exists or not, as appropriate, before calling add/remove_source on the chunk
|
||||
/datum/chunk/proc/add_source(var/atom/source)
|
||||
if(source in sources)
|
||||
return FALSE
|
||||
sources += source
|
||||
visibility_changed()
|
||||
return TRUE
|
||||
|
||||
/datum/chunk/proc/remove_source(var/atom/source)
|
||||
if(sources.Remove(source))
|
||||
visibility_changed()
|
||||
return TRUE
|
||||
return FALSE
|
||||
|
||||
// Visualnet adds and removes eyes.
|
||||
|
||||
/datum/chunk/proc/add_eye(mob/abstract/eye/eye)
|
||||
seenby += eye
|
||||
eye.visibleChunks += src
|
||||
if(eye.owner && eye.owner.client)
|
||||
eye.owner.client.images += obscured
|
||||
|
||||
/datum/chunk/proc/remove_eye(mob/abstract/eye/eye)
|
||||
seenby -= eye
|
||||
eye.visibleChunks -= src
|
||||
if(eye.owner && eye.owner.client)
|
||||
eye.owner.client.images -= obscured
|
||||
|
||||
// Updates the chunk, makes sure that it doesn't update too much. If the chunk isn't being watched it will
|
||||
// instead be flagged to update the next time an AI Eye moves near it.
|
||||
|
||||
/datum/chunk/proc/visibility_changed(var/update_now = FALSE)
|
||||
if(update_now)
|
||||
update(TRUE)
|
||||
return
|
||||
|
||||
if(updating)
|
||||
return
|
||||
|
||||
if(seenby.len)
|
||||
updating = TRUE
|
||||
addtimer(CALLBACK(src, .proc/update), UPDATE_BUFFER)
|
||||
else
|
||||
dirty = TRUE
|
||||
|
||||
// The actual updating.
|
||||
|
||||
/datum/chunk/proc/update(var/forced = FALSE)
|
||||
if(!updating && !forced)
|
||||
return
|
||||
|
||||
var/list/newVisibleTurfs = new()
|
||||
acquire_visible_turfs(newVisibleTurfs)
|
||||
|
||||
// Removes turf that isn't in turfs.
|
||||
newVisibleTurfs &= turfs
|
||||
|
||||
var/list/visAdded = newVisibleTurfs - visibleTurfs
|
||||
var/list/visRemoved = visibleTurfs - newVisibleTurfs
|
||||
|
||||
visibleTurfs = newVisibleTurfs
|
||||
obscuredTurfs = turfs - newVisibleTurfs
|
||||
|
||||
for(var/turf in visAdded)
|
||||
var/turf/t = turf
|
||||
if(obfuscation.has_obfuscation(t))
|
||||
var/image/obfuscation_image = obfuscation.get_obfuscation(t)
|
||||
obscured -= obfuscation_image
|
||||
for(var/eye in seenby)
|
||||
var/mob/abstract/eye/m = eye
|
||||
if (m && m.owner && m.owner.client)
|
||||
m.owner.client.images -= obfuscation_image
|
||||
|
||||
for(var/turf in visRemoved)
|
||||
var/turf/t = turf
|
||||
if(obscuredTurfs[t])
|
||||
var/image/obfuscation_image = obfuscation.get_obfuscation(t)
|
||||
obscured += obfuscation_image
|
||||
|
||||
for(var/eye in seenby)
|
||||
var/mob/abstract/eye/m = eye
|
||||
if (m && m.owner && m.owner.client)
|
||||
m.owner.client.images += obfuscation_image
|
||||
|
||||
dirty = FALSE
|
||||
updating = FALSE
|
||||
|
||||
/datum/chunk/proc/acquire_visible_turfs(var/list/visible)
|
||||
return
|
||||
|
||||
/proc/seen_turfs_in_range(var/source, var/range)
|
||||
var/turf/pos = get_turf(source)
|
||||
if(pos)
|
||||
. = hear(range, pos)
|
||||
else
|
||||
. = list()
|
||||
|
||||
#undef UPDATE_BUFFER
|
||||
@@ -5,6 +5,7 @@
|
||||
|
||||
/mob/abstract/eye
|
||||
name = "Eye"
|
||||
var/name_suffix = "Eye"
|
||||
icon = 'icons/mob/eye.dmi'
|
||||
icon_state = "default-eye"
|
||||
alpha = 127
|
||||
@@ -39,6 +40,10 @@
|
||||
qdel(ghostimage)
|
||||
ghostimage = null
|
||||
updateallghostimages()
|
||||
|
||||
release(owner)
|
||||
owner = null
|
||||
visualnet = null
|
||||
return ..()
|
||||
|
||||
/mob/abstract/eye/Move(n, direct)
|
||||
@@ -61,32 +66,58 @@
|
||||
return 0
|
||||
|
||||
/mob/abstract/eye/examine(mob/user)
|
||||
return
|
||||
|
||||
/mob/abstract/eye/proc/possess(var/mob/user)
|
||||
if(owner && owner != user)
|
||||
return
|
||||
if(owner && owner.eyeobj != src)
|
||||
return
|
||||
|
||||
owner = user
|
||||
owner.eyeobj = src
|
||||
name = "[owner.name] ([name_suffix])"
|
||||
if(owner.client)
|
||||
owner.client.eye = src
|
||||
setLoc(owner)
|
||||
visualnet.update_eye_chunks(src, TRUE)
|
||||
|
||||
/mob/abstract/eye/proc/release(var/mob/user)
|
||||
if(owner != user || !user)
|
||||
return
|
||||
if(owner.eyeobj != src)
|
||||
return
|
||||
visualnet.remove_eye(src)
|
||||
owner.eyeobj = null
|
||||
owner = null
|
||||
name = initial(name)
|
||||
|
||||
// Use this when setting the eye's location.
|
||||
// It will also stream the chunk that the new loc is in.
|
||||
/mob/abstract/eye/proc/setLoc(var/T)
|
||||
if(owner)
|
||||
T = get_turf(T)
|
||||
if(T != loc)
|
||||
forceMove(T)
|
||||
if(!owner)
|
||||
return FALSE
|
||||
|
||||
T = get_turf(T)
|
||||
if(!T || T == loc)
|
||||
return FALSE
|
||||
|
||||
if(owner.client)
|
||||
owner.client.eye = src
|
||||
forceMove(T)
|
||||
|
||||
if(owner_follows_eye)
|
||||
visualnet.updateVisibility(owner, 0)
|
||||
owner.forceMove(loc)
|
||||
visualnet.updateVisibility(owner, 0)
|
||||
|
||||
visualnet.visibility(src)
|
||||
return 1
|
||||
return 0
|
||||
if(owner.client)
|
||||
owner.client.eye = src
|
||||
if(owner_follows_eye)
|
||||
owner.forceMove(loc)
|
||||
|
||||
visualnet.update_eye_chunks(src)
|
||||
return TRUE
|
||||
|
||||
/mob/abstract/eye/proc/getLoc()
|
||||
if(owner)
|
||||
if(!isturf(owner.loc) || !owner.client)
|
||||
return
|
||||
return loc
|
||||
|
||||
/mob
|
||||
var/mob/abstract/eye/eyeobj
|
||||
|
||||
|
||||
@@ -0,0 +1,5 @@
|
||||
/datum/chunk/proc/log_visualnet(var/message, var/datum/source)
|
||||
visualnet.log_visualnet("[src] ([x]-[y]-[z]) - [message]", source)
|
||||
|
||||
/datum/visualnet/proc/log_visualnet(var/message, var/datum/source)
|
||||
log_debug("[src] - [message]: [istype(source) ? "[source] ([source.type])" : (source ? source : "NULL") ]")
|
||||
@@ -1,36 +0,0 @@
|
||||
// CULT CHUNK
|
||||
//
|
||||
// A 16x16 grid of the map with a list of turfs that can be seen, are visible and are dimmed.
|
||||
// Allows the Eye to stream these chunks and know what it can and cannot see.
|
||||
|
||||
/datum/obfuscation/cult
|
||||
icon_state = "white"
|
||||
|
||||
/datum/chunk/cult
|
||||
obfuscation = new /datum/obfuscation/cult()
|
||||
|
||||
/datum/chunk/cult/acquireVisibleTurfs(var/list/visible)
|
||||
for(var/mob/living/L in living_mob_list)
|
||||
for(var/turf/t in L.seen_cult_turfs())
|
||||
visible[t] = t
|
||||
|
||||
/mob/living/proc/seen_cult_turfs()
|
||||
return seen_turfs_in_range(src, 3)
|
||||
|
||||
/mob/living/carbon/human/seen_cult_turfs()
|
||||
if(mind in cult.current_antagonists)
|
||||
return seen_turfs_in_range(src, world.view)
|
||||
return ..()
|
||||
|
||||
/mob/living/silicon/seen_cult_turfs()
|
||||
return list()
|
||||
|
||||
/mob/living/simple_animal/seen_cult_turfs()
|
||||
return seen_turfs_in_range(src, 1)
|
||||
|
||||
/mob/living/simple_animal/shade/narsie/seen_cult_turfs()
|
||||
return view(2, src)
|
||||
|
||||
/proc/seen_turfs_in_range(var/source, var/range)
|
||||
var/turf/pos = get_turf(source)
|
||||
return hear(range, pos)
|
||||
@@ -1,15 +0,0 @@
|
||||
// CULT NET
|
||||
//
|
||||
// The datum containing all the chunks.
|
||||
|
||||
/datum/visualnet/cult
|
||||
chunk_type = /datum/chunk/cult
|
||||
|
||||
/datum/visualnet/cult/proc/provides_vision(var/mob/living/L)
|
||||
return L.provides_cult_vision()
|
||||
|
||||
/mob/living/proc/provides_cult_vision()
|
||||
return 1
|
||||
|
||||
/mob/living/silicon/provides_cult_vision()
|
||||
return 0
|
||||
@@ -1,13 +0,0 @@
|
||||
// MASK EYE
|
||||
//
|
||||
// A mob that a cultists controls to look around the station with.
|
||||
// It streams chunks as it moves around, which will show it what the cultist can and cannot see.
|
||||
|
||||
/mob/abstract/eye/maskEye
|
||||
name = "Eye of Nar-Sie"
|
||||
acceleration = 0
|
||||
owner_follows_eye = 1
|
||||
|
||||
/mob/abstract/eye/maskEye/New()
|
||||
..()
|
||||
visualnet = cultnet
|
||||
@@ -1,51 +0,0 @@
|
||||
//UPDATE TRIGGERS, when the chunk (and the surrounding chunks) should update.
|
||||
|
||||
#define CULT_UPDATE_BUFFER 30
|
||||
|
||||
/mob/living/var/updating_cult_vision = 0
|
||||
|
||||
/mob/living/Move()
|
||||
var/oldLoc = src.loc
|
||||
. = ..()
|
||||
if(.)
|
||||
if(cultnet.provides_vision(src))
|
||||
if(!updating_cult_vision)
|
||||
updating_cult_vision = 1
|
||||
spawn(CULT_UPDATE_BUFFER)
|
||||
if(oldLoc != src.loc)
|
||||
cultnet.updateVisibility(oldLoc, 0)
|
||||
cultnet.updateVisibility(loc, 0)
|
||||
updating_cult_vision = 0
|
||||
|
||||
#undef CULT_UPDATE_BUFFER
|
||||
|
||||
/mob/living/New()
|
||||
..()
|
||||
cultnet.updateVisibility(src, 0)
|
||||
|
||||
/mob/living/Destroy()
|
||||
cultnet.updateVisibility(src, 0)
|
||||
return ..()
|
||||
|
||||
/mob/living/rejuvenate()
|
||||
var/was_dead = stat == DEAD
|
||||
..()
|
||||
if(was_dead && stat != DEAD)
|
||||
// Arise!
|
||||
cultnet.updateVisibility(src, 0)
|
||||
|
||||
/mob/living/death(gibbed, deathmessage="seizes up and falls limp...")
|
||||
. = ..()
|
||||
if(.)
|
||||
// If true, the mob went from living to dead (assuming everyone has been overriding as they should...)
|
||||
cultnet.updateVisibility(src)
|
||||
|
||||
/datum/antagonist/add_antagonist(var/datum/mind/player)
|
||||
. = ..()
|
||||
if(src == cult)
|
||||
cultnet.updateVisibility(player.current, 0)
|
||||
|
||||
/datum/antagonist/remove_antagonist(var/datum/mind/player, var/show_message, var/implanted)
|
||||
..()
|
||||
if(src == cult)
|
||||
cultnet.updateVisibility(player.current, 0)
|
||||
@@ -2,35 +2,29 @@
|
||||
|
||||
// TURFS
|
||||
|
||||
/proc/updateVisibility(atom/A, var/opacity_check = 1)
|
||||
for(var/datum/visualnet/VN in visual_nets)
|
||||
VN.updateVisibility(A, opacity_check)
|
||||
|
||||
/turf
|
||||
var/list/image/obfuscations
|
||||
/proc/updateVisibility(atom/A, var/opacity_check = TRUE)
|
||||
if(SSticker)
|
||||
for(var/datum/visualnet/VN in visual_nets)
|
||||
VN.update_visibility(A, opacity_check)
|
||||
|
||||
/turf/drain_power()
|
||||
return -1
|
||||
|
||||
/turf/simulated/Destroy()
|
||||
updateVisibility(src)
|
||||
return ..()
|
||||
|
||||
// STRUCTURES
|
||||
|
||||
/obj/structure/Destroy()
|
||||
updateVisibility(src)
|
||||
return ..()
|
||||
|
||||
// EFFECTS
|
||||
|
||||
/obj/effect/Destroy()
|
||||
updateVisibility(src)
|
||||
return ..()
|
||||
|
||||
/obj/effect/Initialize()
|
||||
/atom/Destroy()
|
||||
if(opacity)
|
||||
updateVisibility(src)
|
||||
. = ..()
|
||||
updateVisibility(src)
|
||||
|
||||
|
||||
/atom/movable/Move()
|
||||
. = ..()
|
||||
if(opacity && .)
|
||||
updateVisibility(src)
|
||||
|
||||
/atom/movable/forceMove()
|
||||
. = ..()
|
||||
if(opacity && .)
|
||||
updateVisibility(src)
|
||||
|
||||
// DOORS
|
||||
|
||||
@@ -40,4 +34,9 @@
|
||||
// Glass door glass = 1
|
||||
// don't check then?
|
||||
if(!glass)
|
||||
updateVisibility(src, 0)
|
||||
updateVisibility(src, FALSE)
|
||||
|
||||
/turf/ChangeTurf()
|
||||
. = ..()
|
||||
if(.)
|
||||
updateVisibility(src, FALSE)
|
||||
|
||||
@@ -5,125 +5,181 @@
|
||||
/datum/visualnet
|
||||
// The chunks of the map, mapping the areas that an object can see.
|
||||
var/list/chunks = list()
|
||||
var/ready = 0
|
||||
var/list/sources = list()
|
||||
var/chunk_type = /datum/chunk
|
||||
var/list/valid_source_types
|
||||
|
||||
/datum/visualnet/New()
|
||||
..()
|
||||
visual_nets += src
|
||||
if(!valid_source_types)
|
||||
valid_source_types = list()
|
||||
|
||||
/datum/visualnet/Destroy()
|
||||
visual_nets -= src
|
||||
for(var/source in sources)
|
||||
remove_source(source, FALSE)
|
||||
sources.Cut()
|
||||
for(var/chunk in chunks)
|
||||
var/chunk_datum = chunks[chunk]
|
||||
qdel(chunk_datum)
|
||||
chunks.Cut()
|
||||
return ..()
|
||||
|
||||
// Checks if a chunk has been Generated in x, y, z.
|
||||
/datum/visualnet/proc/chunkGenerated(x, y, z)
|
||||
/datum/visualnet/proc/is_chunk_generated(x, y, z)
|
||||
x &= ~0xf
|
||||
y &= ~0xf
|
||||
var/key = "[x],[y],[z]"
|
||||
return (chunks[key])
|
||||
return !isnull(chunks[key])
|
||||
|
||||
// Returns the chunk in the x, y, z.
|
||||
// If there is no chunk, it creates a new chunk and returns that.
|
||||
/datum/visualnet/proc/getChunk(x, y, z)
|
||||
/datum/visualnet/proc/get_chunk(x, y, z)
|
||||
x &= ~0xf
|
||||
y &= ~0xf
|
||||
var/key = "[x],[y],[z]"
|
||||
if(!chunks[key])
|
||||
chunks[key] = new chunk_type(null, x, y, z)
|
||||
chunks[key] = new chunk_type(src, x, y, z)
|
||||
|
||||
return chunks[key]
|
||||
|
||||
// Updates what the aiEye can see. It is recommended you use this when the aiEye moves or it's location is set.
|
||||
// Updates what the eye can see. It is recommended you use this when the eye moves or it's location is set.
|
||||
|
||||
/datum/visualnet/proc/visibility(mob/abstract/eye/eye)
|
||||
// 0xf = 15
|
||||
var/x1 = max(0, eye.x - 16) & ~0xf
|
||||
var/y1 = max(0, eye.y - 16) & ~0xf
|
||||
var/x2 = min(world.maxx, eye.x + 16) & ~0xf
|
||||
var/y2 = min(world.maxy, eye.y + 16) & ~0xf
|
||||
|
||||
var/list/visibleChunks = list()
|
||||
|
||||
for(var/x = x1; x <= x2; x += 16)
|
||||
for(var/y = y1; y <= y2; y += 16)
|
||||
visibleChunks += getChunk(x, y, eye.z)
|
||||
|
||||
var/list/remove = eye.visibleChunks - visibleChunks
|
||||
var/list/add = visibleChunks - eye.visibleChunks
|
||||
|
||||
for(var/chunk in remove)
|
||||
var/datum/chunk/c = chunk
|
||||
c.remove(eye)
|
||||
|
||||
for(var/chunk in add)
|
||||
var/datum/chunk/c = chunk
|
||||
c.add(eye)
|
||||
|
||||
// Updates the chunks that the turf is located in. Use this when obstacles are destroyed or when doors open.
|
||||
|
||||
/datum/visualnet/proc/updateVisibility(atom/A, var/opacity_check = 1)
|
||||
|
||||
if((opacity_check && !A.opacity))
|
||||
return
|
||||
majorChunkChange(A, 2)
|
||||
|
||||
/datum/visualnet/proc/updateChunk(x, y, z)
|
||||
// 0xf = 15
|
||||
if(!chunkGenerated(x, y, z))
|
||||
return
|
||||
var/datum/chunk/chunk = getChunk(x, y, z)
|
||||
chunk.hasChanged()
|
||||
|
||||
// Never access this proc directly!!!!
|
||||
// This will update the chunk and all the surrounding chunks.
|
||||
// It will also add the atom to the cameras list if you set the choice to 1.
|
||||
// Setting the choice to 0 will remove the camera from the chunks.
|
||||
// If you want to update the chunks around an object, without adding/removing a camera, use choice 2.
|
||||
|
||||
/datum/visualnet/proc/majorChunkChange(atom/c, var/choice)
|
||||
// 0xf = 15
|
||||
if(!c)
|
||||
return
|
||||
|
||||
var/turf/T = get_turf(c)
|
||||
/datum/visualnet/proc/update_eye_chunks(mob/abstract/eye/eye, var/full_update = FALSE)
|
||||
. = list()
|
||||
var/turf/T = get_turf(eye)
|
||||
if(T)
|
||||
var/x1 = max(0, T.x - 8) & ~0xf
|
||||
var/y1 = max(0, T.y - 8) & ~0xf
|
||||
var/x2 = min(world.maxx, T.x + 8) & ~0xf
|
||||
var/y2 = min(world.maxy, T.y + 8) & ~0xf
|
||||
// 0xf = 15
|
||||
var/x1 = max(0, T.x - 16) & ~0xf
|
||||
var/y1 = max(0, T.y - 16) & ~0xf
|
||||
var/x2 = min(world.maxx, T.x + 16) & ~0xf
|
||||
var/y2 = min(world.maxy, T.y + 16) & ~0xf
|
||||
|
||||
for(var/x = x1; x <= x2; x += 16)
|
||||
for(var/y = y1; y <= y2; y += 16)
|
||||
if(chunkGenerated(x, y, T.z))
|
||||
var/datum/chunk/chunk = getChunk(x, y, T.z)
|
||||
onMajorChunkChange(c, choice, chunk)
|
||||
chunk.hasChanged()
|
||||
. += get_chunk(x, y, T.z)
|
||||
|
||||
/datum/visualnet/proc/onMajorChunkChange(atom/c, var/choice, var/datum/chunk/chunk)
|
||||
if(full_update)
|
||||
eye.visibleChunks.Cut()
|
||||
|
||||
// Will check if a mob is on a viewable turf. Returns 1 if it is, otherwise returns 0.
|
||||
var/list/remove = eye.visibleChunks - .
|
||||
var/list/add = . - eye.visibleChunks
|
||||
|
||||
/datum/visualnet/proc/checkVis(mob/living/target as mob)
|
||||
// 0xf = 15
|
||||
for(var/chunk in remove)
|
||||
var/datum/chunk/c = chunk
|
||||
c.remove_eye(eye)
|
||||
|
||||
for(var/chunk in add)
|
||||
var/datum/chunk/c = chunk
|
||||
c.add_eye(eye)
|
||||
|
||||
/datum/visualnet/proc/remove_eye(mob/abstract/eye/eye)
|
||||
for(var/chunk in eye.visibleChunks)
|
||||
var/datum/chunk/c = chunk
|
||||
c.remove_eye(eye)
|
||||
|
||||
// Updates the chunks that the turf is located in. Use this when obstacles are destroyed or when doors open.
|
||||
|
||||
/datum/visualnet/proc/update_visibility(atom/A, var/opacity_check = TRUE)
|
||||
if((opacity_check && !A.opacity))
|
||||
return
|
||||
major_chunk_change(A)
|
||||
|
||||
/datum/visualnet/proc/update_visibility_nocheck(atom/A)
|
||||
update_visibility(A, FALSE)
|
||||
|
||||
// Will check if an atom is on a viewable turf. Returns TRUE if it is, otherwise FALSE.
|
||||
/datum/visualnet/proc/is_visible(var/atom/target)
|
||||
var/turf/position = get_turf(target)
|
||||
return checkTurfVis(position)
|
||||
return position && is_turf_visible(position)
|
||||
|
||||
/datum/visualnet/proc/checkTurfVis(var/turf/position)
|
||||
var/datum/chunk/chunk = getChunk(position.x, position.y, position.z)
|
||||
/datum/visualnet/proc/is_turf_visible(var/turf/position)
|
||||
if(!position)
|
||||
return FALSE
|
||||
var/datum/chunk/chunk = get_chunk(position.x, position.y, position.z)
|
||||
if(chunk)
|
||||
if(chunk.changed)
|
||||
chunk.hasChanged(1) // Update now, no matter if it's visible or not.
|
||||
if(chunk.visibleTurfs[position])
|
||||
return 1
|
||||
return 0
|
||||
if(chunk.dirty)
|
||||
chunk.update(TRUE) // Update if it's visible or not
|
||||
if(position in chunk.visibleTurfs)
|
||||
return TRUE
|
||||
return FALSE
|
||||
|
||||
// Never access this proc directly!!!!
|
||||
// This will update the chunk and all the surrounding chunks.
|
||||
|
||||
/datum/visualnet/proc/major_chunk_change(var/atom/source)
|
||||
for_all_chunks_in_range(source, /datum/chunk/proc/visibility_changed, list())
|
||||
|
||||
/datum/visualnet/proc/add_source(var/atom/source, var/update_visibility = TRUE, var/opacity_check = FALSE)
|
||||
if(!(source && is_type_in_list(source, valid_source_types)))
|
||||
log_visualnet("Was given an unhandled source", source)
|
||||
return FALSE
|
||||
if(source in sources)
|
||||
return FALSE
|
||||
sources += source
|
||||
moved_event.register(source, src, /datum/visualnet/proc/source_moved)
|
||||
destroyed_event.register(source, src, /datum/visualnet/proc/remove_source)
|
||||
for_all_chunks_in_range(source, /datum/chunk/proc/add_source, list(source))
|
||||
if(update_visibility)
|
||||
update_visibility(source, opacity_check)
|
||||
return TRUE
|
||||
|
||||
/datum/visualnet/proc/remove_source(var/atom/source, var/update_visibility = TRUE, var/opacity_check = FALSE)
|
||||
if(!sources.Remove(source))
|
||||
return FALSE
|
||||
moved_event.unregister(source, src)
|
||||
destroyed_event.unregister(source, src)
|
||||
for_all_chunks_in_range(source, /datum/chunk/proc/remove_source, list(source))
|
||||
if(update_visibility)
|
||||
update_visibility(source, opacity_check)
|
||||
return TRUE
|
||||
|
||||
/datum/visualnet/proc/source_moved(var/atom/movable/source, var/old_loc, var/new_loc)
|
||||
var/turf/old_turf = get_turf(old_loc)
|
||||
var/turf/new_turf = get_turf(new_loc)
|
||||
|
||||
if(old_turf == new_turf)
|
||||
return
|
||||
|
||||
// A more proper way would be to figure out which chunks have gone out of range, and which have come into range
|
||||
// and only remove/add to those.
|
||||
if(old_turf)
|
||||
for_all_chunks_in_range(source, /datum/chunk/proc/remove_source, list(source), old_turf)
|
||||
if(new_turf)
|
||||
for_all_chunks_in_range(source, /datum/chunk/proc/add_source, list(source), new_turf)
|
||||
|
||||
/datum/visualnet/proc/for_all_chunks_in_range(var/atom/source, var/proc_call, var/list/proc_args, var/turf/T)
|
||||
T = T ? T : get_turf(source)
|
||||
if(!T)
|
||||
return
|
||||
|
||||
var/x1 = max(0, T.x - 8) & ~0xf
|
||||
var/y1 = max(0, T.y - 8) & ~0xf
|
||||
var/x2 = min(world.maxx, T.x + 8) & ~0xf
|
||||
var/y2 = min(world.maxy, T.y + 8) & ~0xf
|
||||
|
||||
for(var/x = x1; x <= x2; x += 16)
|
||||
for(var/y = y1; y <= y2; y += 16)
|
||||
if(is_chunk_generated(x, y, T.z))
|
||||
var/datum/chunk/c = get_chunk(x, y, T.z)
|
||||
call(c, proc_call)(arglist(proc_args))
|
||||
|
||||
// Debug verb for VVing the chunk that the turf is in.
|
||||
/*
|
||||
/turf/verb/view_chunk()
|
||||
/turf/proc/view_chunk()
|
||||
set name = "View Chunk"
|
||||
set category = "Debug"
|
||||
set src in world
|
||||
|
||||
if(cameranet.chunkGenerated(x, y, z))
|
||||
var/datum/chunk/chunk = cameranet.getCameraChunk(x, y, z)
|
||||
if(cameranet.is_chunk_generated(x, y, z))
|
||||
var/datum/chunk/chunk = cameranet.get_chunk(x, y, z)
|
||||
usr.client.debug_variables(chunk)
|
||||
*/
|
||||
|
||||
/turf/proc/update_chunk()
|
||||
set name = "Update Chunk"
|
||||
set category = "Debug"
|
||||
set src in world
|
||||
|
||||
if(cameranet.is_chunk_generated(x, y, z))
|
||||
var/datum/chunk/chunk = cameranet.get_chunk(x, y, z)
|
||||
chunk.visibility_changed(TRUE)
|
||||
@@ -234,7 +234,7 @@ This saves us from having to call add_fingerprint() any time something is put in
|
||||
var/obj/item/clothing/ears/offear/O = new(W)
|
||||
O.forceMove(src)
|
||||
src.r_ear = O
|
||||
O.layer = 20
|
||||
O.layer = SCREEN_LAYER+0.01
|
||||
W.equipped(src, slot)
|
||||
update_inv_ears(redraw_mob)
|
||||
if(slot_r_ear)
|
||||
@@ -243,7 +243,7 @@ This saves us from having to call add_fingerprint() any time something is put in
|
||||
var/obj/item/clothing/ears/offear/O = new(W)
|
||||
O.forceMove(src)
|
||||
src.l_ear = O
|
||||
O.layer = 20
|
||||
O.layer = SCREEN_LAYER+0.01
|
||||
W.equipped(src, slot)
|
||||
update_inv_ears(redraw_mob)
|
||||
if(slot_glasses)
|
||||
@@ -311,7 +311,7 @@ This saves us from having to call add_fingerprint() any time something is put in
|
||||
src.r_hand = null
|
||||
update_inv_r_hand()
|
||||
|
||||
W.layer = 20
|
||||
W.layer = SCREEN_LAYER+0.01
|
||||
|
||||
if(W.action_button_name)
|
||||
update_action_buttons()
|
||||
|
||||
@@ -173,7 +173,7 @@
|
||||
reset_view(null)
|
||||
|
||||
/mob/living/proc/update_sight()
|
||||
if(stat == DEAD)
|
||||
if(stat == DEAD || eyeobj)
|
||||
update_dead_sight()
|
||||
else
|
||||
sight &= ~(SEE_TURFS|SEE_MOBS|SEE_OBJS)
|
||||
|
||||
@@ -216,6 +216,7 @@ var/list/ai_verbs_default = list(
|
||||
|
||||
job = "AI"
|
||||
setup_icon()
|
||||
eyeobj.possess(src)
|
||||
|
||||
/mob/living/silicon/ai/Destroy()
|
||||
qdel(aiPDA)
|
||||
|
||||
@@ -20,5 +20,3 @@
|
||||
for(var/obj/machinery/ai_status_display/O in SSmachinery.all_status_displays) //change status
|
||||
O.mode = 1
|
||||
O.emotion = "Neutral"
|
||||
src.view_core()
|
||||
return
|
||||
|
||||
@@ -228,21 +228,21 @@
|
||||
return
|
||||
if(!module_state_1)
|
||||
module_state_1 = O
|
||||
O.layer = 20
|
||||
O.layer = SCREEN_LAYER
|
||||
O.screen_loc = inv1.screen_loc
|
||||
contents += O
|
||||
if(istype(module_state_1,/obj/item/borg/sight))
|
||||
sight_mode |= module_state_1:sight_mode
|
||||
else if(!module_state_2)
|
||||
module_state_2 = O
|
||||
O.layer = 20
|
||||
O.layer = SCREEN_LAYER
|
||||
O.screen_loc = inv2.screen_loc
|
||||
contents += O
|
||||
if(istype(module_state_2,/obj/item/borg/sight))
|
||||
sight_mode |= module_state_2:sight_mode
|
||||
else if(!module_state_3)
|
||||
module_state_3 = O
|
||||
O.layer = 20
|
||||
O.layer = SCREEN_LAYER
|
||||
O.screen_loc = inv3.screen_loc
|
||||
contents += O
|
||||
if(istype(module_state_3,/obj/item/borg/sight))
|
||||
|
||||
@@ -127,7 +127,7 @@
|
||||
|
||||
robot_modules_background = new()
|
||||
robot_modules_background.icon_state = "block"
|
||||
robot_modules_background.layer = 19 //Objects that appear on screen are on layer 20, UI should be just below it.
|
||||
robot_modules_background.layer = SCREEN_LAYER //Objects that appear on screen are on layer 20, UI should be just below it.
|
||||
ident = rand(1, 999)
|
||||
module_sprites["Basic"] = "robot"
|
||||
icontype = "Basic"
|
||||
@@ -917,19 +917,19 @@
|
||||
return 1
|
||||
if(!module_state_1)
|
||||
module_state_1 = O
|
||||
O.layer = 20
|
||||
O.layer = SCREEN_LAYER
|
||||
contents += O
|
||||
if(istype(module_state_1,/obj/item/borg/sight))
|
||||
sight_mode |= module_state_1:sight_mode
|
||||
else if(!module_state_2)
|
||||
module_state_2 = O
|
||||
O.layer = 20
|
||||
O.layer = SCREEN_LAYER
|
||||
contents += O
|
||||
if(istype(module_state_2,/obj/item/borg/sight))
|
||||
sight_mode |= module_state_2:sight_mode
|
||||
else if(!module_state_3)
|
||||
module_state_3 = O
|
||||
O.layer = 20
|
||||
O.layer = SCREEN_LAYER
|
||||
contents += O
|
||||
if(istype(module_state_3,/obj/item/borg/sight))
|
||||
sight_mode |= module_state_3:sight_mode
|
||||
|
||||
@@ -51,6 +51,9 @@
|
||||
client.eye = src
|
||||
client.perspective = MOB_PERSPECTIVE
|
||||
|
||||
if(eyeobj)
|
||||
eyeobj.possess(src)
|
||||
|
||||
//set macro to normal incase it was overriden (like cyborg currently does)
|
||||
winset(src, null, "mainwindow.macro=macro hotkey_toggle.is-checked=false input.focus=true input.background-color=#D3B5B5")
|
||||
MOB_STOP_THINKING(src)
|
||||
|
||||
Reference in New Issue
Block a user