Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions code/__DEFINES/machines.dm
Original file line number Diff line number Diff line change
Expand Up @@ -155,6 +155,7 @@
#define CAMERA_UPGRADE_XRAY (1<<0)
#define CAMERA_UPGRADE_EMP_PROOF (1<<1)
#define CAMERA_UPGRADE_MOTION (1<<2)
#define CAMERA_UPGRADE_NO_AI (1<<3)

/// Max length of a status line in the status display
#define MAX_STATUS_LINE_LENGTH 40
Expand Down
2 changes: 1 addition & 1 deletion code/_onclick/ai.dm
Original file line number Diff line number Diff line change
Expand Up @@ -295,4 +295,4 @@
//

/mob/living/silicon/ai/TurfAdjacent(turf/target_turf)
return (SScameras && SScameras.turf_visible_by_cameras(target_turf))
return (SScameras && SScameras.turf_visible_by_cameras(target_turf, src))
20 changes: 10 additions & 10 deletions code/controllers/subsystem/cameras.dm
Original file line number Diff line number Diff line change
Expand Up @@ -123,20 +123,20 @@ SUBSYSTEM_DEF(cameras)
var/datum/cameranet/net = nets[net_id]
net.bare_major_chunk_change(changed)

/datum/controller/subsystem/cameras/proc/is_visible_by_cameras(atom/target)
return default_net.is_visible_by_cameras(target)
/datum/controller/subsystem/cameras/proc/is_visible_by_cameras(atom/target, mob/user)
return default_net.is_visible_by_cameras(target, user)

/datum/controller/subsystem/cameras/proc/turf_visible_by_cameras(turf/position)
return default_net.turf_visible_by_cameras(position)
/datum/controller/subsystem/cameras/proc/turf_visible_by_cameras(turf/position, mob/user)
return default_net.turf_visible_by_cameras(position, user)

/datum/controller/subsystem/cameras/proc/get_turf_camera_chunk(turf/position)
return default_net.get_turf_camera_chunk(position)
/datum/controller/subsystem/cameras/proc/get_turf_camera_chunk(turf/position, mob/user)
return default_net.get_turf_camera_chunk(position, user)

/datum/controller/subsystem/cameras/proc/get_available_cameras_data(list/networks_available, list/z_levels_available)
return default_net.get_available_cameras_data(networks_available, z_levels_available)
/datum/controller/subsystem/cameras/proc/get_available_cameras_data(list/networks_available, list/z_levels_available, mob/user)
return default_net.get_available_cameras_data(networks_available, z_levels_available, user)

/datum/controller/subsystem/cameras/proc/get_available_camera_by_tag_list(list/networks_available, list/z_levels_available)
return default_net.get_available_camera_by_tag_list(networks_available, z_levels_available)
/datum/controller/subsystem/cameras/proc/get_available_camera_by_tag_list(list/networks_available, list/z_levels_available, mob/user)
return default_net.get_available_camera_by_tag_list(networks_available, z_levels_available, user)

/obj/effect/overlay/camera_static
name = "static"
Expand Down
8 changes: 5 additions & 3 deletions code/datums/station_alert.dm
Original file line number Diff line number Diff line change
Expand Up @@ -66,9 +66,11 @@
if(.)
return

var/mob/user = ui.user

switch(action)
if("select_camera")
var/mob/living/silicon/ai/ai = usr
var/mob/living/silicon/ai/ai = user
if(!istype(ai))
return

