mirror of
https://github.com/VOREStation/VOREStation.git
synced 2026-07-18 10:34:10 +01:00
AI Multicam improved (#17807)
* Add /obj/screen/map_view_tg and use it for camera tgui module * Allow AI to pop out multicams to separate UI windows
This commit is contained in:
@@ -2,7 +2,7 @@
|
||||
|
||||
/obj/screen/movable/pic_in_pic/ai
|
||||
var/mob/living/silicon/ai/ai
|
||||
var/list/highlighted_mas = list()
|
||||
var/mutable_appearance/highlighted_background
|
||||
var/highlighted = FALSE
|
||||
var/mob/observer/eye/aiEye/pic_in_pic/aiEye
|
||||
|
||||
@@ -26,51 +26,21 @@
|
||||
|
||||
/obj/screen/movable/pic_in_pic/ai/make_backgrounds()
|
||||
..()
|
||||
var/mutable_appearance/base = new /mutable_appearance()
|
||||
base.icon = 'icons/misc/pic_in_pic.dmi'
|
||||
base.layer = DISPOSAL_LAYER
|
||||
base.plane = PLATING_PLANE
|
||||
base.appearance_flags = PIXEL_SCALE
|
||||
|
||||
for(var/direction in GLOB.cardinal)
|
||||
var/mutable_appearance/dir = new /mutable_appearance(base)
|
||||
dir.dir = direction
|
||||
dir.icon_state = "background_highlight_[direction]"
|
||||
highlighted_mas += dir
|
||||
highlighted_background = new /mutable_appearance()
|
||||
highlighted_background.icon = 'icons/hud/pic_in_pic.dmi'
|
||||
highlighted_background.icon_state = "background_highlight"
|
||||
highlighted_background.layer = DISPOSAL_LAYER
|
||||
highlighted_background.plane = PLATING_PLANE
|
||||
highlighted_background.appearance_flags = PIXEL_SCALE
|
||||
|
||||
/obj/screen/movable/pic_in_pic/ai/add_background()
|
||||
if((width > 0) && (height > 0))
|
||||
if(!highlighted)
|
||||
return ..()
|
||||
|
||||
for(var/mutable_appearance/dir in highlighted_mas)
|
||||
var/matrix/M = matrix()
|
||||
var/x_scale = 1
|
||||
var/y_scale = 1
|
||||
|
||||
var/x_off = 0
|
||||
var/y_off = 0
|
||||
|
||||
if(dir.dir & (NORTH|SOUTH))
|
||||
x_scale = width
|
||||
x_off = (width-1)/2 * world.icon_size
|
||||
if(dir.dir & NORTH)
|
||||
y_off = ((height-1) * world.icon_size) + 3
|
||||
else
|
||||
y_off = -3
|
||||
|
||||
if(dir.dir & (EAST|WEST))
|
||||
y_scale = height
|
||||
y_off = (height-1)/2 * world.icon_size
|
||||
if(dir.dir & EAST)
|
||||
x_off = ((width-1) * world.icon_size) + 3
|
||||
else
|
||||
x_off = -3
|
||||
|
||||
M.Scale(x_scale, y_scale)
|
||||
M.Translate(x_off, y_off)
|
||||
dir.transform = M
|
||||
add_overlay(dir)
|
||||
var/matrix/M = matrix()
|
||||
M.Scale(width + 0.5, height + 0.5)
|
||||
M.Translate((width-1)/2 * ICON_SIZE_X, (height-1)/2 * ICON_SIZE_Y)
|
||||
highlighted_background.transform = M
|
||||
standard_background.transform = M
|
||||
add_overlay(highlighted ? highlighted_background : standard_background)
|
||||
|
||||
/obj/screen/movable/pic_in_pic/ai/set_view_size(width, height, do_refresh = TRUE)
|
||||
if(!aiEye) // Exploit fix
|
||||
@@ -98,24 +68,16 @@
|
||||
/obj/screen/movable/pic_in_pic/ai/proc/highlight()
|
||||
if(highlighted)
|
||||
return
|
||||
if(!aiEye)
|
||||
qdel(src)
|
||||
return
|
||||
highlighted = TRUE
|
||||
cut_overlays()
|
||||
add_background()
|
||||
add_buttons()
|
||||
cut_overlay(standard_background)
|
||||
add_overlay(highlighted_background)
|
||||
|
||||
/obj/screen/movable/pic_in_pic/ai/proc/unhighlight()
|
||||
if(!highlighted)
|
||||
return
|
||||
if(!aiEye)
|
||||
qdel(src)
|
||||
return
|
||||
highlighted = FALSE
|
||||
cut_overlays()
|
||||
add_background()
|
||||
add_buttons()
|
||||
cut_overlay(highlighted_background)
|
||||
add_overlay(standard_background)
|
||||
|
||||
/obj/screen/movable/pic_in_pic/ai/proc/set_ai(mob/living/silicon/ai/new_ai)
|
||||
if(!aiEye && !QDELETED(src))
|
||||
@@ -143,7 +105,7 @@ Whatever you did that made the last camera window disappear-- don't do that agai
|
||||
|
||||
/turf/unsimulated/ai_visible
|
||||
name = ""
|
||||
icon = 'icons/misc/pic_in_pic.dmi'
|
||||
icon = 'icons/hud/pic_in_pic.dmi'
|
||||
icon_state = "room_background"
|
||||
flags = NOJAUNT
|
||||
plane = SPACE_PLANE
|
||||
|
||||
@@ -1,3 +1,67 @@
|
||||
#define DEFAULT_MAP_SIZE 15
|
||||
|
||||
/obj/screen/map_view_tg/camera
|
||||
var/obj/screen/background/cam_background
|
||||
var/obj/screen/background/cam_foreground
|
||||
var/obj/screen/skybox/local_skybox
|
||||
|
||||
/obj/screen/map_view_tg/camera/Destroy()
|
||||
QDEL_NULL(cam_background)
|
||||
QDEL_NULL(cam_foreground)
|
||||
QDEL_NULL(local_skybox)
|
||||
return ..()
|
||||
|
||||
/obj/screen/map_view_tg/camera/generate_view(map_key)
|
||||
. = ..()
|
||||
cam_background = new()
|
||||
cam_background.del_on_map_removal = FALSE
|
||||
cam_background.assigned_map = assigned_map
|
||||
|
||||
local_skybox = new()
|
||||
local_skybox.del_on_map_removal = FALSE
|
||||
local_skybox.assigned_map = assigned_map
|
||||
|
||||
// FG
|
||||
cam_foreground = new
|
||||
cam_foreground.del_on_map_removal = FALSE
|
||||
cam_foreground.assigned_map = assigned_map
|
||||
|
||||
var/mutable_appearance/scanlines = mutable_appearance('icons/effects/static.dmi', "scanlines")
|
||||
scanlines.alpha = 50
|
||||
scanlines.layer = FULLSCREEN_LAYER
|
||||
|
||||
var/mutable_appearance/noise = mutable_appearance('icons/effects/static.dmi', "1 light")
|
||||
noise.layer = FULLSCREEN_LAYER
|
||||
|
||||
cam_foreground.plane = PLANE_FULLSCREEN
|
||||
cam_foreground.add_overlay(scanlines)
|
||||
cam_foreground.add_overlay(noise)
|
||||
|
||||
/obj/screen/map_view_tg/camera/display_to_client(client/show_to)
|
||||
show_to.register_map_obj(cam_background)
|
||||
show_to.register_map_obj(cam_foreground)
|
||||
show_to.register_map_obj(local_skybox)
|
||||
. = ..()
|
||||
|
||||
/obj/screen/map_view_tg/camera/proc/show_camera(list/visible_turfs, turf/newturf, size_x, size_y)
|
||||
vis_contents = visible_turfs
|
||||
cam_background.icon_state = "clear"
|
||||
cam_background.fill_rect(1, 1, size_x, size_y)
|
||||
|
||||
cam_foreground.fill_rect(1, 1, size_x, size_y)
|
||||
|
||||
local_skybox.cut_overlays()
|
||||
local_skybox.add_overlay(SSskybox.get_skybox(get_z(newturf)))
|
||||
local_skybox.scale_to_view(size_x)
|
||||
local_skybox.set_position("CENTER", "CENTER", (world.maxx>>1) - newturf.x, (world.maxy>>1) - newturf.y)
|
||||
|
||||
/obj/screen/map_view_tg/camera/proc/show_camera_static()
|
||||
vis_contents.Cut()
|
||||
cam_background.icon_state = "scanline2"
|
||||
cam_background.fill_rect(1, 1, DEFAULT_MAP_SIZE, DEFAULT_MAP_SIZE)
|
||||
local_skybox.cut_overlays()
|
||||
|
||||
|
||||
/datum/tgui_module/camera
|
||||
name = "Security Cameras"
|
||||
tgui_id = "CameraConsole"
|
||||
@@ -11,13 +75,9 @@
|
||||
|
||||
// Stuff needed to render the map
|
||||
var/map_name
|
||||
var/const/default_map_size = 15
|
||||
var/obj/screen/map_view/cam_screen
|
||||
/// All the plane masters that need to be applied.
|
||||
var/list/cam_plane_masters
|
||||
var/obj/screen/background/cam_background
|
||||
var/obj/screen/background/cam_foreground
|
||||
var/obj/screen/skybox/local_skybox
|
||||
|
||||
var/obj/screen/map_view_tg/camera/cam_screen_tg
|
||||
|
||||
// Stuff for moving cameras
|
||||
var/turf/last_camera_turf
|
||||
|
||||
@@ -28,63 +88,29 @@
|
||||
else
|
||||
network = network_computer
|
||||
map_name = "camera_console_[REF(src)]_map"
|
||||
|
||||
// Initialize map objects
|
||||
cam_screen = new
|
||||
cam_screen.name = "screen"
|
||||
cam_screen.assigned_map = map_name
|
||||
cam_screen.del_on_map_removal = FALSE
|
||||
cam_screen.screen_loc = "[map_name]:1,1"
|
||||
|
||||
cam_plane_masters = get_tgui_plane_masters()
|
||||
|
||||
for(var/obj/screen/instance as anything in cam_plane_masters)
|
||||
instance.assigned_map = map_name
|
||||
instance.del_on_map_removal = FALSE
|
||||
instance.screen_loc = "[map_name]:CENTER"
|
||||
|
||||
local_skybox = new()
|
||||
local_skybox.assigned_map = map_name
|
||||
local_skybox.del_on_map_removal = FALSE
|
||||
local_skybox.screen_loc = "[map_name]:CENTER,CENTER"
|
||||
cam_plane_masters += local_skybox
|
||||
|
||||
cam_background = new
|
||||
cam_background.assigned_map = map_name
|
||||
cam_background.del_on_map_removal = FALSE
|
||||
|
||||
var/mutable_appearance/scanlines = mutable_appearance('icons/effects/static.dmi', "scanlines")
|
||||
scanlines.alpha = 50
|
||||
scanlines.layer = FULLSCREEN_LAYER
|
||||
|
||||
var/mutable_appearance/noise = mutable_appearance('icons/effects/static.dmi', "1 light")
|
||||
noise.layer = FULLSCREEN_LAYER
|
||||
|
||||
cam_foreground = new
|
||||
cam_foreground.assigned_map = map_name
|
||||
cam_foreground.del_on_map_removal = FALSE
|
||||
cam_foreground.plane = PLANE_FULLSCREEN
|
||||
cam_foreground.add_overlay(scanlines)
|
||||
cam_foreground.add_overlay(noise)
|
||||
cam_screen_tg = new
|
||||
cam_screen_tg.generate_view(map_name)
|
||||
|
||||
/datum/tgui_module/camera/Destroy()
|
||||
if(active_camera)
|
||||
UnregisterSignal(active_camera, COMSIG_OBSERVER_MOVED)
|
||||
active_camera = null
|
||||
last_camera_turf = null
|
||||
qdel(cam_screen)
|
||||
QDEL_LIST(cam_plane_masters)
|
||||
qdel(cam_background)
|
||||
qdel(cam_foreground)
|
||||
QDEL_NULL(cam_screen_tg)
|
||||
return ..()
|
||||
|
||||
/datum/tgui_module/camera/tgui_interact(mob/user, datum/tgui/ui = null)
|
||||
if(!user.client)
|
||||
return
|
||||
|
||||
// Update UI
|
||||
ui = SStgui.try_update_ui(user, src, ui)
|
||||
var/turf/newturf = get_turf(active_camera)
|
||||
var/area/B = newturf?.loc // No cam tracking in dorms!
|
||||
// Show static if can't use the camera
|
||||
if(!active_camera?.can_use() || B?.flag_check(AREA_BLOCK_TRACKING))
|
||||
show_camera_static()
|
||||
|
||||
// Update the camera, showing static if necessary and updating data if the location has moved.
|
||||
update_active_camera_screen()
|
||||
|
||||
if(!ui)
|
||||
var/user_ref = REF(user)
|
||||
var/is_living = isliving(user)
|
||||
@@ -95,15 +121,11 @@
|
||||
// Turn on the console
|
||||
if(length(concurrent_users) == 1 && is_living)
|
||||
playsound(tgui_host(), 'sound/machines/terminal_on.ogg', 25, FALSE)
|
||||
// Register map objects
|
||||
user.client.register_map_obj(cam_screen)
|
||||
for(var/plane in cam_plane_masters)
|
||||
user.client.register_map_obj(plane)
|
||||
user.client.register_map_obj(cam_background)
|
||||
user.client.register_map_obj(cam_foreground)
|
||||
// Open UI
|
||||
ui = new(user, src, tgui_id, name)
|
||||
ui.open()
|
||||
// Register map objects
|
||||
cam_screen_tg.display_to(user, ui.window)
|
||||
|
||||
/datum/tgui_module/camera/tgui_data()
|
||||
var/list/data = list()
|
||||
@@ -181,15 +203,15 @@
|
||||
|
||||
/datum/tgui_module/camera/proc/update_active_camera_screen()
|
||||
SIGNAL_HANDLER
|
||||
if(!active_camera)
|
||||
show_camera_static()
|
||||
if(!active_camera?.can_use())
|
||||
cam_screen_tg.show_camera_static()
|
||||
return TRUE
|
||||
|
||||
var/turf/newturf = get_turf(active_camera)
|
||||
var/area/B = newturf?.loc // No cam tracking in dorms!
|
||||
// Show static if can't use the camera
|
||||
if(!active_camera.can_use() || B?.flag_check(AREA_BLOCK_TRACKING))
|
||||
show_camera_static()
|
||||
if(B?.flag_check(AREA_BLOCK_TRACKING))
|
||||
cam_screen_tg.show_camera_static()
|
||||
return TRUE
|
||||
|
||||
// If we're not forcing an update for some reason and the cameras are in the same location,
|
||||
@@ -199,7 +221,7 @@
|
||||
return
|
||||
|
||||
// Cameras that get here are moving, and are likely attached to some moving atom such as cyborgs.
|
||||
last_camera_turf = get_turf(active_camera)
|
||||
last_camera_turf = newturf
|
||||
|
||||
var/list/visible_turfs = list()
|
||||
for(var/turf/T in (active_camera.isXRay() \
|
||||
@@ -211,16 +233,7 @@
|
||||
var/size_x = bbox[3] - bbox[1] + 1
|
||||
var/size_y = bbox[4] - bbox[2] + 1
|
||||
|
||||
cam_screen.vis_contents = visible_turfs
|
||||
cam_background.icon_state = "clear"
|
||||
cam_background.fill_rect(1, 1, size_x, size_y)
|
||||
|
||||
cam_foreground.fill_rect(1, 1, size_x, size_y)
|
||||
|
||||
local_skybox.cut_overlays()
|
||||
local_skybox.add_overlay(SSskybox.get_skybox(get_z(newturf)))
|
||||
local_skybox.scale_to_view(size_x)
|
||||
local_skybox.set_position("CENTER", "CENTER", (world.maxx>>1) - newturf.x, (world.maxy>>1) - newturf.y)
|
||||
cam_screen_tg.show_camera(visible_turfs, newturf, size_x, size_y)
|
||||
|
||||
// Returns the list of cameras accessible from this computer
|
||||
// This proc operates in two distinct ways depending on the context in which the module is created.
|
||||
@@ -266,12 +279,6 @@
|
||||
else
|
||||
return check_access(user, network_access)
|
||||
|
||||
/datum/tgui_module/camera/proc/show_camera_static()
|
||||
cam_screen.vis_contents.Cut()
|
||||
cam_background.icon_state = "scanline2"
|
||||
cam_background.fill_rect(1, 1, default_map_size, default_map_size)
|
||||
local_skybox.cut_overlays()
|
||||
|
||||
/datum/tgui_module/camera/tgui_close(mob/user)
|
||||
. = ..()
|
||||
var/user_ref = REF(user)
|
||||
@@ -279,13 +286,13 @@
|
||||
// living creature or not, we remove you anyway.
|
||||
concurrent_users -= user_ref
|
||||
// Unregister map objects
|
||||
if(user.client)
|
||||
user.client.clear_map(map_name)
|
||||
cam_screen_tg?.hide_from(user)
|
||||
// Turn off the console
|
||||
if(length(concurrent_users) == 0 && is_living)
|
||||
if(active_camera)
|
||||
UnregisterSignal(active_camera, COMSIG_OBSERVER_MOVED)
|
||||
active_camera = null
|
||||
last_camera_turf = null
|
||||
playsound(tgui_host(), 'sound/machines/terminal_off.ogg', 25, FALSE)
|
||||
|
||||
// NTOS Version
|
||||
@@ -309,3 +316,5 @@
|
||||
|
||||
/datum/tgui_module/camera/bigscreen/tgui_state(mob/user)
|
||||
return GLOB.tgui_physical_state_bigscreen
|
||||
|
||||
#undef DEFAULT_MAP_SIZE
|
||||
|
||||
@@ -370,7 +370,7 @@
|
||||
send_message("ping/reply", payload)
|
||||
if("visible")
|
||||
visible = TRUE
|
||||
// SEND_SIGNAL(src, COMSIG_TGUI_WINDOW_VISIBLE, client) // Not used yet
|
||||
SEND_SIGNAL(src, COMSIG_TGUI_WINDOW_VISIBLE, client)
|
||||
if("suspend")
|
||||
close(can_be_suspended = TRUE)
|
||||
if("close")
|
||||
|
||||
Reference in New Issue
Block a user