mirror of
https://github.com/PolarisSS13/Polaris.git
synced 2025-12-19 22:51:40 +00:00
This adds a system for picture-in-picture UI windows using vis_contents. Essentially, it allows you to make UI windows that show an area of turfs. It also refactors how cameranet visibility works. Currently, this is implemented on AIs. They gain two new UI buttons - "Enter Multicam Mode", and "Create Multicam". When they go into Multicam Mode, they see a background of animated binary numbers, and they are allowed to create an infinite amount of these picture in picture windows, which subsequently creates an AI Eye for each one. They are able to control each AI eye individually, by first clicking on the PIP window to select it as "active" and then using the normal arrow key controls. The PIP windows can be freely resized and moved around the area. You can control everything inside these PIP windows EXACTLY the same as you can using a traditional AI Eye, as demonstrated below. For admins, there is a config option to disable PIP entirely - simply set `var/multicam_allowed = TRUE` to FALSE if you wish to disable it from being used. (Please be reasonable.) <3 You can see an example of how this works here:  AI Multicam functionality. Do note that if the lightbulb in the AI core is busted, the multicam room is dark(er) than it would be, but you can still see your camera windows just fine. (I'll probably fix this later.) It only affects the "matrix" backdrop, the PIP windows are still fine. This has been runtime-tested with the latest `master` revision and produces 0 runtimes, and has no noticeable impact on server CPU usage. Polarisport is here! Port of https://github.com/VOREStation/VOREStation/pull/7752
168 lines
4.7 KiB
Plaintext
168 lines
4.7 KiB
Plaintext
// VISUAL NET
|
|
//
|
|
// The datum containing all the chunks.
|
|
|
|
#define CHUNK_SIZE 16
|
|
|
|
/datum/visualnet
|
|
// The chunks of the map, mapping the areas that an object can see.
|
|
var/list/chunks = list()
|
|
var/ready = 0
|
|
var/chunk_type = /datum/chunk
|
|
|
|
/datum/visualnet/New()
|
|
..()
|
|
visual_nets += src
|
|
|
|
/datum/visualnet/Destroy()
|
|
visual_nets -= src
|
|
return ..()
|
|
|
|
// Checks if a chunk has been Generated in x, y, z.
|
|
/datum/visualnet/proc/chunkGenerated(x, y, z)
|
|
x &= ~0xf
|
|
y &= ~0xf
|
|
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/visualnet/proc/getChunk(x, y, z)
|
|
x &= ~0xf
|
|
y &= ~0xf
|
|
var/key = "[x],[y],[z]"
|
|
if(!chunks[key])
|
|
chunks[key] = new chunk_type(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/visualnet/proc/visibility(list/moved_eyes, client/C, list/other_eyes)
|
|
if(!islist(moved_eyes))
|
|
moved_eyes = moved_eyes ? list(moved_eyes) : list()
|
|
if(islist(other_eyes))
|
|
other_eyes = (other_eyes - moved_eyes)
|
|
else
|
|
other_eyes = list()
|
|
|
|
var/list/chunks_pre_seen = list()
|
|
var/list/chunks_post_seen = list()
|
|
|
|
for(var/V in moved_eyes)
|
|
var/mob/observer/eye/eye = V
|
|
if(C)
|
|
chunks_pre_seen |= eye.visibleChunks
|
|
// 0xf = 15
|
|
var/static_range = eye.static_visibility_range
|
|
var/x1 = max(0, eye.x - static_range) & ~(CHUNK_SIZE - 1)
|
|
var/y1 = max(0, eye.y - static_range) & ~(CHUNK_SIZE - 1)
|
|
var/x2 = min(world.maxx, eye.x + static_range) & ~(CHUNK_SIZE - 1)
|
|
var/y2 = min(world.maxy, eye.y + static_range) & ~(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 |= 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, FALSE)
|
|
|
|
for(var/chunk in add)
|
|
var/datum/chunk/c = chunk
|
|
c.add(eye, FALSE)
|
|
|
|
if(C)
|
|
chunks_post_seen |= eye.visibleChunks
|
|
|
|
if(C)
|
|
for(var/V in other_eyes)
|
|
var/mob/observer/eye/eye = V
|
|
chunks_post_seen |= eye.visibleChunks
|
|
|
|
var/list/remove = chunks_pre_seen - chunks_post_seen
|
|
var/list/add = chunks_post_seen - chunks_pre_seen
|
|
|
|
for(var/chunk in remove)
|
|
var/datum/chunk/c = chunk
|
|
C.images -= c.obscured
|
|
|
|
for(var/chunk in add)
|
|
var/datum/chunk/c = chunk
|
|
C.images += c.obscured
|
|
|
|
// 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(!ticker || (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)
|
|
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
|
|
|
|
//to_world("X1: [x1] - Y1: [y1] - X2: [x2] - Y2: [y2]")
|
|
|
|
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()
|
|
|
|
/datum/visualnet/proc/onMajorChunkChange(atom/c, var/choice, var/datum/chunk/chunk)
|
|
|
|
// Will check if a mob is on a viewable turf. Returns 1 if it is, otherwise returns 0.
|
|
|
|
/datum/visualnet/proc/checkVis(mob/living/target as mob)
|
|
// 0xf = 15
|
|
var/turf/position = get_turf(target)
|
|
return checkTurfVis(position)
|
|
|
|
/datum/visualnet/proc/checkTurfVis(var/turf/position)
|
|
var/datum/chunk/chunk = getChunk(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/chunk/chunk = cameranet.getCameraChunk(x, y, z)
|
|
usr.client.debug_variables(chunk)
|
|
*/
|