Expand Down Expand Up @@ -96,8 +98,8 @@
if(isnull(chosen_camera))
return
var/obj/machinery/camera/selected_camera = named_cameras[chosen_camera]
if(!selected_camera.can_use())
to_chat(ai, span_warning("Camera is unavailable!"))
if(!selected_camera.can_use(user))
to_chat(user, span_warning("Camera is unavailable!"))
return
ai.switchCamera(selected_camera)
return TRUE
2 changes: 1 addition & 1 deletion code/game/machinery/_machinery.dm
Original file line number Diff line number Diff line change
Expand Up @@ -709,7 +709,7 @@
var/mob/user = ui.user
add_fingerprint(user)
update_last_used(user)
if(isAI(user) && !SScameras.turf_visible_by_cameras(get_turf(src))) //We check if they're an AI specifically here, so borgs/adminghosts/human wand can still access off-camera stuff.
if(isAI(user) && !SScameras.turf_visible_by_cameras(get_turf(src), user)) //We check if they're an AI specifically here, so borgs/adminghosts/human wand can still access off-camera stuff.
to_chat(user, span_warning("You can no longer connect to this device!"))
return FALSE
return ..()
Expand Down
6 changes: 3 additions & 3 deletions code/game/machinery/camera/camera.dm
Original file line number Diff line number Diff line change
Expand Up @@ -296,7 +296,7 @@ MAPPING_DIRECTIONAL_HELPERS(/obj/machinery/camera/autoname/old, 0)
/obj/machinery/camera/attack_ai(mob/living/silicon/ai/user)
if (!istype(user))
return
if (!can_use())
if (!can_use(user))
return
user.switchCamera(src)

Expand Down Expand Up @@ -381,7 +381,7 @@ MAPPING_DIRECTIONAL_HELPERS(/obj/machinery/camera/autoname/old, 0)

/obj/machinery/camera/proc/toggle_cam(mob/user, displaymessage = TRUE)
camera_enabled = !camera_enabled
if(can_use())
if(can_use(user))
SScameras.add_camera_to_chunk(src)
if (isturf(loc))
myarea = get_area(src)
Expand Down Expand Up @@ -432,7 +432,7 @@ MAPPING_DIRECTIONAL_HELPERS(/obj/machinery/camera/autoname/old, 0)
alarm_on = FALSE
alarm_manager.clear_alarm(ALARM_CAMERA)

/obj/machinery/camera/proc/can_use()
/obj/machinery/camera/proc/can_use(mob/living/user)
if(!camera_enabled)
return FALSE
if(machine_stat & EMPED)
Expand Down
4 changes: 2 additions & 2 deletions code/game/machinery/computer/camera.dm
Original file line number Diff line number Diff line change
Expand Up @@ -84,11 +84,11 @@
)
return data

/obj/machinery/computer/security/ui_static_data()
/obj/machinery/computer/security/ui_static_data(mob/user)
var/list/data = list()
data["network"] = network
data["mapRef"] = cam_screen.assigned_map
data["cameras"] = SScameras.get_available_cameras_data(network)
data["cameras"] = SScameras.get_available_cameras_data(network, user = null) //AIs can check bodycams through this.
return data

/obj/machinery/computer/security/ui_act(action, list/params, datum/tgui/ui, datum/ui_state/state)
Expand Down
6 changes: 3 additions & 3 deletions code/game/machinery/computer/camera_advanced.dm
Original file line number Diff line number Diff line change
Expand Up @@ -182,11 +182,11 @@
else
camera_location = myturf
else
if((!consider_zlock || (myturf.z in z_lock)) && camnet.turf_visible_by_cameras(myturf))
if((!consider_zlock || (myturf.z in z_lock)) && camnet.turf_visible_by_cameras(myturf, user))
camera_location = myturf
else
for(var/obj/machinery/camera/C as anything in camnet.cameras)
if(!C.can_use() || consider_zlock && !(C.z in z_lock))
if(!C.can_use(user) || consider_zlock && !(C.z in z_lock))
continue
var/list/network_overlap = networks & C.network
if(length(network_overlap))
Expand Down Expand Up @@ -228,7 +228,7 @@
var/mob/eye/camera/remote/remote_eye = owner.remote_control
var/obj/machinery/computer/camera_advanced/origin = remote_eye.origin_ref.resolve()

