diff --git a/code/_onclick/ai.dm b/code/_onclick/ai.dm
index 082665ccea657..d07bcb897861b 100644
--- a/code/_onclick/ai.dm
+++ b/code/_onclick/ai.dm
@@ -74,7 +74,7 @@
if(aicamera.in_camera_mode)
aicamera.camera_mode_off()
- aicamera.captureimage(pixel_turf, usr)
+ aicamera.captureimage(pixel_turf, usr, null, aicamera.picture_size_y - 1, aicamera.picture_size_y - 1)
return
if(waypoint_mode)
waypoint_mode = 0
diff --git a/code/_onclick/cyborg.dm b/code/_onclick/cyborg.dm
index f9dfef70633f7..0cedde0462430 100644
--- a/code/_onclick/cyborg.dm
+++ b/code/_onclick/cyborg.dm
@@ -44,7 +44,7 @@
if(aicamera.in_camera_mode) //Cyborg picture taking
aicamera.camera_mode_off()
- aicamera.captureimage(A, usr)
+ aicamera.captureimage(A, usr, null, aicamera.picture_size_x - 1, aicamera.picture_size_y - 1)
return
var/obj/item/W = get_active_held_item()
diff --git a/code/_onclick/pai.dm b/code/_onclick/pai.dm
index 06c1d9dfdfe0a..11212bc6247be 100644
--- a/code/_onclick/pai.dm
+++ b/code/_onclick/pai.dm
@@ -2,5 +2,5 @@
..()
if(aicamera.in_camera_mode) //pAI picture taking
aicamera.camera_mode_off()
- aicamera.captureimage(A, usr, null, aicamera.picture_size_x, aicamera.picture_size_y)
+ aicamera.captureimage(A, usr, null, aicamera.picture_size_x - 1, aicamera.picture_size_y - 1)
return
diff --git a/code/modules/mob/living/silicon/ai/ai.dm b/code/modules/mob/living/silicon/ai/ai.dm
index 710b0f1cdea03..9c90f2d94e859 100644
--- a/code/modules/mob/living/silicon/ai/ai.dm
+++ b/code/modules/mob/living/silicon/ai/ai.dm
@@ -1055,7 +1055,6 @@
/mob/living/silicon/ai/zMove(dir, feedback = FALSE, feedback_to = src)
. = eyeobj.zMove(dir, feedback, feedback_to)
-
/// Proc to hook behavior to the changes of the value of [aiRestorePowerRoutine].
/mob/living/silicon/ai/proc/setAiRestorePowerRoutine(new_value)
if(new_value == aiRestorePowerRoutine)
@@ -1074,3 +1073,16 @@
/mob/living/silicon/on_handsblocked_end()
return // AIs have no hands
+
+/mob/living/silicon/ai/verb/change_photo_camera_radius()
+ set category = "AI Commands"
+ set name = "Adjust Camera Zoom"
+ set desc = "Change the zoom of your builtin camera."
+
+ if(incapacitated())
+ return
+ if(isnull(aicamera))
+ to_chat(usr, "You don't have a built-in camera!")
+ return
+
+ aicamera.adjust_zoom(src)
diff --git a/code/modules/modular_computers/file_system/programs/borg_self_monitor.dm b/code/modules/modular_computers/file_system/programs/borg_self_monitor.dm
index dda9a6c99d9ed..38f50f6184885 100644
--- a/code/modules/modular_computers/file_system/programs/borg_self_monitor.dm
+++ b/code/modules/modular_computers/file_system/programs/borg_self_monitor.dm
@@ -53,6 +53,7 @@
data["printerPictures"] = borgo.connected_ai ? length(borgo.connected_ai.aicamera?.stored) : length(borgo.aicamera?.stored) //Number of pictures taken, synced to AI if available
data["printerToner"] = borgo.toner //amount of toner
data["printerTonerMax"] = borgo.tonermax //It's a variable, might as well use it
+ data["cameraRadius"] = isnull(borgo.aicamera) ? 1 : borgo.aicamera.picture_size_x // picture_size_x and picture_size_y should always be the same.
data["thrustersInstalled"] = borgo.ionpulse //If we have a thruster uprade
data["thrustersStatus"] = "[borgo.ionpulse_on?"ACTIVE":"DISABLED"]" //Feedback for thruster status
data["selfDestructAble"] = (borgo.emagged || istype(borgo, /mob/living/silicon/robot/modules/syndicate))
@@ -133,6 +134,20 @@
borgo.lamp_intensity = clamp(text2num(params["ref"]), 1, 5)
borgo.toggle_headlamp(FALSE, TRUE)
+ if("cameraRadius")
+ var/obj/item/camera/siliconcam/robot_camera/borgcam = borgo.aicamera
+ if(isnull(borgcam))
+ CRASH("Cyborg embedded AI camera is null somehow, was it qdeleted?")
+ var/desired_radius = text2num(params["ref"])
+ if(isnull(desired_radius))
+ return
+ // respect the limits
+ if(desired_radius > borgcam.picture_size_x_max || desired_radius < borgcam.picture_size_x_min)
+ log_href_exploit(usr, " attempted to select an invalid borg camera size '[desired_radius]'.")
+ return
+ borgcam.picture_size_x = desired_radius
+ borgcam.picture_size_y = desired_radius
+
if("selfDestruct")
if(borgo.stat || borgo.lockcharge) //No detonation while stunned or locked down
return
diff --git a/code/modules/modular_computers/file_system/programs/ntmessenger.dm b/code/modules/modular_computers/file_system/programs/ntmessenger.dm
index 27349cdb3fe06..4ba422c8782bf 100644
--- a/code/modules/modular_computers/file_system/programs/ntmessenger.dm
+++ b/code/modules/modular_computers/file_system/programs/ntmessenger.dm
@@ -186,6 +186,14 @@
computer.saved_image = null
photo_path = null
return TRUE
+ if("PDA_viewPhotos")
+ if(!issilicon(usr))
+ return
+ var/mob/living/silicon/user = usr
+ var/obj/item/camera/siliconcam/aicamera = user.aicamera
+ if(isnull(aicamera))
+ return
+ aicamera.viewpictures(user)
if("PDA_selectPhoto")
if(!issilicon(usr))
return
diff --git a/tgui/packages/tgui/interfaces/NtosCyborgSelfMonitor.js b/tgui/packages/tgui/interfaces/NtosCyborgSelfMonitor.js
index f0325524aaf59..1d1d9f5833d6a 100644
--- a/tgui/packages/tgui/interfaces/NtosCyborgSelfMonitor.js
+++ b/tgui/packages/tgui/interfaces/NtosCyborgSelfMonitor.js
@@ -34,6 +34,7 @@ export const NtosCyborgSelfMonitorContent = (_, context) => {
printerPictures,
printerToner,
printerTonerMax,
+ cameraRadius,
thrustersInstalled,
thrustersStatus,
selfDestructAble,
@@ -139,6 +140,20 @@ export const NtosCyborgSelfMonitorContent = (_, context) => {
+
+
+ act('cameraRadius', {
+ ref: value,
+ })
+ }
+ />
+
{!!thrustersInstalled && (