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 += "" - - 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 && ( +
[entry][functions]