var/list/cameras_by_tag = origin.camnet.get_available_camera_by_tag_list(origin.networks, origin.z_lock)
var/list/cameras_by_tag = origin.camnet.get_available_camera_by_tag_list(origin.networks, origin.z_lock, owner)

playsound(origin, 'sound/machines/terminal_prompt.ogg', 25, FALSE)
var/camera = tgui_input_list(usr, "Camera to view", "Cameras", cameras_by_tag)
Expand Down
4 changes: 2 additions & 2 deletions code/modules/antagonists/abductor/machinery/camera.dm
Original file line number Diff line number Diff line change
Expand Up @@ -68,7 +68,7 @@

use_delay = (world.time + abductor_pad_cooldown)

if(SScameras.turf_visible_by_cameras(remote_eye.loc))
if(SScameras.turf_visible_by_cameras(remote_eye.loc, owner))
P.PadToLoc(remote_eye.loc)

/datum/action/innate/teleport_out
Expand Down Expand Up @@ -108,7 +108,7 @@

use_delay = (world.time + teleport_self_cooldown)

if(SScameras.turf_visible_by_cameras(remote_eye.loc))
if(SScameras.turf_visible_by_cameras(remote_eye.loc, owner))
P.MobToLoc(remote_eye.loc,C)

/datum/action/innate/vest_mode_swap
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -96,7 +96,7 @@ GLOBAL_DATUM(thrallnet, /datum/cameranet)
continue
if(!length(netcam.network & origin.networks))
continue
T["[netcam.c_tag][netcam.can_use() ? null : " (Deactivated)"]"] = netcam
T["[netcam.c_tag][netcam.can_use(owner) ? null : " (Deactivated)"]"] = netcam

playsound(origin, "crawling_shadows_walk", 25, FALSE)
var/camera = tgui_input_list(usr, menu_prompt, menu_title, T)
Expand Down
2 changes: 1 addition & 1 deletion code/modules/mob/living/living.dm
Original file line number Diff line number Diff line change
Expand Up @@ -1329,7 +1329,7 @@
if(is_away_level(T.z))
return FALSE
// Now, are they viewable by a camera? (This is last because it's the most intensive check)
if(!SScameras.is_visible_by_cameras(src))
if(!SScameras.is_visible_by_cameras(src, user))
return FALSE
return TRUE

Expand Down
18 changes: 9 additions & 9 deletions code/modules/mob/living/silicon/ai/ai.dm
Original file line number Diff line number Diff line change
Expand Up @@ -492,7 +492,7 @@
return ISINRANGE(target_turf.x, ai_turf.x - interaction_range, ai_turf.x + interaction_range) \
&& ISINRANGE(target_turf.y, ai_turf.y - interaction_range, ai_turf.y + interaction_range)
else
return SScameras.turf_visible_by_cameras(target_turf)
return SScameras.turf_visible_by_cameras(target_turf, src)

/mob/living/silicon/ai/cancel_camera()
view_core()
Expand Down Expand Up @@ -589,7 +589,7 @@
if(controlled_equipment)
to_chat(src, span_warning("You are already loaded into an onboard computer!"))
return
if(!SScameras.is_visible_by_cameras(M))
if(!SScameras.is_visible_by_cameras(M, src))
to_chat(src, span_warning("Exosuit is no longer near active cameras."))
return
if(!isvalidAIloc(loc))
Expand Down Expand Up @@ -649,7 +649,7 @@
//The target must be in view of a camera or near the core.
if(turf_check in range(get_turf(src)))
call_bot(turf_check)
else if(SScameras && SScameras.turf_visible_by_cameras(turf_check))
else if(SScameras && SScameras.turf_visible_by_cameras(turf_check, src))
call_bot(turf_check)
else
to_chat(src, span_danger("Selected location is not visible."))
Expand Down Expand Up @@ -678,7 +678,7 @@

