Files
CHOMPStation2/code/WorkInProgress/AI_Visibility.dm

522 lines
13 KiB
Plaintext

//All credit for this goes to Uristqwerty.
//And some to me! -Mini
//This file is partly designed around being able to uninclude it to go back to the old ai viewing system completely.
//(And therefore also be portable to another similar codebase simply by transferring the file and including it after the other AI code files.)
//There are probably a few parts that don't do that at the moment, but I'll fix them at some point.
/turf
var/image/obscured
var/image/dim
/turf/proc/visibilityChanged()
cameranet.updateVisibility(src)
/turf/New()
..()
cameranet.updateVisibility(src)
/*
/turf/Del()
..()
cameranet.updateVisibility(src)
*/
/datum/camerachunk
var/list/obscuredTurfs = list()
var/list/visibleTurfs = list()
var/list/dimTurfs = list()
var/list/obscured = list()
var/list/dim = list()
var/list/cameras = list()
var/list/turfs = list()
var/list/seenby = list()
var/visible = 0
var/changed = 1
var/updating = 0
var/x
var/y
var/z
var/minimap_updating = 0
var/icon/minimap_icon = new('minimap.dmi', "chunk_base")
var/obj/minimap_obj/minimap_obj = new()
/obj/minimap_obj/Click(location, control, params)
var/list/par = params2list(params)
var/screen_loc = par["screen-loc"]
if(findtext(screen_loc, "minimap:") != 1)
return
screen_loc = copytext(screen_loc, length("minimap:") + 1)
var/x_text = copytext(screen_loc, 1, findtext(screen_loc, ","))
var/y_text = copytext(screen_loc, findtext(screen_loc, ",") + 1)
var/x = (text2num(copytext(x_text, 1, findtext(x_text, ":"))) - 1) * 16
x += round((text2num(copytext(x_text, findtext(x_text, ":") + 1)) + 1) / 2)
var/y = (text2num(copytext(y_text, 1, findtext(y_text, ":"))) - 1) * 16
y += round((text2num(copytext(y_text, findtext(y_text, ":") + 1)) + 1) / 2)
usr.loc = locate(max(1, x - 1), max(1, y - 1), usr.z)
/mob/verb/minimap_test()
winshow(src, "minimapwindow", 1)
client.screen |= cameranet.minimap
/datum/camerachunk/proc/update_minimap()
if(changed && !updating)
update()
minimap_icon.Blend(rgb(255, 0, 0), ICON_MULTIPLY)
var/list/turfs = visibleTurfs | dimTurfs
for(var/turf/turf in turfs)
var/x = (turf.x & 0xf) * 2
var/y = (turf.y & 0xf) * 2
if(turf.density)
minimap_icon.DrawBox(rgb(100, 100, 100), x + 1, y + 1, x + 2, y + 2)
continue
else if(istype(turf, /turf/space))
minimap_icon.DrawBox(rgb(0, 0, 0), x + 1, y + 1, x + 2, y + 2)
else
minimap_icon.DrawBox(rgb(200, 200, 200), x + 1, y + 1, x + 2, y + 2)
for(var/obj/structure/o in turf)
if(o.density)
if(istype(o, /obj/structure/window) && (o.dir == NORTH || o.dir == SOUTH || o.dir == EAST || o.dir == WEST))
if(o.dir == NORTH)
minimap_icon.DrawBox(rgb(150, 150, 200), x + 1, y + 2, x + 2, y + 2)
else if(o.dir == SOUTH)
minimap_icon.DrawBox(rgb(150, 150, 200), x + 1, y + 1, x + 2, y + 1)
else if(o.dir == EAST)
minimap_icon.DrawBox(rgb(150, 150, 200), x + 3, y + 1, x + 2, y + 2)
else if(o.dir == WEST)
minimap_icon.DrawBox(rgb(150, 150, 200), x + 1, y + 1, x + 1, y + 2)
else
minimap_icon.DrawBox(rgb(150, 150, 150), x + 1, y + 1, x + 2, y + 2)
break
for(var/obj/machinery/door/o in turf)
if(istype(o, /obj/machinery/door/window))
if(o.dir == NORTH)
minimap_icon.DrawBox(rgb(100, 150, 100), x + 1, y + 2, x + 2, y + 2)
else if(o.dir == SOUTH)
minimap_icon.DrawBox(rgb(100, 150, 100), x + 1, y + 1, x + 2, y + 1)
else if(o.dir == EAST)
minimap_icon.DrawBox(rgb(100, 150, 100), x + 2, y + 1, x + 2, y + 2)
else if(o.dir == WEST)
minimap_icon.DrawBox(rgb(100, 150, 100), x + 1, y + 1, x + 1, y + 2)
else
minimap_icon.DrawBox(rgb(100, 150, 100), x + 1, y + 1, x + 2, y + 2)
break
minimap_obj.screen_loc = "minimap:[src.x / 16],[src.y / 16]"
minimap_obj.icon = minimap_icon
/mob/aiEye
var/list/visibleCameraChunks = list()
var/mob/ai = null
density = 0
/datum/camerachunk/proc/add(mob/aiEye/ai)
ai.visibleCameraChunks += src
if(ai.ai.client)
ai.ai.client.images += obscured
ai.ai.client.images += dim
visible++
seenby += ai
if(changed && !updating)
update()
changed = 0
/datum/camerachunk/proc/remove(mob/aiEye/ai)
ai.visibleCameraChunks -= src
if(ai.ai.client)
ai.ai.client.images -= obscured
ai.ai.client.images -= dim
seenby -= ai
if(visible > 0)
visible--
/datum/camerachunk/proc/visibilityChanged(turf/loc)
if(!(loc in visibleTurfs))
return
hasChanged()
/datum/camerachunk/proc/hasChanged()
if(visible)
if(!updating)
updating = 1
spawn(10)//Batch large changes, such as many doors opening or closing at once
update()
updating = 0
else
changed = 1
if(!minimap_updating)
minimap_updating = 1
spawn(1200)
if(changed && !updating)
update()
changed = 0
update_minimap()
minimap_updating = 0
/datum/camerachunk/proc/update()
var/list/newDimTurfs = list()
var/list/newVisibleTurfs = list()
for(var/obj/machinery/camera/c in cameras)
var/lum = c.luminosity
c.luminosity = 7
newDimTurfs |= turfs & view(7, c)
newVisibleTurfs |= turfs & view(6, c)
c.luminosity = lum
var/list/dimAdded = newDimTurfs - dimTurfs
var/list/dimRemoved = dimTurfs - newDimTurfs
var/list/visAdded = newVisibleTurfs - visibleTurfs
var/list/visRemoved = visibleTurfs - newVisibleTurfs
visibleTurfs = newVisibleTurfs
dimTurfs = newDimTurfs
obscuredTurfs = turfs - dimTurfs
dimTurfs -= visibleTurfs
for(var/turf/t in dimRemoved)
if(t.dim)
dim -= t.dim
for(var/mob/aiEye/m in seenby)
if(m.ai.client)
m.ai.client.images -= t.dim
if(!(t in visibleTurfs))
if(!t.obscured)
t.obscured = image('cameravis.dmi', t, "black", 15)
obscured += t.obscured
for(var/mob/aiEye/m in seenby)
if(m.ai.client)
m.ai.client.images += t.obscured
for(var/turf/t in dimAdded)
if(!(t in visibleTurfs))
if(!t.dim)
t.dim = image('cameravis.dmi', t, "dim", 15)
t.mouse_opacity = 0
dim += t.dim
for(var/mob/aiEye/m in seenby)
if(m.ai.client)
m.ai.client.images += t.dim
if(t.obscured)
obscured -= t.obscured
for(var/mob/aiEye/m in seenby)
if(m.ai.client)
m.ai.client.images -= t.obscured
for(var/turf/t in visAdded)
if(t.obscured)
obscured -= t.obscured
for(var/mob/aiEye/m in seenby)
if(m.ai.client)
m.ai.client.images -= t.obscured
for(var/turf/t in visRemoved)
if(t in obscuredTurfs)
if(!t.obscured)
t.obscured = image('cameravis.dmi', t, "black", 15)
obscured += t.obscured
for(var/mob/aiEye/m in seenby)
if(m.ai.client)
m.ai.client.images += t.obscured
/datum/camerachunk/New(loc, x, y, z)
x &= ~0xf
y &= ~0xf
src.x = x
src.y = y
src.z = z
for(var/obj/machinery/camera/c in range(16, locate(x + 8, y + 8, z)))
if(c.status)
cameras += c
turfs = block(locate(x, y, z), locate(min(world.maxx, x + 15), min(world.maxy, y + 15), z))
for(var/obj/machinery/camera/c in cameras)
var/lum = c.luminosity
c.luminosity = 7
dimTurfs |= turfs & view(7, c)
visibleTurfs |= turfs & view(6, c)
c.luminosity = lum
obscuredTurfs = turfs - dimTurfs
dimTurfs -= visibleTurfs
for(var/turf/t in obscuredTurfs)
if(!t.obscured)
t.obscured = image('cameravis.dmi', t, "black", 15)
obscured += t.obscured
for(var/turf/t in dimTurfs)
if(!(t in visibleTurfs))
if(!t.dim)
t.dim = image('cameravis.dmi', t, "dim", TURF_LAYER)
t.dim.mouse_opacity = 0
dim += t.dim
cameranet.minimap += minimap_obj
var/datum/cameranet/cameranet = new()
/datum/cameranet
var/list/cameras = list()
var/list/chunks = list()
var/network = "net1"
var/ready = 0
var/list/minimap = list()
/datum/cameranet/New()
..()
spawn(200)
for(var/x = 0, x <= world.maxx, x += 16)
for(var/y = 0, y <= world.maxy, y += 16)
sleep(1)
var/datum/camerachunk/c = getCameraChunk(x, y, 1)
c.update_minimap()
/datum/cameranet/proc/chunkGenerated(x, y, z)
var/key = "[x],[y],[z]"
return key in chunks
/datum/cameranet/proc/getCameraChunk(x, y, z)
var/key = "[x],[y],[z]"
if(!(key in chunks))
chunks[key] = new /datum/camerachunk(null, x, y, z)
return chunks[key]
/datum/cameranet/proc/visibility(mob/aiEye/ai)
var/x1 = max(0, ai.x - 16) & ~0xf
var/y1 = max(0, ai.y - 16) & ~0xf
var/x2 = min(world.maxx, ai.x + 16) & ~0xf
var/y2 = min(world.maxy, ai.y + 16) & ~0xf
var/list/visibleChunks = list()
for(var/x = x1; x <= x2; x += 16)
for(var/y = y1; y <= y2; y += 16)
visibleChunks += getCameraChunk(x, y, ai.z)
var/list/remove = ai.visibleCameraChunks - visibleChunks
var/list/add = visibleChunks - ai.visibleCameraChunks
for(var/datum/camerachunk/c in remove)
c.remove(ai)
for(var/datum/camerachunk/c in add)
c.add(ai)
/datum/cameranet/proc/updateVisibility(turf/loc)
if(!chunkGenerated(loc.x & ~0xf, loc.y & ~0xf, loc.z))
return
var/datum/camerachunk/chunk = getCameraChunk(loc.x & ~0xf, loc.y & ~0xf, loc.z)
chunk.visibilityChanged(loc)
/datum/cameranet/proc/addCamera(obj/machinery/camera/c)
var/x1 = max(0, c.x - 16) & ~0xf
var/y1 = max(0, c.y - 16) & ~0xf
var/x2 = min(world.maxx, c.x + 16) & ~0xf
var/y2 = min(world.maxy, c.y + 16) & ~0xf
for(var/x = x1; x <= x2; x += 16)
for(var/y = y1; y <= y2; y += 16)
if(chunkGenerated(x, y, c.z))
var/datum/camerachunk/chunk = getCameraChunk(x, y, c.z)
if(!(c in chunk.cameras))
chunk.cameras += c
chunk.hasChanged()
/datum/cameranet/proc/removeCamera(obj/machinery/camera/c)
var/x1 = max(0, c.x - 16) & ~0xf
var/y1 = max(0, c.y - 16) & ~0xf
var/x2 = min(world.maxx, c.x + 16) & ~0xf
var/y2 = min(world.maxy, c.y + 16) & ~0xf
for(var/x = x1; x <= x2; x += 16)
for(var/y = y1; y <= y2; y += 16)
if(chunkGenerated(x, y, c.z))
var/datum/camerachunk/chunk = getCameraChunk(x, y, c.z)
if(!c)
chunk.hasChanged()
if(c in chunk.cameras)
chunk.cameras -= c
chunk.hasChanged()
/mob/living/silicon/ai/var/mob/aiEye/eyeobj = new()
/mob/living/silicon/ai/New()
..()
eyeobj.ai = src
spawn(20)
freelook()
/mob/living/silicon/ai/death(gibbed)
if(client && client.eye == eyeobj)
for(var/datum/camerachunk/c in eyeobj.visibleCameraChunks)
c.remove(eyeobj)
client.eye = src
return ..(gibbed)
/mob/living/silicon/ai/verb/freelook()
set category = "AI Commands"
set name = "freelook"
current = null //cancel camera view first, it causes problems
cameraFollow = null
// machine = null
if(!eyeobj) //if it got deleted somehow (like an admin trying to fix things <.<')
eyeobj = new()
client.eye = eyeobj
eyeobj.loc = loc
cameranet.visibility(eyeobj)
cameraFollow = null
/mob/aiEye/Move()
. = ..()
if(.)
cameranet.visibility(src)
/client/AIMove(n, direct, var/mob/living/silicon/ai/user)
if(eye == user.eyeobj)
user.eyeobj.loc = get_step(user.eyeobj, direct)
cameranet.visibility(user.eyeobj)
else
return ..()
/*
/client/AIMoveZ(direct, var/mob/living/silicon/ai/user)
if(eye == user.eyeobj)
var/dif = 0
if(direct == UP && user.eyeobj.z > 1)
dif = -1
else if(direct == DOWN && user.eyeobj.z < 4)
dif = 1
user.eyeobj.loc = locate(user.eyeobj.x, user.eyeobj.y, user.eyeobj.z + dif)
cameranet.visibility(user.eyeobj)
else
return ..()
*/
/turf/move_camera_by_click()
if(istype(usr, /mob/living/silicon/ai))
var/mob/living/silicon/ai/AI = usr
if(AI.client.eye == AI.eyeobj)
return
return ..()
/obj/machinery/door/update_nearby_tiles(need_rebuild)
. = ..(need_rebuild)
cameranet.updateVisibility(loc)
/obj/machinery/camera/New()
..()
cameranet.addCamera(src)
/obj/machinery/camera/Del()
cameranet.removeCamera(src)
..()
/obj/machinery/camera/attackby(var/obj/item/weapon/W as obj, var/mob/user as mob)
. = ..(W, user)
if(istype(W, /obj/item/weapon/wirecutters))
if(status)
cameranet.addCamera(src)
else
cameranet.removeCamera(src)
/proc/checkcameravis(atom/A)
for(var/obj/machinery/camera/C in view(A,7))
if(!C.status || C.stat == 2)
continue
return 1
return 0
/mob/living/silicon/ai/switchCamera(var/obj/machinery/camera/C)
eyeobj.loc = C.loc
cameranet.visibility(eyeobj)
return
/mob/living/silicon/ai/attack_ai(var/mob/user as mob)
if (user != src)
return
if (stat == 2)
return
var/list/L = list()
for (var/obj/machinery/camera/C in world)
L.Add(C)
camera_sort(L)
L = camera_network_sort(L)
var/list/D = list()
for (var/obj/machinery/camera/C in L)
if ( C.network in src.networks )
D[text("[]: [][]", C.network, C.c_tag, (C.status ? null : " (Deactivated)"))] = C
D["Cancel"] = "Cancel"
var/t = input(user, "Which camera should you change to?") as null|anything in D
if (!t || t == "Cancel")
return 0
var/obj/machinery/camera/C = D[t]
eyeobj.loc = C.loc
cameranet.visibility(eyeobj)
return
/mob/living/silicon/ai/cancel_camera()
set name = "Cancel Camera View"
set category = "OOC"
reset_view(null)
machine = null
del eyeobj
src.freelook()