Files
GS13NG/code/game/machinery/computer/camera.dm
2021-02-14 17:08:16 +08:00

374 lines
12 KiB
Plaintext

#define DEFAULT_MAP_SIZE 15
/obj/machinery/computer/security
name = "security camera console"
desc = "Used to access the various cameras on the station."
icon_screen = "cameras"
icon_keyboard = "security_key"
circuit = /obj/item/circuitboard/computer/security
light_color = LIGHT_COLOR_RED
var/list/network = list("ss13")
var/obj/machinery/camera/active_camera
/// The turf where the camera was last updated.
var/turf/last_camera_turf
var/list/concurrent_users = list()
// Stuff needed to render the map
var/map_name
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
interaction_flags_machine = INTERACT_MACHINE_ALLOW_SILICON | INTERACT_MACHINE_SET_MACHINE //| INTERACT_MACHINE_REQUIRES_SIGHT
/obj/machinery/computer/security/Initialize()
. = ..()
// Map name has 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:
map_name = "camera_console_[REF(src)]_map"
// Convert networks to lowercase
for(var/i in network)
network -= i
network += lowertext(i)
// 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 = list()
for(var/plane in subtypesof(/obj/screen/plane_master))
var/obj/screen/instance = new plane()
instance.assigned_map = map_name
instance.del_on_map_removal = FALSE
instance.screen_loc = "[map_name]:CENTER"
cam_plane_masters += instance
cam_background = new
cam_background.assigned_map = map_name
cam_background.del_on_map_removal = FALSE
/obj/machinery/computer/security/Destroy()
qdel(cam_screen)
QDEL_LIST(cam_plane_masters)
qdel(cam_background)
return ..()
/obj/machinery/computer/security/connect_to_shuttle(obj/docking_port/mobile/port, obj/docking_port/stationary/dock, idnum, override=FALSE)
for(var/i in network)
network -= i
network += "[idnum][i]"
/obj/machinery/computer/security/ui_interact(mob/user, datum/tgui/ui)
// Update UI
ui = SStgui.try_update_ui(user, src, ui)
// 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)
// Ghosts shouldn't count towards concurrent users, which produces
// an audible terminal_on click.
if(is_living)
concurrent_users += user_ref
// Turn on the console
if(length(concurrent_users) == 1 && is_living)
playsound(src, 'sound/machines/terminal_on.ogg', 25, FALSE)
use_power(active_power_usage)
// 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)
// Open UI
ui = new(user, src, "CameraConsole", name)
ui.open()
/obj/machinery/computer/security/ui_data()
var/list/data = list()
data["network"] = network
data["activeCamera"] = null
if(active_camera)
data["activeCamera"] = list(
name = active_camera.c_tag,
status = active_camera.status,
)
return data
/obj/machinery/computer/security/ui_static_data()
var/list/data = list()
data["mapRef"] = map_name
var/list/cameras = get_available_cameras()
data["cameras"] = list()
for(var/i in cameras)
var/obj/machinery/camera/C = cameras[i]
data["cameras"] += list(list(
name = C.c_tag,
))
return data
/obj/machinery/computer/security/ui_act(action, params)
. = ..()
if(.)
return
if(action == "switch_camera")
var/c_tag = params["name"]
var/list/cameras = get_available_cameras()
var/obj/machinery/camera/selected_camera = cameras[c_tag]
active_camera = selected_camera
playsound(src, get_sfx("terminal_type"), 25, FALSE)
if(!selected_camera)
return TRUE
update_active_camera_screen()
return TRUE
/obj/machinery/computer/security/proc/update_active_camera_screen()
// Show static if can't use the camera
if(!active_camera?.can_use())
show_camera_static()
return
var/list/visible_turfs = list()
// Is this camera located in or attached to a living thing? If so, assume the camera's loc is the living thing.
var/cam_location = isliving(active_camera.loc) ? active_camera.loc : active_camera
// If we're not forcing an update for some reason and the cameras are in the same location,
// we don't need to update anything.
// Most security cameras will end here as they're not moving.
var/newturf = get_turf(cam_location)
if(last_camera_turf == newturf)
return
// Cameras that get here are moving, and are likely attached to some moving atom such as cyborgs.
last_camera_turf = get_turf(cam_location)
var/list/visible_things = active_camera.isXRay() ? range(active_camera.view_range, cam_location) : view(active_camera.view_range, cam_location)
for(var/turf/visible_turf in visible_things)
visible_turfs += visible_turf
var/list/bbox = get_bbox_of_atoms(visible_turfs)
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)
/obj/machinery/computer/security/ui_close(mob/user)
var/user_ref = REF(user)
var/is_living = isliving(user)
// Living creature or not, we remove you anyway.
concurrent_users -= user_ref
// Unregister map objects
user.client.clear_map(map_name)
// Turn off the console
if(length(concurrent_users) == 0 && is_living)
active_camera = null
playsound(src, 'sound/machines/terminal_off.ogg', 25, FALSE)
use_power(0)
/obj/machinery/computer/security/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)
// Returns the list of cameras accessible from this computer
/obj/machinery/computer/security/proc/get_available_cameras()
var/list/L = list()
for (var/obj/machinery/camera/C in GLOB.cameranet.cameras)
if((is_away_level(z) || is_away_level(C.z)) && (C.z != z))//if on away mission, can only receive feed from same z_level cameras
continue
L.Add(C)
var/list/D = list()
for(var/obj/machinery/camera/C in L)
if(!C.network)
stack_trace("Camera in a cameranet has no camera network")
continue
if(!(islist(C.network)))
stack_trace("Camera in a cameranet has a non-list camera network")
continue
var/list/tempnetwork = C.network & network
if(tempnetwork.len)
D["[C.c_tag]"] = C
return D
// SECURITY MONITORS
/obj/machinery/computer/security/wooden_tv
name = "security camera monitor"
desc = "An old TV hooked into the station's camera network."
icon_state = "television"
icon_keyboard = "no_keyboard"
icon_screen = "detective_tv"
pass_flags = PASSTABLE
/obj/machinery/computer/security/mining
name = "outpost camera console"
desc = "Used to access the various cameras on the outpost."
icon_screen = "mining"
icon_keyboard = "mining_key"
network = list("mine", "auxbase")
circuit = /obj/item/circuitboard/computer/mining
/obj/machinery/computer/security/research
name = "research camera console"
desc = "Used to access the various cameras in science."
network = list("rd")
circuit = /obj/item/circuitboard/computer/research
/obj/machinery/computer/security/hos
name = "\improper Head of Security's camera console"
desc = "A custom security console with added access to the labor camp network."
network = list("ss13", "labor")
circuit = null
/obj/machinery/computer/security/labor
name = "labor camp monitoring"
desc = "Used to access the various cameras on the labor camp."
network = list("labor")
circuit = null
/obj/machinery/computer/security/qm
name = "\improper Quartermaster's camera console"
desc = "A console with access to the mining, auxiliary base and vault camera networks."
network = list("mine", "auxbase", "vault")
circuit = null
// TELESCREENS
/obj/machinery/computer/security/telescreen
name = "\improper Telescreen"
desc = "Used for watching an empty arena."
icon = 'icons/obj/stationobjs.dmi'
icon_state = "telescreen"
layer = SIGN_LAYER
network = list("thunder")
density = FALSE
circuit = null
light_power = 0
/obj/machinery/computer/security/telescreen/update_icon_state()
icon_state = initial(icon_state)
if(stat & BROKEN)
icon_state += "b"
/obj/machinery/computer/security/telescreen/entertainment
name = "entertainment monitor"
desc = "Damn, they better have the /tg/ channel on these things."
icon = 'icons/obj/status_display.dmi'
icon_state = "entertainment_blank"
network = list("thunder")
density = FALSE
circuit = null
interaction_flags_atom = NONE // interact() is called by BigClick()
var/icon_state_off = "entertainment_blank"
var/icon_state_on = "entertainment"
/obj/machinery/computer/security/telescreen/entertainment/Initialize()
. = ..()
RegisterSignal(src, COMSIG_CLICK, .proc/BigClick)
// Bypass clickchain to allow humans to use the telescreen from a distance
/obj/machinery/computer/security/telescreen/entertainment/proc/BigClick()
SIGNAL_HANDLER
INVOKE_ASYNC(src, /atom.proc/interact, usr)
/obj/machinery/computer/security/telescreen/entertainment/proc/notify(on)
if(on && icon_state == icon_state_off)
say(pick(
"Feats of bravery live now at the thunderdome!",
"Two enter, one leaves! Tune in now!",
"Violence like you've never seen it before!",
"Spears! Camera! Action! LIVE NOW!"))
icon_state = icon_state_on
else
icon_state = icon_state_off
/obj/machinery/computer/security/telescreen/rd
name = "\improper Research Director's telescreen"
desc = "Used for watching the AI and the RD's goons from the safety of his office."
network = list("rd", "aicore", "aiupload", "minisat", "xeno", "test")
/obj/machinery/computer/security/telescreen/circuitry
name = "research telescreen"
desc = "A telescreen with access to the research division's camera network."
network = list("rd")
/obj/machinery/computer/security/telescreen/ce
name = "\improper Chief Engineer's telescreen"
desc = "Used for watching the engine, telecommunications and the minisat."
network = list("engine", "singularity", "tcomms", "minisat")
/obj/machinery/computer/security/telescreen/cmo
name = "\improper Chief Medical Officer's telescreen"
desc = "A telescreen with access to the medbay's camera network."
network = list("medbay")
/obj/machinery/computer/security/telescreen/vault
name = "vault monitor"
desc = "A telescreen that connects to the vault's camera network."
network = list("vault")
/obj/machinery/computer/security/telescreen/toxins
name = "bomb test site monitor"
desc = "A telescreen that connects to the bomb test site's camera."
network = list("toxins")
/obj/machinery/computer/security/telescreen/engine
name = "engine monitor"
desc = "A telescreen that connects to the engine's camera network."
network = list("engine")
/obj/machinery/computer/security/telescreen/turbine
name = "turbine monitor"
desc = "A telescreen that connects to the turbine's camera."
network = list("turbine")
/obj/machinery/computer/security/telescreen/interrogation
name = "interrogation room monitor"
desc = "A telescreen that connects to the interrogation room's camera."
network = list("interrogation")
/obj/machinery/computer/security/telescreen/prison
name = "prison monitor"
desc = "A telescreen that connects to the permabrig's camera network."
network = list("prison")
/obj/machinery/computer/security/telescreen/auxbase
name = "auxiliary base monitor"
desc = "A telescreen that connects to the auxiliary base's camera."
network = list("auxbase")
/obj/machinery/computer/security/telescreen/minisat
name = "minisat monitor"
desc = "A telescreen that connects to the minisat's camera network."
network = list("minisat")
/obj/machinery/computer/security/telescreen/aiupload
name = "\improper AI upload monitor"
desc = "A telescreen that connects to the AI upload's camera network."
network = list("aiupload")
// Subtype that connects to shuttles.
/obj/machinery/computer/security/shuttle
circuit = /obj/item/circuitboard/computer/security/shuttle
/obj/machinery/computer/security/shuttle/connect_to_shuttle(obj/docking_port/mobile/port, obj/docking_port/stationary/dock, idnum, override=FALSE)
for(var/i in network)
network -= i
network += "[idnum][i]"
#undef DEFAULT_MAP_SIZE