if (length(cameras))
var/obj/machinery/camera/cam = cameras[1]
if (cam.can_use())
if (cam.can_use(src))
queueAlarm("--- [alarm_type] alarm detected in [home_name]! (<A HREF='byond://?src=[REF(src)];switchcamera=[REF(cam)]'>[cam.c_tag]</A>)", alarm_type)
else
var/first_run = FALSE
Expand Down Expand Up @@ -716,7 +716,7 @@
var/list/tempnetwork = C.network
if(!camera_turf || !(is_station_level(camera_turf.z) || is_mining_level(camera_turf.z) || (CAMERANET_NETWORK_SS13 in tempnetwork)))
continue
if(!C.can_use())
if(!C.can_use(src))
continue
tempnetwork.Remove(CAMERANET_NETWORK_RD, CAMERANET_NETWORK_ORDNANCE, CAMERANET_NETWORK_PRISON)
if(length(tempnetwork))
Expand All @@ -733,7 +733,7 @@
network = old_network // If nothing is selected
else
for(var/obj/machinery/camera/C in SScameras.cameras)
if(!C.can_use())
if(!C.can_use(src))
continue
if(network in C.network)
U.eyeobj.setLoc(get_turf(C))
Expand Down Expand Up @@ -889,7 +889,7 @@
for(var/obj/machinery/camera/camera as anything in z_cameras)
if(QDELETED(camera))
continue
if(!camera.can_use() || get_dist(camera, eyeobj) > 7 || !camera.internal_light)
if(!camera.can_use(src) || get_dist(camera, eyeobj) > 7 || !camera.internal_light)
continue
visible |= camera

Expand Down Expand Up @@ -962,7 +962,7 @@
if(isvalidAIloc(loc)) //AI in core, check if on cameras
//get_turf_pixel() is because APCs in maint aren't actually in view of the inner camera
//apc_override is needed here because AIs use their own APC when depowered
return ((SScameras && SScameras.turf_visible_by_cameras(get_turf_pixel(A))) || (A == apc_override))
return ((SScameras && SScameras.turf_visible_by_cameras(get_turf_pixel(A), src)) || (A == apc_override))
//AI is carded/shunted
//view(src) returns nothing for carded/shunted AIs and they have X-ray vision so just use get_dist
var/list/viewscale = getviewsize(client.view)
Expand Down Expand Up @@ -1235,7 +1235,7 @@
REMOVE_TRAIT(src, TRAIT_INCAPACITATED, POWER_LACK_TRAIT)

/mob/living/silicon/ai/proc/show_camera_list()
var/list/cameras = SScameras.get_available_camera_by_tag_list(network)
var/list/cameras = SScameras.get_available_camera_by_tag_list(network, user = src)
var/camera_tag = tgui_input_list(src, "Choose which camera you want to view", "Cameras", cameras)
if(isnull(camera_tag))
return
Expand Down
29 changes: 18 additions & 11 deletions code/modules/mob/living/silicon/ai/freelook/cameranet.dm
Original file line number Diff line number Diff line change
Expand Up @@ -187,39 +187,43 @@

/// Will check if an atom is on a viewable turf.
/// Returns TRUE if the atom is visible by any camera, FALSE otherwise.
/datum/cameranet/proc/is_visible_by_cameras(atom/target)
return turf_visible_by_cameras(get_turf(target))
/datum/cameranet/proc/is_visible_by_cameras(atom/target, mob/user)
return turf_visible_by_cameras(get_turf(target), user)

/// Checks if the passed turf is visible by any camera.
/// Returns TRUE if the turf is visible by any camera, FALSE otherwise.
/datum/cameranet/proc/turf_visible_by_cameras(turf/position)
/datum/cameranet/proc/turf_visible_by_cameras(turf/position, mob/user)
if(isnull(position))
return FALSE
var/datum/camerachunk/chunk = generate_chunk(position.x, position.y, position.z)
if(isnull(chunk))
return FALSE
chunk.force_update(only_if_necessary = TRUE) // Update NOW if necessary
if(!isAI(user) && chunk.cameraTurfs[position])
return TRUE
if(chunk.visibleTurfs[position])
return TRUE
return FALSE

