From 88b24403246e1635a30551cc4b67ab27c3c74376 Mon Sep 17 00:00:00 2001 From: CHOMPStation2StaffMirrorBot <94713762+CHOMPStation2StaffMirrorBot@users.noreply.github.com> Date: Sat, 7 Jun 2025 15:05:22 -0700 Subject: [PATCH] [MIRROR] AI Multicam improved (#11026) Co-authored-by: ShadowLarkens --- code/__defines/dcs/signals/signals_client.dm | 2 + code/_onclick/hud/map_popups.dm | 1 + code/_onclick/hud/map_view.dm | 76 ++++++++ code/_onclick/hud/picture_in_picture.dm | 117 ++++++------ .../modules/mob/living/silicon/ai/multicam.dm | 74 ++------ code/modules/tgui/modules/camera.dm | 171 +++++++++--------- code/modules/tgui/tgui_window.dm | 2 +- icons/hud/pic_in_pic.dmi | Bin 0 -> 2639 bytes icons/misc/pic_in_pic.dmi | Bin 3598 -> 0 bytes interface/skin.dmf | 12 ++ vorestation.dme | 1 + 11 files changed, 265 insertions(+), 191 deletions(-) create mode 100644 code/_onclick/hud/map_view.dm create mode 100644 icons/hud/pic_in_pic.dmi delete mode 100644 icons/misc/pic_in_pic.dmi diff --git a/code/__defines/dcs/signals/signals_client.dm b/code/__defines/dcs/signals/signals_client.dm index 1fe8737c5d..460c4a3f47 100644 --- a/code/__defines/dcs/signals/signals_client.dm +++ b/code/__defines/dcs/signals/signals_client.dm @@ -1,2 +1,4 @@ /// Called after a client logs into a mob: (mob) #define COMSIG_CLIENT_MOB_LOGIN "client_mob_changed" +// from /client/proc/handle_popup_close() : (window_id) +#define COMSIG_POPUP_CLEARED "popup_cleared" diff --git a/code/_onclick/hud/map_popups.dm b/code/_onclick/hud/map_popups.dm index 53ce6b6aa9..56413e0ed6 100644 --- a/code/_onclick/hud/map_popups.dm +++ b/code/_onclick/hud/map_popups.dm @@ -169,3 +169,4 @@ /client/verb/handle_popup_close(window_id as text) set hidden = TRUE clear_map("[window_id]_map") + SEND_SIGNAL(src, COMSIG_POPUP_CLEARED, window_id) diff --git a/code/_onclick/hud/map_view.dm b/code/_onclick/hud/map_view.dm new file mode 100644 index 0000000000..6d8e35f3fc --- /dev/null +++ b/code/_onclick/hud/map_view.dm @@ -0,0 +1,76 @@ +/** + * /obj/screen/map_view_tg is map_view on steroids, existing simultaneously for compatibility and not driving me crazy + * during implementation + */ +INITIALIZE_IMMEDIATE(/obj/screen/map_view_tg) +/obj/screen/map_view_tg + name = "screen" + icon_state = "blank" + // Map view has to be on the lowest plane to enable proper lighting + layer = MAP_VIEW_LAYER + plane = MAP_VIEW_PLANE + del_on_map_removal = FALSE + + // Weakrefs of all our viewers + var/list/datum/weakref/viewing_clients = list() + var/list/popup_plane_masters + +/obj/screen/map_view_tg/Destroy() + for(var/datum/weakref/client_ref in viewing_clients) + hide_from_client(client_ref.resolve()) + + return ..() + +/obj/screen/map_view_tg/proc/generate_view(map_key) + // Map keys have to start and end with an A-Z character, + // and definitely NOT with a square bracket or even a number. + // I wasted 6 hours on this. :agony: + // -- Stylemistake + assigned_map = map_key + set_position(1, 1) + + popup_plane_masters = get_tgui_plane_masters() + + for(var/obj/screen/instance as anything in popup_plane_masters) + instance.assigned_map = assigned_map + instance.del_on_map_removal = FALSE + instance.screen_loc = "[assigned_map]:1,1" + +/** + * Generates and displays the map view to a client + * Make sure you at least try to pass tgui_window if map view needed on UI, + * so it will wait a signal from TGUI, which tells windows is fully visible. + * + * If you use map view not in TGUI, just call it as usualy. + * If UI needs planes, call display_to_client. + * + * * show_to - Mob which needs map view + * * window - Optional. TGUI window which needs map view + */ +/obj/screen/map_view_tg/proc/display_to(mob/show_to, datum/tgui_window/window) + if(window && !window.visible) + RegisterSignal(window, COMSIG_TGUI_WINDOW_VISIBLE, PROC_REF(display_on_ui_visible)) + else + display_to_client(show_to.client) + +/obj/screen/map_view_tg/proc/display_on_ui_visible(datum/tgui_window/window, client/show_to) + SIGNAL_HANDLER + display_to_client(show_to) + UnregisterSignal(window, COMSIG_TGUI_WINDOW_VISIBLE) + +/obj/screen/map_view_tg/proc/display_to_client(client/show_to) + show_to.register_map_obj(src) + + for(var/plane in popup_plane_masters) + show_to.register_map_obj(plane) + + viewing_clients |= WEAKREF(show_to) + +/obj/screen/map_view_tg/proc/hide_from(mob/hide_from) + // hide_from_client(hide_from?.canon_client) + hide_from_client(hide_from?.client) + +/obj/screen/map_view_tg/proc/hide_from_client(client/hide_from) + if(!hide_from) + return + hide_from.clear_map(assigned_map) diff --git a/code/_onclick/hud/picture_in_picture.dm b/code/_onclick/hud/picture_in_picture.dm index 4b7da6b978..fb82d83d00 100644 --- a/code/_onclick/hud/picture_in_picture.dm +++ b/code/_onclick/hud/picture_in_picture.dm @@ -10,13 +10,16 @@ var/obj/screen/component_button/button_x var/obj/screen/component_button/button_expand var/obj/screen/component_button/button_shrink + var/obj/screen/component_button/button_pop + var/obj/screen/map_view_tg/popup_screen - var/list/background_mas = list() - var/const/max_dimensions = 10 + var/mutable_appearance/standard_background /obj/screen/movable/pic_in_pic/Initialize(mapload) . = ..() make_backgrounds() + popup_screen = new + popup_screen.generate_view("camera-[REF(src)]_map") /obj/screen/movable/pic_in_pic/Destroy() for(var/C in shown_to) @@ -24,28 +27,28 @@ QDEL_NULL(button_x) QDEL_NULL(button_shrink) QDEL_NULL(button_expand) + QDEL_NULL(button_pop) + QDEL_NULL(popup_screen) return ..() /obj/screen/movable/pic_in_pic/component_click(obj/screen/component_button/component, params) if(component == button_x) + usr.client?.close_popup("camera-[REF(src)]") qdel(src) else if(component == button_expand) set_view_size(width+1, height+1) else if(component == button_shrink) set_view_size(width-1, height-1) + else if(component == button_pop) + pop_to_screen() /obj/screen/movable/pic_in_pic/proc/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_[direction]" - background_mas += dir + standard_background = new /mutable_appearance() + standard_background.icon = 'icons/hud/pic_in_pic.dmi' + standard_background.icon_state = "background" + standard_background.layer = DISPOSAL_LAYER + standard_background.plane = PLATING_PLANE + standard_background.appearance_flags = PIXEL_SCALE /obj/screen/movable/pic_in_pic/proc/add_buttons() var/static/mutable_appearance/move_tab @@ -53,19 +56,19 @@ move_tab = new /mutable_appearance() //all these properties are always the same, and since adding something to the overlay //list makes a copy, there is no reason to make a new one each call - move_tab.icon = 'icons/misc/pic_in_pic.dmi' + move_tab.icon = 'icons/hud/pic_in_pic.dmi' move_tab.icon_state = "move" move_tab.plane = PLANE_PLAYER_HUD var/matrix/M = matrix() M.Translate(0, (height + 0.25) * world.icon_size) move_tab.transform = M - overlays += move_tab + add_overlay(move_tab) if(!button_x) button_x = new /obj/screen/component_button(null, src) var/mutable_appearance/MA = new /mutable_appearance() MA.name = "close" - MA.icon = 'icons/misc/pic_in_pic.dmi' + MA.icon = 'icons/hud/pic_in_pic.dmi' MA.icon_state = "x" MA.plane = PLANE_PLAYER_HUD button_x.appearance = MA @@ -78,7 +81,7 @@ button_expand = new /obj/screen/component_button(null, src) var/mutable_appearance/MA = new /mutable_appearance() MA.name = "expand" - MA.icon = 'icons/misc/pic_in_pic.dmi' + MA.icon = 'icons/hud/pic_in_pic.dmi' MA.icon_state = "expand" MA.plane = PLANE_PLAYER_HUD button_expand.appearance = MA @@ -91,7 +94,7 @@ button_shrink = new /obj/screen/component_button(null, src) var/mutable_appearance/MA = new /mutable_appearance() MA.name = "shrink" - MA.icon = 'icons/misc/pic_in_pic.dmi' + MA.icon = 'icons/hud/pic_in_pic.dmi' MA.icon_state = "shrink" MA.plane = PLANE_PLAYER_HUD button_shrink.appearance = MA @@ -100,44 +103,34 @@ button_shrink.transform = M vis_contents += button_shrink + if(!button_pop) + button_pop = new /obj/screen/component_button(null, src) + var/mutable_appearance/MA = new /mutable_appearance() + MA.name = "pop" + MA.icon = 'icons/hud/pic_in_pic.dmi' + MA.icon_state = "pop" + MA.plane = PLANE_PLAYER_HUD + button_pop.appearance = MA + M = matrix() + M.Translate((max(4, width) - 0.75) * ICON_SIZE_X, (height + 0.25) * ICON_SIZE_Y + 16) + button_pop.transform = M + vis_contents += button_pop + /obj/screen/movable/pic_in_pic/proc/add_background() if((width > 0) && (height > 0)) - for(var/mutable_appearance/dir in background_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 - overlays += 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) + standard_background.transform = M + add_overlay(standard_background) /obj/screen/movable/pic_in_pic/proc/set_view_size(width, height, do_refresh = TRUE) - width = CLAMP(width, 0, max_dimensions) - height = CLAMP(height, 0, max_dimensions) + width = CLAMP(width, 0, 10) + height = CLAMP(height, 0, 10) src.width = width src.height = height - y_off = -height * world.icon_size - 16 + y_off = (-height * ICON_SIZE_Y) - (ICON_SIZE_Y / 2) cut_overlays() add_background() @@ -154,14 +147,19 @@ vis_contents -= viewing_turfs if(!width || !height) return + viewing_turfs = get_visible_turfs() + vis_contents += viewing_turfs + if(popup_screen) + popup_screen.vis_contents.Cut() + popup_screen.vis_contents += viewing_turfs + +/obj/screen/movable/pic_in_pic/proc/get_visible_turfs() var/turf/T = get_turf(center) if(!T) - return + return list() var/turf/lowerleft = locate(max(1, T.x - round(width/2)), max(1, T.y - round(height/2)), T.z) var/turf/upperright = locate(min(world.maxx, lowerleft.x + width - 1), min(world.maxy, lowerleft.y + height - 1), lowerleft.z) - viewing_turfs = block(lowerleft, upperright) - vis_contents += viewing_turfs - + return block(lowerleft, upperright) /obj/screen/movable/pic_in_pic/proc/show_to(client/C) if(C) @@ -172,3 +170,16 @@ if(C) shown_to -= C C.screen -= src + +/obj/screen/movable/pic_in_pic/proc/pop_to_screen() + if(usr.client.screen_maps["camera-[REF(src)]_map"]) + return + usr.client.setup_popup("camera-[REF(src)]", width, height, 2, "1984") + popup_screen.display_to(usr) + RegisterSignal(usr.client, COMSIG_POPUP_CLEARED, PROC_REF(on_popup_clear)) + +/obj/screen/movable/pic_in_pic/proc/on_popup_clear(client/source, window) + SIGNAL_HANDLER + if(window == "camera-[REF(src)]") + UnregisterSignal(usr.client, COMSIG_POPUP_CLEARED) + popup_screen.hide_from(usr) diff --git a/code/modules/mob/living/silicon/ai/multicam.dm b/code/modules/mob/living/silicon/ai/multicam.dm index c022581acd..c01e81c3a9 100644 --- a/code/modules/mob/living/silicon/ai/multicam.dm +++ b/code/modules/mob/living/silicon/ai/multicam.dm @@ -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 diff --git a/code/modules/tgui/modules/camera.dm b/code/modules/tgui/modules/camera.dm index 82215ad19f..619860d1fe 100644 --- a/code/modules/tgui/modules/camera.dm +++ b/code/modules/tgui/modules/camera.dm @@ -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 diff --git a/code/modules/tgui/tgui_window.dm b/code/modules/tgui/tgui_window.dm index 38675b150d..d20c54070a 100644 --- a/code/modules/tgui/tgui_window.dm +++ b/code/modules/tgui/tgui_window.dm @@ -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") diff --git a/icons/hud/pic_in_pic.dmi b/icons/hud/pic_in_pic.dmi new file mode 100644 index 0000000000000000000000000000000000000000..516b933125dedca31d7109a072ad640e15e071c8 GIT binary patch literal 2639 zcma)8c{tQtA3wkO$qbr7qPa2|ig<~#R7fUEwz5UGCetEIG-B-AFVt0pY*_|FxuH99 zZ_Ld;xE0wMN#2_l*@s?x4D(LUectDN-v8d`Ip=)8=lgs=&-tG3cFtWp8*{9vtSA5g zYiVKXAfSvN6C*5GlX|@l2}nbPqYKT{Gw4d7PXNt_dINwk=>CIF(bmHfX2TuM2_b5q z#b{qnyFC`$6jQ3XBDG;*d6^lzKv4*mQd9^)F+Do!8oNFnky+@7}_K2Nl@x&|6?N4wj4v($VuaA_2dXK?z~_AV}BLH%mH6Nl8S}2s-$o4J}X=~ zX2_ZWNiQ%|ZqFX{-8vd-RUS>MWGB2^5n7*3pT9?{gr)^NL zNo@|#9YcRD-MqFIX|TD;4-Hw%XAaEYR({PIft(8L&djOH2RhJntO@o`HK@Hu`(**BvdH$3B==Z{isyGTGL3&uwHFI@Pp9P<%6*R=h12-v>IdD1c zW5!7a<0#-%ds7Pa4i5pwqCC4>9RMLxKaX%z`U0)WokqeUKxH2W0BdrsG(m23kqB&B z4tdmO{bV<)kAat1KkT1){~3V;X{r3?i~V0X7XbX-SAJy7jxRMfB8 zO_(F)eXJAKw_Um9ML>B8R##VbBO*f7?z*_Vc#@qxktKc$oB(#Pz1e}Km%srh?QKZe z$+&ZAtZC~NPCwSmc&mx88~k-_50mhH`+01+^9_DQ&zzyJpSD4y`%67tB-7-!8WId{ zjI#DGy(VACb&R);_WfEKzQVm_GLwW()gFzm4oZqxc$@it!|PcEwdmZFKX6xB?iXWR zFl;TWM{*S=GZ0zMuHH@P?H26oIn2bgR!h}YtIi?=KoL3m7Op$~Q9slg$QTrJ>$^W9 z7{>h-r1Az9wc?TL3Dto*FN%_9%W1i)GkE?%O_2leCq)|DOh^tLm z+tBwjxG57Ng1gDC7E^|3H;ppj32p-x_oi6?#lEUC_?OqW^zS9}X;<}#U+pf5GSc8{ zWbTYg;ErD(CBhE4nvPkBOy~2Z236-fX+aW zK>RO~fY-&K82cmyn4EeCHKQ&TK}ezyl-)T6N?ObkMI(1A7ZfE)2(ir)x#s(UhA}=~ z0bz+C0ufObBm(+IDOr%~i%Fu0rRDgZ?%u}-z%tC%f`{+#vn2v$CHwRgz=NyKC|V6j zf{b(tWKEzhL?Qpj2St{afTWuoMg-uotdPKrM8Pe($mLn`*G6$Dj4g0%BZ7Vb%X&bU=XU`QQJpRdEDh1Zn}$Po!{3hiVE52(NbQS7-n?zJ8~rkn?+B#}`TH?b-IdzjV|o4|`=PlHKja|7?N6#IB={r=pd z2vREG;Ames2@w;0+PUcY726Mi`t0VY)hiQ=2hZ7Z9(0-q5x(&XM1rp^^kZ*p)OPdr z7>h(>Y0`VBCUWQ^v)qj-1AUo^_@!@jkaSEIJG9P}^zWTO_BbmKeZ0_Iv3B<9pu2k~ z!8{^A7nd{q{pj&Bw7Mq9fPL3L+j8AJTdNQ4K_}nx84`KU%9=(v@SB7VNIWX6Z2F=n z{cz(v^Vt)+T;KQ)#rwuM3qwle4oV<9tl=T;i1WcNH}h06L4{9TG#Yd1qP=>--D_TV zfA-ZSIoLtmr4jfEddzdho;~LFXr0=3^4h7|gqiE zHxbKY+O>Jsd*%9qz|wr%2)!!NI=faJU!RA|hx3|xgGn>cRtUSgvvfg3`E^*h{h!cE zjwazK`i%JrWm+Jq1LFkDnM?lYya;v_^i4e{g4Eyl-6Jr?}+NB#~ zk!X&;yU5^C$gXA_iCkT-2%7BC<;SkhxdyMzM}7LT&=D_duhW@<42vU%pprW-*`o)G*qBzOXs6A&-s{Wu!=W zblWeVr0|v>wP%RC^S=l}_Y^08(PsSRb4tfr+jLr&{IJkJZhiZ-;#VhQ_dA~tmsBPw UiUhEkf*&HVG_x_SG^WJ;8xkRym;e9( literal 0 HcmV?d00001 diff --git a/icons/misc/pic_in_pic.dmi b/icons/misc/pic_in_pic.dmi deleted file mode 100644 index cdac1295132945eeb87decca007cef4a35d5f92b..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 3598 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 diff --git a/interface/skin.dmf b/interface/skin.dmf index 2b65417108..3fef6faf15 100644 --- a/interface/skin.dmf +++ b/interface/skin.dmf @@ -1363,6 +1363,18 @@ window "output_browser" background-color = none saved-params = "" +window "popupwindow" + elem "popupwindow" + type = MAIN + pos = 281,0 + size = 120x120 + anchor1 = -1,-1 + anchor2 = -1,-1 + is-visible = false + saved-params = "pos;size;is-minimized;is-maximized" + statusbar = false + can-resize = false + window "prefs_markings_subwindow" elem "prefs_markings_subwindow" type = MAIN diff --git a/vorestation.dme b/vorestation.dme index 5b12f184af..b2bcbe518c 100644 --- a/vorestation.dme +++ b/vorestation.dme @@ -300,6 +300,7 @@ #include "code\_onclick\hud\hud.dm" #include "code\_onclick\hud\human.dm" #include "code\_onclick\hud\map_popups.dm" +#include "code\_onclick\hud\map_view.dm" #include "code\_onclick\hud\minihud.dm" #include "code\_onclick\hud\minihud_mapper.dm" #include "code\_onclick\hud\minihud_rigmech.dm"