mirror of
https://github.com/PolarisSS13/Polaris.git
synced 2025-12-19 14:42:25 +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
155 lines
4.0 KiB
Plaintext
155 lines
4.0 KiB
Plaintext
#define UPDATE_BUFFER 25 // 2.5 seconds
|
|
|
|
// 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
|
|
var/icon = 'icons/effects/cameravis.dmi'
|
|
var/icon_state = "black"
|
|
|
|
/datum/chunk
|
|
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/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/observer/eye/eye, add_images = TRUE)
|
|
if(add_images)
|
|
var/client/client = eye.GetViewerClient()
|
|
if(client)
|
|
client.images += obscured
|
|
eye.visibleChunks += src
|
|
visible++
|
|
seenby += eye
|
|
if(changed && !updating)
|
|
update()
|
|
|
|
// Remove an eye from the chunk, then update if changed.
|
|
|
|
/datum/chunk/proc/remove(mob/observer/eye/eye, remove_images = TRUE)
|
|
if(remove_images)
|
|
var/client/client = eye.GetViewerClient()
|
|
if(client)
|
|
client.images -= obscured
|
|
eye.visibleChunks -= src
|
|
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
|
|
spawn(UPDATE_BUFFER) // Batch large changes, such as many doors opening or closing at once
|
|
update()
|
|
updating = 0
|
|
else
|
|
changed = 1
|
|
|
|
// The actual updating.
|
|
|
|
/datum/chunk/proc/update()
|
|
|
|
set background = 1
|
|
|
|
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(t.obfuscations[obfuscation.type])
|
|
obscured -= t.obfuscations[obfuscation.type]
|
|
for(var/eye in seenby)
|
|
var/mob/observer/eye/m = eye
|
|
if(!m)
|
|
continue
|
|
var/client/client = m.GetViewerClient()
|
|
if(client)
|
|
client.images -= t.obfuscations[obfuscation.type]
|
|
|
|
for(var/turf in visRemoved)
|
|
var/turf/t = turf
|
|
if(obscuredTurfs[t])
|
|
LAZYINITLIST(t.obfuscations)
|
|
if(!t.obfuscations[obfuscation.type])
|
|
var/image/ob_image = image(obfuscation.icon, t, obfuscation.icon_state, OBFUSCATION_LAYER)
|
|
ob_image.plane = PLANE_FULLSCREEN
|
|
t.obfuscations[obfuscation.type] = ob_image
|
|
|
|
obscured += t.obfuscations[obfuscation.type]
|
|
for(var/eye in seenby)
|
|
var/mob/observer/eye/m = eye
|
|
if(!m)
|
|
seenby -= m
|
|
continue
|
|
var/client/client = m.GetViewerClient()
|
|
if(client)
|
|
client.images += 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)
|
|
|
|
// 0xf = 15
|
|
x &= ~0xf
|
|
y &= ~0xf
|
|
|
|
src.x = x
|
|
src.y = y
|
|
src.z = z
|
|
|
|
for(var/turf/t in range(10, locate(x + 8, y + 8, z)))
|
|
if(t.x >= x && t.y >= y && t.x < x + 16 && t.y < y + 16)
|
|
turfs[t] = t
|
|
|
|
acquireVisibleTurfs(visibleTurfs)
|
|
|
|
// Removes turf that isn't in turfs.
|
|
visibleTurfs &= turfs
|
|
|
|
obscuredTurfs = turfs - visibleTurfs
|
|
|
|
for(var/turf in obscuredTurfs)
|
|
var/turf/t = turf
|
|
LAZYINITLIST(t.obfuscations)
|
|
if(!t.obfuscations[obfuscation.type])
|
|
var/image/ob_image = image(obfuscation.icon, t, obfuscation.icon_state, OBFUSCATION_LAYER)
|
|
ob_image.plane = PLANE_FULLSCREEN
|
|
t.obfuscations[obfuscation.type] = ob_image
|
|
obscured += t.obfuscations[obfuscation.type]
|
|
|
|
#undef UPDATE_BUFFER
|