/// Gets the camera chunk the passed turf is in.
/// Returns the chunk if it exists and is visible, null otherwise.
/datum/cameranet/proc/get_turf_camera_chunk(turf/position)
/datum/cameranet/proc/get_turf_camera_chunk(turf/position, mob/user)
RETURN_TYPE(/datum/camerachunk)
var/datum/camerachunk/chunk = generate_chunk(position.x, position.y, position.z)
if(!chunk)
return null
chunk.force_update(only_if_necessary = TRUE) // Update NOW if necessary
if(!isAI(user) && chunk.cameraTurfs[position])
return TRUE
if(chunk.visibleTurfs[position])
return chunk
return null

/// Returns list of available cameras, ready to use for UIs displaying list of them
/// The format is: list("name" = "camera.c_tag", ref = REF(camera))
/datum/cameranet/proc/get_available_cameras_data(list/networks_available, list/z_levels_available)
/datum/cameranet/proc/get_available_cameras_data(list/networks_available, list/z_levels_available, mob/user)
var/list/available_cameras_data = list()
for(var/obj/machinery/camera/camera as anything in get_filtered_and_sorted_cameras(networks_available, z_levels_available))
for(var/obj/machinery/camera/camera as anything in get_filtered_and_sorted_cameras(networks_available, z_levels_available, user))
available_cameras_data += list(list(
name = camera.c_tag,
ref = REF(camera),
Expand All @@ -236,28 +240,28 @@
* networks_available - List of networks that we use to see which cameras are visible to it.
* z_levels_available - List of z levels to filter camera by. If empty, all z levels are considered valid.
*/
/datum/cameranet/proc/get_available_camera_by_tag_list(list/networks_available, list/z_levels_available)
/datum/cameranet/proc/get_available_camera_by_tag_list(list/networks_available, list/z_levels_available, mob/user)
var/list/available_cameras_by_tag = list()
for(var/obj/machinery/camera/camera as anything in get_filtered_and_sorted_cameras(networks_available, z_levels_available))
for(var/obj/machinery/camera/camera as anything in get_filtered_and_sorted_cameras(networks_available, z_levels_available, user))
available_cameras_by_tag["[camera.c_tag][camera.can_use() ? null : " (Deactivated)"]"] = camera

return available_cameras_by_tag

/// Returns list of all cameras that passed `is_camera_available` filter and sorted by `cmp_camera_ctag_asc`
/datum/cameranet/proc/get_filtered_and_sorted_cameras(list/networks_available, list/z_levels_available)
/datum/cameranet/proc/get_filtered_and_sorted_cameras(list/networks_available, list/z_levels_available, mob/user)
PRIVATE_PROC(TRUE)

var/list/filtered_cameras = list()
for(var/obj/machinery/camera/camera as anything in cameras)
if(!is_camera_available(camera, networks_available, z_levels_available))
if(!is_camera_available(camera, networks_available, z_levels_available, user))
continue

filtered_cameras += camera

return sortTim(filtered_cameras, GLOBAL_PROC_REF(cmp_camera_ctag_asc))

/// Checks if the `camera_to_check` meets the requirements of availability.
/datum/cameranet/proc/is_camera_available(obj/machinery/camera/camera_to_check, list/networks_available, list/z_levels_available)
/datum/cameranet/proc/is_camera_available(obj/machinery/camera/camera_to_check, list/networks_available, list/z_levels_available, mob/user)
PRIVATE_PROC(TRUE)

if(!camera_to_check.c_tag)
Expand All @@ -266,6 +270,9 @@
if(length(z_levels_available) && !(camera_to_check.z in z_levels_available))
return FALSE

if(user && isAI(user) && (camera_to_check.camera_upgrade_bitflags & CAMERA_UPGRADE_NO_AI))
return FALSE

return length(camera_to_check.network & networks_available) > 0

#undef ADD_CAMERA
Expand Down
Loading
Loading