From 30d57e41dcbecf92161691fd683c72dab5a480a7 Mon Sep 17 00:00:00 2001
From: SkyratBot <59378654+SkyratBot@users.noreply.github.com>
Date: Wed, 23 Aug 2023 22:33:01 +0200
Subject: [PATCH] [MIRROR] Replaces Camera bug with Camera tablet app [MDB
IGNORE] (#23275)
* Replaces Camera bug with Camera tablet app
* Modular changes
---------
Co-authored-by: John Willard <53777086+JohnFulpWillard@users.noreply.github.com>
Co-authored-by: Giz <13398309+vinylspiders@users.noreply.github.com>
---
.../SpaceRuins/old_infiltrator.dmm | 2 +-
.../SpaceRuins/skyrat/scrapheap.dmm | 2 +-
.../SpaceRuins/turretedoutpost.dmm | 2 +-
_maps/RandomZLevels/mothership_astrum.dmm | 2 +-
code/_globalvars/bitfields.dm | 14 +-
code/game/machinery/camera/camera.dm | 22 --
code/game/machinery/camera/trackable.dm | 2 +-
.../telecomms/computers/telemonitor.dm | 1 +
.../objects/effects/spawners/random/exotic.dm | 2 +-
code/game/objects/items/devices/camera_bug.dm | 319 ------------------
.../game/objects/items/storage/uplink_kits.dm | 6 +-
code/modules/jobs/job_types/scientist.dm | 1 -
.../living/silicon/ai/freelook/cameranet.dm | 11 +-
.../computers/item/computer_ui.dm | 9 +-
.../computers/item/disks/unique_disks.dm | 8 +
.../modular_computers/file_system/program.dm | 11 +-
.../file_system/programs/airestorer.dm | 2 +-
.../file_system/programs/antagonist/dos.dm | 2 +-
.../file_system/programs/borg_monitor.dm | 6 +-
.../file_system/programs/card.dm | 2 +-
.../maintenance/_maintenance_program.dm | 8 +-
.../file_system/programs/ntdownloader.dm | 2 +-
.../file_system/programs/ntnrc_client.dm | 2 +-
.../file_system/programs/radar.dm | 4 +-
.../file_system/programs/secureye.dm | 109 ++++--
.../file_system/programs/signalcommander.dm | 2 +-
.../file_system/programs/sm_monitor.dm | 2 +-
.../uplink/uplink_items/device_tools.dm | 9 +-
.../modules/aesthetics/device/device.dm | 6 -
.../faction/code/mapping/mapping_helpers.dm | 2 +-
.../code/syndicate_loadout.dm | 4 +-
.../opposing_force/code/equipment/utility.dm | 6 +-
tgstation.dme | 2 +-
.../packages/tgui/interfaces/NtosSecurEye.tsx | 10 +-
34 files changed, 167 insertions(+), 427 deletions(-)
delete mode 100644 code/game/objects/items/devices/camera_bug.dm
create mode 100644 code/modules/modular_computers/computers/item/disks/unique_disks.dm
diff --git a/_maps/RandomRuins/SpaceRuins/old_infiltrator.dmm b/_maps/RandomRuins/SpaceRuins/old_infiltrator.dmm
index eb3d1ca2ba4..afa11afbc9a 100644
--- a/_maps/RandomRuins/SpaceRuins/old_infiltrator.dmm
+++ b/_maps/RandomRuins/SpaceRuins/old_infiltrator.dmm
@@ -215,7 +215,7 @@
pixel_y = -4;
pixel_x = -7
},
-/obj/item/camera_bug{
+/obj/item/computer_disk/syndicate/camera_app{
pixel_x = -5;
pixel_y = 9
},
diff --git a/_maps/RandomRuins/SpaceRuins/skyrat/scrapheap.dmm b/_maps/RandomRuins/SpaceRuins/skyrat/scrapheap.dmm
index 050983fc760..3e18590cb99 100644
--- a/_maps/RandomRuins/SpaceRuins/skyrat/scrapheap.dmm
+++ b/_maps/RandomRuins/SpaceRuins/skyrat/scrapheap.dmm
@@ -909,7 +909,7 @@
"yO" = (
/obj/machinery/light/red/directional/west,
/obj/structure/table/reinforced,
-/obj/item/camera_bug,
+/obj/item/computer_disk/syndicate/camera_app,
/obj/item/disk/design_disk/bepis,
/obj/item/disk/design_disk/bepis,
/obj/item/stack/spacecash/c500,
diff --git a/_maps/RandomRuins/SpaceRuins/turretedoutpost.dmm b/_maps/RandomRuins/SpaceRuins/turretedoutpost.dmm
index ea8945d63a2..4be262c6fd0 100644
--- a/_maps/RandomRuins/SpaceRuins/turretedoutpost.dmm
+++ b/_maps/RandomRuins/SpaceRuins/turretedoutpost.dmm
@@ -244,7 +244,7 @@
/area/ruin/space/has_grav/turretedoutpost)
"Iq" = (
/obj/structure/table/reinforced,
-/obj/item/camera_bug,
+/obj/item/computer_disk/syndicate/camera_app,
/turf/open/floor/iron,
/area/ruin/space/has_grav/turretedoutpost)
"LS" = (
diff --git a/_maps/RandomZLevels/mothership_astrum.dmm b/_maps/RandomZLevels/mothership_astrum.dmm
index fae863f52cb..26bebe36e55 100644
--- a/_maps/RandomZLevels/mothership_astrum.dmm
+++ b/_maps/RandomZLevels/mothership_astrum.dmm
@@ -2673,7 +2673,7 @@
/obj/structure/window/spawner/directional/north,
/obj/structure/window/spawner/directional/east,
/obj/structure/window/spawner/directional/west,
-/obj/item/camera_bug,
+/obj/item/computer_disk/syndicate/camera_app,
/turf/open/floor/plating/abductor2,
/area/awaymission/mothership_astrum/halls)
"Ns" = (
diff --git a/code/_globalvars/bitfields.dm b/code/_globalvars/bitfields.dm
index f365d84b9fe..80d9d3e9b09 100644
--- a/code/_globalvars/bitfields.dm
+++ b/code/_globalvars/bitfields.dm
@@ -286,18 +286,18 @@ DEFINE_BITFIELD(movement_type, list(
))
DEFINE_BITFIELD(obj_flags, list(
- "BLOCK_Z_IN_DOWN" = BLOCK_Z_IN_DOWN,
- "BLOCK_Z_IN_UP" = BLOCK_Z_IN_UP,
- "BLOCK_Z_OUT_DOWN" = BLOCK_Z_OUT_DOWN,
- "BLOCK_Z_OUT_UP" = BLOCK_Z_OUT_UP,
+ "IN_USE" = IN_USE,
+ "EMAGGED" = EMAGGED,
"CAN_BE_HIT" = CAN_BE_HIT,
"DANGEROUS_POSSESSION" = DANGEROUS_POSSESSION,
- "EMAGGED" = EMAGGED,
- "IN_USE" = IN_USE,
+ "UNIQUE_RENAME" = UNIQUE_RENAME,
+ "BLOCK_Z_OUT_DOWN" = BLOCK_Z_OUT_DOWN,
+ "BLOCK_Z_OUT_UP" = BLOCK_Z_OUT_UP,
+ "BLOCK_Z_IN_DOWN" = BLOCK_Z_IN_DOWN,
+ "BLOCK_Z_IN_UP" = BLOCK_Z_IN_UP,
"BLOCKS_CONSTRUCTION" = BLOCKS_CONSTRUCTION,
"BLOCKS_CONSTRUCTION_DIR" = BLOCKS_CONSTRUCTION_DIR,
"IGNORE_DENSITY" = IGNORE_DENSITY,
- "UNIQUE_RENAME" = UNIQUE_RENAME,
))
DEFINE_BITFIELD(pass_flags, list(
diff --git a/code/game/machinery/camera/camera.dm b/code/game/machinery/camera/camera.dm
index f47449644d7..a47115a9f60 100644
--- a/code/game/machinery/camera/camera.dm
+++ b/code/game/machinery/camera/camera.dm
@@ -18,7 +18,6 @@
var/status = TRUE
var/start_active = FALSE //If it ignores the random chance to start broken on round start
var/invuln = null
- var/obj/item/camera_bug/bug = null
var/datum/weakref/assembly_ref = null
var/area/myarea = null
@@ -129,12 +128,6 @@ MAPPING_DIRECTIONAL_HELPERS(/obj/machinery/camera/xray, 0)
LAZYREMOVE(myarea.cameras, src)
QDEL_NULL(alarm_manager)
QDEL_NULL(assembly_ref)
- if(bug)
- bug.bugged_cameras -= c_tag
- if(bug.current == src)
- bug.current = null
- bug = null
-
QDEL_NULL(last_shown_paper)
return ..()
@@ -422,21 +415,6 @@ MAPPING_DIRECTIONAL_HELPERS(/obj/machinery/camera/xray, 0)
to_chat(potential_viewer, "[span_name(user)] holds \a [item_name] up to your camera...")
return
-
- if(istype(attacking_item, /obj/item/camera_bug))
- if(!can_use())
- to_chat(user, span_notice("Camera non-functional."))
- return
- if(bug)
- to_chat(user, span_notice("Camera bug removed."))
- bug.bugged_cameras -= src.c_tag
- bug = null
- else
- to_chat(user, span_notice("Camera bugged."))
- bug = attacking_item
- bug.bugged_cameras[src.c_tag] = WEAKREF(src)
- return
-
return ..()
diff --git a/code/game/machinery/camera/trackable.dm b/code/game/machinery/camera/trackable.dm
index 86f6f4cfb90..8aedd1b80a8 100644
--- a/code/game/machinery/camera/trackable.dm
+++ b/code/game/machinery/camera/trackable.dm
@@ -21,7 +21,7 @@
///List of all non-humans trackable by cameras, split so humans take priority.
VAR_PRIVATE/static/list/others = list()
-/datum/trackable/New(mob/source)
+/datum/trackable/New(atom/source)
. = ..()
tracking_holder = source
RegisterSignal(tracking_holder, COMSIG_MOB_RESET_PERSPECTIVE, PROC_REF(cancel_target_tracking))
diff --git a/code/game/machinery/telecomms/computers/telemonitor.dm b/code/game/machinery/telecomms/computers/telemonitor.dm
index 3d12932d99d..b862a6372b7 100644
--- a/code/game/machinery/telecomms/computers/telemonitor.dm
+++ b/code/game/machinery/telecomms/computers/telemonitor.dm
@@ -98,6 +98,7 @@
screen = MAIN_VIEW
return TRUE
return TRUE
+
/obj/machinery/computer/telecomms/monitor/attackby()
. = ..()
updateUsrDialog()
diff --git a/code/game/objects/effects/spawners/random/exotic.dm b/code/game/objects/effects/spawners/random/exotic.dm
index e82b73672f8..add4faf5c50 100644
--- a/code/game/objects/effects/spawners/random/exotic.dm
+++ b/code/game/objects/effects/spawners/random/exotic.dm
@@ -9,7 +9,7 @@
loot = list( // Space loot spawner. Couple of random bits of technology-adjacent stuff including anomaly cores and BEPIS techs.
/obj/item/raw_anomaly_core/random,
/obj/item/disk/design_disk/bepis,
- /obj/item/camera_bug,
+ /obj/item/computer_disk/syndicate/camera_app,
)
/obj/effect/spawner/random/exotic/languagebook
diff --git a/code/game/objects/items/devices/camera_bug.dm b/code/game/objects/items/devices/camera_bug.dm
deleted file mode 100644
index f0610f27f04..00000000000
--- a/code/game/objects/items/devices/camera_bug.dm
+++ /dev/null
@@ -1,319 +0,0 @@
-
-#define BUGMODE_LIST 0
-#define BUGMODE_MONITOR 1
-#define BUGMODE_TRACK 2
-
-
-
-/obj/item/camera_bug //SKYRAT EDIT - ICON OVERRIDDEN BY AESTHETICS - SEE MODULE
- name = "camera bug"
- desc = "For illicit snooping through the camera network."
- icon = 'icons/obj/device.dmi'
- icon_state = "camera_bug"
- w_class = WEIGHT_CLASS_TINY
- inhand_icon_state = "camera_bug"
- throw_speed = 4
- throw_range = 20
- item_flags = NOBLUDGEON
-
- var/obj/machinery/camera/current = null
-
- var/last_net_update = 0
- var/list/bugged_cameras = list()
-
- var/track_mode = BUGMODE_LIST
- var/last_tracked = 0
- var/refresh_interval = 50
-
- var/tracked_name = null
- var/atom/tracking = null
-
- var/last_found = null
- var/last_seen = null
-
-/obj/item/camera_bug/Initialize(mapload)
- . = ..()
- START_PROCESSING(SSobj, src)
-
-/obj/item/camera_bug/Destroy()
- STOP_PROCESSING(SSobj, src)
- get_cameras()
- for(var/cam_tag in bugged_cameras)
- var/datum/weakref/camera_ref = bugged_cameras[cam_tag]
- var/obj/machinery/camera/camera = camera_ref.resolve()
- if(camera && camera.bug == src)
- camera.bug = null
- bugged_cameras = list()
- if(tracking)
- tracking = null
- return ..()
-
-/obj/item/camera_bug/interact(mob/user)
- ui_interact(user)
-
-/obj/item/camera_bug/ui_interact(mob/user = usr)
- . = ..()
- var/datum/browser/popup = new(user, "camerabug","Camera Bug",nref=src)
- popup.set_content(menu(get_cameras()))
- popup.open()
-
-/obj/item/camera_bug/attack_self(mob/user)
- user.set_machine(src)
- interact(user)
-
-/obj/item/camera_bug/check_eye(mob/user)
- if ( loc != user || user.incapacitated() || user.is_blind() || !current )
- user.unset_machine()
- return FALSE
- if(!is_valid_z_level(get_turf(current), get_turf(user.loc)) || !current.can_use())
- to_chat(user, span_danger("[src] has lost the signal."))
- current = null
- user.unset_machine()
- return FALSE
- return TRUE
-/obj/item/camera_bug/on_unset_machine(mob/user)
- user.reset_perspective(null)
-
-/obj/item/camera_bug/proc/get_cameras()
- if( world.time > (last_net_update + 100))
- bugged_cameras = list()
- for(var/obj/machinery/camera/camera as anything in GLOB.cameranet.cameras)
- if(camera.machine_stat || !camera.can_use())
- continue
- if(length(list("ss13","mine", "rd", "labor", "ordnance", "minisat") & camera.network))
- var/datum/weakref/camera_ref = WEAKREF(camera)
- if(!camera_ref || !camera.c_tag)
- continue
- bugged_cameras[camera.c_tag] = camera_ref
- return sort_list(bugged_cameras)
-
-
-/obj/item/camera_bug/proc/menu(list/cameras)
- if(!cameras || !cameras.len)
- return "No bugged cameras found."
-
- var/html
- switch(track_mode)
- if(BUGMODE_LIST)
- html = "
Select a camera:
\[Cancel camera view\]
"
- for(var/entry in cameras)
- var/datum/weakref/camera_ref = cameras[entry]
- var/obj/machinery/camera/camera = camera_ref.resolve()
- if(!camera)
- cameras -= camera_ref
- continue
- var/functions = ""
- if(camera.bug == src)
- functions = " - \[Monitor\] \[Disable\]"
- else
- functions = " - \[Monitor\]"
- html += "| [entry] | [functions] |
"
-
- if(BUGMODE_MONITOR)
- if(current)
- html = "Analyzing Camera '[current.c_tag]' \[Select Camera\]
"
- html += camera_report()
- else
- track_mode = BUGMODE_LIST
- return .(cameras)
- if(BUGMODE_TRACK)
- if(tracking)
- html = "Tracking '[tracked_name]' \[Cancel Tracking\] \[Cancel camera view\]
"
- if(last_found)
- var/time_diff = round((world.time - last_seen) / 150)
- var/datum/weakref/camera_ref = bugged_cameras[last_found]
- var/obj/machinery/camera/camera = camera_ref.resolve()
- var/outstring
- if(camera)
- outstring = "[last_found]"
- else
- outstring = last_found
- if(!time_diff)
- html += "Last seen near [outstring] (now)
"
- else
- // 15 second intervals ~ 1/4 minute
- var/m = round(time_diff/4)
- var/s = (time_diff - 4*m) * 15
- if(!s)
- s = "00"
- html += "Last seen near [outstring] ([m]:[s] minute\s ago)
"
- if(camera && (camera.bug == src)) //Checks to see if the camera has a bug
- html += "\[Disable\]"
-
- else
- html += "Not yet seen."
- else
- track_mode = BUGMODE_LIST
- return .(cameras)
- return html
-
-/obj/item/camera_bug/proc/get_seens()
- return current?.can_see()
-
-/obj/item/camera_bug/proc/camera_report()
- // this should only be called if current exists
- var/dat = ""
- var/list/seen = get_seens()
- if(seen && seen.len >= 1)
- var/list/names = list()
- for(var/obj/singularity/S in seen) // god help you if you see more than one
- if(S.name in names)
- names[S.name]++
- dat += "[S.name] ([names[S.name]])"
- else
- names[S.name] = 1
- dat += "[S.name]"
- var/stage = round(S.current_size / 2)+1
- dat += " (Stage [stage])"
- dat += " \[Track\]
"
-
- for(var/obj/vehicle/sealed/mecha/M in seen)
- if(M.name in names)
- names[M.name]++
- dat += "[M.name] ([names[M.name]])"
- else
- names[M.name] = 1
- dat += "[M.name]"
- dat += " \[Track\]
"
-
-
- for(var/mob/living/M in seen)
- if(M.name in names)
- names[M.name]++
- dat += "[M.name] ([names[M.name]])"
- else
- names[M.name] = 1
- dat += "[M.name]"
- if(M.body_position == LYING_DOWN)
- if(M.buckled)
- dat += " (Sitting)"
- else
- dat += " (Laying down)"
- dat += " \[Track\]
"
- if(length(dat) == 0)
- dat += "No motion detected."
- return dat
- else
- return "Camera Offline
"
-
-/obj/item/camera_bug/Topic(href,list/href_list)
- if(usr != loc)
- usr.unset_machine()
- usr << browse(null, "window=camerabug")
- return
- usr.set_machine(src)
- if("mode" in href_list)
- track_mode = text2num(href_list["mode"])
- if("monitor" in href_list)
- //You can't locate on a list with keys
- var/list/cameras = flatten_list(bugged_cameras)
- var/datum/weakref/camera_ref = locate(href_list["monitor"]) in cameras
- var/obj/machinery/camera/camera = camera_ref.resolve()
- if(camera && istype(camera))
- if(!same_z_level(camera))
- return
- track_mode = BUGMODE_MONITOR
- current = camera
- usr.reset_perspective(null)
- interact()
- if("track" in href_list)
- var/list/seen = get_seens()
- if(seen && seen.len >= 1)
- var/atom/A = locate(href_list["track"]) in seen
- if(A && istype(A))
- tracking = A
- tracked_name = A.name
- last_found = current.c_tag
- last_seen = world.time
- track_mode = BUGMODE_TRACK
- if("emp" in href_list)
- //You can't locate on a list with keys
- var/list/cameras = flatten_list(bugged_cameras)
- var/datum/weakref/camera_ref = locate(href_list["emp"]) in cameras
- var/obj/machinery/camera/camera = camera_ref.resolve()
- if(camera && istype(camera) && camera.bug == src)
- if(!same_z_level(camera))
- return
- camera.emp_act(EMP_HEAVY)
- camera.bug = null
- bugged_cameras -= camera.c_tag
- interact()
- return
- if("close" in href_list)
- usr.unset_machine()
- current = null
- return
- if("view" in href_list)
- //You can't locate on a list with keys
- var/list/cameras = flatten_list(bugged_cameras)
- var/datum/weakref/camera_ref = locate(href_list["view"]) in cameras
- var/obj/machinery/camera/camera = camera_ref.resolve()
- if(camera && istype(camera))
- if(!same_z_level(camera))
- return
- if(!camera.can_use())
- to_chat(usr, span_warning("Something's wrong with that camera! You can't get a feed."))
- return
- current = camera
- addtimer(CALLBACK(src, PROC_REF(view_camera), usr, camera), 0.6 SECONDS)
- return
- else
- usr.unset_machine()
-
- interact()
-
-/obj/item/camera_bug/proc/view_camera(mob/show, obj/machinery/camera/camera)
- if(check_eye(show))
- show.reset_perspective(camera)
- interact()
- else
- show.unset_machine()
- show << browse(null, "window=camerabug")
-
-/obj/item/camera_bug/process()
- if(track_mode == BUGMODE_LIST || (world.time < (last_tracked + refresh_interval)))
- return
- last_tracked = world.time
- if(track_mode == BUGMODE_TRACK ) // search for user
- // Note that it will be tricked if your name appears to change.
- // This is not optimal but it is better than tracking you relentlessly despite everything.
- if(!tracking)
- src.updateSelfDialog()
- return
-
- if(tracking.name != tracked_name) // Hiding their identity, tricksy
- var/mob/M = tracking
- if(istype(M))
- if(!(tracked_name == "Unknown" && findtext(tracking.name,"Unknown"))) // we saw then disguised before
- if(!(tracked_name == M.real_name && findtext(tracking.name,M.real_name))) // or they're still ID'd
- src.updateSelfDialog()//But if it's neither of those cases
- return // you won't find em on the cameras
- else
- src.updateSelfDialog()
- return
-
- var/list/tracking_cams = list()
- var/list/b_cams = get_cameras()
- for(var/entry in b_cams)
- tracking_cams += b_cams[entry]
- var/list/target_region = view(tracking)
-
- for(var/obj/machinery/camera/C in (target_region & tracking_cams))
- if(!can_see(C,tracking)) // target may have xray, that doesn't make them visible to cameras
- continue
- if(C.can_use())
- last_found = C.c_tag
- last_seen = world.time
- break
- src.updateSelfDialog()
-
-/obj/item/camera_bug/proc/same_z_level(obj/machinery/camera/C)
- var/turf/T_bug = get_turf(loc)
- if(!T_bug || !is_valid_z_level(T_bug, get_turf(C)))
- to_chat(usr, span_warning("You can't get a signal!"))
- return FALSE
- return TRUE
-
-#undef BUGMODE_LIST
-#undef BUGMODE_MONITOR
-#undef BUGMODE_TRACK
diff --git a/code/game/objects/items/storage/uplink_kits.dm b/code/game/objects/items/storage/uplink_kits.dm
index b1c8df58238..ba9c6ef4812 100644
--- a/code/game/objects/items/storage/uplink_kits.dm
+++ b/code/game/objects/items/storage/uplink_kits.dm
@@ -52,7 +52,7 @@
new /obj/item/clothing/under/chameleon(src) // 2 tc since it's not the full set
new /obj/item/clothing/mask/chameleon(src) // Goes with above
new /obj/item/clothing/shoes/chameleon/noslip(src) // 2 tc
- new /obj/item/camera_bug(src) // 1 tc
+ new /obj/item/computer_disk/syndicate/camera_app(src) // 1 tc
new /obj/item/multitool/ai_detect(src) // 1 tc
new /obj/item/encryptionkey/syndicate(src) // 2 tc
new /obj/item/reagent_containers/syringe/mulligan(src) // 4 tc
@@ -117,7 +117,7 @@
new /obj/item/ai_module/toy_ai(src) // ~6 tc
new /obj/item/multitool/ai_detect(src) // 1 tc
new /obj/item/storage/toolbox/syndicate(src) // 1 tc
- new /obj/item/camera_bug(src) // 1 tc
+ new /obj/item/computer_disk/syndicate/camera_app(src) // 1 tc
new /obj/item/clothing/glasses/thermal/syndi(src) // 4 tc
new /obj/item/card/id/advanced/chameleon(src) // 2 tc
@@ -138,7 +138,7 @@
if(KIT_SABOTAGE)
new /obj/item/storage/backpack/duffelbag/syndie/sabotage(src) // 5 tc for 3 c4 and 2 x4
- new /obj/item/camera_bug(src) // 1 tc
+ new /obj/item/computer_disk/syndicate/camera_app(src) // 1 tc
new /obj/item/sbeacondrop/powersink(src) // 11 tc
new /obj/item/computer_disk/virus/detomatix(src) // 6 tc
new /obj/item/storage/toolbox/syndicate(src) // 1 tc
diff --git a/code/modules/jobs/job_types/scientist.dm b/code/modules/jobs/job_types/scientist.dm
index 2dc97c2f89d..06be18a02b6 100644
--- a/code/modules/jobs/job_types/scientist.dm
+++ b/code/modules/jobs/job_types/scientist.dm
@@ -30,7 +30,6 @@
mail_goodies = list(
/obj/item/raw_anomaly_core/random = 10,
/obj/item/disk/design_disk/bepis = 2,
- /obj/item/camera_bug = 1
)
rpg_title = "Thaumaturgist"
job_flags = STATION_JOB_FLAGS
diff --git a/code/modules/mob/living/silicon/ai/freelook/cameranet.dm b/code/modules/mob/living/silicon/ai/freelook/cameranet.dm
index 4c2cc371f53..a9ad9884045 100644
--- a/code/modules/mob/living/silicon/ai/freelook/cameranet.dm
+++ b/code/modules/mob/living/silicon/ai/freelook/cameranet.dm
@@ -169,7 +169,6 @@ GLOBAL_DATUM_INIT(cameranet, /datum/cameranet, new)
return
return checkTurfVis(position)
-
/datum/cameranet/proc/checkTurfVis(turf/position)
var/datum/camerachunk/chunk = getCameraChunk(position.x, position.y, position.z)
if(chunk)
@@ -179,6 +178,16 @@ GLOBAL_DATUM_INIT(cameranet, /datum/cameranet, new)
return TRUE
return FALSE
+/datum/cameranet/proc/getTurfVis(turf/position)
+ RETURN_TYPE(/datum/camerachunk)
+ var/datum/camerachunk/chunk = getCameraChunk(position.x, position.y, position.z)
+ if(!chunk)
+ return FALSE
+ if(chunk.changed)
+ chunk.hasChanged(1) // Update now, no matter if it's visible or not.
+ if(chunk.visibleTurfs[position])
+ return chunk
+
/obj/effect/overlay/camera_static
name = "static"
icon = null
diff --git a/code/modules/modular_computers/computers/item/computer_ui.dm b/code/modules/modular_computers/computers/item/computer_ui.dm
index fa00efae0a2..11c12ea0c47 100644
--- a/code/modules/modular_computers/computers/item/computer_ui.dm
+++ b/code/modules/modular_computers/computers/item/computer_ui.dm
@@ -128,7 +128,7 @@
switch(action)
if("PC_exit")
- active_program.kill_program()
+ active_program.kill_program(usr)
return TRUE
if("PC_shutdown")
shutdown_computer()
@@ -146,7 +146,7 @@
if(!istype(killed_program))
return
- killed_program.kill_program()
+ killed_program.kill_program(usr)
to_chat(usr, span_notice("Program [killed_program.filename].[killed_program.filetype] with PID [rand(100,999)] has been killed."))
return TRUE
@@ -221,3 +221,8 @@
if(physical)
return physical
return src
+
+/obj/item/modular_computer/ui_close(mob/user)
+ . = ..()
+ if(active_program)
+ active_program.ui_close(user)
diff --git a/code/modules/modular_computers/computers/item/disks/unique_disks.dm b/code/modules/modular_computers/computers/item/disks/unique_disks.dm
new file mode 100644
index 00000000000..144fa52c65a
--- /dev/null
+++ b/code/modules/modular_computers/computers/item/disks/unique_disks.dm
@@ -0,0 +1,8 @@
+/obj/item/computer_disk/syndicate
+ name = "golden data disk"
+ desc = "A data disk with some high-tech programs, probably expensive as hell."
+ icon_state = "datadisk8"
+ custom_materials = list(/datum/material/gold = SMALL_MATERIAL_AMOUNT)
+
+/obj/item/computer_disk/syndicate/camera_app
+ starting_programs = list(/datum/computer_file/program/secureye/syndicate)
diff --git a/code/modules/modular_computers/file_system/program.dm b/code/modules/modular_computers/file_system/program.dm
index c8034335af4..59ef183f6d6 100644
--- a/code/modules/modular_computers/file_system/program.dm
+++ b/code/modules/modular_computers/file_system/program.dm
@@ -41,6 +41,8 @@
var/alert_pending = FALSE
/// How well this program will help combat detomatix viruses.
var/detomatix_resistance = NONE
+ ///Boolean on whether or not only one copy of the app can exist. This means it deletes itself when cloned elsewhere.
+ var/unique_copy = FALSE
/datum/computer_file/program/clone()
var/datum/computer_file/program/temp = ..()
@@ -49,6 +51,11 @@
temp.program_icon_state = program_icon_state
temp.requires_ntnet = requires_ntnet
temp.usage_flags = usage_flags
+ if(unique_copy)
+ if(computer)
+ computer.remove_file(src)
+ if(disk_host)
+ disk_host.remove_file(src)
return temp
/**
@@ -173,9 +180,9 @@
* Use this proc to kill the program.
* Designed to be implemented by each program if it requires on-quit logic, such as the NTNRC client.
* Args:
- * - reload_ui - Whether we reload the UI on computer's shutdown.
+ * - user - If there's a user, this is the person killing the program.
**/
-/datum/computer_file/program/proc/kill_program()
+/datum/computer_file/program/proc/kill_program(mob/user)
SHOULD_CALL_PARENT(TRUE)
if(src == computer.active_program)
diff --git a/code/modules/modular_computers/file_system/programs/airestorer.dm b/code/modules/modular_computers/file_system/programs/airestorer.dm
index 21d66d4b0fc..4f24b2c61d8 100644
--- a/code/modules/modular_computers/file_system/programs/airestorer.dm
+++ b/code/modules/modular_computers/file_system/programs/airestorer.dm
@@ -30,7 +30,7 @@
examine_text += span_info("Alt-click to eject the intelliCard.")
return examine_text
-/datum/computer_file/program/ai_restorer/kill_program()
+/datum/computer_file/program/ai_restorer/kill_program(mob/user)
try_eject(forced = TRUE)
return ..()
diff --git a/code/modules/modular_computers/file_system/programs/antagonist/dos.dm b/code/modules/modular_computers/file_system/programs/antagonist/dos.dm
index 4e165ed70d4..339dd3175eb 100644
--- a/code/modules/modular_computers/file_system/programs/antagonist/dos.dm
+++ b/code/modules/modular_computers/file_system/programs/antagonist/dos.dm
@@ -32,7 +32,7 @@
target = null
error = "Connection to destination relay lost."
-/datum/computer_file/program/ntnet_dos/kill_program()
+/datum/computer_file/program/ntnet_dos/kill_program(mob/user)
if(target)
target.dos_sources.Remove(src)
target = null
diff --git a/code/modules/modular_computers/file_system/programs/borg_monitor.dm b/code/modules/modular_computers/file_system/programs/borg_monitor.dm
index c085ad3ae4e..2a2e494c1ec 100644
--- a/code/modules/modular_computers/file_system/programs/borg_monitor.dm
+++ b/code/modules/modular_computers/file_system/programs/borg_monitor.dm
@@ -19,7 +19,7 @@
DL_source = null
return ..()
-/datum/computer_file/program/borg_monitor/kill_program()
+/datum/computer_file/program/borg_monitor/kill_program(mob/user)
loglist = null //Not everything is saved if you close an app
DL_source = null
DL_progress = 0
@@ -99,9 +99,9 @@
)
data["cyborgs"] += list(cyborg_data)
data["DL_progress"] = DL_progress
-
+
data["borglog"] = loglist
-
+
return data
/datum/computer_file/program/borg_monitor/ui_act(action, params, datum/tgui/ui, datum/ui_state/state)
diff --git a/code/modules/modular_computers/file_system/programs/card.dm b/code/modules/modular_computers/file_system/programs/card.dm
index 815ef740f18..529cf813d1b 100644
--- a/code/modules/modular_computers/file_system/programs/card.dm
+++ b/code/modules/modular_computers/file_system/programs/card.dm
@@ -79,7 +79,7 @@
return FALSE
computer.crew_manifest_update = TRUE
-/datum/computer_file/program/card_mod/kill_program()
+/datum/computer_file/program/card_mod/kill_program(mob/user)
computer.crew_manifest_update = FALSE
var/obj/item/card/id/inserted_auth_card = computer.computer_id_slot
if(inserted_auth_card)
diff --git a/code/modules/modular_computers/file_system/programs/maintenance/_maintenance_program.dm b/code/modules/modular_computers/file_system/programs/maintenance/_maintenance_program.dm
index 0575aa8a0f0..25a2d1ad941 100644
--- a/code/modules/modular_computers/file_system/programs/maintenance/_maintenance_program.dm
+++ b/code/modules/modular_computers/file_system/programs/maintenance/_maintenance_program.dm
@@ -7,10 +7,4 @@
/datum/computer_file/program/maintenance
filetype = "MNT"
available_on_ntnet = FALSE
-
-/datum/computer_file/program/maintenance/clone(rename = FALSE)
- . = ..()
- if(computer)
- computer.remove_file(src)
- if(disk_host)
- disk_host.remove_file(src)
+ unique_copy = TRUE
diff --git a/code/modules/modular_computers/file_system/programs/ntdownloader.dm b/code/modules/modular_computers/file_system/programs/ntdownloader.dm
index 53a68f2c6d5..efa61b2630c 100644
--- a/code/modules/modular_computers/file_system/programs/ntdownloader.dm
+++ b/code/modules/modular_computers/file_system/programs/ntdownloader.dm
@@ -162,6 +162,6 @@
return TRUE
return FALSE
-/datum/computer_file/program/ntnetdownload/kill_program()
+/datum/computer_file/program/ntnetdownload/kill_program(mob/user)
abort_file_download()
return ..()
diff --git a/code/modules/modular_computers/file_system/programs/ntnrc_client.dm b/code/modules/modular_computers/file_system/programs/ntnrc_client.dm
index 30aa03a613b..aa780fc3cf8 100644
--- a/code/modules/modular_computers/file_system/programs/ntnrc_client.dm
+++ b/code/modules/modular_computers/file_system/programs/ntnrc_client.dm
@@ -200,7 +200,7 @@
channel.offline_clients.Remove(src)
channel.active_clients.Add(src)
-/datum/computer_file/program/chatclient/kill_program()
+/datum/computer_file/program/chatclient/kill_program(mob/user)
for(var/datum/ntnet_conversation/channel as anything in SSmodular_computers.chat_channels)
channel.go_offline(src)
active_channel = null
diff --git a/code/modules/modular_computers/file_system/programs/radar.dm b/code/modules/modular_computers/file_system/programs/radar.dm
index 06aefba487f..c230614339d 100644
--- a/code/modules/modular_computers/file_system/programs/radar.dm
+++ b/code/modules/modular_computers/file_system/programs/radar.dm
@@ -31,7 +31,7 @@
scan()
START_PROCESSING(SSfastprocess, src)
-/datum/computer_file/program/radar/kill_program()
+/datum/computer_file/program/radar/kill_program(mob/user)
objects = list()
selected = null
STOP_PROCESSING(SSfastprocess, src)
@@ -320,7 +320,7 @@
RegisterSignal(SSdcs, COMSIG_GLOB_NUKE_DEVICE_ARMED, PROC_REF(on_nuke_armed))
-/datum/computer_file/program/radar/fission360/kill_program()
+/datum/computer_file/program/radar/fission360/kill_program(mob/user)
UnregisterSignal(SSdcs, COMSIG_GLOB_NUKE_DEVICE_ARMED)
return ..()
diff --git a/code/modules/modular_computers/file_system/programs/secureye.dm b/code/modules/modular_computers/file_system/programs/secureye.dm
index c14c6ee4efc..bba55b4474e 100644
--- a/code/modules/modular_computers/file_system/programs/secureye.dm
+++ b/code/modules/modular_computers/file_system/programs/secureye.dm
@@ -14,18 +14,42 @@
tgui_id = "NtosSecurEye"
program_icon = "eye"
+ ///Boolean on whether or not the app will make noise when flipping around the channels.
+ var/spying = FALSE
+
var/list/network = list("ss13")
+ ///List of weakrefs of all users watching the program.
+ var/list/concurrent_users = list()
+
/// Weakref to the active camera
var/datum/weakref/camera_ref
/// 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/atom/movable/screen/map_view/cam_screen
+ /// All the plane masters that need to be applied.
var/atom/movable/screen/background/cam_background
-/datum/computer_file/program/secureye/New()
+ ///Internal tracker used to find a specific person and keep them on cameras.
+ var/datum/trackable/internal_tracker
+
+///Syndicate subtype that has no access restrictions and is available on Syndinet
+/datum/computer_file/program/secureye/syndicate
+ filename = "syndeye"
+ filedesc = "SyndEye"
+ extended_desc = "This program allows for illegal access to security camera networks."
+ transfer_access = list()
+ available_on_ntnet = FALSE
+ available_on_syndinet = TRUE
+ requires_ntnet = FALSE
+ usage_flags = PROGRAM_ALL
+ unique_copy = TRUE
+
+ network = list("ss13", "mine", "rd", "labor", "ordnance", "minisat")
+ spying = TRUE
+
+/datum/computer_file/program/secureye/on_install(datum/computer_file/source, obj/item/modular_computer/computer_installing)
. = ..()
// Map name has to start and end with an A-Z character,
// and definitely NOT with a square bracket or even a number.
@@ -40,30 +64,33 @@
cam_background = new
cam_background.assigned_map = map_name
cam_background.del_on_map_removal = FALSE
+ RegisterSignal(src, COMSIG_TRACKABLE_TRACKING_TARGET, PROC_REF(on_track_target))
/datum/computer_file/program/secureye/Destroy()
QDEL_NULL(cam_screen)
QDEL_NULL(cam_background)
+ QDEL_NULL(internal_tracker)
+ last_camera_turf = null
+ return ..()
+
+/datum/computer_file/program/secureye/kill_program(mob/user)
+ if(user)
+ ui_close(user)
return ..()
/datum/computer_file/program/secureye/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
- // Register map objects
- cam_screen.display_to(user)
- user.client.register_map_obj(cam_background)
- return ..()
+ 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
+ // Register map objects
+ cam_screen.display_to(user)
+ user.client.register_map_obj(cam_background)
/datum/computer_file/program/secureye/ui_status(mob/user)
. = ..()
@@ -86,6 +113,7 @@
/datum/computer_file/program/secureye/ui_static_data(mob/user)
var/list/data = list()
data["mapRef"] = cam_screen.assigned_map
+ data["can_spy"] = !!spying
var/list/cameras = get_camera_list(network)
data["cameras"] = list()
for(var/i in cameras)
@@ -100,22 +128,49 @@
. = ..()
if(.)
return
- if(action == "switch_camera")
- var/c_tag = format_text(params["name"])
- var/list/cameras = get_camera_list(network)
- var/obj/machinery/camera/selected_camera = cameras[c_tag]
- camera_ref = WEAKREF(selected_camera)
- playsound(src, get_sfx(SFX_TERMINAL_TYPE), 25, FALSE)
+ switch(action)
+ if("switch_camera")
+ var/c_tag = format_text(params["name"])
+ var/list/cameras = get_camera_list(network)
+ var/obj/machinery/camera/selected_camera = cameras[c_tag]
+ camera_ref = WEAKREF(selected_camera)
+ if(!spying)
+ playsound(computer, get_sfx(SFX_TERMINAL_TYPE), 25, FALSE)
+ if(!selected_camera)
+ return TRUE
+ if(internal_tracker && internal_tracker.tracking)
+ internal_tracker.set_tracking(FALSE)
- if(!selected_camera)
+ update_active_camera_screen()
return TRUE
- update_active_camera_screen()
+ if("start_tracking")
+ if(!internal_tracker)
+ internal_tracker = new(src)
+ internal_tracker.set_tracked_mob(usr)
+ return TRUE
- return TRUE
+/datum/computer_file/program/secureye/proc/on_track_target(datum/trackable/source, mob/living/target)
+ SIGNAL_HANDLER
+ var/datum/camerachunk/target_camerachunk = GLOB.cameranet.getTurfVis(get_turf(target))
+ if(!target_camerachunk)
+ CRASH("[src] was able to track [target] through /datum/trackable, but was not on a visible turf to cameras.")
+ for(var/obj/machinery/camera/cameras as anything in target_camerachunk.cameras["[target.z]"])
+ var/found_target = locate(target) in cameras.can_see()
+ if(!found_target)
+ continue
+ var/new_camera = WEAKREF(cameras)
+ if(camera_ref == new_camera)
+ return
+ camera_ref = new_camera
+ update_active_camera_screen()
+ return
/datum/computer_file/program/secureye/ui_close(mob/user)
. = ..()
+ //don't track anyone while we're shutting off.
+ if(internal_tracker && internal_tracker.tracking)
+ internal_tracker.set_tracking(FALSE)
var/user_ref = REF(user)
var/is_living = isliving(user)
// Living creature or not, we remove you anyway.
@@ -125,7 +180,9 @@
// Turn off the console
if(length(concurrent_users) == 0 && is_living)
camera_ref = null
- playsound(src, 'sound/machines/terminal_off.ogg', 25, FALSE)
+ last_camera_turf = null
+ if(!spying)
+ playsound(computer, 'sound/machines/terminal_off.ogg', 25, FALSE)
/datum/computer_file/program/secureye/proc/update_active_camera_screen()
var/obj/machinery/camera/active_camera = camera_ref?.resolve()
diff --git a/code/modules/modular_computers/file_system/programs/signalcommander.dm b/code/modules/modular_computers/file_system/programs/signalcommander.dm
index b6b17722430..6d636bab370 100644
--- a/code/modules/modular_computers/file_system/programs/signalcommander.dm
+++ b/code/modules/modular_computers/file_system/programs/signalcommander.dm
@@ -19,7 +19,7 @@
. = ..()
set_frequency(signal_frequency)
-/datum/computer_file/program/signal_commander/kill_program()
+/datum/computer_file/program/signal_commander/kill_program(mob/user)
. = ..()
SSradio.remove_object(computer, signal_frequency)
diff --git a/code/modules/modular_computers/file_system/programs/sm_monitor.dm b/code/modules/modular_computers/file_system/programs/sm_monitor.dm
index b95927417cd..0ba8a721407 100644
--- a/code/modules/modular_computers/file_system/programs/sm_monitor.dm
+++ b/code/modules/modular_computers/file_system/programs/sm_monitor.dm
@@ -22,7 +22,7 @@
refresh()
/// Apparently destroy calls this [/datum/computer_file/Destroy]. Here just to clean our references.
-/datum/computer_file/program/supermatter_monitor/kill_program()
+/datum/computer_file/program/supermatter_monitor/kill_program(mob/user)
for(var/supermatter in supermatters)
clear_supermatter(supermatter)
return ..()
diff --git a/code/modules/uplink/uplink_items/device_tools.dm b/code/modules/uplink/uplink_items/device_tools.dm
index ee064e8534e..20792cfae70 100644
--- a/code/modules/uplink/uplink_items/device_tools.dm
+++ b/code/modules/uplink/uplink_items/device_tools.dm
@@ -83,11 +83,10 @@
item = /obj/item/storage/box/syndie_kit/syndicate_teleporter
cost = 8
-/datum/uplink_item/device_tools/camera_bug
- name = "Camera Bug"
- desc = "Enables you to view all cameras on the main network, set up motion alerts and track a target. \
- Bugging cameras allows you to disable them remotely."
- item = /obj/item/camera_bug
+/datum/uplink_item/device_tools/camera_app
+ name = "SyndEye Program"
+ desc = "A data disk containing a unique PC app that allows you to watch cameras and track crewmembers."
+ item = /obj/item/computer_disk/syndicate/camera_app
cost = 1
surplus = 90
purchasable_from = ~(UPLINK_NUKE_OPS | UPLINK_CLOWN_OPS)
diff --git a/modular_skyrat/modules/aesthetics/device/device.dm b/modular_skyrat/modules/aesthetics/device/device.dm
index 9dae3fdd45e..f7f4b8e5d9b 100644
--- a/modular_skyrat/modules/aesthetics/device/device.dm
+++ b/modular_skyrat/modules/aesthetics/device/device.dm
@@ -13,12 +13,6 @@
/obj/item/geiger_counter
icon = 'modular_skyrat/modules/aesthetics/device/device.dmi'
-/obj/item/desynchronizer
- icon = 'modular_skyrat/modules/aesthetics/device/device.dmi'
-
-/obj/item/camera_bug
- icon = 'modular_skyrat/modules/aesthetics/device/device.dmi'
-
// This needs default but is a subtype. Pain.
/obj/item/t_scanner/adv_mining_scanner
icon = 'icons/obj/device.dmi'
diff --git a/modular_skyrat/modules/faction/code/mapping/mapping_helpers.dm b/modular_skyrat/modules/faction/code/mapping/mapping_helpers.dm
index 5b37a5ef9c0..035e1597f4e 100644
--- a/modular_skyrat/modules/faction/code/mapping/mapping_helpers.dm
+++ b/modular_skyrat/modules/faction/code/mapping/mapping_helpers.dm
@@ -160,7 +160,7 @@
if(1) //Random traitor items
new /obj/item/storage/box/syndie_kit/chameleon(src)
new /obj/item/storage/backpack/duffelbag/syndie/c4(src)
- new /obj/item/camera_bug(src)
+ new /obj/item/computer_disk/syndicate/camera_app(src)
new /obj/item/gun/chem(src)
new /obj/item/card/emag(src)
new /obj/item/card/emag/doorjack(src)
diff --git a/modular_skyrat/modules/moretraitoritems/code/syndicate_loadout.dm b/modular_skyrat/modules/moretraitoritems/code/syndicate_loadout.dm
index d756ff42810..8a49d1b6cf5 100644
--- a/modular_skyrat/modules/moretraitoritems/code/syndicate_loadout.dm
+++ b/modular_skyrat/modules/moretraitoritems/code/syndicate_loadout.dm
@@ -41,7 +41,7 @@
new /obj/item/clothing/mask/chameleon(src)
new /obj/item/card/id/advanced/chameleon(src)
new /obj/item/clothing/shoes/chameleon/noslip(src)
- new /obj/item/camera_bug(src)
+ new /obj/item/computer_disk/syndicate/camera_app(src)
new /obj/item/multitool/ai_detect(src)
new /obj/item/encryptionkey/syndicate(src)
new /obj/item/reagent_containers/syringe/mulligan(src)
@@ -72,7 +72,7 @@
new /obj/item/ai_module/toy_ai(src)
new /obj/item/multitool/ai_detect(src)
new /obj/item/storage/toolbox/syndicate(src)
- new /obj/item/camera_bug(src)
+ new /obj/item/computer_disk/syndicate/camera_app(src)
new /obj/item/clothing/glasses/thermal/syndi(src)
new /obj/item/card/id/advanced/chameleon(src)
diff --git a/modular_skyrat/modules/opposing_force/code/equipment/utility.dm b/modular_skyrat/modules/opposing_force/code/equipment/utility.dm
index ddb83d4ddbe..17c7c6ed8ce 100644
--- a/modular_skyrat/modules/opposing_force/code/equipment/utility.dm
+++ b/modular_skyrat/modules/opposing_force/code/equipment/utility.dm
@@ -78,9 +78,9 @@
description = "A briefcase containing a launchpad, a device able to teleport items and people to and from targets up to eight tiles away from the briefcase. \
Also includes a remote control, disguised as an ordinary folder. Touch the briefcase with the remote to link it."
-/datum/opposing_force_equipment/gear/camera_bug
- name = "Camera Bug"
- item_type = /obj/item/camera_bug
+/datum/opposing_force_equipment/gear/camera_app
+ name = "SyndEye Program"
+ item_type = /obj/item/computer_disk/syndicate/camera_app
/datum/opposing_force_equipment/gear/microlaser
name = "Radioactive Microlaser"
diff --git a/tgstation.dme b/tgstation.dme
index 77070c6b29e..0164a642cc6 100644
--- a/tgstation.dme
+++ b/tgstation.dme
@@ -2148,7 +2148,6 @@
#include "code\game\objects\items\devices\anomaly_neutralizer.dm"
#include "code\game\objects\items\devices\anomaly_releaser.dm"
#include "code\game\objects\items\devices\beacon.dm"
-#include "code\game\objects\items\devices\camera_bug.dm"
#include "code\game\objects\items\devices\chameleonproj.dm"
#include "code\game\objects\items\devices\destabilizing_crystal.dm"
#include "code\game\objects\items\devices\desynchronizer.dm"
@@ -4669,6 +4668,7 @@
#include "code\modules\modular_computers\computers\item\disks\computer_disk.dm"
#include "code\modules\modular_computers\computers\item\disks\maintenance_disks.dm"
#include "code\modules\modular_computers\computers\item\disks\role_disks.dm"
+#include "code\modules\modular_computers\computers\item\disks\unique_disks.dm"
#include "code\modules\modular_computers\computers\item\disks\virus_disk.dm"
#include "code\modules\modular_computers\computers\machinery\console_presets.dm"
#include "code\modules\modular_computers\computers\machinery\modular_computer.dm"
diff --git a/tgui/packages/tgui/interfaces/NtosSecurEye.tsx b/tgui/packages/tgui/interfaces/NtosSecurEye.tsx
index b06e9711b79..84e3be0dd6c 100644
--- a/tgui/packages/tgui/interfaces/NtosSecurEye.tsx
+++ b/tgui/packages/tgui/interfaces/NtosSecurEye.tsx
@@ -5,6 +5,7 @@ import { prevNextCamera, selectCameras, CameraConsoleContent } from './CameraCon
type Data = {
mapRef: string;
+ can_spy: boolean;
activeCamera: Camera;
cameras: Camera[];
};
@@ -29,7 +30,7 @@ export const NtosSecurEye = (props, context) => {
/** Displays info and controls for the current camera */
const CameraControls = (props, context) => {
const { act, data } = useBackend(context);
- const { activeCamera, mapRef } = data;
+ const { can_spy, activeCamera, mapRef } = data;
const cameras = selectCameras(data.cameras);
const [prevCameraName, nextCameraName] = prevNextCamera(
cameras,
@@ -43,6 +44,13 @@ const CameraControls = (props, context) => {
{(activeCamera && activeCamera.name) || '—'}
+ {can_spy && (
+