modifying visibility interface of ai to use generic visibility_interface

Conflicts:
	baystation12.dme
	code/game/gamemodes/malfunction/Malf_Modules.dm
	code/modules/mob/living/silicon/ai/freelook/cameranet.dm
	code/modules/mob/living/silicon/ai/freelook/chunk.dm
	code/modules/mob/living/silicon/ai/freelook/eye.dm
	code/modules/mob/living/silicon/ai/freelook/update_triggers.dm
This commit is contained in:
jack-fractal
2014-05-15 04:43:49 -04:00
committed by ZomgPonies
parent 466070e10f
commit 3df35fe03c
19 changed files with 119 additions and 461 deletions
+2 -2
View File
@@ -58,7 +58,7 @@ var/intercom_range_display_status = 0
del(C)
if(camera_range_display_status)
for(var/obj/machinery/camera/C in cameranet.cameras)
for(var/obj/machinery/camera/C in cameranet.viewpoints)
new/obj/effect/debugging/camera_range(C.loc)
feedback_add_details("admin_verb","mCRD") //If you are copy-pasting this, ensure the 2nd parameter is unique to the new proc!
@@ -74,7 +74,7 @@ var/intercom_range_display_status = 0
var/list/obj/machinery/camera/CL = list()
for(var/obj/machinery/camera/C in cameranet.cameras)
for(var/obj/machinery/camera/C in cameranet.viewpoints)
CL += C
var/output = {"<B>CAMERA ANOMALIES REPORT</B><HR>
+3 -3
View File
@@ -396,7 +396,7 @@ var/list/ai_list = list()
unset_machine()
src << browse(null, t1)
if (href_list["switchcamera"])
switchCamera(locate(href_list["switchcamera"])) in cameranet.cameras
switchCamera(locate(href_list["switchcamera"])) in cameranet.viewpoints
if (href_list["showalerts"])
ai_alerts()
//Carn: holopad requests
@@ -626,7 +626,7 @@ var/list/ai_list = list()
var/mob/living/silicon/ai/U = usr
for (var/obj/machinery/camera/C in cameranet.cameras)
for (var/obj/machinery/camera/C in cameranet.viewpoints)
if(!C.can_use())
continue
@@ -644,7 +644,7 @@ var/list/ai_list = list()
if(isnull(network))
network = old_network // If nothing is selected
else
for(var/obj/machinery/camera/C in cameranet.cameras)
for(var/obj/machinery/camera/C in cameranet.viewpoints)
if(!C.can_use())
continue
if(network in C.network)
@@ -1,150 +1,14 @@
// CAMERA NET
//
// The datum containing all the chunks.
var/const/CHUNK_SIZE = 16 // Only chunk sizes that are to the power of 2. E.g: 2, 4, 8, 16, etc..
var/datum/cameranet/cameranet = new()
/datum/cameranet
// 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()
// The chunks of the map, mapping the areas that the cameras can see.
var/list/chunks = list()
var/ready = 0
// Checks if a chunk has been Generated in x, y, z.
/datum/cameranet/proc/chunkGenerated(x, y, z)
x &= ~(CHUNK_SIZE - 1)
y &= ~(CHUNK_SIZE - 1)
var/key = "[x],[y],[z]"
return (chunks[key])
// Returns the chunk in the x, y, z.
// If there is no chunk, it creates a new chunk and returns that.
/datum/cameranet/proc/getCameraChunk(x, y, z)
x &= ~(CHUNK_SIZE - 1)
y &= ~(CHUNK_SIZE - 1)
var/key = "[x],[y],[z]"
if(!chunks[key])
chunks[key] = new /datum/camerachunk(null, 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.
/datum/cameranet/proc/visibility(mob/camera/aiEye/ai)
// 0xf = 15
var/x1 = max(0, ai.x - 16) & ~(CHUNK_SIZE - 1)
var/y1 = max(0, ai.y - 16) & ~(CHUNK_SIZE - 1)
var/x2 = min(world.maxx, ai.x + 16) & ~(CHUNK_SIZE - 1)
var/y2 = min(world.maxy, ai.y + 16) & ~(CHUNK_SIZE - 1)
var/list/visibleChunks = list()
for(var/x = x1; x <= x2; x += CHUNK_SIZE)
for(var/y = y1; y <= y2; y += CHUNK_SIZE)
visibleChunks |= getCameraChunk(x, y, ai.z)
var/list/remove = ai.visibleCameraChunks - visibleChunks
var/list/add = visibleChunks - ai.visibleCameraChunks
for(var/chunk in remove)
var/datum/camerachunk/c = chunk
c.remove(ai)
for(var/chunk in add)
var/datum/camerachunk/c = chunk
c.add(ai)
// Updates the chunks that the turf is located in. Use this when obstacles are destroyed or when doors open.
/datum/cameranet/proc/updateVisibility(atom/A, var/opacity_check = 1)
if(!ticker || (opacity_check && !A.opacity))
return
majorChunkChange(A, 2)
/datum/cameranet/proc/updateChunk(x, y, z)
// 0xf = 15
if(!chunkGenerated(x, y, z))
return
var/datum/camerachunk/chunk = getCameraChunk(x, y, z)
chunk.hasChanged()
// Removes a camera from a chunk.
/datum/cameranet/proc/removeCamera(obj/machinery/camera/c)
if(c.can_use())
majorChunkChange(c, 0)
// Add a camera to a chunk.
/datum/cameranet/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/cameranet/proc/updatePortableCamera(obj/machinery/camera/c)
if(c.can_use())
majorChunkChange(c, 1)
//else
// majorChunkChange(c, 0)
// 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/cameranet/proc/majorChunkChange(atom/c, var/choice)
// 0xf = 15
if(!c)
return
var/turf/T = get_turf(c)
if(T)
var/x1 = max(0, T.x - (CHUNK_SIZE / 2)) & ~(CHUNK_SIZE - 1)
var/y1 = max(0, T.y - (CHUNK_SIZE / 2)) & ~(CHUNK_SIZE - 1)
var/x2 = min(world.maxx, T.x + (CHUNK_SIZE / 2)) & ~(CHUNK_SIZE - 1)
var/y2 = min(world.maxy, T.y + (CHUNK_SIZE / 2)) & ~(CHUNK_SIZE - 1)
//world << "X1: [x1] - Y1: [y1] - X2: [x2] - Y2: [y2]"
for(var/x = x1; x <= x2; x += CHUNK_SIZE)
for(var/y = y1; y <= y2; y += CHUNK_SIZE)
if(chunkGenerated(x, y, T.z))
var/datum/camerachunk/chunk = getCameraChunk(x, y, T.z)
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
chunk.hasChanged()
// Will check if a mob is on a viewable turf. Returns 1 if it is, otherwise returns 0.
/datum/cameranet/proc/checkCameraVis(mob/living/target as mob)
// 0xf = 15
var/turf/position = get_turf(target)
var/datum/camerachunk/chunk = getCameraChunk(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
// Debug verb for VVing the chunk that the turf is in.
/*
/turf/verb/view_chunk()
set src in world
if(cameranet.chunkGenerated(x, y, z))
var/datum/camerachunk/chunk = cameranet.getCameraChunk(x, y, z)
usr.client.debug_variables(chunk)
*/
/datum/visibility_network/cameras
ChunkType = /datum/visibility_chunk/camera
/datum/visibility_network/cameras/getViewpointFromMob(var/mob/currentMob)
var/mob/living/silicon/robot/currentRobot=currentMob
if(currentRobot)
return currentRobot.camera
return FALSE
/datum/visibility_network/cameras/validViewpoint(var/viewpoint)
var/obj/machinery/camera/c = viewpoint
if (!c)
return FALSE
return c.can_use()
@@ -1,174 +1,23 @@
#define UPDATE_BUFFER 25 // 2.5 seconds
// CAMERA CHUNK
//
// A 16x16 grid of the map with a list of turfs that can be seen, are visible and are dimmed.
// Allows the AI Eye to stream these chunks and know what it can and cannot see.
/datum/camerachunk
var/list/obscuredTurfs = list()
var/list/visibleTurfs = list()
var/list/obscured = list()
var/list/cameras = list()
var/list/turfs = list()
var/list/seenby = list()
var/visible = 0
var/changed = 0
var/updating = 0
var/x = 0
var/y = 0
var/z = 0
// Add an AI eye to the chunk, then update if changed.
/datum/camerachunk/proc/add(mob/camera/aiEye/ai)
if(!ai.ai)
return
ai.visibleCameraChunks += src
if(ai.ai.client)
ai.ai.client.images += obscured
visible++
seenby += ai
if(changed && !updating)
update()
// Remove an AI eye from the chunk, then update if changed.
/datum/camerachunk/proc/remove(mob/camera/aiEye/ai)
if(!ai.ai)
return
ai.visibleCameraChunks -= src
if(ai.ai.client)
ai.ai.client.images -= obscured
seenby -= ai
if(visible > 0)
visible--
// Called when a chunk has changed. I.E: A wall was deleted.
/datum/camerachunk/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/camerachunk/proc/hasChanged(var/update_now = 0)
if(visible || update_now)
if(!updating)
updating = 1
spawn(UPDATE_BUFFER) // Batch large changes, such as many doors opening or closing at once
update()
updating = 0
else
changed = 1
// The actual updating. It gathers the visible turfs from cameras and puts them into the appropiate lists.
/datum/camerachunk/proc/update()
//set background = 1
var/list/newVisibleTurfs = list()
for(var/camera in cameras)
var/obj/machinery/camera/c = camera
if(!c)
continue
if(!c.can_use())
continue
var/turf/point = locate(src.x + (CHUNK_SIZE / 2), src.y + (CHUNK_SIZE / 2), src.z)
if(get_dist(point, c) > CHUNK_SIZE + (CHUNK_SIZE / 2))
continue
for(var/turf/t in c.can_see())
// Possible optimization: if(turfs[t]) here, rather than &= turfs afterwards.
// List associations use a tree or hashmap of some sort (alongside the list itself)
// so are surprisingly fast. (significantly faster than var/thingy/x in list, in testing)
newVisibleTurfs[t] = t
// 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(t.obscured)
obscured -= t.obscured
for(var/eye in seenby)
var/mob/camera/aiEye/m = eye
if(!m || !m.ai)
continue
if(m.ai.client)
m.ai.client.images -= t.obscured
for(var/turf in visRemoved)
var/turf/t = turf
if(obscuredTurfs[t])
if(!t.obscured)
t.obscured = image('icons/effects/cameravis.dmi', t, "black", 15)
obscured += t.obscured
for(var/eye in seenby)
var/mob/camera/aiEye/m = eye
if(!m || !m.ai)
seenby -= m
continue
if(m.ai.client)
m.ai.client.images += t.obscured
changed = 0
// Create a new camera chunk, since the chunks are made as they are needed.
/datum/camerachunk/New(loc, x, y, z)
// 0xf = 15
x &= ~(CHUNK_SIZE - 1)
y &= ~(CHUNK_SIZE - 1)
src.x = x
src.y = y
src.z = z
for(var/obj/machinery/camera/c in range(CHUNK_SIZE, locate(x + (CHUNK_SIZE / 2), y + (CHUNK_SIZE / 2), z)))
if(c.can_use())
cameras += c
for(var/turf/t in block(locate(x, y, z), locate(min(x + CHUNK_SIZE - 1, world.maxx), min(y + CHUNK_SIZE - 1, world.maxy), z)))
turfs[t] = t
for(var/camera in cameras)
var/obj/machinery/camera/c = camera
if(!c)
continue
if(!c.can_use())
continue
for(var/turf/t in c.can_see())
// Possible optimization: if(turfs[t]) here, rather than &= turfs afterwards.
// List associations use a tree or hashmap of some sort (alongside the list itself)
// so are surprisingly fast. (significantly faster than var/thingy/x in list, in testing)
visibleTurfs[t] = t
// Removes turf that isn't in turfs.
visibleTurfs &= turfs
obscuredTurfs = turfs - visibleTurfs
for(var/turf in obscuredTurfs)
var/turf/t = turf
if(!t.obscured)
t.obscured = image('icons/effects/cameravis.dmi', t, "black", 15)
obscured += t.obscured
#undef UPDATE_BUFFER
/datum/visibility_chunk/camera
/datum/visibility_chunk/camera/validViewpoint(var/viewpoint)
var/obj/machinery/camera/c = viewpoint
if(!c)
return FALSE
if(!c.can_use())
return FALSE
var/turf/point = locate(src.x + 8, src.y + 8, src.z)
if(get_dist(point, c) > 24)
return FALSE
return TRUE
/datum/visibility_chunk/camera/getVisibleTurfsForViewpoint(var/viewpoint)
var/obj/machinery/camera/c = viewpoint
return c.can_see()
/datum/visibility_chunk/camera/findNearbyViewpoints()
for(var/obj/machinery/camera/c in range(16, locate(x + 8, y + 8, z)))
if(c.can_use())
viewpoints += c
@@ -3,17 +3,43 @@
// An invisible (no icon) 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/camera/aiEye
/mob/aiEye
name = "Inactive AI Eye"
var/list/visibleCameraChunks = list()
icon = 'icons/obj/status_display.dmi' // For AI friend secret shh :o
var/mob/living/silicon/ai/ai = null
density = 0
status_flags = GODMODE // You can't damage it.
mouse_opacity = 0
see_in_dark = 7
/mob/aiEye/New()
..()
visibility_interface = new /datum/visibility_interface/ai_eye(src)
// Movement code. Returns 0 to stop air movement from moving it.
/mob/aiEye/Move()
return 0
// Hide popout menu verbs
/mob/aiEye/examine()
set popup_menu = 0
set src = usr.contents
return 0
/mob/aiEye/pull()
set popup_menu = 0
set src = usr.contents
return 0
/mob/aiEye/point()
set popup_menu = 0
set src = usr.contents
return 0
// Use this when setting the aiEye's location.
// It will also stream the chunk that the new loc is in.
/mob/camera/aiEye/proc/setLoc(var/T)
/mob/aiEye/proc/setLoc(var/T)
if(ai)
if(!isturf(ai.loc))
return
@@ -28,7 +54,7 @@
H.move_hologram()
/mob/camera/aiEye/Move()
/mob/aiEye/Move()
return 0
// AI MOVEMENT
@@ -36,7 +62,7 @@
// The AI's "eye". Described on the top of the page.
/mob/living/silicon/ai
var/mob/camera/aiEye/eyeobj = new()
var/mob/aiEye/eyeobj = new()
var/sprint = 10
var/cooldown = 0
var/acceleration = 1
@@ -116,7 +142,8 @@
if(client && client.eye)
client.eye = src
for(var/datum/camerachunk/c in eyeobj.visibleCameraChunks)
for(var/datum/visibility_chunk/camera/c in eyeobj.visibility_interface.visible_chunks)
c.remove(eyeobj)
/mob/living/silicon/ai/verb/toggle_acceleration()
@@ -43,7 +43,7 @@
WHERE IS EVERYTHING?
cameranet.dm = Everything about the cameranet datum.
cameraNetwork.dm = Everything about the cameraNetwork datum.
chunk.dm = Everything about the chunk datum.
eye.dm = Everything about the AI and the AIEye.
updating.dm = Everything about triggers that will update chunks.
@@ -1,79 +1,3 @@
#define BORG_CAMERA_BUFFER 30
//UPDATE TRIGGERS, when the chunk (and the surrounding chunks) should update.
// TURFS
/turf
var/image/obscured
/turf/proc/visibilityChanged()
if(ticker)
cameranet.updateVisibility(src)
/turf/simulated/Destroy()
visibilityChanged()
..()
/turf/simulated/New()
..()
visibilityChanged()
// STRUCTURES
/obj/structure/Destroy()
if(ticker)
cameranet.updateVisibility(src)
..()
/obj/structure/New()
..()
if(ticker)
cameranet.updateVisibility(src)
// EFFECTS
/obj/effect/Destroy()
if(ticker)
cameranet.updateVisibility(src)
..()
/obj/effect/New()
..()
if(ticker)
cameranet.updateVisibility(src)
// DOORS
// Simply updates the visibility of the area when it opens/closes/destroyed.
/obj/machinery/door/proc/update_freelok_sight()
// Glass door glass = 1
// don't check then?
if(!glass && cameranet)
cameranet.updateVisibility(src, 0)
// ROBOT MOVEMENT
// Update the portable camera everytime the Robot moves.
// This might be laggy, comment it out if there are problems.
/mob/living/silicon/robot/var/updating = 0
/mob/living/silicon/robot/Move()
var/oldLoc = src.loc
. = ..()
if(.)
if(src.camera && src.camera.network.len)
if(!updating)
updating = 1
spawn(BORG_CAMERA_BUFFER)
if(oldLoc != src.loc)
cameranet.updatePortableCamera(src.camera)
updating = 0
// CAMERA
// An addition to deactivate which removes/adds the camera from the chunk list based on if it works or not.
@@ -81,23 +5,23 @@
/obj/machinery/camera/deactivate(user as mob, var/choice = 1)
..(user, choice)
if(src.can_use())
cameranet.addCamera(src)
cameranet.addViewpoint(src)
else
src.SetLuminosity(0)
cameranet.removeCamera(src)
cameranet.removeViewpoint(src)
/obj/machinery/camera/New()
..()
cameranet.cameras += src //Camera must be added to global list of all cameras no matter what...
cameranet.viewpoints += src //Camera must be added to global list of all cameras no matter what...
var/list/open_networks = difflist(network,RESTRICTED_CAMERA_NETWORKS) //...but if all of camera's networks are restricted, it only works for specific camera consoles.
if(open_networks.len) //If there is at least one open network, chunk is available for AI usage.
cameranet.addCamera(src)
cameranet.addViewpoint(src)
/obj/machinery/camera/Destroy()
cameranet.cameras -= src
/obj/machinery/camera/Del()
cameranet.viewpoints -= src
var/list/open_networks = difflist(network,RESTRICTED_CAMERA_NETWORKS)
if(open_networks.len)
cameranet.removeCamera(src)
cameranet.removeViewpoint(src)
..()
#undef BORG_CAMERA_BUFFER
@@ -0,0 +1,10 @@
/datum/visibility_interface/ai_eye
chunk_type = /datum/visibility_chunk/camera
/datum/visibility_interface/ai_eye/getClient()
var/mob/aiEye/eye = controller
if (!eye)
return FALSE
if (!eye.ai)
return FALSE
return eye.ai.client
+2 -1
View File
@@ -205,6 +205,7 @@
var/obj/control_object //Used by admins to possess objects. All mobs should have this var
var/datum/visibility_interface/visibility_interface = null // used by the visibility system to provide an interface for the visibility networks
//Whether or not mobs can understand other mobtypes. These stay in /mob so that ghosts can hear everything.
var/universal_speak = 0 // Set to 1 to enable the mob to speak to everyone -- TLE
@@ -224,4 +225,4 @@
var/list/active_genes=list()
var/last_movement = -100 // Last world.time the mob actually moved of its own accord.
var/last_movement = -100 // Last world.time the mob actually moved of its own accord.
+1 -1
View File
@@ -101,7 +101,7 @@ proc/isembryo(A)
return 0
/proc/isAIEye(A)
if(istype(A, /mob/camera/aiEye))
if(istype(A, /mob/aiEye))
return 1
return 0