Skip to content
Open
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
132 changes: 128 additions & 4 deletions modular_pentest/modules/xenobiology/code/xenobio_camera.dm
Original file line number Diff line number Diff line change
Expand Up @@ -17,15 +17,16 @@

/mob/camera/aiEye/remote/xenobio/setLoc(t)
var/area/new_area = get_area(t)
if(new_area && new_area.name == allowed_area || new_area && (new_area.area_flags & XENOBIOLOGY_COMPATIBLE))
// Only allow movement within the same area name
if(new_area && new_area.name == allowed_area)
return ..()
else
return

/obj/machinery/computer/camera_advanced/xenobio
name = "Slime management console"
desc = "A computer used for remotely handling slimes."
networks = list("ss13")
networks = list("xenobio_local") // Dummy network that doesn't match anything
circuit = /obj/item/circuitboard/computer/xenobiology
var/datum/action/innate/slime_place/slime_place_action
var/datum/action/innate/slime_pick_up/slime_up_action
Expand All @@ -41,6 +42,9 @@
var/max_slimes = 5
var/monkeys = 0

/// Internal camera built into the console as a fallback
var/obj/machinery/camera/internal_camera

icon_screen = "slime_comp"
icon_keyboard = "rd_key"

Expand All @@ -56,6 +60,13 @@
potion_action = new
hotkey_help = new
stored_slimes = list()

// Create internal camera
internal_camera = new /obj/machinery/camera(src)
internal_camera.c_tag = "[src] Internal Camera"
internal_camera.network = list("xenobio_internal")
internal_camera.internal_light = FALSE // Don't light up when viewed

for(var/obj/machinery/monkey_recycler/recycler in GLOB.monkey_recyclers)
if(get_area(recycler.loc) == get_area(loc))
connected_recycler = recycler
Expand All @@ -70,6 +81,7 @@
if(connected_recycler)
connected_recycler.connected -= src
connected_recycler = null
QDEL_NULL(internal_camera) // Clean up our camera
return ..()

/obj/machinery/computer/camera_advanced/xenobio/handle_atom_del(atom/A)
Expand All @@ -87,8 +99,21 @@
eyeobj.icon_state = "generic_camera"

/obj/machinery/computer/camera_advanced/xenobio/GrantActions(mob/living/user)
..()

// Don't call parent - we're replacing the jump action
if(off_action)
off_action.target = user
off_action.Grant(user)
actions += off_action

// Use our custom xenobio jump action instead of the parent's
if(!jump_action || !istype(jump_action, /datum/action/innate/camera_jump/xenobio))
jump_action = new /datum/action/innate/camera_jump/xenobio()
if(jump_action)
jump_action.target = user
jump_action.Grant(user)
actions += jump_action

// Rest of the xenobio-specific actions
if(slime_up_action)
slime_up_action.target = src
slime_up_action.Grant(user)
Expand Down Expand Up @@ -176,6 +201,27 @@
return
..()

/obj/machinery/computer/camera_advanced/xenobio/attack_hand(mob/user, list/modifiers)
. = ..()
if(.)
return
if(!is_operational)
return

var/mob/living/L = user
if(!eyeobj)
CreateEye()

if(!eyeobj.eye_initialized)
// Start at internal camera if it exists, otherwise at console
var/turf/starting_turf = internal_camera ? get_turf(internal_camera) : get_turf(src)
eyeobj.eye_initialized = TRUE
give_eye_control(L)
eyeobj.setLoc(starting_turf, TRUE)
else
give_eye_control(L)
eyeobj.setLoc(eyeobj.loc, TRUE)

/obj/machinery/computer/camera_advanced/xenobio/multitool_act(mob/living/user, obj/item/multitool/I)
. = ..()
if (istype(I) && istype(I.buffer,/obj/machinery/monkey_recycler))
Expand All @@ -184,6 +230,84 @@
connected_recycler.connected += src
return TRUE

/obj/machinery/computer/camera_advanced/xenobio/proc/get_area_cameras()
var/area/console_area = get_area(src)
if(!console_area)
// Emergency fallback - just return our internal camera
if(internal_camera)
return list(internal_camera)
return list()

var/list/area_cameras = list()

// First, add cameras from the area
for(var/obj/machinery/camera/C in console_area.cameras)
if(C.can_use() && C != internal_camera) // Don't double-add our internal camera
area_cameras += C

// Always include our internal camera as a fallback option
if(internal_camera && internal_camera.can_use())
area_cameras += internal_camera

// If we found no cameras at all, at least return our internal one
if(!area_cameras.len && internal_camera)
return list(internal_camera)

return area_cameras

/datum/action/innate/camera_jump/xenobio
// Inherits from the parent camera_jump action

/datum/action/innate/camera_jump/xenobio/Activate()
if(!target || !isliving(target))
return
var/mob/living/C = target
var/mob/camera/aiEye/remote/remote_eye = C.remote_control
var/obj/machinery/computer/camera_advanced/xenobio/origin = remote_eye.origin

// Get cameras in our area (includes internal camera)
var/list/area_cameras = origin.get_area_cameras()
if(!area_cameras.len)
to_chat(C, span_warning("No cameras detected."))
return

camera_sort(area_cameras)

var/list/T = list()
for(var/obj/machinery/camera/cam in area_cameras)
var/cam_name = cam.c_tag
// Mark the internal camera specially so users know it's the console's own camera
if(cam == origin.internal_camera)
cam_name = "[cam.c_tag] (Console)"
T["[cam_name][cam.can_use() ? null : " (Deactivated)"]"] = cam

playsound(origin, 'sound/machines/terminal_prompt.ogg', 25, FALSE)
var/camera = input("Choose which camera you want to view", "Cameras") as null|anything in T
var/obj/machinery/camera/final = T[camera]
playsound(src, "terminal_type", 25, FALSE)
if(final)
playsound(origin, 'sound/machines/terminal_prompt_confirm.ogg', 25, FALSE)
remote_eye.setLoc(get_turf(final), TRUE)
C.overlay_fullscreen("flash", /atom/movable/screen/fullscreen/flash/static)
C.clear_fullscreen("flash", 3)
else
playsound(origin, 'sound/machines/terminal_prompt_deny.ogg', 25, FALSE)

/obj/machinery/computer/camera_advanced/xenobio/examine(mob/user)
. = ..()
var/area/console_area = get_area(src)
var/camera_count = 0
for(var/obj/machinery/camera/C in console_area.cameras)
if(C.can_use() && C != internal_camera)
camera_count++

if(camera_count > 0)
. += span_notice("Detects [camera_count] camera[camera_count == 1 ? "" : "s"] in [console_area.name].")
else
. += span_notice("No external cameras detected. Using internal console camera only.")

. += span_info("The console has a built-in camera for remote viewing.")

/datum/action/innate/slime_place
name = "Place Slimes"
icon_icon = 'icons/mob/actions/actions_silicon.dmi'
Expand Down
Loading