mirror of
https://github.com/ParadiseSS13/Paradise.git
synced 2026-08-23 12:07:27 +01:00
Refactors AI / camera eyes and slows holopad holograms to walk speed (#25078)
* Refactor/deduplicate camera eye code Camera Eyes previously had duplicated logic across several files. This change uncooks the spaghetti. Additionally, half-baked support for TG's multicam feature has been removed, as it was not functional or in use. * lets ff now * Camera Eye refactor fixes and finishing touches This change completes a refactor of AI eyes, which were previously used by xenobio consoles, syndicate and abductor camera consoles, shuttle docking computers, holograms, and, of course, the AI. Duplicated logic has been extracted to an abstract base mob, /mob/camera/eye, from which new types for each of the above now derive. Functionality is largely the same, with only a few minor cosmetic differences (i.e. camera eyes are now appropriately named given their type and user), as well as a quality-of-life enhancement for holograms, slowing their movement speed to base run speed to prevent users from accidentally zooming out of calls. * Camera eye refactor: Fix AI acceleration toggle The acceleration toggle was broken in the camera eye refactor, as previously the boolean was stored on the AI rather than its eye. This change fixes that. * Camera eye refactor: Fix syndicate cam visibility With the camera eye refactor, the syndicate advanced camera consoles lost the ability to view maintenance tunnels and other areas without active cameras, seeing static in their place instead (as all other cameras do). This change reinstates the original behavior. * Camera eye refactor: Convert spaces to tabs * Camera eye refactor: Fix CRLF * Apply suggestions from code review General minor code quality improvements suggested by GDNgit Co-authored-by: GDN <96800819+GDNgit@users.noreply.github.com> * Apply suggestions from code review Rename parameter names to avoid src accesses, remove an ambiguous and unused mob_define and holopad range variable from a previous WIP, change the for loop in /mob/camera/eye/relaymove to a for-to loop, and change the chat message warning, sent when an AI Eye is created on an AI that already has one, to a stack trace * Adds toggle to AI commands for fast holograms * Refactor ripped Hologram Eye relaymove Previously, the relaymove proc for hologram eyes was redundant and nearly impossible to read. It has been separated out into a few different named procs, and has had its use of `spawn` removed. * Remove unnecessary src access * Fix bug involving shuttle placement outlines The camera eye refactor that this commit is a part of introduced a bug that prevented shuttle placement outlines from showing up on first use of the shuttle console. This change fixes that bug. * Unrevert some changes from #26306 lost in merge * Remove erroneous free xray vision on advanced cams * Autodoc camera acceleration vars * Remove redundant null var initialization per code review Co-authored-by: Drsmail <60036448+Drsmail@users.noreply.github.com> Signed-off-by: asciodev <81930475+asciodev@users.noreply.github.com> * Changed variables to camel_case, autodocs, cleanup Changed a number of camera eye-related variables to camel_case style, added appropriate autodoc comments, as per code review. Also removed an unused cameranet function, modified the call signature of a cameranet function to be more semantic, and changed a qdel-on-initialize in camera eyes to return INITIALIZE_HINT_QDEL instead. Co-authored-by: Luc <89928798+lewcc@users.noreply.github.com> * Remove stray qdel(src) per code review Co-authored-by: Luc <89928798+lewcc@users.noreply.github.com> Signed-off-by: asciodev <81930475+asciodev@users.noreply.github.com> --------- Signed-off-by: asciodev <81930475+asciodev@users.noreply.github.com> Co-authored-by: GDN <96800819+GDNgit@users.noreply.github.com> Co-authored-by: Drsmail <60036448+Drsmail@users.noreply.github.com> Co-authored-by: Luc <89928798+lewcc@users.noreply.github.com>
This commit is contained in:
co-authored by
Luc
GDN
Drsmail
parent
dac57002ff
commit
93ed0f096d
@@ -259,7 +259,7 @@
|
||||
#define ismorph(A) (istype((A), /mob/living/simple_animal/hostile/morph))
|
||||
|
||||
#define issilicon(A) (istype((A), /mob/living/silicon))
|
||||
#define isAI(A) (istype((A), /mob/living/silicon/ai))
|
||||
#define is_ai(A) (istype((A), /mob/living/silicon/ai))
|
||||
#define isrobot(A) (istype((A), /mob/living/silicon/robot))
|
||||
#define isdrone(A) (istype((A), /mob/living/silicon/robot/drone))
|
||||
#define ispAI(A) (istype((A), /mob/living/silicon/pai))
|
||||
@@ -273,7 +273,7 @@
|
||||
#define ispathanimal(A) (ispath(A, /mob/living/simple_animal))
|
||||
|
||||
#define iscameramob(A) (istype((A), /mob/camera))
|
||||
#define isAIEye(A) (istype((A), /mob/camera/ai_eye))
|
||||
#define is_ai_eye(A) (istype((A), /mob/camera/eye))
|
||||
#define isovermind(A) (istype((A), /mob/camera/blob))
|
||||
|
||||
#define isSpirit(A) (istype((A), /mob/spirit))
|
||||
|
||||
@@ -879,7 +879,7 @@ Returns 1 if the chain up to the area contains the given typepath
|
||||
continue
|
||||
|
||||
O.loc.Exited(O)
|
||||
O.setLoc(X)
|
||||
O.set_loc(X)
|
||||
O.loc.Entered(O)
|
||||
|
||||
for(var/mob/M in T)
|
||||
|
||||
@@ -102,20 +102,20 @@
|
||||
add_attack_logs(src, src, "[key_name_admin(src)] might be running a modified client! (failed can_see on AI click of [A]([ADMIN_COORDJMP(pixel_turf)]))", ATKLOG_ALL)
|
||||
var/message = "[key_name(src)] might be running a modified client! (failed can_see on AI click of [A]([COORD(pixel_turf)]))"
|
||||
log_admin(message)
|
||||
GLOB.discord_manager.send2discord_simple_noadmins("**\[Warning]** [key_name(src)] might be running a modified client! (failed checkTurfVis on AI click of [A]([COORD(pixel_turf)]))")
|
||||
GLOB.discord_manager.send2discord_simple_noadmins("**\[Warning]** [key_name(src)] might be running a modified client! (failed check_turf_vis on AI click of [A]([COORD(pixel_turf)]))")
|
||||
return FALSE
|
||||
|
||||
var/turf_visible
|
||||
if(pixel_turf)
|
||||
turf_visible = GLOB.cameranet.checkTurfVis(pixel_turf)
|
||||
turf_visible = GLOB.cameranet.check_turf_vis(pixel_turf)
|
||||
if(!turf_visible)
|
||||
if((istype(loc, /obj/item/aicard) || ismecha(loc)) && (pixel_turf in range(client.view, loc)))
|
||||
turf_visible = TRUE
|
||||
else
|
||||
if(pixel_turf.obscured)
|
||||
log_admin("[key_name_admin(src)] might be running a modified client! (failed checkTurfVis on AI click of [A]([COORD(pixel_turf)])")
|
||||
add_attack_logs(src, src, "[key_name_admin(src)] might be running a modified client! (failed checkTurfVis on AI click of [A]([ADMIN_COORDJMP(pixel_turf)]))", ATKLOG_ALL)
|
||||
GLOB.discord_manager.send2discord_simple_noadmins("**\[Warning]** [key_name(src)] might be running a modified client! (failed checkTurfVis on AI click of [A]([COORD(pixel_turf)]))")
|
||||
log_admin("[key_name_admin(src)] might be running a modified client! (failed check_turf_vis on AI click of [A]([COORD(pixel_turf)])")
|
||||
add_attack_logs(src, src, "[key_name_admin(src)] might be running a modified client! (failed check_turf_vis on AI click of [A]([ADMIN_COORDJMP(pixel_turf)]))", ATKLOG_ALL)
|
||||
GLOB.discord_manager.send2discord_simple_noadmins("**\[Warning]** [key_name(src)] might be running a modified client! (failed check_turf_vis on AI click of [A]([COORD(pixel_turf)]))")
|
||||
return FALSE
|
||||
return TRUE
|
||||
|
||||
@@ -184,7 +184,7 @@
|
||||
return
|
||||
|
||||
/mob/living/silicon/ai/TurfAdjacent(turf/T)
|
||||
return (GLOB.cameranet && GLOB.cameranet.checkTurfVis(T))
|
||||
return (GLOB.cameranet && GLOB.cameranet.check_turf_vis(T))
|
||||
|
||||
|
||||
// APC
|
||||
|
||||
@@ -105,7 +105,7 @@
|
||||
/atom/movable/screen/ai/state_laws/Click()
|
||||
if(..())
|
||||
return
|
||||
if(isAI(usr))
|
||||
if(is_ai(usr))
|
||||
var/mob/living/silicon/ai/AI = usr
|
||||
AI.subsystem_law_manager()
|
||||
|
||||
@@ -156,7 +156,7 @@
|
||||
/atom/movable/screen/ai/sensors/Click()
|
||||
if(..())
|
||||
return
|
||||
if(isAI(usr))
|
||||
if(is_ai(usr))
|
||||
var/mob/living/silicon/ai/AI = usr
|
||||
AI.sensor_mode()
|
||||
else if(isrobot(usr))
|
||||
|
||||
@@ -514,7 +514,7 @@ so as to remain in compliance with the most up-to-date laws."
|
||||
var/mob/living/silicon/ai/AI = usr
|
||||
var/turf/T = get_turf(target)
|
||||
if(T)
|
||||
AI.eyeobj.setLoc(T)
|
||||
AI.eyeobj.set_loc(T)
|
||||
|
||||
//MECHS
|
||||
/atom/movable/screen/alert/low_mech_integrity
|
||||
|
||||
@@ -173,7 +173,7 @@ SUBSYSTEM_DEF(shuttle)
|
||||
var/callShuttle = 1
|
||||
|
||||
for(var/thing in GLOB.shuttle_caller_list)
|
||||
if(isAI(thing))
|
||||
if(is_ai(thing))
|
||||
var/mob/living/silicon/ai/AI = thing
|
||||
if(AI.stat || !AI.client)
|
||||
continue
|
||||
|
||||
@@ -161,7 +161,7 @@ SUBSYSTEM_DEF(tickets)
|
||||
if(M)
|
||||
L += "([ADMIN_QUE(M,"?")]) ([ADMIN_PP(M,"PP")]) ([ADMIN_VV(M,"VV")]) ([ADMIN_TP(M,"TP")]) ([ADMIN_SM(M,"SM")]) ([admin_jump_link(M)])"
|
||||
L += "(<a href='byond://?_src_=holder;openticket=[ticketNum][anchor_link_extra]'>TICKET</a>) "
|
||||
L += "[isAI(M) ? "(<a href='byond://?_src_=holder;adminchecklaws=[M.UID()]'>CL</a>)" : ""] (<a href='byond://?_src_=holder;take_question=[ticketNum][anchor_link_extra]'>TAKE</a>) "
|
||||
L += "[is_ai(M) ? "(<a href='byond://?_src_=holder;adminchecklaws=[M.UID()]'>CL</a>)" : ""] (<a href='byond://?_src_=holder;take_question=[ticketNum][anchor_link_extra]'>TAKE</a>) "
|
||||
L += "(<a href='byond://?_src_=holder;resolve=[ticketNum][anchor_link_extra]'>RESOLVE</a>) (<a href='byond://?_src_=holder;autorespond=[ticketNum][anchor_link_extra]'>AUTO</a>) "
|
||||
L += "(<a href='byond://?_src_=holder;convert_ticket=[ticketNum][anchor_link_extra]'>CONVERT</a>) :</span> <span class='[ticket_help_span]'>[one_line ? " " : "<br><br>"][msg]</span>"
|
||||
return L.Join()
|
||||
|
||||
@@ -22,7 +22,7 @@
|
||||
if(!M.anchored && (M.flags & CONDUCT))
|
||||
step_towards(M,affected_mob)
|
||||
for(var/mob/living/silicon/S in orange(2,affected_mob))
|
||||
if(isAI(S)) continue
|
||||
if(is_ai(S)) continue
|
||||
step_towards(S,affected_mob)
|
||||
if(3)
|
||||
if(prob(2))
|
||||
@@ -37,7 +37,7 @@
|
||||
for(i=0,i<iter,i++)
|
||||
step_towards(M,affected_mob)
|
||||
for(var/mob/living/silicon/S in orange(4,affected_mob))
|
||||
if(isAI(S)) continue
|
||||
if(is_ai(S)) continue
|
||||
var/i
|
||||
var/iter = rand(1,2)
|
||||
for(i=0,i<iter,i++)
|
||||
@@ -55,7 +55,7 @@
|
||||
for(i=0,i<iter,i++)
|
||||
step_towards(M,affected_mob)
|
||||
for(var/mob/living/silicon/S in orange(6,affected_mob))
|
||||
if(isAI(S)) continue
|
||||
if(is_ai(S)) continue
|
||||
var/i
|
||||
var/iter = rand(1,3)
|
||||
for(i=0,i<iter,i++)
|
||||
|
||||
@@ -405,7 +405,7 @@
|
||||
. = message_larva
|
||||
else if(issilicon(user) && message_robot)
|
||||
. = message_robot
|
||||
else if(isAI(user) && message_AI)
|
||||
else if(is_ai(user) && message_AI)
|
||||
. = message_AI
|
||||
else if(ismonkeybasic(user) && message_monkey)
|
||||
. = message_monkey
|
||||
|
||||
+23
-31
@@ -1,24 +1,23 @@
|
||||
/mob/camera/ai_eye/remote/holo/setLoc()
|
||||
. = ..()
|
||||
var/obj/machinery/hologram/holopad/H = origin
|
||||
H.move_hologram(eye_user, loc)
|
||||
ai_detector_visible = FALSE // Holocalls dont trigger the Ai Detector
|
||||
|
||||
//this datum manages it's own references
|
||||
|
||||
/datum/holocall
|
||||
var/mob/living/user //the one that called
|
||||
var/obj/machinery/hologram/holopad/calling_holopad //the one that sent the call
|
||||
var/obj/machinery/hologram/holopad/connected_holopad //the one that answered the call (may be null)
|
||||
var/list/dialed_holopads //all things called, will be cleared out to just connected_holopad once answered
|
||||
|
||||
var/mob/camera/ai_eye/remote/holo/eye //user's eye, once connected
|
||||
var/obj/effect/overlay/holo_pad_hologram/hologram //user's hologram, once connected
|
||||
var/datum/action/innate/end_holocall/hangup //hangup action
|
||||
/// The calling user
|
||||
var/mob/living/user
|
||||
/// The calling holopad
|
||||
var/obj/machinery/hologram/holopad/calling_holopad
|
||||
/// The receiving holopad (may be null)
|
||||
var/obj/machinery/hologram/holopad/connected_holopad
|
||||
/// All holopads currently being dialed. Once answered, this will be cleared with `[connected_holopad]`.
|
||||
var/list/dialed_holopads
|
||||
|
||||
/// Camera eye, once connected
|
||||
var/mob/camera/eye/eye
|
||||
/// The user's hologram, once connected
|
||||
var/obj/effect/overlay/holo_pad_hologram/hologram
|
||||
/// The hangup action handler, for handling the hangup button displayed in the top left corner of the screen
|
||||
var/datum/action/innate/end_holocall/hangup
|
||||
/// The `world.time` at the time the holocall is created
|
||||
var/call_start_time
|
||||
|
||||
//creates a holocall made by `caller` from `calling_pad` to `callees`
|
||||
/// Creates a holocall made by `caller` from `calling_pad` to `callees`
|
||||
/datum/holocall/New(mob/living/caller, obj/machinery/hologram/holopad/calling_pad, list/callees)
|
||||
call_start_time = world.time
|
||||
user = caller
|
||||
@@ -49,7 +48,7 @@
|
||||
user.remote_control = null
|
||||
|
||||
if(!QDELETED(eye))
|
||||
eye.RemoveImages()
|
||||
eye.remove_images()
|
||||
QDEL_NULL(eye)
|
||||
|
||||
if(connected_holopad && !QDELETED(hologram))
|
||||
@@ -81,7 +80,7 @@
|
||||
return ..()
|
||||
|
||||
|
||||
//Gracefully disconnects a holopad `H` from a call. Pads not in the call are ignored. Notifies participants of the disconnection
|
||||
/// Gracefully disconnects a holopad `H` from a call. Pads not in the call are ignored. Notifies participants of the disconnection
|
||||
/datum/holocall/proc/Disconnect(obj/machinery/hologram/holopad/H)
|
||||
if(H == connected_holopad)
|
||||
var/area/A = get_area(connected_holopad)
|
||||
@@ -95,7 +94,7 @@
|
||||
|
||||
ConnectionFailure(H, TRUE)
|
||||
|
||||
//Forcefully disconnects a holopad `H` from a call. Pads not in the call are ignored.
|
||||
/// Forcefully disconnects a holopad `H` from a call. Pads not in the call are ignored.
|
||||
/datum/holocall/proc/ConnectionFailure(obj/machinery/hologram/holopad/H, graceful = FALSE)
|
||||
if(H == connected_holopad || H == calling_holopad)
|
||||
if(!graceful && H != calling_holopad)
|
||||
@@ -110,7 +109,7 @@
|
||||
calling_holopad.atom_say("Call rejected.")
|
||||
qdel(src)
|
||||
|
||||
//Answers a call made to a holopad `H` which cannot be the calling holopad. Pads not in the call are ignored
|
||||
/// Answers a call made to a holopad `H` which cannot be the calling holopad. Pads not in the call are ignored
|
||||
/datum/holocall/proc/Answer(obj/machinery/hologram/holopad/H)
|
||||
if(H == calling_holopad)
|
||||
return
|
||||
@@ -137,23 +136,15 @@
|
||||
return
|
||||
|
||||
hologram = H.activate_holo(user)
|
||||
eye = H.eye
|
||||
hologram.HC = src
|
||||
|
||||
user.unset_machine(H)
|
||||
//eyeobj code is horrid, this is the best copypasta I could make
|
||||
eye = new()
|
||||
eye.origin = H
|
||||
eye.eye_initialized = TRUE
|
||||
eye.eye_user = user
|
||||
eye.name = "Camera Eye ([user.name])"
|
||||
user.remote_control = eye
|
||||
user.reset_perspective(eye)
|
||||
eye.setLoc(get_turf(H))
|
||||
|
||||
hangup = new(eye,src)
|
||||
hangup.Grant(user)
|
||||
|
||||
//Checks the validity of a holocall and qdels itself if it's not. Returns TRUE if valid, FALSE otherwise
|
||||
/// Checks the validity of a holocall and qdels itself if it's not. Returns TRUE if valid, FALSE otherwise
|
||||
/datum/holocall/proc/Check()
|
||||
for(var/I in dialed_holopads)
|
||||
var/obj/machinery/hologram/holopad/H = I
|
||||
@@ -174,6 +165,7 @@
|
||||
if(!.)
|
||||
qdel(src)
|
||||
|
||||
/// The hangup action handler, for handling the hangup button displayed in the top left corner of the screen
|
||||
/datum/action/innate/end_holocall
|
||||
name = "End Holocall"
|
||||
button_overlay_icon_state = "camera_off"
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
category = KB_CATEGORY_AI
|
||||
|
||||
/datum/keybinding/ai/can_use(client/C, mob/M)
|
||||
return isAI(M) && ..()
|
||||
return is_ai(M) && ..()
|
||||
|
||||
/datum/keybinding/ai/to_core
|
||||
name = "Jump to Core"
|
||||
@@ -54,7 +54,7 @@
|
||||
to_chat(AI, "<span class='warning'>You haven't set location [location_number] yet!</span>")
|
||||
return
|
||||
|
||||
AI.eyeobj.setLoc(AI.stored_locations[location_number])
|
||||
AI.eyeobj.set_loc(AI.stored_locations[location_number])
|
||||
|
||||
/datum/keybinding/ai/to_location/one
|
||||
name = "Jump to Location One"
|
||||
|
||||
+1
-1
@@ -1509,7 +1509,7 @@
|
||||
message_admins("[key_name_admin(usr)] has un-emagged [key_name_admin(current)]")
|
||||
|
||||
if("unemagcyborgs")
|
||||
if(!isAI(current))
|
||||
if(!is_ai(current))
|
||||
return
|
||||
var/mob/living/silicon/ai/ai = current
|
||||
for(var/mob/living/silicon/robot/R in ai.connected_robots)
|
||||
|
||||
@@ -213,7 +213,7 @@
|
||||
|
||||
var/cybernetic_type = job_to_cybernetic[job.type]
|
||||
if(!cybernetic_type)
|
||||
if(isAI(spawned))
|
||||
if(is_ai(spawned))
|
||||
var/mob/living/silicon/ai/ai = spawned
|
||||
ai.eyeobj.relay_speech = TRUE //surveillance upgrade. the ai gets cybernetics too.
|
||||
return
|
||||
|
||||
@@ -198,9 +198,9 @@
|
||||
return FALSE
|
||||
return TRUE
|
||||
|
||||
// Used in shuttle movement and AI eye stuff.
|
||||
// Primarily used to notify objects being moved by a shuttle/bluespace fuckup.
|
||||
/atom/movable/proc/setLoc(T, teleported=0)
|
||||
/// Used in shuttle movement and camera eye stuff.
|
||||
/// Primarily used to notify objects being moved by a shuttle/bluespace fuckup.
|
||||
/atom/movable/proc/set_loc(T, teleported=0)
|
||||
var/old_loc = loc
|
||||
loc = T
|
||||
Moved(old_loc, get_dir(old_loc, loc))
|
||||
|
||||
@@ -534,7 +534,7 @@
|
||||
else if(isrobot(commenter))
|
||||
var/mob/living/silicon/robot/U = commenter
|
||||
commenter_display = "[U.name] ([U.modtype] [U.braintype])"
|
||||
else if(isAI(commenter))
|
||||
else if(is_ai(commenter))
|
||||
var/mob/living/silicon/ai/U = commenter
|
||||
commenter_display = "[U.name] (artificial intelligence)"
|
||||
comment_text = "Made by [commenter_display] on [GLOB.current_date_string] [station_time_timestamp()]:<br>[comment_text]"
|
||||
|
||||
@@ -72,7 +72,7 @@
|
||||
if(player.mind.has_antag_datum(/datum/antagonist/traitor))
|
||||
traitor_count += 1
|
||||
continue
|
||||
if(ishuman(player) || isAI(player))
|
||||
if(ishuman(player) || is_ai(player))
|
||||
if((ROLE_TRAITOR in player.client.prefs.be_special) && !player.client.skip_antag && !jobban_isbanned(player, ROLE_TRAITOR) && !jobban_isbanned(player, ROLE_SYNDICATE))
|
||||
possible_traitors += player.mind
|
||||
for(var/datum/mind/player in possible_traitors)
|
||||
|
||||
@@ -126,7 +126,7 @@
|
||||
/datum/module_picker/Topic(href, href_list)
|
||||
..()
|
||||
|
||||
if(!isAI(usr))
|
||||
if(!is_ai(usr))
|
||||
return
|
||||
var/mob/living/silicon/ai/A = usr
|
||||
|
||||
@@ -573,8 +573,8 @@
|
||||
var/turf/T = turfs[n]
|
||||
if(!isfloorturf(T))
|
||||
success = FALSE
|
||||
var/datum/camerachunk/C = GLOB.cameranet.getCameraChunk(T.x, T.y, T.z)
|
||||
if(!C.visibleTurfs[T])
|
||||
var/datum/camerachunk/C = GLOB.cameranet.get_camera_chunk(T.x, T.y, T.z)
|
||||
if(!C.visible_turfs[T])
|
||||
alert_msg = "You don't have camera vision of this location!"
|
||||
success = FALSE
|
||||
for(var/atom/movable/AM in T.contents)
|
||||
@@ -673,12 +673,12 @@
|
||||
I.loc = deploylocation
|
||||
client.images += I
|
||||
I.icon_state = "redOverlay"
|
||||
var/datum/camerachunk/C = GLOB.cameranet.getCameraChunk(deploylocation.x, deploylocation.y, deploylocation.z)
|
||||
var/datum/camerachunk/C = GLOB.cameranet.get_camera_chunk(deploylocation.x, deploylocation.y, deploylocation.z)
|
||||
|
||||
if(!istype(deploylocation))
|
||||
to_chat(src, "<span class='warning'>There isn't enough room! Make sure you are placing the machine in a clear area and on a floor.</span>")
|
||||
return FALSE
|
||||
if(!C.visibleTurfs[deploylocation])
|
||||
if(!C.visible_turfs[deploylocation])
|
||||
to_chat(src, "<span class='warning'>You don't have camera vision of this location!</span>")
|
||||
addtimer(CALLBACK(src, PROC_REF(remove_transformer_image), client, I, deploylocation), 3 SECONDS)
|
||||
return FALSE
|
||||
|
||||
@@ -23,7 +23,8 @@
|
||||
return ..()
|
||||
|
||||
/obj/machinery/computer/camera_advanced/abductor/CreateEye()
|
||||
..()
|
||||
eyeobj = new /mob/camera/eye/abductor(loc, name, src, current_user)
|
||||
give_eye_control(current_user)
|
||||
eyeobj.visible_icon = 1
|
||||
eyeobj.icon = 'icons/obj/abductor.dmi'
|
||||
eyeobj.icon_state = "camera_target"
|
||||
@@ -74,10 +75,10 @@
|
||||
if(!target || !iscarbon(owner))
|
||||
return
|
||||
var/mob/living/carbon/human/C = owner
|
||||
var/mob/camera/ai_eye/remote/remote_eye = C.remote_control
|
||||
var/mob/camera/eye/abductor/remote_eye = C.remote_control
|
||||
var/obj/machinery/abductor/pad/P = target
|
||||
|
||||
if(GLOB.cameranet.checkTurfVis(remote_eye.loc))
|
||||
if(GLOB.cameranet.check_turf_vis(remote_eye.loc))
|
||||
P.PadToLoc(remote_eye.loc)
|
||||
|
||||
/datum/action/innate/teleport_out
|
||||
@@ -101,10 +102,10 @@
|
||||
if(!target || !iscarbon(owner))
|
||||
return
|
||||
var/mob/living/carbon/human/C = owner
|
||||
var/mob/camera/ai_eye/remote/remote_eye = C.remote_control
|
||||
var/mob/camera/eye/abductor/remote_eye = C.remote_control
|
||||
var/obj/machinery/abductor/pad/P = target
|
||||
|
||||
if(GLOB.cameranet.checkTurfVis(remote_eye.loc))
|
||||
if(GLOB.cameranet.check_turf_vis(remote_eye.loc))
|
||||
P.MobToLoc(remote_eye.loc,C)
|
||||
|
||||
/datum/action/innate/vest_mode_swap
|
||||
@@ -137,7 +138,7 @@
|
||||
return
|
||||
|
||||
var/mob/living/carbon/human/C = owner
|
||||
var/mob/camera/ai_eye/remote/remote_eye = C.remote_control
|
||||
var/mob/camera/eye/abductor/remote_eye = C.remote_control
|
||||
|
||||
var/obj/machinery/abductor/console/console = target
|
||||
console.SetDroppoint(remote_eye.loc,owner)
|
||||
|
||||
@@ -501,7 +501,7 @@
|
||||
|
||||
for(var/mob in GLOB.mob_living_list)
|
||||
var/mob/living/C = mob
|
||||
if(ishuman(C) || isAI(C) || isrobot(C))
|
||||
if(ishuman(C) || is_ai(C) || isrobot(C))
|
||||
if(C.stat == DEAD)
|
||||
continue
|
||||
if(!C.client)
|
||||
|
||||
@@ -135,7 +135,7 @@ GLOBAL_VAR(scoreboard) // Variable to save the scoreboard string once it's been
|
||||
/datum/scoreboard/proc/check_station_player(mob/M)
|
||||
if(!is_station_level(M.z) || M.stat != DEAD)
|
||||
return
|
||||
if(isAI(M))
|
||||
if(is_ai(M))
|
||||
dead_ai = TRUE
|
||||
score_dead_crew++
|
||||
else if(ishuman(M))
|
||||
|
||||
@@ -23,7 +23,7 @@ GLOBAL_LIST_EMPTY(ai_displays)
|
||||
return ..()
|
||||
|
||||
/obj/machinery/ai_status_display/attack_ai(mob/living/silicon/ai/user)
|
||||
if(isAI(user))
|
||||
if(is_ai(user))
|
||||
user.ai_statuschange()
|
||||
|
||||
/obj/machinery/ai_status_display/emp_act(severity)
|
||||
|
||||
@@ -55,7 +55,7 @@
|
||||
GLOB.cameranet.cameras += src
|
||||
part_of_camera_network = should_add_to_cameranet
|
||||
if(part_of_camera_network)
|
||||
GLOB.cameranet.addCamera(src)
|
||||
GLOB.cameranet.add_camera(src)
|
||||
if(isturf(loc))
|
||||
var/area/our_area = get_area(src)
|
||||
LAZYADD(our_area.cameras, UID())
|
||||
@@ -81,7 +81,7 @@
|
||||
kick_out_watchers()
|
||||
QDEL_NULL(assembly)
|
||||
QDEL_NULL(wires)
|
||||
GLOB.cameranet.removeCamera(src)
|
||||
GLOB.cameranet.remove_camera(src)
|
||||
GLOB.cameranet.cameras -= src
|
||||
var/area/our_area = get_area(src)
|
||||
if(our_area) // We should probably send out the warning alarms if this doesn't exist, because this should always have an area!
|
||||
@@ -134,7 +134,7 @@
|
||||
|
||||
/obj/machinery/camera/proc/setViewRange(num = CAMERA_VIEW_DISTANCE)
|
||||
view_range = num
|
||||
GLOB.cameranet.updateVisibility(src, 0)
|
||||
GLOB.cameranet.update_visibility(src, 0)
|
||||
|
||||
/obj/machinery/camera/singularity_pull(S, current_size)
|
||||
if(status && current_size >= STAGE_FIVE) // If the singulo is strong enough to pull anchored objects and the camera is still active, turn off the camera as it gets ripped off the wall.
|
||||
@@ -192,7 +192,7 @@
|
||||
to_chat(U, "You hold \the [itemname] up to the camera ...")
|
||||
U.changeNext_move(CLICK_CD_MELEE)
|
||||
for(var/mob/O in GLOB.player_list)
|
||||
if(isAI(O))
|
||||
if(is_ai(O))
|
||||
var/mob/living/silicon/ai/AI = O
|
||||
if(AI.control_disabled || (AI.stat == DEAD))
|
||||
return
|
||||
@@ -415,7 +415,7 @@
|
||||
user.overlay_fullscreen("remote_view", /atom/movable/screen/fullscreen/stretch/impaired, 2)
|
||||
|
||||
/obj/machinery/camera/update_remote_sight(mob/living/user)
|
||||
if(isXRay() && isAI(user))
|
||||
if(isXRay() && is_ai(user))
|
||||
user.sight |= (SEE_TURFS|SEE_MOBS|SEE_OBJS)
|
||||
user.see_in_dark = max(user.see_in_dark, 8)
|
||||
user.lighting_alpha = LIGHTING_PLANE_ALPHA_MOSTLY_INVISIBLE
|
||||
@@ -446,5 +446,5 @@
|
||||
return
|
||||
|
||||
SEND_SIGNAL(src, COMSIG_CAMERA_MOVED, prev_turf)
|
||||
GLOB.cameranet.updatePortableCamera(src, prev_turf)
|
||||
GLOB.cameranet.update_portable_camera(src, prev_turf)
|
||||
prev_turf = get_turf(src)
|
||||
|
||||
@@ -146,7 +146,7 @@
|
||||
assembly.upgrades.Add(new /obj/item/analyzer(assembly))
|
||||
setPowerUsage()
|
||||
//Update what it can see.
|
||||
GLOB.cameranet.updateVisibility(src, 0)
|
||||
GLOB.cameranet.update_visibility(src, 0)
|
||||
|
||||
// If you are upgrading Motion, and it isn't in the camera's New(), add it to the machines list.
|
||||
/obj/machinery/camera/proc/upgradeMotion()
|
||||
|
||||
@@ -22,7 +22,7 @@
|
||||
return localMotionTargets
|
||||
|
||||
/obj/machinery/camera/proc/newTarget(mob/target)
|
||||
if(isAI(target))
|
||||
if(is_ai(target))
|
||||
return FALSE
|
||||
if(isbot(target)) //No armsky, you don't get to set off the motion alarm constantly
|
||||
return FALSE
|
||||
|
||||
@@ -41,7 +41,7 @@
|
||||
return 0
|
||||
|
||||
var/obj/machinery/camera/C = track.cameras[camera]
|
||||
src.eyeobj.setLoc(C)
|
||||
src.eyeobj.set_loc(C)
|
||||
|
||||
return
|
||||
|
||||
@@ -104,18 +104,18 @@
|
||||
ai_actual_track(target)
|
||||
|
||||
/mob/living/silicon/ai/proc/ai_cancel_tracking(forced = 0)
|
||||
if(!cameraFollow)
|
||||
if(!camera_follow)
|
||||
return
|
||||
|
||||
to_chat(src, "Follow camera mode [forced ? "terminated" : "ended"].")
|
||||
cameraFollow = null
|
||||
camera_follow = null
|
||||
|
||||
/mob/living/silicon/ai/proc/ai_actual_track(mob/living/target, doubleclick = FALSE)
|
||||
if(!istype(target))
|
||||
return
|
||||
var/mob/living/silicon/ai/U = usr
|
||||
|
||||
U.cameraFollow = target
|
||||
U.camera_follow = target
|
||||
U.tracking = TRUE
|
||||
|
||||
to_chat(U, "<span class='notice'>Attempting to track [target.get_visible_name()]...</span>")
|
||||
@@ -126,20 +126,20 @@
|
||||
|
||||
if(target.is_jammed())
|
||||
to_chat(U, "<span class='warning'>Unable to track [target.get_visible_name()]...</span>")
|
||||
U.cameraFollow = null
|
||||
U.camera_follow = null
|
||||
return
|
||||
|
||||
if(!target || !target.can_track(usr))
|
||||
to_chat(U, "<span class='warning'>Target is not near any active cameras.</span>")
|
||||
U.cameraFollow = null
|
||||
U.camera_follow = null
|
||||
return
|
||||
|
||||
to_chat(U, "<span class='notice'>Now tracking [target.get_visible_name()] on camera.</span>")
|
||||
|
||||
var/cameraticks = 0
|
||||
spawn(0)
|
||||
while(U.cameraFollow == target)
|
||||
if(U.cameraFollow == null)
|
||||
while(U.camera_follow == target)
|
||||
if(U.camera_follow == null)
|
||||
return
|
||||
|
||||
if(!target.can_track(usr))
|
||||
@@ -148,7 +148,7 @@
|
||||
to_chat(U, "<span class='warning'>Target is not near any active cameras. Attempting to reacquire...</span>")
|
||||
cameraticks++
|
||||
if(cameraticks > 9)
|
||||
U.cameraFollow = null
|
||||
U.camera_follow = null
|
||||
to_chat(U, "<span class='warning'>Unable to reacquire, cancelling track...</span>")
|
||||
U.tracking = FALSE
|
||||
return
|
||||
@@ -161,11 +161,11 @@
|
||||
U.tracking = FALSE
|
||||
|
||||
if(U.eyeobj)
|
||||
U.eyeobj.setLoc(get_turf(target))
|
||||
U.eyeobj.set_loc(get_turf(target))
|
||||
|
||||
else
|
||||
view_core()
|
||||
U.cameraFollow = null
|
||||
U.camera_follow = null
|
||||
return
|
||||
|
||||
sleep(10)
|
||||
@@ -175,9 +175,9 @@
|
||||
return 0
|
||||
if(isrobot(M))
|
||||
var/mob/living/silicon/robot/R = M
|
||||
if(!(R.camera && R.camera.can_use()) && !GLOB.cameranet.checkCameraVis(M))
|
||||
if(!(R.camera && R.camera.can_use()) && !GLOB.cameranet.check_camera_vis(M))
|
||||
return 0
|
||||
else if(!GLOB.cameranet.checkCameraVis(M))
|
||||
else if(!GLOB.cameranet.check_camera_vis(M))
|
||||
return 0
|
||||
return 1
|
||||
|
||||
@@ -186,7 +186,7 @@
|
||||
return
|
||||
if(!src.can_use())
|
||||
return
|
||||
user.eyeobj.setLoc(get_turf(src))
|
||||
user.eyeobj.set_loc(get_turf(src))
|
||||
|
||||
|
||||
/mob/living/silicon/ai/attack_ai(mob/user)
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
desc = "Used to access the various cameras on the station."
|
||||
icon_screen = "cameras"
|
||||
icon_keyboard = "security_key"
|
||||
var/mob/camera/ai_eye/remote/eyeobj
|
||||
var/mob/camera/eye/eyeobj
|
||||
var/mob/living/carbon/human/current_user = null
|
||||
var/list/networks = list("SS13")
|
||||
var/datum/action/innate/camera_off/off_action = new
|
||||
@@ -11,8 +11,8 @@
|
||||
var/list/actions = list()
|
||||
|
||||
/obj/machinery/computer/camera_advanced/proc/CreateEye()
|
||||
eyeobj = new()
|
||||
eyeobj.origin = src
|
||||
eyeobj = new /mob/camera/eye/syndicate(loc, name, src, current_user)
|
||||
give_eye_control(current_user)
|
||||
|
||||
/obj/machinery/computer/camera_advanced/proc/GrantActions(mob/living/user)
|
||||
if(off_action)
|
||||
@@ -25,19 +25,17 @@
|
||||
jump_action.Grant(user)
|
||||
actions += jump_action
|
||||
|
||||
/obj/machinery/computer/camera_advanced/proc/remove_eye_control(mob/living/user)
|
||||
if(!user)
|
||||
/obj/machinery/computer/camera_advanced/proc/RemoveActions()
|
||||
if(!istype(current_user))
|
||||
return
|
||||
for(var/V in actions)
|
||||
var/datum/action/A = V
|
||||
A.Remove(user)
|
||||
A.Remove(current_user)
|
||||
actions.Cut()
|
||||
if(user.client)
|
||||
user.reset_perspective(null)
|
||||
eyeobj.RemoveImages()
|
||||
eyeobj.eye_user = null
|
||||
user.remote_control = null
|
||||
|
||||
/obj/machinery/computer/camera_advanced/proc/remove_eye_control(mob/living/user)
|
||||
RemoveActions()
|
||||
eyeobj.release_control()
|
||||
current_user = null
|
||||
remove_eye(user)
|
||||
playsound(src, 'sound/machines/terminal_off.ogg', 25, 0)
|
||||
@@ -57,7 +55,7 @@
|
||||
return ..()
|
||||
|
||||
/obj/machinery/computer/camera_advanced/proc/remove_eye(mob/M)
|
||||
if(M == current_user)
|
||||
if(istype(M) && M == current_user)
|
||||
remove_eye_control(M)
|
||||
|
||||
/obj/machinery/computer/camera_advanced/attack_hand(mob/user)
|
||||
@@ -68,102 +66,17 @@
|
||||
return
|
||||
if(..())
|
||||
return
|
||||
current_user = user
|
||||
|
||||
if(!eyeobj)
|
||||
CreateEye()
|
||||
|
||||
if(!eyeobj.eye_initialized)
|
||||
var/camera_location
|
||||
for(var/obj/machinery/camera/C in GLOB.cameranet.cameras)
|
||||
if(!C.can_use())
|
||||
continue
|
||||
if(length(C.network & networks))
|
||||
camera_location = get_turf(C)
|
||||
break
|
||||
if(camera_location)
|
||||
eyeobj.eye_initialized = 1
|
||||
give_eye_control(user)
|
||||
eyeobj.setLoc(camera_location)
|
||||
else
|
||||
// An abberant case - silent failure is obnoxious
|
||||
to_chat(user, "<span class='warning'>ERROR: No linked and active camera network found.</span>")
|
||||
remove_eye(user)
|
||||
else
|
||||
give_eye_control(user)
|
||||
eyeobj.setLoc(eyeobj.loc)
|
||||
|
||||
eyeobj.set_loc(eyeobj.loc)
|
||||
|
||||
/obj/machinery/computer/camera_advanced/proc/give_eye_control(mob/user)
|
||||
eyeobj.give_control(user)
|
||||
GrantActions(user)
|
||||
current_user = user
|
||||
eyeobj.eye_user = user
|
||||
eyeobj.name = "Camera Eye ([user.name])"
|
||||
user.remote_control = eyeobj
|
||||
user.reset_perspective(eyeobj)
|
||||
|
||||
/mob/camera/ai_eye/remote
|
||||
name = "Inactive Camera Eye"
|
||||
// Abductors dont trigger the Ai Detector
|
||||
ai_detector_visible = FALSE
|
||||
var/sprint = 10
|
||||
var/cooldown = 0
|
||||
var/acceleration = 1
|
||||
var/mob/living/carbon/human/eye_user = null
|
||||
var/obj/machinery/computer/camera_advanced/origin
|
||||
var/eye_initialized = 0
|
||||
var/visible_icon = 0
|
||||
var/image/user_image = null
|
||||
|
||||
/mob/camera/ai_eye/remote/Destroy()
|
||||
eye_user = null
|
||||
origin = null
|
||||
return ..()
|
||||
|
||||
/mob/camera/ai_eye/remote/RemoveImages()
|
||||
..()
|
||||
if(visible_icon)
|
||||
var/client/C = GetViewerClient()
|
||||
if(C)
|
||||
C.images -= user_image
|
||||
|
||||
/mob/camera/ai_eye/remote/GetViewerClient()
|
||||
if(eye_user)
|
||||
return eye_user.client
|
||||
return null
|
||||
|
||||
/mob/camera/ai_eye/remote/setLoc(T)
|
||||
if(eye_user)
|
||||
if(!isturf(eye_user.loc))
|
||||
return
|
||||
T = get_turf(T)
|
||||
var/old_loc = loc
|
||||
loc = T
|
||||
Moved(old_loc, get_dir(old_loc, loc))
|
||||
if(use_static)
|
||||
GLOB.cameranet.visibility(src, GetViewerClient())
|
||||
if(visible_icon)
|
||||
if(eye_user.client)
|
||||
eye_user.client.images -= user_image
|
||||
user_image = image(icon,loc,icon_state,FLY_LAYER)
|
||||
eye_user.client.images += user_image
|
||||
|
||||
/mob/camera/ai_eye/remote/relaymove(mob/user,direct)
|
||||
var/initial = initial(sprint)
|
||||
var/max_sprint = 50
|
||||
|
||||
if(cooldown && cooldown < world.timeofday) // 3 seconds
|
||||
sprint = initial
|
||||
|
||||
for(var/i = 0; i < max(sprint, initial); i += 20)
|
||||
var/turf/step = get_turf(get_step(src, direct))
|
||||
if(step)
|
||||
src.setLoc(step)
|
||||
|
||||
cooldown = world.timeofday + 5
|
||||
if(acceleration)
|
||||
sprint = min(sprint + 0.5, max_sprint)
|
||||
else
|
||||
sprint = initial
|
||||
|
||||
/datum/action/innate/camera_off
|
||||
name = "End Camera View"
|
||||
@@ -173,7 +86,7 @@
|
||||
if(!target || !iscarbon(target))
|
||||
return
|
||||
var/mob/living/carbon/C = target
|
||||
var/mob/camera/ai_eye/remote/remote_eye = C.remote_control
|
||||
var/mob/camera/eye/remote_eye = C.remote_control
|
||||
var/obj/machinery/computer/camera_advanced/console = remote_eye.origin
|
||||
console.remove_eye_control(target)
|
||||
|
||||
@@ -185,7 +98,7 @@
|
||||
if(!target || !iscarbon(target))
|
||||
return
|
||||
var/mob/living/carbon/C = target
|
||||
var/mob/camera/ai_eye/remote/remote_eye = C.remote_control
|
||||
var/mob/camera/eye/remote_eye = C.remote_control
|
||||
var/obj/machinery/computer/camera_advanced/origin = remote_eye.origin
|
||||
|
||||
var/list/L = list()
|
||||
@@ -209,7 +122,7 @@
|
||||
playsound(origin, "terminal_type", 25, 0)
|
||||
if(final)
|
||||
playsound(origin, 'sound/machines/terminal_prompt_confirm.ogg', 25, FALSE)
|
||||
remote_eye.setLoc(get_turf(final))
|
||||
remote_eye.set_loc(get_turf(final))
|
||||
C.overlay_fullscreen("flash", /atom/movable/screen/fullscreen/stretch/flash/noise)
|
||||
C.clear_fullscreen("flash", 3) //Shorter flash than normal since it's an ~~advanced~~ console!
|
||||
else
|
||||
|
||||
@@ -173,7 +173,7 @@
|
||||
ui_interact(user)
|
||||
|
||||
/obj/machinery/computer/security/attack_ai(mob/user)
|
||||
if(isAI(user))
|
||||
if(is_ai(user))
|
||||
to_chat(user, "<span class='notice'>You realise it's kind of stupid to access a camera console when you have the entire camera network at your metaphorical fingertips.</span>")
|
||||
return
|
||||
|
||||
|
||||
@@ -134,7 +134,7 @@
|
||||
setMenuState(ui.user, COMM_SCREEN_MAIN)
|
||||
|
||||
if("newalertlevel")
|
||||
if(isAI(ui.user) || isrobot(ui.user))
|
||||
if(is_ai(ui.user) || isrobot(ui.user))
|
||||
to_chat(ui.user, "<span class='warning'>Firewalls prevent you from changing the alert level.</span>")
|
||||
return
|
||||
else if(ADMIN_CHECK(ui.user))
|
||||
@@ -184,7 +184,7 @@
|
||||
setMenuState(ui.user, COMM_SCREEN_MAIN)
|
||||
|
||||
if("cancelshuttle")
|
||||
if(isAI(ui.user) || isrobot(ui.user))
|
||||
if(is_ai(ui.user) || isrobot(ui.user))
|
||||
to_chat(ui.user, "<span class='warning'>Firewalls prevent you from recalling the shuttle.</span>")
|
||||
return
|
||||
var/response = tgui_alert(usr, "Are you sure you wish to recall the shuttle?", "Confirm", list("Yes", "No"))
|
||||
@@ -418,7 +418,7 @@
|
||||
|
||||
/obj/machinery/computer/communications/ui_data(mob/user)
|
||||
var/list/data = list()
|
||||
data["is_ai"] = isAI(user) || isrobot(user)
|
||||
data["is_ai"] = is_ai(user) || isrobot(user)
|
||||
data["noauthbutton"] = !ishuman(user)
|
||||
data["menu_state"] = data["is_ai"] ? ai_menu_state : menu_state
|
||||
data["emagged"] = emagged
|
||||
@@ -515,19 +515,19 @@
|
||||
return data
|
||||
|
||||
/obj/machinery/computer/communications/proc/setCurrentMessage(mob/user, value)
|
||||
if(isAI(user) || isrobot(user))
|
||||
if(is_ai(user) || isrobot(user))
|
||||
aicurrmsg = value
|
||||
else
|
||||
currmsg = value
|
||||
|
||||
/obj/machinery/computer/communications/proc/getCurrentMessage(mob/user)
|
||||
if(isAI(user) || isrobot(user))
|
||||
if(is_ai(user) || isrobot(user))
|
||||
return aicurrmsg
|
||||
else
|
||||
return currmsg
|
||||
|
||||
/obj/machinery/computer/communications/proc/setMenuState(mob/user, value)
|
||||
if(isAI(user) || isrobot(user))
|
||||
if(is_ai(user) || isrobot(user))
|
||||
ai_menu_state=value
|
||||
else
|
||||
menu_state=value
|
||||
|
||||
@@ -129,7 +129,7 @@
|
||||
else
|
||||
for(var/n = ++i; n <= optioncount; n++)
|
||||
dat += "<dd><font color='blue'>	[n]. ---------------</font><br></dd>"
|
||||
if((isAI(user) || isrobot(user)) && (user.mind.special_role && user.mind.is_original_mob(user)))
|
||||
if((is_ai(user) || isrobot(user)) && (user.mind.special_role && user.mind.is_original_mob(user)))
|
||||
//Malf/Traitor AIs can bruteforce into the system to gain the Key.
|
||||
dat += "<dd><A href='byond://?src=[UID()];hack=1'><i><font color='Red'>*&@#. Bruteforce Key</font></i></font></a><br></dd>"
|
||||
else
|
||||
@@ -159,7 +159,7 @@
|
||||
dat += "</table>"
|
||||
//Hacking screen.
|
||||
if(2)
|
||||
if(isAI(user) || isrobot(user))
|
||||
if(is_ai(user) || isrobot(user))
|
||||
dat += "Brute-forcing for server key.<br> It will take 20 seconds for every character that the password has."
|
||||
dat += "In the meantime, this console can reveal your true intentions if you let someone access it. Make sure no humans enter the room during that time."
|
||||
else
|
||||
@@ -349,7 +349,7 @@
|
||||
|
||||
//Hack the Console to get the password
|
||||
if(href_list["hack"])
|
||||
if((isAI(usr) || isrobot(usr)) && (usr.mind.special_role && usr.mind.is_original_mob(usr)))
|
||||
if((is_ai(usr) || isrobot(usr)) && (usr.mind.special_role && usr.mind.is_original_mob(usr)))
|
||||
src.hacking = 1
|
||||
src.screen = 2
|
||||
src.icon_screen = hack_icon
|
||||
|
||||
@@ -66,7 +66,7 @@
|
||||
return FALSE
|
||||
if(!console_shows(R))
|
||||
return FALSE
|
||||
if(isAI(user))
|
||||
if(is_ai(user))
|
||||
if(R.connected_ai != user)
|
||||
if(telluserwhy)
|
||||
to_chat(user, "<span class='warning'>AIs can only control cyborgs which are linked to them.</span>")
|
||||
@@ -107,7 +107,7 @@
|
||||
return FALSE
|
||||
if(user.can_admin_interact())
|
||||
return TRUE
|
||||
if(!isAI(user))
|
||||
if(!is_ai(user))
|
||||
return FALSE
|
||||
return (user.mind.special_role && user.mind.is_original_mob(user))
|
||||
|
||||
|
||||
@@ -95,7 +95,7 @@
|
||||
if(!anchored)
|
||||
to_chat(user,"<span class='warning'>This device must be anchored by a wrench!</span>")
|
||||
return
|
||||
if(!Adjacent(user) && !isAI(user))
|
||||
if(!Adjacent(user) && !is_ai(user))
|
||||
return
|
||||
user.set_machine(src)
|
||||
var/list/dat = list()
|
||||
|
||||
@@ -466,7 +466,7 @@
|
||||
|
||||
/obj/machinery/door/proc/update_freelook_sight()
|
||||
if(!glass && GLOB.cameranet)
|
||||
GLOB.cameranet.updateVisibility(src, 0)
|
||||
GLOB.cameranet.update_visibility(src, 0)
|
||||
|
||||
/obj/machinery/door/proc/check_unres() //unrestricted sides. This overlay indicates which directions the player can access even without an ID
|
||||
if(hasPower() && unres_sides)
|
||||
|
||||
@@ -92,6 +92,7 @@ GLOBAL_LIST_EMPTY(holopads)
|
||||
var/ringing = FALSE
|
||||
/// Whether or not the user is currently selecting where to send their call.
|
||||
var/dialling_input = FALSE
|
||||
var/mob/camera/eye/hologram/eye
|
||||
|
||||
/obj/machinery/hologram/holopad/Initialize(mapload)
|
||||
. = ..()
|
||||
@@ -190,7 +191,7 @@ GLOBAL_LIST_EMPTY(holopads)
|
||||
/obj/machinery/hologram/holopad/AltClick(mob/living/carbon/human/user)
|
||||
if(..())
|
||||
return
|
||||
if(isAI(user))
|
||||
if(is_ai(user))
|
||||
hangup_all_calls()
|
||||
return
|
||||
|
||||
@@ -240,7 +241,7 @@ GLOBAL_LIST_EMPTY(holopads)
|
||||
popup.open()
|
||||
|
||||
/obj/machinery/hologram/holopad/Topic(href, href_list)
|
||||
if(..() || isAI(usr))
|
||||
if(..() || is_ai(usr))
|
||||
return
|
||||
add_fingerprint(usr)
|
||||
if(stat & NOPOWER)
|
||||
@@ -319,7 +320,7 @@ GLOBAL_LIST_EMPTY(holopads)
|
||||
I don't need to check for client since they're clicking on an object.
|
||||
This may change in the future but for now will suffice.*/
|
||||
else if(ai.eyeobj.loc != loc)//Set client eye on the object if it's not already.
|
||||
ai.eyeobj.setLoc(get_turf(src))
|
||||
ai.eyeobj.set_loc(get_turf(src))
|
||||
else if(!LAZYLEN(masters) || !masters[ai])//If there is no hologram, possibly make one.
|
||||
activate_holo(ai, 1)
|
||||
else//If there is a hologram, remove it.
|
||||
@@ -358,7 +359,7 @@ GLOBAL_LIST_EMPTY(holopads)
|
||||
|
||||
//Try to transfer hologram to another pad that can project on T
|
||||
/obj/machinery/hologram/holopad/proc/transfer_to_nearby_pad(turf/T, mob/holo_owner)
|
||||
if(!isAI(holo_owner))
|
||||
if(!is_ai(holo_owner))
|
||||
return
|
||||
for(var/pad in GLOB.holopads)
|
||||
var/obj/machinery/hologram/holopad/another = pad
|
||||
@@ -375,7 +376,7 @@ GLOBAL_LIST_EMPTY(holopads)
|
||||
if(QDELETED(user) || user.incapacitated() || !user.client)
|
||||
return FALSE
|
||||
|
||||
if(isAI(user))
|
||||
if(is_ai(user))
|
||||
var/mob/living/silicon/ai/AI = user
|
||||
if(!AI.current)
|
||||
return FALSE
|
||||
@@ -383,8 +384,8 @@ GLOBAL_LIST_EMPTY(holopads)
|
||||
|
||||
//Can we display holos there
|
||||
//Area check instead of line of sight check because this is a called a lot if AI wants to move around.
|
||||
/obj/machinery/hologram/holopad/proc/validate_location(turf/T,check_los = FALSE)
|
||||
if(T.z == z && get_dist(T, src) <= holo_range && T.loc == get_area(src))
|
||||
/obj/machinery/hologram/holopad/proc/validate_location(turf/T)
|
||||
if(T.z == z && (get_dist(T, src) <= holo_range) && T.loc == get_area(src))
|
||||
return TRUE
|
||||
return FALSE
|
||||
|
||||
@@ -418,7 +419,7 @@ GLOBAL_LIST_EMPTY(holopads)
|
||||
return
|
||||
|
||||
var/obj/effect/overlay/holo_pad_hologram/hologram = new(loc)//Spawn a blank effect at the location.
|
||||
if(isAI(user))
|
||||
if(is_ai(user))
|
||||
hologram.icon = AI.holo_icon
|
||||
else //make it like real life
|
||||
if(isrobot(user))
|
||||
@@ -438,6 +439,7 @@ GLOBAL_LIST_EMPTY(holopads)
|
||||
hologram.set_light(2) //hologram lighting
|
||||
move_hologram()
|
||||
|
||||
eye = new /mob/camera/eye/hologram(src, user.name, src, user)
|
||||
set_holo(user, hologram)
|
||||
|
||||
if(!masters[user])//If there is not already a hologram.
|
||||
@@ -490,6 +492,8 @@ For the other part of the code, check silicon say.dm. Particularly robot talk.*/
|
||||
|
||||
|
||||
/obj/machinery/hologram/holopad/proc/set_holo(mob/living/user, obj/effect/overlay/holo_pad_hologram/h)
|
||||
eye = user.remote_control
|
||||
eye.holopad = src
|
||||
masters[user] = h
|
||||
holorays[user] = new /obj/effect/overlay/holoray(loc)
|
||||
var/mob/living/silicon/ai/AI = user
|
||||
@@ -501,10 +505,13 @@ For the other part of the code, check silicon say.dm. Particularly robot talk.*/
|
||||
|
||||
/obj/machinery/hologram/holopad/proc/clear_holo(mob/living/user)
|
||||
qdel(masters[user]) // Get rid of user's hologram
|
||||
if(!QDELETED(eye))
|
||||
QDEL_NULL(eye)
|
||||
unset_holo(user)
|
||||
return TRUE
|
||||
|
||||
/obj/machinery/hologram/holopad/proc/unset_holo(mob/living/user)
|
||||
eye = null
|
||||
var/mob/living/silicon/ai/AI = user
|
||||
if(istype(AI) && AI.current == src)
|
||||
AI.current = null
|
||||
|
||||
@@ -165,7 +165,7 @@
|
||||
step_towards(M, center)
|
||||
|
||||
for(var/mob/living/silicon/S in orange(magnetic_field, center))
|
||||
if(isAI(S)) continue
|
||||
if(is_ai(S)) continue
|
||||
step_towards(S, center)
|
||||
|
||||
use_power(electricity_level * 5)
|
||||
|
||||
@@ -102,7 +102,7 @@
|
||||
QDEL_IN(decal, 25)
|
||||
|
||||
/obj/machinery/poolcontroller/proc/handleTemp(mob/M)
|
||||
if(!M || isAIEye(M) || issilicon(M) || isobserver(M) || M.stat == DEAD)
|
||||
if(!M || is_ai_eye(M) || issilicon(M) || isobserver(M) || M.stat == DEAD)
|
||||
return
|
||||
M.water_act(100, temperature, src)//leave temp at 0, we handle it in the switch. oh wait
|
||||
switch(temperature) //Apply different effects based on what the temperature is set to.
|
||||
|
||||
@@ -189,7 +189,7 @@ GLOBAL_LIST_EMPTY(turret_icons)
|
||||
/obj/machinery/porta_turret/proc/isLocked(mob/user)
|
||||
if(HasController())
|
||||
return TRUE
|
||||
if(isrobot(user) || isAI(user))
|
||||
if(isrobot(user) || is_ai(user))
|
||||
if(ailock)
|
||||
to_chat(user, "<span class='notice'>There seems to be a firewall preventing you from accessing this device.</span>")
|
||||
return TRUE
|
||||
|
||||
@@ -147,7 +147,7 @@
|
||||
return TRUE
|
||||
|
||||
/obj/machinery/quantumpad/attack_hand(mob/user)
|
||||
if(isAI(user))
|
||||
if(is_ai(user))
|
||||
return
|
||||
if(!check_usable(user))
|
||||
return
|
||||
@@ -161,13 +161,13 @@
|
||||
if(!istype(AI))
|
||||
return
|
||||
if(AI.eyeobj.loc != loc)
|
||||
AI.eyeobj.setLoc(get_turf(loc))
|
||||
AI.eyeobj.set_loc(get_turf(loc))
|
||||
return
|
||||
if(!check_usable(user))
|
||||
return
|
||||
var/turf/T = get_turf(linked_pad)
|
||||
if(GLOB.cameranet && GLOB.cameranet.checkTurfVis(T))
|
||||
AI.eyeobj.setLoc(T)
|
||||
if(GLOB.cameranet && GLOB.cameranet.check_turf_vis(T))
|
||||
AI.eyeobj.set_loc(T)
|
||||
else
|
||||
to_chat(user, "<span class='warning'>Linked pad is not on or near any active cameras on the station.</span>")
|
||||
|
||||
|
||||
@@ -334,8 +334,8 @@
|
||||
Prevents AI from using the teleporter, prints out failure messages for clarity
|
||||
*/
|
||||
/obj/machinery/teleport/proc/blockAI(atom/A)
|
||||
if(isAI(A) || istype(A, /obj/structure/ai_core))
|
||||
if(isAI(A))
|
||||
if(is_ai(A) || istype(A, /obj/structure/ai_core))
|
||||
if(is_ai(A))
|
||||
var/mob/living/silicon/ai/T = A
|
||||
if(T.allow_teleporter)
|
||||
return FALSE
|
||||
|
||||
@@ -88,7 +88,7 @@
|
||||
update_icon(UPDATE_ICON_STATE)
|
||||
|
||||
/obj/machinery/turretid/proc/isLocked(mob/user)
|
||||
if(isrobot(user) || isAI(user))
|
||||
if(isrobot(user) || is_ai(user))
|
||||
if(ailock)
|
||||
to_chat(user, "<span class='notice'>There seems to be a firewall preventing you from accessing this device.</span>")
|
||||
return TRUE
|
||||
|
||||
@@ -660,7 +660,7 @@
|
||||
occupant.SetSleeping(destruction_sleep_duration)
|
||||
go_out()
|
||||
for(var/mob/M in src) //Let's just be ultra sure
|
||||
if(isAI(M))
|
||||
if(is_ai(M))
|
||||
var/mob/living/silicon/ai/AI = M //AIs are loaded into the mech computer itself. When the mech dies, so does the AI. They can be recovered with an AI card from the wreck.
|
||||
AI.gib() //No wreck, no AI to recover
|
||||
else
|
||||
@@ -949,7 +949,7 @@
|
||||
/////////////////////////////////////
|
||||
|
||||
/obj/mecha/attack_ai(mob/living/silicon/ai/user)
|
||||
if(!isAI(user))
|
||||
if(!is_ai(user))
|
||||
return
|
||||
//Allows the Malf to scan a mech's status and loadout, helping it to decide if it is a worthy chariot.
|
||||
if(user.can_dominate_mechs)
|
||||
@@ -987,7 +987,7 @@
|
||||
to_chat(user, "<span class='warning'>[name] must have maintenance protocols active in order to allow a transfer.</span>")
|
||||
return
|
||||
AI = occupant
|
||||
if(!AI || !isAI(occupant)) //Mech does not have an AI for a pilot
|
||||
if(!AI || !is_ai(occupant)) //Mech does not have an AI for a pilot
|
||||
to_chat(user, "<span class='warning'>No AI detected in the [name] onboard computer.</span>")
|
||||
return
|
||||
if(AI.mind.special_role) //Malf AIs cannot leave mechs. Except through death.
|
||||
@@ -1042,6 +1042,7 @@
|
||||
AI.cancel_camera()
|
||||
AI.controlled_mech = src
|
||||
AI.remote_control = src
|
||||
AI.reset_perspective(src)
|
||||
AI.can_shunt = FALSE //ONE AI ENTERS. NO AI LEAVES.
|
||||
to_chat(AI, "[AI.can_dominate_mechs ? "<span class='boldnotice'>Takeover of [name] complete! You are now permanently loaded onto the onboard computer. Do not attempt to leave the station sector!</span>" \
|
||||
: "<span class='notice'>You have been uploaded to a mech's onboard computer."]")
|
||||
@@ -1273,7 +1274,7 @@
|
||||
/obj/mecha/Exited(atom/movable/M, direction)
|
||||
var/new_loc = get_step(M, direction)
|
||||
if(occupant && occupant == M) // The occupant exited the mech without calling go_out()
|
||||
if(!isAI(occupant)) //This causes carded AIS to gib, so we do not want this to be called during carding.
|
||||
if(!is_ai(occupant)) //This causes carded AIS to gib, so we do not want this to be called during carding.
|
||||
go_out(1, new_loc)
|
||||
|
||||
/obj/mecha/proc/go_out(forced, atom/newloc = loc)
|
||||
@@ -1292,7 +1293,7 @@
|
||||
var/mob/living/brain/brain = occupant
|
||||
RemoveActions(brain)
|
||||
mob_container = brain.container
|
||||
else if(isAI(occupant))
|
||||
else if(is_ai(occupant))
|
||||
var/mob/living/silicon/ai/AI = occupant
|
||||
if(forced)//This should only happen if there are multiple AIs in a round, and at least one is Malf.
|
||||
RemoveActions(occupant)
|
||||
@@ -1306,7 +1307,11 @@
|
||||
return
|
||||
to_chat(AI, "<span class='notice'>Returning to core...</span>")
|
||||
AI.controlled_mech = null
|
||||
AI.remote_control = null
|
||||
if(istype(AI.eyeobj))
|
||||
AI.remote_control = AI.eyeobj
|
||||
AI.reset_perspective(AI.eyeobj)
|
||||
else
|
||||
AI.eyeobj = new /mob/camera/eye/ai(loc, AI.name, AI, AI)
|
||||
RemoveActions(occupant, 1)
|
||||
mob_container = AI
|
||||
newloc = get_turf(AI.linked_core)
|
||||
@@ -1581,7 +1586,7 @@
|
||||
/obj/mecha/obj_destruction()
|
||||
if(wreckage)
|
||||
var/mob/living/silicon/ai/AI
|
||||
if(isAI(occupant))
|
||||
if(is_ai(occupant))
|
||||
AI = occupant
|
||||
occupant = null
|
||||
var/obj/structure/mecha_wreckage/WR = new wreckage(loc, AI)
|
||||
|
||||
@@ -13,11 +13,11 @@ would spawn and follow the beaker, even if it is carried or thrown.
|
||||
/obj/effect/particle_effect/New()
|
||||
..()
|
||||
if(SSticker)
|
||||
GLOB.cameranet.updateVisibility(src)
|
||||
GLOB.cameranet.update_visibility(src)
|
||||
|
||||
/obj/effect/particle_effect/Destroy()
|
||||
if(SSticker)
|
||||
GLOB.cameranet.updateVisibility(src)
|
||||
GLOB.cameranet.update_visibility(src)
|
||||
return ..()
|
||||
|
||||
/datum/effect_system
|
||||
|
||||
@@ -71,7 +71,7 @@
|
||||
var/mob/living/carbon/human/H = loc
|
||||
if(H.l_ear == src || H.r_ear == src)
|
||||
return ..()
|
||||
else if(isanimal(loc) || isAI(loc))
|
||||
else if(isanimal(loc) || is_ai(loc))
|
||||
return ..()
|
||||
|
||||
return FALSE
|
||||
|
||||
@@ -411,7 +411,7 @@ GLOBAL_LIST_EMPTY(deadsay_radio_systems)
|
||||
jobname = "No id"
|
||||
|
||||
// --- AI ---
|
||||
else if(isAI(M))
|
||||
else if(is_ai(M))
|
||||
jobname = "AI"
|
||||
|
||||
// --- Cyborg ---
|
||||
|
||||
@@ -497,7 +497,7 @@ SLIME SCANNER
|
||||
scan_type = "robot"
|
||||
else if(ishuman(M))
|
||||
scan_type = "prosthetics"
|
||||
else if(isAI(M))
|
||||
else if(is_ai(M))
|
||||
scan_type = "ai"
|
||||
else
|
||||
to_chat(user, "<span class='warning'>You can't analyze non-robotic things!</span>")
|
||||
|
||||
@@ -94,15 +94,15 @@
|
||||
/obj/item/multitool/ai_detect/proc/multitool_detect()
|
||||
var/turf/our_turf = get_turf(src)
|
||||
for(var/mob/living/silicon/ai/AI in GLOB.ai_list)
|
||||
if(AI.cameraFollow == src)
|
||||
if(AI.camera_follow == src)
|
||||
detect_state = PROXIMITY_ON_SCREEN
|
||||
break
|
||||
|
||||
if(!detect_state && GLOB.cameranet.chunkGenerated(our_turf.x, our_turf.y, our_turf.z))
|
||||
var/datum/camerachunk/chunk = GLOB.cameranet.getCameraChunk(our_turf.x, our_turf.y, our_turf.z)
|
||||
if(!detect_state && GLOB.cameranet.chunk_generated(our_turf.x, our_turf.y, our_turf.z))
|
||||
var/datum/camerachunk/chunk = GLOB.cameranet.get_camera_chunk(our_turf.x, our_turf.y, our_turf.z)
|
||||
if(chunk)
|
||||
if(length(chunk.seenby))
|
||||
for(var/mob/camera/ai_eye/A in chunk.seenby)
|
||||
for(var/mob/camera/eye/ai/A in chunk.seenby)
|
||||
//Checks if the A is to be detected or not
|
||||
if(!A.ai_detector_visible)
|
||||
continue
|
||||
|
||||
@@ -515,7 +515,7 @@
|
||||
..()
|
||||
playsound(src, 'sound/effects/meteorimpact.ogg', 40, 1)
|
||||
for(var/mob/M in range(10, src))
|
||||
if(!M.stat && !isAI(M))\
|
||||
if(!M.stat && !is_ai(M))\
|
||||
shake_camera(M, 3, 1)
|
||||
qdel(src)
|
||||
|
||||
@@ -1378,7 +1378,7 @@
|
||||
playsound(src, 'sound/effects/explosionfar.ogg', 50, FALSE, 0)
|
||||
flick("bigred_press", src)
|
||||
for(var/mob/M in range(10, src)) // Checks range
|
||||
if(!M.stat && !isAI(M)) // Checks to make sure whoever's getting shaken is alive/not the AI
|
||||
if(!M.stat && !is_ai(M)) // Checks to make sure whoever's getting shaken is alive/not the AI
|
||||
sleep(8) // Short delay to match up with the explosion sound
|
||||
shake_camera(M, 2, 1) // Shakes player camera 2 squares for 1 second.
|
||||
|
||||
|
||||
@@ -113,7 +113,7 @@
|
||||
if(M.client && M.machine == src)
|
||||
is_in_use = TRUE
|
||||
src.attack_hand(M)
|
||||
if(isAI(usr) || isrobot(usr))
|
||||
if(is_ai(usr) || isrobot(usr))
|
||||
if(!(usr in nearby))
|
||||
if(usr.client && usr.machine==src) // && M.machine == src is omitted because if we triggered this by using the dialog, it doesn't matter if our machine changed in between triggering it and this - the dialog is probably still supposed to refresh.
|
||||
is_in_use = TRUE
|
||||
|
||||
@@ -22,7 +22,7 @@
|
||||
if(smoothing_flags & SMOOTH_CORNERS)
|
||||
icon_state = ""
|
||||
if(SSticker)
|
||||
GLOB.cameranet.updateVisibility(src)
|
||||
GLOB.cameranet.update_visibility(src)
|
||||
|
||||
/obj/structure/Initialize(mapload)
|
||||
if(!armor)
|
||||
@@ -34,7 +34,7 @@
|
||||
/obj/structure/Destroy()
|
||||
climbers = null
|
||||
if(SSticker)
|
||||
GLOB.cameranet.updateVisibility(src)
|
||||
GLOB.cameranet.update_visibility(src)
|
||||
if(smoothing_flags & (SMOOTH_CORNERS|SMOOTH_BITMASK))
|
||||
var/turf/T = get_turf(src)
|
||||
QUEUE_SMOOTH_NEIGHBORS(T)
|
||||
|
||||
@@ -247,7 +247,7 @@
|
||||
continue
|
||||
if(M.buckled || M.anchored || M.has_buckled_mobs())
|
||||
continue
|
||||
if(isAI(M))
|
||||
if(is_ai(M))
|
||||
continue
|
||||
|
||||
M.forceMove(src)
|
||||
|
||||
@@ -107,7 +107,7 @@
|
||||
var/is_operating = FALSE
|
||||
|
||||
/obj/structure/inflatable/door/attack_ai(mob/user as mob) //those aren't machinery, they're just big fucking slabs of a mineral
|
||||
if(isAI(user)) //so the AI can't open it
|
||||
if(is_ai(user)) //so the AI can't open it
|
||||
return
|
||||
else if(isrobot(user)) //but cyborgs can
|
||||
if(get_dist(user,src) <= 1) //not remotely though
|
||||
|
||||
@@ -87,7 +87,7 @@
|
||||
deconstruct(TRUE)
|
||||
|
||||
/obj/structure/kitchenspike/MouseDrop_T(mob/living/victim, mob/living/user)
|
||||
if(!user.Adjacent(src) || !user.Adjacent(victim) || isAI(user) || !ismob(victim))
|
||||
if(!user.Adjacent(src) || !user.Adjacent(victim) || is_ai(user) || !ismob(victim))
|
||||
return
|
||||
if(isanimal(user) && victim != user)
|
||||
return // animals cannot put mobs other than themselves onto spikes
|
||||
|
||||
@@ -47,7 +47,7 @@
|
||||
return try_to_operate(user)
|
||||
|
||||
/obj/structure/mineral_door/attack_ai(mob/user) //those aren't machinery, they're just big fucking slabs of a mineral
|
||||
if(isAI(user)) //so the AI can't open it
|
||||
if(is_ai(user)) //so the AI can't open it
|
||||
return
|
||||
else if(isrobot(user) && Adjacent(user)) //but cyborgs can, but not remotely
|
||||
return try_to_operate(user)
|
||||
|
||||
@@ -118,7 +118,7 @@
|
||||
SET_BITFLAG_LIST(canSmoothWith)
|
||||
if(smoothing_flags & (SMOOTH_CORNERS|SMOOTH_BITMASK))
|
||||
QUEUE_SMOOTH(src)
|
||||
visibilityChanged()
|
||||
visibility_changed()
|
||||
|
||||
for(var/atom/movable/AM in src)
|
||||
Entered(AM)
|
||||
@@ -150,7 +150,7 @@
|
||||
qdel(A)
|
||||
return
|
||||
REMOVE_FROM_SMOOTH_QUEUE(src)
|
||||
visibilityChanged()
|
||||
visibility_changed()
|
||||
QDEL_LIST_CONTENTS(blueprint_data)
|
||||
initialized = FALSE
|
||||
bound_air = null
|
||||
@@ -480,9 +480,9 @@
|
||||
ChangeTurf(baseturf)
|
||||
return 2
|
||||
|
||||
/turf/proc/visibilityChanged()
|
||||
/turf/proc/visibility_changed()
|
||||
if(SSticker)
|
||||
GLOB.cameranet.updateVisibility(src)
|
||||
GLOB.cameranet.update_visibility(src)
|
||||
|
||||
/turf/attack_by(obj/item/attacking, mob/user, params)
|
||||
if(..())
|
||||
|
||||
@@ -177,10 +177,10 @@ GLOBAL_VAR_INIT(admin_ooc_colour, "#b82e00")
|
||||
|
||||
if(target.mob in heard)
|
||||
send = 1
|
||||
if(isAI(target.mob))
|
||||
if(is_ai(target.mob))
|
||||
prefix = " (Core)"
|
||||
|
||||
else if(isAI(target.mob)) // Special case
|
||||
else if(is_ai(target.mob)) // Special case
|
||||
var/mob/living/silicon/ai/A = target.mob
|
||||
if(A.eyeobj in hearers(7, source))
|
||||
send = 1
|
||||
|
||||
@@ -387,9 +387,9 @@ GLOBAL_LIST_INIT(view_runtimes_verbs, list(
|
||||
if(ishuman(mob))
|
||||
var/mob/living/carbon/human/H = mob
|
||||
H.regenerate_icons() // workaround for #13269
|
||||
if(isAI(mob)) // client.mob, built in byond client var
|
||||
if(is_ai(mob)) // client.mob, built in byond client var
|
||||
var/mob/living/silicon/ai/ai = mob
|
||||
ai.eyeobj.setLoc(old_turf)
|
||||
ai.eyeobj.set_loc(old_turf)
|
||||
else if(isnewplayer(mob))
|
||||
to_chat(src, "<font color='red'>Error: Aghost: Can't admin-ghost whilst in the lobby. Join or observe first.</font>")
|
||||
else
|
||||
|
||||
@@ -157,7 +157,7 @@ GLOBAL_VAR_INIT(disable_explosions, FALSE)
|
||||
"}
|
||||
|
||||
var/jumptoeye = ""
|
||||
if(isAI(M))
|
||||
if(is_ai(M))
|
||||
var/mob/living/silicon/ai/A = M
|
||||
if(A.client && A.eyeobj) // No point following clientless AI eyes
|
||||
jumptoeye = " <b>(<A href='byond://?_src_=holder;jumpto=[A.eyeobj.UID()]'>Eye</A>)</b>"
|
||||
@@ -199,7 +199,7 @@ GLOBAL_VAR_INIT(disable_explosions, FALSE)
|
||||
body += "<A href='byond://?_src_=holder;corgione=[M.UID()]'>Corgize</A> | "
|
||||
|
||||
//AI / Cyborg
|
||||
if(isAI(M))
|
||||
if(is_ai(M))
|
||||
body += "<B>Is an AI</B> "
|
||||
else if(ishuman(M))
|
||||
body += {"<A href='byond://?_src_=holder;makeai=[M.UID()]'>Make AI</A> |
|
||||
@@ -800,7 +800,7 @@ GLOBAL_VAR_INIT(disable_explosions, FALSE)
|
||||
if(istype(S, /mob/living/silicon/decoy) && !S.client)
|
||||
continue
|
||||
ai_number++
|
||||
if(isAI(S))
|
||||
if(is_ai(S))
|
||||
messages += "<b>AI [key_name(S, TRUE)]'s laws:</b>"
|
||||
else if(isrobot(S))
|
||||
var/mob/living/silicon/robot/R = S
|
||||
|
||||
@@ -255,7 +255,7 @@
|
||||
M_job = "Carbon-based"
|
||||
|
||||
else if(issilicon(M)) //silicon
|
||||
if(isAI(M))
|
||||
if(is_ai(M))
|
||||
M_job = "AI"
|
||||
else if(ispAI(M))
|
||||
M_job = "pAI"
|
||||
@@ -298,7 +298,7 @@
|
||||
M_key = replacetext(M_key, "\\", "")
|
||||
|
||||
var/M_eyeUID = ""
|
||||
if(isAI(M))
|
||||
if(is_ai(M))
|
||||
var/mob/living/silicon/ai/A = M
|
||||
if(A.client && A.eyeobj) // No point following clientless AI eyes
|
||||
M_eyeUID = "[A.eyeobj.UID()]"
|
||||
|
||||
@@ -1146,7 +1146,7 @@
|
||||
if(!ismob(M))
|
||||
to_chat(usr, "<span class='warning'>This can only be used on instances of type /mob</span>")
|
||||
return
|
||||
if(isAI(M))
|
||||
if(is_ai(M))
|
||||
to_chat(usr, "<span class='warning'>This cannot be used on instances of type /mob/living/silicon/ai</span>")
|
||||
return
|
||||
|
||||
@@ -1297,7 +1297,7 @@
|
||||
if(!ismob(M))
|
||||
to_chat(usr, "<span class='warning'>This can only be used on instances of type /mob</span>")
|
||||
return
|
||||
if(isAI(M))
|
||||
if(is_ai(M))
|
||||
to_chat(usr, "<span class='warning'>This cannot be used on instances of type /mob/living/silicon/ai</span>")
|
||||
return
|
||||
|
||||
@@ -1329,7 +1329,7 @@
|
||||
if(!ismob(M))
|
||||
to_chat(usr, "<span class='warning'>This can only be used on instances of type /mob</span>")
|
||||
return
|
||||
if(isAI(M))
|
||||
if(is_ai(M))
|
||||
to_chat(usr, "<span class='warning'>This cannot be used on instances of type /mob/living/silicon/ai</span>")
|
||||
return
|
||||
|
||||
@@ -1361,7 +1361,7 @@
|
||||
if(!ismob(M))
|
||||
to_chat(usr, "<span class='warning'>This can only be used on instances of type /mob</span>")
|
||||
return
|
||||
if(isAI(M))
|
||||
if(is_ai(M))
|
||||
to_chat(usr, "<span class='warning'>This cannot be used on instances of type /mob/living/silicon/ai</span>")
|
||||
return
|
||||
|
||||
@@ -1385,7 +1385,7 @@
|
||||
if(!ismob(M))
|
||||
to_chat(usr, "<span class='warning'>This can only be used on instances of type /mob</span>")
|
||||
return
|
||||
if(isAI(M))
|
||||
if(is_ai(M))
|
||||
to_chat(usr, "<span class='warning'>This cannot be used on instances of type /mob/living/silicon/ai</span>")
|
||||
return
|
||||
|
||||
@@ -1492,7 +1492,7 @@
|
||||
if(!ismob(M))
|
||||
to_chat(usr, "<span class='warning'>This can only be used on instances of type /mob</span>")
|
||||
return
|
||||
if(isAI(M))
|
||||
if(is_ai(M))
|
||||
to_chat(usr, "<span class='warning'>This cannot be used on instances of type /mob/living/silicon/ai</span>")
|
||||
return
|
||||
|
||||
@@ -2255,7 +2255,7 @@
|
||||
if(!href_list["cryoafk"] && !isLivingSSD(M))
|
||||
to_chat(usr, "<span class='warning'>This can only be used on living, SSD players.</span>")
|
||||
return
|
||||
if(isAI(M))
|
||||
if(is_ai(M))
|
||||
var/mob/living/silicon/ai/A = M
|
||||
A.cryo_AI()
|
||||
if(istype(M.loc, /obj/machinery/cryopod))
|
||||
@@ -3615,7 +3615,7 @@
|
||||
target = C.mob
|
||||
|
||||
. = ADMIN_FLW(target, "FLW")
|
||||
if(isAI(target)) // AI core/eye follow links
|
||||
if(is_ai(target)) // AI core/eye follow links
|
||||
var/mob/living/silicon/ai/A = target
|
||||
if(A.client && A.eyeobj) // No point following clientless AI eyes
|
||||
. += "|[ADMIN_FLW(A.eyeobj,"EYE")]"
|
||||
|
||||
@@ -23,7 +23,7 @@
|
||||
return
|
||||
|
||||
if(ismob(M))
|
||||
if(isAI(M))
|
||||
if(is_ai(M))
|
||||
alert("The AI can't be sent to prison you jerk!", null, null, null, null, null)
|
||||
return
|
||||
//strip their stuff before they teleport into a cell :downs:
|
||||
|
||||
@@ -44,7 +44,7 @@ RESTRICT_TYPE(/datum/antagonist/traitor)
|
||||
|
||||
/datum/antagonist/traitor/Destroy(force, ...)
|
||||
// Remove all associated malf AI abilities.
|
||||
if(isAI(owner.current))
|
||||
if(is_ai(owner.current))
|
||||
var/mob/living/silicon/ai/A = owner.current
|
||||
A.clear_zeroth_law()
|
||||
var/obj/item/radio/headset/heads/ai_integrated/radio = A.get_radio()
|
||||
@@ -84,7 +84,7 @@ RESTRICT_TYPE(/datum/antagonist/traitor)
|
||||
return ..()
|
||||
|
||||
/datum/antagonist/traitor/select_organization()
|
||||
if(isAI(owner.current))
|
||||
if(is_ai(owner.current))
|
||||
return
|
||||
var/chaos = pickweight(list(ORG_CHAOS_HUNTER = ORG_PROB_HUNTER, ORG_CHAOS_MILD = ORG_PROB_MILD, ORG_CHAOS_AVERAGE = ORG_PROB_AVERAGE, ORG_CHAOS_HIJACK = ORG_PROB_HIJACK))
|
||||
for(var/org_type in shuffle(subtypesof(/datum/antag_org/syndicate)))
|
||||
@@ -108,7 +108,7 @@ RESTRICT_TYPE(/datum/antagonist/traitor)
|
||||
return ..()
|
||||
|
||||
/datum/antagonist/traitor/give_objectives()
|
||||
if(isAI(owner.current))
|
||||
if(is_ai(owner.current))
|
||||
forge_ai_objectives()
|
||||
else
|
||||
forge_human_objectives()
|
||||
@@ -163,7 +163,7 @@ RESTRICT_TYPE(/datum/antagonist/traitor)
|
||||
antag_memory += "<b>Organization</b>: [organization.name]<br>"
|
||||
if(give_codewords)
|
||||
messages.Add(give_codewords())
|
||||
if(isAI(owner.current))
|
||||
if(is_ai(owner.current))
|
||||
add_law_zero()
|
||||
owner.current.playsound_local(get_turf(owner.current), 'sound/ambience/antag/malf.ogg', 100, FALSE, pressure_affected = FALSE, use_reverb = FALSE)
|
||||
var/mob/living/silicon/ai/A = owner.current
|
||||
@@ -211,7 +211,7 @@ RESTRICT_TYPE(/datum/antagonist/traitor)
|
||||
* Gives a traitor human their uplink, and uplink code.
|
||||
*/
|
||||
/datum/antagonist/traitor/proc/give_uplink()
|
||||
if(isAI(owner.current))
|
||||
if(is_ai(owner.current))
|
||||
return FALSE
|
||||
|
||||
var/mob/living/carbon/human/traitor_mob = owner.current
|
||||
|
||||
@@ -674,7 +674,7 @@ GLOBAL_LIST_INIT(aalarm_modes, list(
|
||||
return data
|
||||
|
||||
/obj/machinery/alarm/proc/has_rcon_access(mob/user)
|
||||
return user && (isAI(user) || allowed(user) || emagged || rcon_setting == RCON_YES)
|
||||
return user && (is_ai(user) || allowed(user) || emagged || rcon_setting == RCON_YES)
|
||||
|
||||
// Intentional nulls here
|
||||
/obj/machinery/alarm/ui_data(mob/user)
|
||||
@@ -796,7 +796,7 @@ GLOBAL_LIST_INIT(aalarm_modes, list(
|
||||
return thresholds
|
||||
|
||||
/obj/machinery/alarm/ui_state(mob/user)
|
||||
if(isAI(user))
|
||||
if(is_ai(user))
|
||||
var/mob/living/silicon/ai/AI = user
|
||||
if(!AI.lacks_power() || AI.apc_override)
|
||||
return GLOB.always_state
|
||||
@@ -821,7 +821,7 @@ GLOBAL_LIST_INIT(aalarm_modes, list(
|
||||
return TRUE
|
||||
if(user.can_admin_interact())
|
||||
return TRUE
|
||||
else if(isAI(user) || isrobot(user) || emagged || user.has_unlimited_silicon_privilege)
|
||||
else if(is_ai(user) || isrobot(user) || emagged || user.has_unlimited_silicon_privilege)
|
||||
return TRUE
|
||||
else
|
||||
return !locked
|
||||
@@ -830,7 +830,7 @@ GLOBAL_LIST_INIT(aalarm_modes, list(
|
||||
if(buildstage != 2)
|
||||
return UI_CLOSE
|
||||
|
||||
if(aidisabled && (isAI(user) || isrobot(user)))
|
||||
if(aidisabled && (is_ai(user) || isrobot(user)))
|
||||
to_chat(user, "<span class='warning'>AI control for \the [src] interface has been disabled.</span>")
|
||||
return UI_CLOSE
|
||||
|
||||
|
||||
@@ -61,7 +61,7 @@ GLOBAL_LIST_EMPTY(gas_meters)
|
||||
/obj/machinery/atmospherics/meter/examine(mob/user)
|
||||
. = ..()
|
||||
. += "<span class='notice'>Measures the volume and temperature of the pipe under the meter.</span>"
|
||||
if(get_dist(user, src) > 3 && !(isAI(user) || istype(user, /mob/dead)))
|
||||
if(get_dist(user, src) > 3 && !(is_ai(user) || istype(user, /mob/dead)))
|
||||
. += "<span class='boldnotice'>You are too far away to read it.</span>"
|
||||
|
||||
else if(stat & (NOPOWER|BROKEN))
|
||||
@@ -77,7 +77,7 @@ GLOBAL_LIST_EMPTY(gas_meters)
|
||||
. += "The connect error light is blinking."
|
||||
|
||||
/obj/machinery/atmospherics/meter/Click()
|
||||
if(isAI(usr)) // ghosts can call ..() for examine
|
||||
if(is_ai(usr)) // ghosts can call ..() for examine
|
||||
usr.examinate(src)
|
||||
return TRUE
|
||||
|
||||
|
||||
@@ -204,7 +204,7 @@
|
||||
if(!M.anchored && (M.flags & CONDUCT))
|
||||
step_towards(M,src)
|
||||
for(var/mob/living/silicon/S in orange(2,src))
|
||||
if(isAI(S)) continue
|
||||
if(is_ai(S)) continue
|
||||
step_towards(S,src)
|
||||
for(var/mob/living/carbon/human/machine/M in orange(2,src))
|
||||
step_towards(M,src)
|
||||
|
||||
@@ -73,7 +73,7 @@
|
||||
return
|
||||
if(prob(shake_chance))
|
||||
for(var/mob/M in range(10, src))
|
||||
if(!M.stat && !isAI(M))
|
||||
if(!M.stat && !is_ai(M))
|
||||
shake_camera(M, 3, 1)
|
||||
playsound(loc, 'sound/effects/meteorimpact.ogg', 40, 1)
|
||||
|
||||
|
||||
@@ -567,7 +567,7 @@
|
||||
return ..()
|
||||
|
||||
/obj/machinery/fishtank/attack_hand(mob/user)
|
||||
if(isAI(user))
|
||||
if(is_ai(user))
|
||||
return
|
||||
user.changeNext_move(CLICK_CD_MELEE)
|
||||
playsound(get_turf(src), 'sound/effects/glassknock.ogg', 80, TRUE)
|
||||
|
||||
@@ -0,0 +1,160 @@
|
||||
// CAMERA NET
|
||||
//
|
||||
// The datum containing all the chunks.
|
||||
GLOBAL_DATUM_INIT(cameranet, /datum/cameranet, new())
|
||||
|
||||
/datum/cameranet
|
||||
var/name = "Camera Net"
|
||||
|
||||
/// The cameras on the map, no matter if they work or not. Updated in obj/machinery/camera.dm by New() and Destroy().
|
||||
var/list/cameras = list()
|
||||
/// The chunks of the map, mapping the areas that the cameras can see.
|
||||
var/list/chunks = list()
|
||||
var/ready = FALSE
|
||||
|
||||
/// Returns the chunk at (x, y, z) if it exists, otherwise returns null.
|
||||
/datum/cameranet/proc/chunk_generated(x, y, z)
|
||||
x &= ~(CAMERA_CHUNK_SIZE - 1)
|
||||
y &= ~(CAMERA_CHUNK_SIZE - 1)
|
||||
var/key = "[x],[y],[z]"
|
||||
return (chunks[key])
|
||||
|
||||
/// Returns the chunk at (x, y, z) if it exists, otherwise returns a new chunk at that location.
|
||||
/datum/cameranet/proc/get_camera_chunk(x, y, z)
|
||||
x &= ~(CAMERA_CHUNK_SIZE - 1)
|
||||
y &= ~(CAMERA_CHUNK_SIZE - 1)
|
||||
var/key = "[x],[y],[z]"
|
||||
if(!chunks[key])
|
||||
chunks[key] = new /datum/camerachunk(null, x, y, z)
|
||||
|
||||
return chunks[key]
|
||||
|
||||
/// Updates what the camera network can see.
|
||||
/datum/cameranet/proc/visibility(list/moved_eyes, client/C)
|
||||
if(!islist(moved_eyes))
|
||||
moved_eyes = moved_eyes ? list(moved_eyes) : list()
|
||||
|
||||
var/list/chunks_pre_seen = list()
|
||||
var/list/chunks_post_seen = list()
|
||||
|
||||
for(var/V in moved_eyes)
|
||||
var/mob/camera/eye/eye = V
|
||||
if(C)
|
||||
chunks_pre_seen |= eye.visible_camera_chunks
|
||||
// 0xf = 15
|
||||
var/static_range = eye.static_visibility_range
|
||||
var/x1 = max(0, eye.x - static_range) & ~(CAMERA_CHUNK_SIZE - 1)
|
||||
var/y1 = max(0, eye.y - static_range) & ~(CAMERA_CHUNK_SIZE - 1)
|
||||
var/x2 = min(world.maxx, eye.x + static_range) & ~(CAMERA_CHUNK_SIZE - 1)
|
||||
var/y2 = min(world.maxy, eye.y + static_range) & ~(CAMERA_CHUNK_SIZE - 1)
|
||||
|
||||
var/list/visible_chunks = list()
|
||||
|
||||
for(var/x = x1; x <= x2; x += CAMERA_CHUNK_SIZE)
|
||||
for(var/y = y1; y <= y2; y += CAMERA_CHUNK_SIZE)
|
||||
visible_chunks |= get_camera_chunk(x, y, eye.z)
|
||||
|
||||
var/list/remove = eye.visible_camera_chunks - visible_chunks
|
||||
var/list/add = visible_chunks - eye.visible_camera_chunks
|
||||
|
||||
for(var/chunk in remove)
|
||||
var/datum/camerachunk/c = chunk
|
||||
c.remove(eye, FALSE)
|
||||
|
||||
for(var/chunk in add)
|
||||
var/datum/camerachunk/c = chunk
|
||||
c.add(eye, FALSE)
|
||||
|
||||
if(C)
|
||||
chunks_post_seen |= eye.visible_camera_chunks
|
||||
|
||||
if(C)
|
||||
var/list/remove = chunks_pre_seen - chunks_post_seen
|
||||
var/list/add = chunks_post_seen - chunks_pre_seen
|
||||
|
||||
for(var/chunk in remove)
|
||||
var/datum/camerachunk/c = chunk
|
||||
C.images -= c.obscured
|
||||
|
||||
for(var/chunk in add)
|
||||
var/datum/camerachunk/c = chunk
|
||||
C.images += c.obscured
|
||||
|
||||
|
||||
/// Updates the chunks that the turf is located in. Use this when obstacles are destroyed or when doors open.
|
||||
/datum/cameranet/proc/update_visibility(atom/A, opacity_check = 1)
|
||||
if(!SSticker || (opacity_check && !A.opacity))
|
||||
return
|
||||
major_chunk_change(update = A)
|
||||
|
||||
/// Removes a camera from a chunk.
|
||||
/datum/cameranet/proc/remove_camera(obj/machinery/camera/c)
|
||||
major_chunk_change(remove = c)
|
||||
|
||||
/// Add a camera to a chunk.
|
||||
/datum/cameranet/proc/add_camera(obj/machinery/camera/c)
|
||||
major_chunk_change(add = c)
|
||||
|
||||
/// Refreshes the chunk location of a portable camera. Used by Cyborgs.
|
||||
/datum/cameranet/proc/update_portable_camera(obj/machinery/camera/c, turf/old_loc)
|
||||
major_chunk_change(add = c, old_loc = old_loc)
|
||||
|
||||
/// Private method for updating the chunk an atom is in, and all surrounding chunks.
|
||||
/// `add` will be added as a camera to the chunk of its current location and all surrounding chunks.
|
||||
/// `remove` will be removed as a camera from the chunk of its current location and all surrounding chunks.
|
||||
/// `update` will not be added or removed as a camera, but its surrounding chunks will be updated.
|
||||
/// These parameters are mutually exclusive.
|
||||
/datum/cameranet/proc/major_chunk_change(atom/add = null, atom/remove = null, atom/update = null, turf/old_loc = null)
|
||||
// 0xf = 15
|
||||
if(!add && !remove && !update)
|
||||
return
|
||||
if(add && remove)
|
||||
CRASH("Adding and removing a camera to the cameranet simultaneously is not implemented")
|
||||
|
||||
var/atom/c = remove
|
||||
if(!c)
|
||||
c = add
|
||||
if(!c)
|
||||
c = update
|
||||
|
||||
var/turf/T = get_turf(c)
|
||||
if(!T)
|
||||
return
|
||||
|
||||
// Check if the turf to add falls in the same chunk as the old_loc. If so, do nothing
|
||||
if(old_loc)
|
||||
if(T.x & ~(CAMERA_CHUNK_SIZE - 1) == old_loc.x & ~(CAMERA_CHUNK_SIZE - 1) && T.y & ~(CAMERA_CHUNK_SIZE - 1) == old_loc.y & ~(CAMERA_CHUNK_SIZE - 1))
|
||||
return
|
||||
|
||||
// Use camera view distance here to actually know how far a camera can max watch
|
||||
var/x1 = max(0, T.x - CAMERA_VIEW_DISTANCE) & ~(CAMERA_CHUNK_SIZE - 1)
|
||||
var/y1 = max(0, T.y - CAMERA_VIEW_DISTANCE) & ~(CAMERA_CHUNK_SIZE - 1)
|
||||
var/x2 = min(world.maxx, T.x + CAMERA_VIEW_DISTANCE) & ~(CAMERA_CHUNK_SIZE - 1)
|
||||
var/y2 = min(world.maxy, T.y + CAMERA_VIEW_DISTANCE) & ~(CAMERA_CHUNK_SIZE - 1)
|
||||
|
||||
for(var/x = x1; x <= x2; x += CAMERA_CHUNK_SIZE)
|
||||
for(var/y = y1; y <= y2; y += CAMERA_CHUNK_SIZE)
|
||||
if(chunk_generated(x, y, T.z))
|
||||
var/datum/camerachunk/chunk = get_camera_chunk(x, y, T.z)
|
||||
if(remove)
|
||||
// Remove the camera.
|
||||
chunk.remove_camera(c)
|
||||
else if(add)
|
||||
// You can't have the same camera in the list twice.
|
||||
chunk.add_camera(c)
|
||||
chunk.has_changed()
|
||||
|
||||
/// Returns 1 if a mob is on a viewable turf, otherwise returns 0.
|
||||
/datum/cameranet/proc/check_camera_vis(mob/living/target as mob)
|
||||
// 0xf = 15
|
||||
var/turf/position = get_turf(target)
|
||||
return check_turf_vis(position)
|
||||
|
||||
/datum/cameranet/proc/check_turf_vis(turf/position)
|
||||
var/datum/camerachunk/chunk = get_camera_chunk(position.x, position.y, position.z)
|
||||
if(chunk)
|
||||
if(chunk.changed)
|
||||
chunk.has_changed(1) // Update now, no matter if it's visible or not.
|
||||
if(chunk.visible_turfs[position])
|
||||
return 1
|
||||
return 0
|
||||
+41
-43
@@ -1,11 +1,8 @@
|
||||
// CAMERA CHUNK
|
||||
//
|
||||
// A 16x16 grid of the map with a list of turfs that can be seen, are visible and are dimmed.
|
||||
// Allows the AI Eye to stream these chunks and know what it can and cannot see.
|
||||
|
||||
/// A 16x16 grid of the map with a list of turfs that can be seen, are visible and are dimmed.
|
||||
/// Allows camera eyes to stream these chunks and know what they can and cannot see.
|
||||
/datum/camerachunk
|
||||
var/list/obscuredTurfs = list()
|
||||
var/list/visibleTurfs = list()
|
||||
var/list/obscured_turfs = list()
|
||||
var/list/visible_turfs = list()
|
||||
var/list/obscured = list()
|
||||
var/list/active_cameras = list()
|
||||
var/list/inactive_cameras = list()
|
||||
@@ -17,6 +14,7 @@
|
||||
var/y = 0
|
||||
var/z = 0
|
||||
|
||||
/// Adds a camera to the chunk if it has not already been added.
|
||||
/datum/camerachunk/proc/add_camera(obj/machinery/camera/cam)
|
||||
if(active_cameras[cam] || inactive_cameras[cam])
|
||||
return
|
||||
@@ -32,6 +30,7 @@
|
||||
else
|
||||
inactive_cameras[cam] = cam
|
||||
|
||||
/// Handles each movement by a camera that has been added to the chunk.
|
||||
/datum/camerachunk/proc/camera_moved(obj/machinery/camera/cam, atom/old_loc)
|
||||
var/turf/T = get_turf(cam)
|
||||
|
||||
@@ -39,6 +38,7 @@
|
||||
if(T.x + CAMERA_VIEW_DISTANCE < x || T.x - CAMERA_VIEW_DISTANCE >= x + CAMERA_CHUNK_SIZE || T.y + CAMERA_VIEW_DISTANCE < y || T.y - CAMERA_VIEW_DISTANCE >= y + CAMERA_CHUNK_SIZE || T.z != z)
|
||||
remove_camera(cam)
|
||||
|
||||
/// Removes a camera from the chunk.
|
||||
/datum/camerachunk/proc/remove_camera(obj/machinery/camera/cam)
|
||||
UnregisterSignal(cam, list(COMSIG_CAMERA_OFF, COMSIG_CAMERA_ON, COMSIG_PARENT_QDELETING, COMSIG_CAMERA_MOVED))
|
||||
active_cameras -= cam
|
||||
@@ -55,42 +55,40 @@
|
||||
active_cameras -= cam
|
||||
SScamera.queue(src)
|
||||
|
||||
// Add an AI eye to the chunk, then update if changed.
|
||||
/datum/camerachunk/proc/add(mob/camera/ai_eye/eye, add_images = TRUE)
|
||||
/// Add a camera eye to the chunk, then update if changed.
|
||||
/datum/camerachunk/proc/add(mob/camera/eye/eye, add_images = TRUE)
|
||||
if(add_images)
|
||||
var/client/client = eye.GetViewerClient()
|
||||
var/client/client = eye.get_viewer_client()
|
||||
if(client)
|
||||
client.images += obscured
|
||||
eye.visibleCameraChunks += src
|
||||
eye.visible_camera_chunks += src
|
||||
seenby += eye
|
||||
RegisterSignal(eye, COMSIG_PARENT_QDELETING, PROC_REF(aiEye_destroyed))
|
||||
RegisterSignal(eye, COMSIG_PARENT_QDELETING, PROC_REF(eye_destroyed))
|
||||
if(changed)
|
||||
SScamera.queue(src)
|
||||
|
||||
/datum/camerachunk/proc/aiEye_destroyed(mob/camera/ai_eye/eye)
|
||||
/datum/camerachunk/proc/eye_destroyed(mob/camera/eye/eye)
|
||||
remove(eye, FALSE)
|
||||
|
||||
// Remove an AI eye from the chunk, then update if changed.
|
||||
/datum/camerachunk/proc/remove(mob/camera/ai_eye/eye, remove_images = TRUE)
|
||||
/// Remove a camera eye from the chunk, then update if changed.
|
||||
/datum/camerachunk/proc/remove(mob/camera/eye/eye, remove_images = TRUE)
|
||||
if(remove_images)
|
||||
var/client/client = eye.GetViewerClient()
|
||||
var/client/client = eye.get_viewer_client()
|
||||
if(client)
|
||||
client.images -= obscured
|
||||
eye.visibleCameraChunks -= src
|
||||
eye.visible_camera_chunks -= src
|
||||
seenby -= eye
|
||||
UnregisterSignal(eye, COMSIG_PARENT_QDELETING)
|
||||
|
||||
// Called when a chunk has changed. I.E: A wall was deleted.
|
||||
|
||||
/datum/camerachunk/proc/visibilityChanged(turf/loc)
|
||||
if(!visibleTurfs[loc])
|
||||
/// Called when a chunk has changed. I.E: A wall was deleted.
|
||||
/datum/camerachunk/proc/visibility_changed(turf/loc)
|
||||
if(!visible_turfs[loc])
|
||||
return
|
||||
hasChanged()
|
||||
has_changed()
|
||||
|
||||
// Updates the chunk, makes sure that it doesn't update too much. If the chunk isn't being watched it will
|
||||
// instead be flagged to update the next time an AI Eye moves near it.
|
||||
|
||||
/datum/camerachunk/proc/hasChanged(update_now = 0)
|
||||
/// Updates the chunk, makes sure that it doesn't update too much. If the chunk isn't being watched it will
|
||||
/// instead be flagged to update the next time a camera eye moves near it.
|
||||
/datum/camerachunk/proc/has_changed(update_now = 0)
|
||||
if(update_now)
|
||||
update()
|
||||
SScamera.remove_from_queue(src)
|
||||
@@ -100,48 +98,48 @@
|
||||
else
|
||||
changed = TRUE
|
||||
|
||||
// The actual updating. It gathers the visible turfs from cameras and puts them into the appropiate lists.
|
||||
|
||||
/// Gathers the visible turfs from cameras and puts them into the appropiate lists.
|
||||
/datum/camerachunk/proc/update()
|
||||
var/list/newVisibleTurfs = list()
|
||||
var/list/new_visible_turfs = list()
|
||||
|
||||
for(var/obj/machinery/camera/c as anything in active_cameras)
|
||||
var/turf/point = locate(src.x + (CAMERA_CHUNK_SIZE / 2), src.y + (CAMERA_CHUNK_SIZE / 2), src.z)
|
||||
var/turf/T = get_turf(c)
|
||||
if(get_dist(point, T) > CAMERA_VIEW_DISTANCE + (CAMERA_CHUNK_SIZE / 2))
|
||||
continue // Still needed for Ais who get created on Z level 1 on the spot of the new player
|
||||
// Still needed for Ais who get created on Z level 1 on the spot of the new player
|
||||
continue
|
||||
|
||||
for(var/turf/t in c.can_see())
|
||||
if(turfs[t])
|
||||
newVisibleTurfs[t] = t
|
||||
new_visible_turfs[t] = t
|
||||
|
||||
var/list/visAdded = newVisibleTurfs - visibleTurfs
|
||||
var/list/visRemoved = visibleTurfs - newVisibleTurfs
|
||||
var/list/vis_added = new_visible_turfs - visible_turfs
|
||||
var/list/vis_removed = visible_turfs - new_visible_turfs
|
||||
|
||||
visibleTurfs = newVisibleTurfs
|
||||
obscuredTurfs = turfs - newVisibleTurfs
|
||||
visible_turfs = new_visible_turfs
|
||||
obscured_turfs = turfs - new_visible_turfs
|
||||
var/list/images_to_remove = list()
|
||||
var/list/images_to_add = list()
|
||||
for(var/turf/t as anything in visAdded)
|
||||
for(var/turf/t as anything in vis_added)
|
||||
if(t.obscured)
|
||||
obscured -= t.obscured
|
||||
images_to_remove += t.obscured
|
||||
|
||||
for(var/turf/t as anything in visRemoved)
|
||||
for(var/turf/t as anything in vis_removed)
|
||||
if(!t.obscured)
|
||||
t.obscured = image('icons/effects/cameravis.dmi', t, null, BYOND_LIGHTING_LAYER + 0.1)
|
||||
t.obscured.plane = BYOND_LIGHTING_PLANE + 1
|
||||
obscured += t.obscured
|
||||
images_to_add += t.obscured
|
||||
|
||||
for(var/mob/camera/ai_eye/eye as anything in seenby)
|
||||
var/client/client = eye.GetViewerClient()
|
||||
for(var/mob/camera/eye/eye as anything in seenby)
|
||||
var/client/client = eye.get_viewer_client()
|
||||
if(client)
|
||||
client.images -= images_to_remove
|
||||
client.images += images_to_add
|
||||
changed = FALSE
|
||||
|
||||
// Create a new camera chunk, since the chunks are made as they are needed.
|
||||
/// Create a new camera chunk, since the chunks are made as they are needed.
|
||||
/datum/camerachunk/New(loc, x, y, z)
|
||||
|
||||
// 0xf = 15
|
||||
@@ -162,11 +160,11 @@
|
||||
for(var/obj/machinery/camera/c as anything in active_cameras)
|
||||
for(var/turf/t in c.can_see())
|
||||
if(turfs[t])
|
||||
visibleTurfs[t] = t
|
||||
visible_turfs[t] = t
|
||||
|
||||
obscuredTurfs = turfs - visibleTurfs
|
||||
obscured_turfs = turfs - visible_turfs
|
||||
|
||||
for(var/turf/t as anything in obscuredTurfs)
|
||||
for(var/turf/t as anything in obscured_turfs)
|
||||
if(!t.obscured)
|
||||
t.obscured = image('icons/effects/cameravis.dmi', t, "black", BYOND_LIGHTING_LAYER + 0.1)
|
||||
t.obscured.plane = BYOND_LIGHTING_PLANE + 1
|
||||
@@ -0,0 +1,191 @@
|
||||
/// Camera eyes are remote-control mobs that can move and see throughout the global cameranet.
|
||||
/// They're used in AI eyes, holograms, advanced camera consoles, abductor consoles, shuttle consoles,
|
||||
/// and xenobiology consoles. When created, the user with which they are initialized will be granted control,
|
||||
/// and their movements will be relayed to the camera eye instead. When destroyed, the user's control of the
|
||||
/// camera eye will be released; if they were previously remote controlling another object (such as another
|
||||
/// camera eye) then they will be put back in control of that object; otherwise they will return to their body.
|
||||
/mob/camera/eye
|
||||
name = "Inactive Camera Eye"
|
||||
icon = 'icons/obj/abductor.dmi'
|
||||
icon_state = "camera_target"
|
||||
alpha = 127
|
||||
invisibility = SEE_INVISIBLE_OBSERVER
|
||||
|
||||
/// The list of camera chunks currently visible to the camera eye.
|
||||
var/list/visible_camera_chunks = list()
|
||||
/// The user controlling the eye.
|
||||
var/mob/living/user
|
||||
/// The thing that the user was previously remote controlling before this eye.
|
||||
var/user_previous_remote_control
|
||||
/// The object that created the eye.
|
||||
var/origin
|
||||
/// If true, speech near the camera eye will be relayed to its controller.
|
||||
var/relay_speech = FALSE
|
||||
/// Sets the camera eye visibility range; does not expand viewport, only affects cameranet obscuring
|
||||
var/static_visibility_range = 16
|
||||
/// Toggles whether this eye is detectable by AI Detectors.
|
||||
var/ai_detector_visible = TRUE
|
||||
/// Toggles whether the eye's icon should be visible to its user.
|
||||
var/visible_icon = FALSE
|
||||
/// The list of cameranets that this camera eye can see and access.
|
||||
var/list/networks = list("SS13")
|
||||
/// The in-memory image of the camera eye's icon.
|
||||
var/image/user_image
|
||||
|
||||
// Camera acceleration settings
|
||||
// Initially, the camera moves one turf per move. If there is no movement for
|
||||
// cooldown_rate in deciseconds, the camera will reset to this movement rate.
|
||||
// Every move otherwise increases sprint by acceleration_rate, until sprint
|
||||
// exceeds sprint_threshold, and the movement rate increases by one per move.
|
||||
// The movement rate is 1 + round(sprint / sprint_threshold).
|
||||
|
||||
/// The maximum sprint value - this caps acceleration
|
||||
var/max_sprint = 50
|
||||
/// The minimum sprint needed to increase base velocity
|
||||
var/sprint_threshold = 20
|
||||
/// The amount that sprint is increased per move
|
||||
var/acceleration_rate = 0.5
|
||||
/// Keeps track of acceleration - movement rate is 1 + round(sprint / sprint_threshold)
|
||||
var/sprint = 10
|
||||
/// The absolute time that sprint will reset to its initial value
|
||||
var/cooldown = 0
|
||||
/// The time after which sprint should be reset to its initial state, if no movements are made
|
||||
var/cooldown_rate = 5
|
||||
/// Toggles camera acceleration on or off.
|
||||
var/acceleration = 1
|
||||
|
||||
/mob/camera/eye/Initialize(mapload, owner_name, camera_origin, mob/living/user)
|
||||
. = ..()
|
||||
name = "Camera Eye ([owner_name])"
|
||||
origin = camera_origin
|
||||
give_control(user)
|
||||
update_visibility()
|
||||
refresh_visible_icon()
|
||||
if(!validate_active_cameranet())
|
||||
return INITIALIZE_HINT_QDEL
|
||||
|
||||
/// Validates that there is an active cameranet. If strict is 0, does nothing.
|
||||
/// Returns 1 if there is an active cameranet. Warns the user and returns 0 if there is not.
|
||||
/mob/camera/eye/proc/validate_active_cameranet(strict = 0)
|
||||
var/camera = first_active_camera()
|
||||
if(strict && !camera)
|
||||
to_chat(user, "<span class='warning'>ERROR: No linked and active camera network found.</span>")
|
||||
return FALSE
|
||||
return TRUE
|
||||
|
||||
/// Returns the turf of the first active camera in the global cameranet.
|
||||
/mob/camera/eye/proc/first_active_camera()
|
||||
for(var/obj/machinery/camera/C in GLOB.cameranet.cameras)
|
||||
if(!C.can_use())
|
||||
continue
|
||||
if(length(C.network & networks))
|
||||
return get_turf(C)
|
||||
|
||||
/// Updates what the global cameranet can see with respect to this eye and its user's client.
|
||||
/mob/camera/eye/proc/update_visibility()
|
||||
GLOB.cameranet.visibility(src, user.client)
|
||||
|
||||
/// Refreshes user_image in the user's client.images.
|
||||
/mob/camera/eye/proc/refresh_visible_icon()
|
||||
if(visible_icon && user.client)
|
||||
user.client.images -= user_image
|
||||
user_image = image(icon,loc,icon_state,FLY_LAYER)
|
||||
user.client.images += user_image
|
||||
|
||||
/// Sets the camera eye's location to T, updates global cameranet visibility, and refreshes user_images.
|
||||
/mob/camera/eye/set_loc(T)
|
||||
if(user)
|
||||
T = get_turf(T)
|
||||
..(T)
|
||||
update_visibility()
|
||||
refresh_visible_icon()
|
||||
|
||||
/// Disables independent movement by camera eyes; camera eyes must be controlled by relaymove.
|
||||
/mob/camera/eye/Move()
|
||||
return FALSE
|
||||
|
||||
/// If `usr` is an AI, set the camera eye's location to the location of the atom clicked.
|
||||
/atom/proc/move_camera_by_click()
|
||||
if(is_ai(usr))
|
||||
var/mob/living/silicon/ai/AI = usr
|
||||
if(AI.eyeobj && (AI.client.eye == AI.eyeobj) && (AI.eyeobj.z == z))
|
||||
AI.camera_follow = null
|
||||
if(isturf(loc) || isturf(src))
|
||||
AI.eyeobj.set_loc(src)
|
||||
|
||||
/// Returns the user's client, if it exists; otherwise returns null.
|
||||
/mob/camera/eye/proc/get_viewer_client()
|
||||
return user?.client
|
||||
|
||||
/// Removes obscured chunk images and user_images from the user's client.images.
|
||||
/mob/camera/eye/proc/remove_images()
|
||||
var/client/C = get_viewer_client()
|
||||
if(!C)
|
||||
return
|
||||
for(var/datum/camerachunk/chunk as anything in visible_camera_chunks)
|
||||
C.images -= chunk.obscured
|
||||
if(visible_icon)
|
||||
C.images -= user_image
|
||||
|
||||
/// Calls `remove_images`, changes the user's remote control from this camera eye to `user_previous_remote_control`.
|
||||
/mob/camera/eye/proc/release_control()
|
||||
if(!istype(user))
|
||||
return
|
||||
if(user.client)
|
||||
user.reset_perspective(user.client.mob)
|
||||
remove_images()
|
||||
user.remote_control = null
|
||||
if(user_previous_remote_control)
|
||||
user.reset_perspective(user_previous_remote_control)
|
||||
user.remote_control = user_previous_remote_control
|
||||
user_previous_remote_control = null
|
||||
user = null
|
||||
|
||||
/// Forces this eye's current user to release control, renames this eye, and grants `new_user` control of this eye.
|
||||
/mob/camera/eye/proc/give_control(mob/new_user)
|
||||
if(!istype(new_user))
|
||||
return
|
||||
release_control()
|
||||
user = new_user
|
||||
rename_camera(user.name)
|
||||
if(istype(user.remote_control))
|
||||
user_previous_remote_control = user.remote_control
|
||||
user.remote_control = src
|
||||
user.reset_perspective(src)
|
||||
|
||||
/// Renames the camera eye (only visible in observer Orbit menu)
|
||||
/mob/camera/eye/proc/rename_camera(new_name)
|
||||
name = "Camera Eye ([new_name])"
|
||||
|
||||
/// Remove this eye from all chunks containing it.
|
||||
/mob/camera/eye/proc/release_chunks()
|
||||
for(var/datum/camerachunk/chunk as anything in visible_camera_chunks)
|
||||
chunk.remove(src)
|
||||
|
||||
/mob/camera/eye/Destroy()
|
||||
release_control()
|
||||
release_chunks()
|
||||
return ..()
|
||||
|
||||
/// Called when the user controlling this eye attempts to move; uses camera acceleration settings.
|
||||
/mob/camera/eye/relaymove(mob/user,direct)
|
||||
var/initial = initial(sprint)
|
||||
|
||||
if(cooldown && cooldown < world.timeofday)
|
||||
sprint = initial
|
||||
|
||||
for(var/i in 0 to sprint step sprint_threshold)
|
||||
var/turf/next_step= get_turf(get_step(src, direct))
|
||||
if(next_step)
|
||||
set_loc(next_step)
|
||||
|
||||
cooldown = world.timeofday + cooldown_rate
|
||||
if(acceleration)
|
||||
sprint = min(sprint + acceleration_rate, max_sprint)
|
||||
else
|
||||
sprint = initial
|
||||
|
||||
/// If `relay_speech` is truthy, allows the camera eye's user to hear speech spoken at the eye's location.
|
||||
/mob/camera/eye/hear_say(list/message_pieces, verb = "says", italics = 0, mob/speaker = null, sound/speech_sound, sound_vol, sound_frequency, use_voice = TRUE)
|
||||
if(relay_speech)
|
||||
user.hear_say(message_pieces, verb, italics, speaker, speech_sound, sound_vol, sound_frequency)
|
||||
@@ -0,0 +1,14 @@
|
||||
/mob/camera/eye/abductor
|
||||
name = "Abductor Camera Eye"
|
||||
ai_detector_visible = FALSE
|
||||
|
||||
/mob/camera/eye/abductor/Initialize(mapload, owner_name, camera_origin, user)
|
||||
..()
|
||||
set_loc(first_active_camera())
|
||||
|
||||
/mob/camera/eye/abductor/rename_camera(new_name)
|
||||
name = "Abductor Camera Eye ([new_name])"
|
||||
|
||||
/// Requires the cameranet to be validated.
|
||||
/mob/camera/eye/abductor/validate_active_cameranet()
|
||||
..(TRUE)
|
||||
@@ -0,0 +1,34 @@
|
||||
/mob/camera/eye/ai
|
||||
name = "Inactive AI Eye"
|
||||
icon = 'icons/mob/ai.dmi'
|
||||
icon_state = "eye"
|
||||
var/mob/living/silicon/ai/ai = null
|
||||
|
||||
/mob/camera/eye/ai/Initialize(mapload, owner_name, camera_origin, mob/living/user)
|
||||
. = ..()
|
||||
ai = user
|
||||
if(is_ai_eye(ai.eyeobj))
|
||||
stack_trace("Tried to create an AI Eye for [user], but there is one already assigned")
|
||||
return INITIALIZE_HINT_QDEL
|
||||
name = "[owner_name] (AI Eye)"
|
||||
|
||||
/// Ensures that the user's perspective is on this eye (instead of, for example, a mech or hologram eye) and
|
||||
/// updates parallax
|
||||
/mob/camera/eye/ai/set_loc(T)
|
||||
..()
|
||||
user.reset_perspective(src)
|
||||
update_parallax_contents()
|
||||
|
||||
/// Cancels the camera's follow target if tracking has stopped, and lights up nearby lights if the AI has
|
||||
/// "Toggle Camera Lights" enabled
|
||||
/mob/camera/eye/ai/relaymove(mob/user, direct)
|
||||
..()
|
||||
if(!ai.tracking)
|
||||
ai.camera_follow = null
|
||||
if(ai.camera_light_on)
|
||||
ai.light_cameras()
|
||||
|
||||
/// Relays speech near the AI eye to the AI if the AI has surveillance, either from a malf module or a station trait
|
||||
/mob/camera/eye/ai/hear_say(list/message_pieces, verb = "says", italics = 0, mob/speaker = null, sound/speech_sound, sound_vol, sound_frequency, use_voice = TRUE)
|
||||
if(relay_speech)
|
||||
ai.relay_speech(speaker, message_pieces, verb)
|
||||
@@ -0,0 +1,53 @@
|
||||
/mob/camera/eye/hologram
|
||||
name = "Inactive Hologram Eye"
|
||||
ai_detector_visible = FALSE
|
||||
acceleration = FALSE
|
||||
relay_speech = TRUE
|
||||
var/obj/machinery/hologram/holopad/holopad
|
||||
|
||||
/mob/camera/eye/hologram/Initialize(mapload, owner_name, camera_origin, mob/living/user)
|
||||
..()
|
||||
holopad = camera_origin
|
||||
set_loc(holopad)
|
||||
|
||||
/mob/camera/eye/hologram/rename_camera(new_name)
|
||||
name = "Hologram ([new_name])"
|
||||
|
||||
/// Hologram movement copies the delays and diagonal delays of regular mob movement
|
||||
/// for crew, and for AI unless fast holograms are enabled
|
||||
/mob/camera/eye/hologram/relaymove(mob/user, direct)
|
||||
var/mob/living/silicon/ai/ai = user
|
||||
if(istype(ai) && ai.fast_holograms)
|
||||
return ..()
|
||||
var/turf/new_location = get_turf(get_step(src, direct))
|
||||
if(new_location.z != z || get_dist(new_location, src) > 1)
|
||||
return
|
||||
var/base_delay = GLOB.configuration.movement.base_run_speed
|
||||
var/diag_delay = base_delay * SQRT_2
|
||||
var/delay = (direct & (direct - 1)) ? diag_delay : base_delay
|
||||
user.client.move_delay = debounced_move(normalized_delay_speed(delay))
|
||||
user.last_movement = world.time
|
||||
set_loc(new_location)
|
||||
|
||||
/mob/camera/eye/hologram/proc/debounced_move(delay_speed)
|
||||
var/old_move_delay = user.client.move_delay
|
||||
if(old_move_delay + world.tick_lag > world.time)
|
||||
return old_move_delay + delay_speed
|
||||
else
|
||||
return world.time + delay_speed
|
||||
|
||||
/mob/camera/eye/hologram/proc/normalized_delay_speed(delay_speed)
|
||||
return TICKS2DS(-round(-(DS2TICKS(delay_speed))))
|
||||
|
||||
/// Requires the cameranet to be validated.
|
||||
/mob/camera/eye/hologram/validate_active_cameranet()
|
||||
..(TRUE)
|
||||
|
||||
/// Moves the associated hologram, and the previously controlled object (probably an AI eye), to the new location.
|
||||
/mob/camera/eye/hologram/set_loc(T)
|
||||
. = ..()
|
||||
var/turf/new_location = get_turf(T)
|
||||
holopad.move_hologram(user, new_location)
|
||||
var/mob/camera/eye/previous_eye = user_previous_remote_control
|
||||
if(istype(previous_eye))
|
||||
previous_eye.set_loc(new_location)
|
||||
@@ -0,0 +1,30 @@
|
||||
/mob/camera/eye/shuttle_docker
|
||||
name = "Shuttle Docker Camera Eye"
|
||||
ai_detector_visible = FALSE
|
||||
simulated = FALSE
|
||||
var/list/placement_images = list()
|
||||
var/list/placed_images = list()
|
||||
|
||||
/mob/camera/eye/shuttle_docker/Initialize(mapload, owner_name, camera_origin, mob/living/user)
|
||||
..()
|
||||
set_loc(first_active_camera())
|
||||
|
||||
/mob/camera/eye/shuttle_docker/rename_camera(new_name)
|
||||
name = "Shuttle Docker Camera Eye ([new_name])"
|
||||
|
||||
/// Prevents the shuttle docker eye from updating global cameranet chunks. Shuttle dockers don't use station cameras.
|
||||
/mob/camera/eye/shuttle_docker/update_visibility()
|
||||
return FALSE
|
||||
|
||||
/// Prevents moving the camera eye into the station, and updates the current location's landing spot validity.
|
||||
/mob/camera/eye/shuttle_docker/set_loc(T)
|
||||
if(isspaceturf(get_turf(T)) || istype(get_area(T), /area/space) || istype(get_area(T), /area/shuttle))
|
||||
..()
|
||||
var/obj/machinery/computer/camera_advanced/shuttle_docker/console = origin
|
||||
console.check_landing_spot()
|
||||
|
||||
/mob/camera/eye/shuttle_docker/update_remote_sight(mob/living/user)
|
||||
user.sight = SEE_TURFS
|
||||
|
||||
..()
|
||||
return TRUE
|
||||
@@ -0,0 +1,10 @@
|
||||
/mob/camera/eye/syndicate
|
||||
name = "Syndicate Researcher Camera Eye"
|
||||
ai_detector_visible = FALSE
|
||||
|
||||
/mob/camera/eye/syndicate/Initialize(mapload, owner_name, camera_origin, user)
|
||||
..()
|
||||
set_loc(first_active_camera())
|
||||
|
||||
/mob/camera/eye/syndicate/rename_camera(new_name)
|
||||
name = "Syndicate Researcher Camera Eye ([new_name])"
|
||||
@@ -0,0 +1,22 @@
|
||||
/mob/camera/eye/xenobio
|
||||
name = "Xenobiology Console Camera Eye"
|
||||
visible_icon = TRUE
|
||||
ai_detector_visible = FALSE
|
||||
var/allowed_area
|
||||
|
||||
/mob/camera/eye/xenobio/Initialize(mapload, owner_name, camera_origin, mob/living/user)
|
||||
. = ..()
|
||||
var/area/A = get_area(camera_origin)
|
||||
allowed_area = A.name
|
||||
|
||||
/mob/camera/eye/xenobio/rename_camera(new_name)
|
||||
name = "Xenobiology Console ([new_name])"
|
||||
|
||||
/// Prevents the camera eye from going outside of the xenobiology area
|
||||
/mob/camera/eye/xenobio/set_loc(T)
|
||||
var/area/new_area = get_area(T)
|
||||
if(!new_area)
|
||||
return
|
||||
if(new_area.name != allowed_area && !new_area.xenobiology_compatible)
|
||||
return
|
||||
return ..()
|
||||
@@ -255,7 +255,7 @@ This is the proc mobs get to turn into a ghost. Forked from ghostize due to comp
|
||||
warningmsg = "You have committed suicide too early in the round"
|
||||
else if(stat != DEAD)
|
||||
warningmsg = "You are alive"
|
||||
if(isAI(src))
|
||||
if(is_ai(src))
|
||||
warningmsg = "You are a living AI! You should probably use OOC -> Wipe Core instead."
|
||||
else if(GLOB.non_respawnable_keys[ckey])
|
||||
warningmsg = "You have lost your right to respawn"
|
||||
@@ -656,7 +656,7 @@ This is the proc mobs get to turn into a ghost. Forked from ghostize due to comp
|
||||
|
||||
/proc/ghost_follow_link(atom/target, atom/ghost)
|
||||
if((!target) || (!ghost)) return
|
||||
if(isAI(target)) // AI core/eye follow links
|
||||
if(is_ai(target)) // AI core/eye follow links
|
||||
var/mob/living/silicon/ai/A = target
|
||||
. = "<a href='byond://?src=[ghost.UID()];follow=[A.UID()]'>core</a>"
|
||||
if(A.client && A.eyeobj) // No point following clientless AI eyes
|
||||
|
||||
@@ -17,7 +17,7 @@
|
||||
if(!speaker || !ismob(speaker))
|
||||
return speaker_name
|
||||
var/mob/speaker_mob = speaker
|
||||
if(isAI(speaker_mob))
|
||||
if(is_ai(speaker_mob))
|
||||
//AI's can't pretend to be other mobs.
|
||||
return speaker_name
|
||||
if(!check_name_against || check_name_against == speaker_mob.real_name)
|
||||
|
||||
@@ -624,7 +624,7 @@
|
||||
continue
|
||||
else if(drone_only && !isdrone(S))
|
||||
continue
|
||||
else if(isAI(S))
|
||||
else if(is_ai(S))
|
||||
message_start = list("<i><span class='game say'>[name], <a href='byond://?src=[S.UID()];track=\ref[speaker]'><span class='name'>[speaker.name]</span></a>")
|
||||
else if(isrobot(S))
|
||||
var/mob/living/silicon/robot/borg = S
|
||||
|
||||
@@ -364,7 +364,7 @@
|
||||
|
||||
return (hudtype in have_hudtypes)
|
||||
|
||||
else if(isrobot(M) || isAI(M)) //Stand-in/Stopgap to prevent pAIs from freely altering records, pending a more advanced Records system
|
||||
else if(isrobot(M) || is_ai(M)) //Stand-in/Stopgap to prevent pAIs from freely altering records, pending a more advanced Records system
|
||||
return (hudtype in list(EXAMINE_HUD_SECURITY_READ, EXAMINE_HUD_SECURITY_WRITE, EXAMINE_HUD_MEDICAL_READ, EXAMINE_HUD_MEDICAL_WRITE))
|
||||
|
||||
else if(isobserver(M))
|
||||
|
||||
@@ -723,7 +723,7 @@
|
||||
else if(isrobot(user))
|
||||
var/mob/living/silicon/robot/U = user
|
||||
rank = "[U.modtype] [U.braintype]"
|
||||
else if(isAI(user))
|
||||
else if(is_ai(user))
|
||||
rank = "AI"
|
||||
set_criminal_status(user, found_record, new_status, reason, rank)
|
||||
|
||||
|
||||
@@ -30,7 +30,7 @@
|
||||
|
||||
var/now_pushing = null
|
||||
|
||||
var/atom/movable/cameraFollow = null
|
||||
var/atom/movable/camera_follow = null
|
||||
|
||||
var/on_fire = 0 //The "Are we on fire?" var
|
||||
var/fire_stacks = 0 //Tracks how many stacks of fire we have on, max is usually 20
|
||||
|
||||
@@ -10,7 +10,7 @@
|
||||
else
|
||||
icon_state = "ai_dead"
|
||||
if(eyeobj)
|
||||
eyeobj.setLoc(get_turf(src))
|
||||
eyeobj.set_loc(get_turf(src))
|
||||
|
||||
GLOB.shuttle_caller_list -= src
|
||||
SSshuttle.autoEvac()
|
||||
|
||||
@@ -10,7 +10,7 @@
|
||||
|
||||
var/turf/T = get_turf(src)
|
||||
if(stat != CONSCIOUS) //ai's fucked
|
||||
cameraFollow = null
|
||||
camera_follow = null
|
||||
reset_perspective(null)
|
||||
unset_machine()
|
||||
|
||||
|
||||
@@ -14,6 +14,7 @@ GLOBAL_LIST_INIT(ai_verbs_default, list(
|
||||
/mob/living/silicon/ai/proc/pick_icon,
|
||||
/mob/living/silicon/ai/proc/sensor_mode,
|
||||
/mob/living/silicon/ai/proc/show_laws_verb,
|
||||
/mob/living/silicon/ai/proc/toggle_fast_holograms,
|
||||
/mob/living/silicon/ai/proc/toggle_acceleration,
|
||||
/mob/living/silicon/ai/proc/toggle_camera_light,
|
||||
/mob/living/silicon/ai/proc/botcall,
|
||||
@@ -104,10 +105,8 @@ GLOBAL_LIST_INIT(ai_verbs_default, list(
|
||||
var/obj/machinery/doomsday_device/doomsday_device
|
||||
|
||||
var/obj/machinery/hologram/holopad/holo = null
|
||||
var/mob/camera/ai_eye/eyeobj
|
||||
var/sprint = 10
|
||||
var/cooldown = 0
|
||||
var/acceleration = 1
|
||||
var/mob/camera/eye/ai/eyeobj
|
||||
var/fast_holograms = TRUE
|
||||
var/tracking = FALSE //this is 1 if the AI is currently tracking somebody, but the track has not yet been completed.
|
||||
|
||||
/// If true, this AI core can use the teleporter.
|
||||
@@ -121,7 +120,6 @@ GLOBAL_LIST_INIT(ai_verbs_default, list(
|
||||
var/announce_arrivals = TRUE
|
||||
var/arrivalmsg = "$name, $rank, has arrived on the station."
|
||||
|
||||
var/list/all_eyes = list()
|
||||
var/next_text_announcement
|
||||
|
||||
//Used with the hotkeys on 2-5 to store locations.
|
||||
@@ -228,8 +226,8 @@ GLOBAL_LIST_INIT(ai_verbs_default, list(
|
||||
|
||||
spawn(5)
|
||||
new /obj/machinery/ai_powersupply(src)
|
||||
|
||||
create_eye()
|
||||
|
||||
eyeobj = new /mob/camera/eye/ai(loc, name, src, src)
|
||||
|
||||
builtInCamera = new /obj/machinery/camera/portable(src)
|
||||
builtInCamera.c_tag = name
|
||||
@@ -769,7 +767,7 @@ GLOBAL_LIST_INIT(ai_verbs_default, list(
|
||||
if(controlled_mech)
|
||||
to_chat(src, "<span class='warning'>You are already loaded into an onboard computer!</span>")
|
||||
return
|
||||
if(!GLOB.cameranet.checkCameraVis(M))
|
||||
if(!GLOB.cameranet.check_camera_vis(M))
|
||||
to_chat(src, "<span class='warning'>Exosuit is no longer near active cameras.</span>")
|
||||
return
|
||||
if(lacks_power())
|
||||
@@ -826,7 +824,7 @@ GLOBAL_LIST_INIT(ai_verbs_default, list(
|
||||
//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(GLOB.cameranet && GLOB.cameranet.checkTurfVis(turf_check))
|
||||
else if(GLOB.cameranet && GLOB.cameranet.check_turf_vis(turf_check))
|
||||
call_bot(turf_check)
|
||||
else
|
||||
to_chat(src, "<span class='danger'>Selected location is not visible.</span>")
|
||||
@@ -882,7 +880,7 @@ GLOBAL_LIST_INIT(ai_verbs_default, list(
|
||||
/mob/living/silicon/ai/proc/switchCamera(obj/machinery/camera/C)
|
||||
|
||||
if(!tracking)
|
||||
cameraFollow = null
|
||||
camera_follow = null
|
||||
|
||||
if(QDELETED(C) || stat == DEAD) //C.can_use())
|
||||
return FALSE
|
||||
@@ -891,7 +889,7 @@ GLOBAL_LIST_INIT(ai_verbs_default, list(
|
||||
view_core()
|
||||
return
|
||||
// ok, we're alive, camera is good and in our network...
|
||||
eyeobj.setLoc(get_turf(C))
|
||||
eyeobj.set_loc(get_turf(C))
|
||||
//machine = src
|
||||
|
||||
return TRUE
|
||||
@@ -939,7 +937,7 @@ GLOBAL_LIST_INIT(ai_verbs_default, list(
|
||||
if(!C.can_use())
|
||||
continue
|
||||
if(network in C.network)
|
||||
U.eyeobj.setLoc(get_turf(C))
|
||||
U.eyeobj.set_loc(get_turf(C))
|
||||
break
|
||||
to_chat(src, "<span class='notice'>Switched to [network] camera network.</span>")
|
||||
//End of code by Mord_Sith
|
||||
@@ -1238,7 +1236,7 @@ GLOBAL_LIST_INIT(ai_verbs_default, list(
|
||||
var/list/obj/machinery/camera/add = list()
|
||||
var/list/obj/machinery/camera/remove = list()
|
||||
var/list/obj/machinery/camera/visible = list()
|
||||
for(var/datum/camerachunk/CC in eyeobj.visibleCameraChunks)
|
||||
for(var/datum/camerachunk/CC in eyeobj.visible_camera_chunks)
|
||||
for(var/obj/machinery/camera/C in CC.active_cameras)
|
||||
if(!C.can_use() || get_dist(C, eyeobj) > 7)
|
||||
continue
|
||||
@@ -1340,7 +1338,7 @@ GLOBAL_LIST_INIT(ai_verbs_default, list(
|
||||
//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
|
||||
var/turf/T = isturf(A) ? A : get_turf_pixel(A)
|
||||
return (GLOB.cameranet && GLOB.cameranet.checkTurfVis(T)) || apc_override
|
||||
return (GLOB.cameranet && GLOB.cameranet.check_turf_vis(T)) || 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)
|
||||
@@ -1433,8 +1431,45 @@ GLOBAL_LIST_INIT(ai_verbs_default, list(
|
||||
else
|
||||
to_chat(src, "<span class='warning'>Target is not on or near any active cameras on the station.</span>")
|
||||
|
||||
/mob/living/silicon/ai/proc/camera_visibility(mob/camera/ai_eye/moved_eye)
|
||||
GLOB.cameranet.visibility(moved_eye, client, all_eyes)
|
||||
// Return to the Core.
|
||||
/mob/living/silicon/ai/proc/core()
|
||||
set category = "AI Commands"
|
||||
set name = "AI Core"
|
||||
|
||||
view_core()
|
||||
|
||||
/mob/living/silicon/ai/proc/view_core()
|
||||
|
||||
current = null
|
||||
camera_follow = null
|
||||
unset_machine()
|
||||
|
||||
if(eyeobj && loc)
|
||||
eyeobj.loc = loc
|
||||
else
|
||||
to_chat(src, "ERROR: Eyeobj not found. Creating new eye...")
|
||||
eyeobj = new /mob/camera/eye/ai(loc, name, src, src)
|
||||
|
||||
eyeobj.set_loc(loc)
|
||||
|
||||
/mob/living/silicon/ai/proc/toggle_fast_holograms()
|
||||
set category = "AI Commands"
|
||||
set name = "Toggle Fast Holograms"
|
||||
|
||||
if(usr.stat == DEAD || !is_ai_eye(eyeobj))
|
||||
return
|
||||
fast_holograms = !fast_holograms
|
||||
to_chat(usr, "Fast holograms have been toggled [fast_holograms ? "on" : "off"].")
|
||||
|
||||
/mob/living/silicon/ai/proc/toggle_acceleration()
|
||||
set category = "AI Commands"
|
||||
set name = "Toggle Camera Acceleration"
|
||||
|
||||
if(usr.stat == DEAD)
|
||||
return //won't work if dead
|
||||
if(is_ai_eye(eyeobj))
|
||||
eyeobj.acceleration = !eyeobj.acceleration
|
||||
to_chat(usr, "Camera acceleration has been toggled [eyeobj.acceleration ? "on" : "off"].")
|
||||
|
||||
/mob/living/silicon/ai/handle_fire()
|
||||
return
|
||||
|
||||
@@ -28,7 +28,7 @@
|
||||
|
||||
else if(iscarbon(speaker)) // Nonhuman carbon mob
|
||||
jobname = "No ID"
|
||||
else if(isAI(speaker))
|
||||
else if(is_ai(speaker))
|
||||
jobname = "AI"
|
||||
else if(isrobot(speaker))
|
||||
jobname = "Cyborg"
|
||||
|
||||
@@ -1,177 +0,0 @@
|
||||
// CAMERA NET
|
||||
//
|
||||
// The datum containing all the chunks.
|
||||
GLOBAL_DATUM_INIT(cameranet, /datum/cameranet, new())
|
||||
|
||||
/datum/cameranet
|
||||
var/name = "Camera Net" // Name to show for VV and stat()
|
||||
|
||||
// The cameras on the map, no matter if they work or not. Updated in obj/machinery/camera.dm by New() and Destroy().
|
||||
var/list/cameras = list()
|
||||
// The chunks of the map, mapping the areas that the cameras can see.
|
||||
var/list/chunks = list()
|
||||
var/ready = FALSE
|
||||
|
||||
// Checks if a chunk has been Generated in x, y, z.
|
||||
/datum/cameranet/proc/chunkGenerated(x, y, z)
|
||||
x &= ~(CAMERA_CHUNK_SIZE - 1)
|
||||
y &= ~(CAMERA_CHUNK_SIZE - 1)
|
||||
var/key = "[x],[y],[z]"
|
||||
return (chunks[key])
|
||||
|
||||
// Returns the chunk in the x, y, z.
|
||||
// If there is no chunk, it creates a new chunk and returns that.
|
||||
/datum/cameranet/proc/getCameraChunk(x, y, z)
|
||||
x &= ~(CAMERA_CHUNK_SIZE - 1)
|
||||
y &= ~(CAMERA_CHUNK_SIZE - 1)
|
||||
var/key = "[x],[y],[z]"
|
||||
if(!chunks[key])
|
||||
chunks[key] = new /datum/camerachunk(null, x, y, z)
|
||||
|
||||
return chunks[key]
|
||||
|
||||
// Updates what the aiEye can see. It is recommended you use this when the aiEye moves or it's location is set.
|
||||
|
||||
/datum/cameranet/proc/visibility(list/moved_eyes, client/C, list/other_eyes)
|
||||
if(!islist(moved_eyes))
|
||||
moved_eyes = moved_eyes ? list(moved_eyes) : list()
|
||||
if(islist(other_eyes))
|
||||
other_eyes = (other_eyes - moved_eyes)
|
||||
else
|
||||
other_eyes = list()
|
||||
|
||||
var/list/chunks_pre_seen = list()
|
||||
var/list/chunks_post_seen = list()
|
||||
|
||||
for(var/V in moved_eyes)
|
||||
var/mob/camera/ai_eye/eye = V
|
||||
if(C)
|
||||
chunks_pre_seen |= eye.visibleCameraChunks
|
||||
// 0xf = 15
|
||||
var/static_range = eye.static_visibility_range
|
||||
var/x1 = max(0, eye.x - static_range) & ~(CAMERA_CHUNK_SIZE - 1)
|
||||
var/y1 = max(0, eye.y - static_range) & ~(CAMERA_CHUNK_SIZE - 1)
|
||||
var/x2 = min(world.maxx, eye.x + static_range) & ~(CAMERA_CHUNK_SIZE - 1)
|
||||
var/y2 = min(world.maxy, eye.y + static_range) & ~(CAMERA_CHUNK_SIZE - 1)
|
||||
|
||||
var/list/visibleChunks = list()
|
||||
|
||||
for(var/x = x1; x <= x2; x += CAMERA_CHUNK_SIZE)
|
||||
for(var/y = y1; y <= y2; y += CAMERA_CHUNK_SIZE)
|
||||
visibleChunks |= getCameraChunk(x, y, eye.z)
|
||||
|
||||
var/list/remove = eye.visibleCameraChunks - visibleChunks
|
||||
var/list/add = visibleChunks - eye.visibleCameraChunks
|
||||
|
||||
for(var/chunk in remove)
|
||||
var/datum/camerachunk/c = chunk
|
||||
c.remove(eye, FALSE)
|
||||
|
||||
for(var/chunk in add)
|
||||
var/datum/camerachunk/c = chunk
|
||||
c.add(eye, FALSE)
|
||||
|
||||
if(C)
|
||||
chunks_post_seen |= eye.visibleCameraChunks
|
||||
|
||||
if(C)
|
||||
for(var/V in other_eyes)
|
||||
var/mob/camera/ai_eye/eye = V
|
||||
chunks_post_seen |= eye.visibleCameraChunks
|
||||
|
||||
var/list/remove = chunks_pre_seen - chunks_post_seen
|
||||
var/list/add = chunks_post_seen - chunks_pre_seen
|
||||
|
||||
for(var/chunk in remove)
|
||||
var/datum/camerachunk/c = chunk
|
||||
C.images -= c.obscured
|
||||
|
||||
for(var/chunk in add)
|
||||
var/datum/camerachunk/c = chunk
|
||||
C.images += c.obscured
|
||||
|
||||
|
||||
// Updates the chunks that the turf is located in. Use this when obstacles are destroyed or when doors open.
|
||||
|
||||
/datum/cameranet/proc/updateVisibility(atom/A, opacity_check = 1)
|
||||
|
||||
if(!SSticker || (opacity_check && !A.opacity))
|
||||
return
|
||||
majorChunkChange(A, 2)
|
||||
|
||||
/datum/cameranet/proc/updateChunk(x, y, z)
|
||||
// 0xf = 15
|
||||
if(!chunkGenerated(x, y, z))
|
||||
return
|
||||
var/datum/camerachunk/chunk = getCameraChunk(x, y, z)
|
||||
chunk.hasChanged()
|
||||
|
||||
// Removes a camera from a chunk.
|
||||
|
||||
/datum/cameranet/proc/removeCamera(obj/machinery/camera/c)
|
||||
majorChunkChange(c, 0)
|
||||
|
||||
// Add a camera to a chunk.
|
||||
|
||||
/datum/cameranet/proc/addCamera(obj/machinery/camera/c)
|
||||
majorChunkChange(c, 1)
|
||||
|
||||
// Used for Cyborg cameras. Since portable cameras can be in ANY chunk.
|
||||
|
||||
/datum/cameranet/proc/updatePortableCamera(obj/machinery/camera/c, turf/old_loc)
|
||||
majorChunkChange(c, 1, old_loc)
|
||||
|
||||
// Never access this proc directly!!!!
|
||||
// This will update the chunk and all the surrounding chunks.
|
||||
// It will also add the atom to the cameras list if you set the choice to 1.
|
||||
// Setting the choice to 0 will remove the camera from the chunks.
|
||||
// If you want to update the chunks around an object, without adding/removing a camera, use choice 2.
|
||||
|
||||
/datum/cameranet/proc/majorChunkChange(atom/c, choice, turf/old_loc = null)
|
||||
// 0xf = 15
|
||||
if(!c)
|
||||
return
|
||||
|
||||
var/turf/T = get_turf(c)
|
||||
if(!T)
|
||||
return
|
||||
|
||||
if(old_loc)
|
||||
// Check if the current turf falls in the same chunka as the old_loc. If so, don't do anything
|
||||
if(T.x & ~(CAMERA_CHUNK_SIZE - 1) == old_loc.x & ~(CAMERA_CHUNK_SIZE - 1) && T.y & ~(CAMERA_CHUNK_SIZE - 1) == old_loc.y & ~(CAMERA_CHUNK_SIZE - 1))
|
||||
return
|
||||
|
||||
// Use camera view distance here to actually know how far a camera can max watch
|
||||
var/x1 = max(0, T.x - CAMERA_VIEW_DISTANCE) & ~(CAMERA_CHUNK_SIZE - 1)
|
||||
var/y1 = max(0, T.y - CAMERA_VIEW_DISTANCE) & ~(CAMERA_CHUNK_SIZE - 1)
|
||||
var/x2 = min(world.maxx, T.x + CAMERA_VIEW_DISTANCE) & ~(CAMERA_CHUNK_SIZE - 1)
|
||||
var/y2 = min(world.maxy, T.y + CAMERA_VIEW_DISTANCE) & ~(CAMERA_CHUNK_SIZE - 1)
|
||||
|
||||
for(var/x = x1; x <= x2; x += CAMERA_CHUNK_SIZE)
|
||||
for(var/y = y1; y <= y2; y += CAMERA_CHUNK_SIZE)
|
||||
if(chunkGenerated(x, y, T.z))
|
||||
var/datum/camerachunk/chunk = getCameraChunk(x, y, T.z)
|
||||
if(choice == 0)
|
||||
// Remove the camera.
|
||||
chunk.remove_camera(c)
|
||||
else if(choice == 1)
|
||||
// You can't have the same camera in the list twice.
|
||||
chunk.add_camera(c)
|
||||
chunk.hasChanged()
|
||||
|
||||
// Will check if a mob is on a viewable turf. Returns 1 if it is, otherwise returns 0.
|
||||
|
||||
/datum/cameranet/proc/checkCameraVis(mob/living/target as mob)
|
||||
|
||||
// 0xf = 15
|
||||
var/turf/position = get_turf(target)
|
||||
return checkTurfVis(position)
|
||||
|
||||
/datum/cameranet/proc/checkTurfVis(turf/position)
|
||||
var/datum/camerachunk/chunk = getCameraChunk(position.x, position.y, position.z)
|
||||
if(chunk)
|
||||
if(chunk.changed)
|
||||
chunk.hasChanged(1) // Update now, no matter if it's visible or not.
|
||||
if(chunk.visibleTurfs[position])
|
||||
return 1
|
||||
return 0
|
||||
@@ -1,155 +0,0 @@
|
||||
// AI EYE
|
||||
//
|
||||
// An invisible (no icon) mob that the AI controls to look around the station with.
|
||||
// It streams chunks as it moves around, which will show it what the AI can and cannot see.
|
||||
|
||||
/mob/camera/ai_eye
|
||||
name = "Inactive AI Eye"
|
||||
|
||||
icon = 'icons/mob/ai.dmi' //Allows ghosts to see what the AI is looking at.
|
||||
icon_state = "eye"
|
||||
alpha = 127
|
||||
invisibility = SEE_INVISIBLE_OBSERVER
|
||||
|
||||
var/list/visibleCameraChunks = list()
|
||||
var/mob/living/silicon/ai/ai = null
|
||||
var/relay_speech = FALSE
|
||||
var/use_static = TRUE
|
||||
var/static_visibility_range = 16
|
||||
// Decides if it is shown by AI Detector or not
|
||||
var/ai_detector_visible = TRUE
|
||||
|
||||
|
||||
// Use this when setting the aiEye's location.
|
||||
// It will also stream the chunk that the new loc is in.
|
||||
|
||||
/mob/camera/ai_eye/setLoc(T)
|
||||
if(ai)
|
||||
if(!isturf(ai.loc))
|
||||
return
|
||||
T = get_turf(T)
|
||||
..(T)
|
||||
if(use_static)
|
||||
ai.camera_visibility(src)
|
||||
if(ai.client)
|
||||
ai.client.eye = src
|
||||
update_parallax_contents()
|
||||
//Holopad
|
||||
if(istype(ai.current, /obj/machinery/hologram/holopad))
|
||||
var/obj/machinery/hologram/holopad/H = ai.current
|
||||
H.move_hologram(ai, T)
|
||||
|
||||
/mob/camera/ai_eye/Move()
|
||||
return 0
|
||||
|
||||
/mob/camera/ai_eye/Process_Spacemove(movement_dir)
|
||||
// Nothing in space can stop us from moving.
|
||||
return 1
|
||||
|
||||
/mob/camera/ai_eye/proc/GetViewerClient()
|
||||
if(ai)
|
||||
return ai.client
|
||||
return null
|
||||
|
||||
/mob/camera/ai_eye/proc/RemoveImages()
|
||||
var/client/C = GetViewerClient()
|
||||
if(C && use_static)
|
||||
for(var/V in visibleCameraChunks)
|
||||
var/datum/camerachunk/chunk = V
|
||||
C.images -= chunk.obscured
|
||||
|
||||
/mob/camera/ai_eye/Destroy()
|
||||
if(ai)
|
||||
ai.all_eyes -= src
|
||||
ai = null
|
||||
for(var/V in visibleCameraChunks)
|
||||
var/datum/camerachunk/chunk = V
|
||||
chunk.remove(src)
|
||||
return ..()
|
||||
|
||||
/atom/proc/move_camera_by_click()
|
||||
if(isAI(usr))
|
||||
var/mob/living/silicon/ai/AI = usr
|
||||
if(AI.eyeobj && (AI.client.eye == AI.eyeobj) && (AI.eyeobj.z == z))
|
||||
AI.cameraFollow = null
|
||||
if(isturf(loc) || isturf(src))
|
||||
AI.eyeobj.setLoc(src)
|
||||
|
||||
// AI MOVEMENT
|
||||
|
||||
// This will move the AIEye. It will also cause lights near the eye to light up, if toggled.
|
||||
// This is handled in the proc below this one.
|
||||
|
||||
/client/proc/AIMove(n, direct, mob/living/silicon/ai/user)
|
||||
|
||||
var/initial = initial(user.sprint)
|
||||
var/max_sprint = 50
|
||||
|
||||
if(user.cooldown && user.cooldown < world.timeofday) // 3 seconds
|
||||
user.sprint = initial
|
||||
|
||||
for(var/i = 0; i < max(user.sprint, initial); i += 20)
|
||||
var/turf/step = get_turf(get_step(user.eyeobj, direct))
|
||||
if(step)
|
||||
user.eyeobj.setLoc(step)
|
||||
|
||||
user.cooldown = world.timeofday + 5
|
||||
if(user.acceleration)
|
||||
user.sprint = min(user.sprint + 0.5, max_sprint)
|
||||
else
|
||||
user.sprint = initial
|
||||
|
||||
if(!user.tracking)
|
||||
user.cameraFollow = null
|
||||
|
||||
//user.unset_machine() //Uncomment this if it causes problems.
|
||||
//user.lightNearbyCamera()
|
||||
if(user.camera_light_on)
|
||||
user.light_cameras()
|
||||
|
||||
// Return to the Core.
|
||||
/mob/living/silicon/ai/proc/core()
|
||||
set category = "AI Commands"
|
||||
set name = "AI Core"
|
||||
|
||||
view_core()
|
||||
|
||||
/mob/living/silicon/ai/proc/view_core()
|
||||
|
||||
current = null
|
||||
cameraFollow = null
|
||||
unset_machine()
|
||||
|
||||
if(src.eyeobj && src.loc)
|
||||
src.eyeobj.loc = src.loc
|
||||
else
|
||||
to_chat(src, "ERROR: Eyeobj not found. Creating new eye...")
|
||||
create_eye()
|
||||
|
||||
eyeobj.setLoc(loc)
|
||||
|
||||
/mob/living/silicon/ai/proc/create_eye()
|
||||
if(eyeobj)
|
||||
return
|
||||
eyeobj = new /mob/camera/ai_eye()
|
||||
all_eyes += eyeobj
|
||||
eyeobj.ai = src
|
||||
eyeobj.setLoc(loc)
|
||||
eyeobj.name = "[name] (AI Eye)"
|
||||
|
||||
/mob/living/silicon/ai/proc/toggle_acceleration()
|
||||
set category = "AI Commands"
|
||||
set name = "Toggle Camera Acceleration"
|
||||
|
||||
if(usr.stat == DEAD)
|
||||
return //won't work if dead
|
||||
acceleration = !acceleration
|
||||
to_chat(usr, "Camera acceleration has been toggled [acceleration ? "on" : "off"].")
|
||||
|
||||
/mob/camera/ai_eye/hear_say(list/message_pieces, verb = "says", italics = 0, mob/speaker = null, sound/speech_sound, sound_vol, sound_frequency, use_voice = TRUE)
|
||||
if(relay_speech)
|
||||
if(istype(ai))
|
||||
ai.relay_speech(speaker, message_pieces, verb)
|
||||
else
|
||||
var/mob/M = ai
|
||||
M.hear_say(message_pieces, verb, italics, speaker, speech_sound, sound_vol, sound_frequency)
|
||||
@@ -1424,7 +1424,7 @@ GLOBAL_LIST_INIT(robot_verbs_default, list(
|
||||
. = ..()
|
||||
if(camera && last_camera_update + CAMERA_UPDATE_COOLDOWN < world.time)
|
||||
last_camera_update = world.time
|
||||
GLOB.cameranet.updatePortableCamera(camera, OldLoc)
|
||||
GLOB.cameranet.update_portable_camera(camera, OldLoc)
|
||||
SEND_SIGNAL(camera, COMSIG_CAMERA_MOVED, OldLoc)
|
||||
|
||||
#undef CAMERA_UPDATE_COOLDOWN
|
||||
|
||||
@@ -805,8 +805,8 @@ GLOBAL_LIST_INIT(slot_equipment_priority, list( \
|
||||
reset_perspective(null)
|
||||
unset_machine()
|
||||
if(isliving(src))
|
||||
if(src:cameraFollow)
|
||||
src:cameraFollow = null
|
||||
if(src:camera_follow)
|
||||
src:camera_follow = null
|
||||
|
||||
/mob/Topic(href, href_list)
|
||||
if(href_list["flavor_more"])
|
||||
|
||||
@@ -461,7 +461,7 @@
|
||||
if(hud_used && hud_used.action_intent)
|
||||
hud_used.action_intent.icon_state = "[a_intent]"
|
||||
|
||||
else if(isrobot(src) || islarva(src) || isanimal(src) || isAI(src))
|
||||
else if(isrobot(src) || islarva(src) || isanimal(src) || is_ai(src))
|
||||
switch(input)
|
||||
if(INTENT_HELP)
|
||||
a_intent = INTENT_HELP
|
||||
@@ -511,7 +511,7 @@
|
||||
var/obj/item/multitool/P
|
||||
if(isrobot(user) || ishuman(user))
|
||||
P = user.get_active_hand()
|
||||
else if(isAI(user))
|
||||
else if(is_ai(user))
|
||||
var/mob/living/silicon/ai/AI=user
|
||||
P = AI.aiMulti
|
||||
|
||||
|
||||
@@ -91,12 +91,17 @@
|
||||
if(mob.remote_control) //we're controlling something, our movement is relayed to it
|
||||
return mob.remote_control.relaymove(mob, direct)
|
||||
|
||||
if(isAI(mob))
|
||||
if(istype(mob.loc, /obj/item/aicard))
|
||||
var/obj/O = mob.loc
|
||||
return O.relaymove(mob, direct) // aicards have special relaymove stuff
|
||||
return AIMove(n, direct, mob)
|
||||
|
||||
if(is_ai(mob))
|
||||
var/mob/living/silicon/ai/ai = mob
|
||||
var/mob/camera/eye/ai/eye = ai.eyeobj
|
||||
if(istype(eye) && !istype(ai.remote_control))
|
||||
ai.remote_control = eye
|
||||
return eye.relaymove(mob, direct)
|
||||
if(!istype(eye) && !istype(mob.loc, /obj/item/aicard))
|
||||
eye = new /mob/camera/eye/ai(mob.loc, ai.name, ai, ai)
|
||||
if(istype(eye))
|
||||
return eye.relaymove(mob, direct)
|
||||
return FALSE // If the AI is outside of its eye or a mech (e.g. carded), it can't move
|
||||
|
||||
if(Process_Grab())
|
||||
return
|
||||
|
||||
@@ -89,7 +89,7 @@
|
||||
var/mob/other_mob = other
|
||||
if(other_mob.universal_speak)
|
||||
return TRUE
|
||||
if(isAI(src) && ispAI(other_mob))
|
||||
if(is_ai(src) && ispAI(other_mob))
|
||||
return TRUE
|
||||
if(istype(other_mob, src.type) || istype(src, other_mob.type))
|
||||
return TRUE
|
||||
|
||||
@@ -525,7 +525,7 @@
|
||||
toner = 0
|
||||
|
||||
/obj/machinery/photocopier/MouseDrop_T(mob/target, mob/living/user)
|
||||
if(!istype(target) || target.buckled || get_dist(user, src) > 1 || get_dist(user, target) > 1 || user.stat || isAI(user) || target.move_resist > user.pull_force)
|
||||
if(!istype(target) || target.buckled || get_dist(user, src) > 1 || get_dist(user, target) > 1 || user.stat || is_ai(user) || target.move_resist > user.pull_force)
|
||||
return
|
||||
if(check_mob()) //is target mob or another mob on this photocopier already?
|
||||
return
|
||||
|
||||
@@ -165,7 +165,7 @@
|
||||
deletepicture(src)
|
||||
|
||||
/obj/item/camera/siliconcam/proc/getsource()
|
||||
if(isAI(loc))
|
||||
if(is_ai(loc))
|
||||
return src
|
||||
|
||||
var/mob/living/silicon/robot/C = loc
|
||||
|
||||
@@ -518,7 +518,7 @@
|
||||
/obj/machinery/power/apc/proc/is_authenticated(mob/user as mob)
|
||||
if(user.can_admin_interact())
|
||||
return TRUE
|
||||
if(isAI(user) || isrobot(user) || user.has_unlimited_silicon_privilege)
|
||||
if(is_ai(user) || isrobot(user) || user.has_unlimited_silicon_privilege)
|
||||
return TRUE
|
||||
else
|
||||
return !locked
|
||||
@@ -526,7 +526,7 @@
|
||||
/obj/machinery/power/apc/proc/is_locked(mob/user as mob)
|
||||
if(user.can_admin_interact())
|
||||
return FALSE
|
||||
if(isAI(user) || isrobot(user) || user.has_unlimited_silicon_privilege)
|
||||
if(is_ai(user) || isrobot(user) || user.has_unlimited_silicon_privilege)
|
||||
return FALSE
|
||||
else
|
||||
return locked
|
||||
|
||||
@@ -263,7 +263,7 @@
|
||||
var/list/data = list()
|
||||
|
||||
data["active"] = active
|
||||
if(isAI(user))
|
||||
if(is_ai(user))
|
||||
data["is_ai"] = TRUE
|
||||
else if(isrobot(user) && !Adjacent(user))
|
||||
data["is_ai"] = TRUE
|
||||
|
||||
@@ -52,7 +52,7 @@
|
||||
impact_light_color_override = LIGHT_COLOR_DARKRED
|
||||
|
||||
/obj/item/projectile/beam/laser/ai_turret/prehit(atom/target)
|
||||
if(isAI(target))
|
||||
if(is_ai(target))
|
||||
damage = 0 //cheater cheater I don't want AI to die to stupid placement eater
|
||||
nodamage = 1
|
||||
if(isliving(target))
|
||||
|
||||
@@ -273,7 +273,7 @@
|
||||
// mouse drop another mob or self
|
||||
//
|
||||
/obj/machinery/disposal/MouseDrop_T(mob/living/target, mob/living/user)
|
||||
if(!istype(target) || target.buckled || target.has_buckled_mobs() || get_dist(user, src) > 1 || get_dist(user, target) > 1 || user.stat || isAI(user))
|
||||
if(!istype(target) || target.buckled || target.has_buckled_mobs() || get_dist(user, src) > 1 || get_dist(user, target) > 1 || user.stat || is_ai(user))
|
||||
return
|
||||
|
||||
// Animals cannot put mobs other than themselves into disposals.
|
||||
@@ -389,7 +389,7 @@
|
||||
/obj/machinery/disposal/ui_data(mob/user)
|
||||
var/list/data = list()
|
||||
|
||||
data["isAI"] = isAI(user)
|
||||
data["is_ai"] = is_ai(user)
|
||||
data["flushing"] = flush
|
||||
data["mode"] = mode
|
||||
data["pressure"] = round(clamp(100* air_contents.return_pressure() / (SEND_PRESSURE), 0, 100),1)
|
||||
|
||||
@@ -308,7 +308,7 @@
|
||||
. = ..()
|
||||
|
||||
/obj/machinery/disposal/delivery_chute/Bumped(atom/movable/AM) //Go straight into the chute
|
||||
if(isprojectile(AM) || isAI(AM) || QDELETED(AM))
|
||||
if(isprojectile(AM) || is_ai(AM) || QDELETED(AM))
|
||||
return
|
||||
|
||||
// We may already contain the object because thrown objects
|
||||
|
||||
@@ -1,26 +1,3 @@
|
||||
//Xenobio control console
|
||||
/mob/camera/ai_eye/remote/xenobio
|
||||
visible_icon = 1
|
||||
icon = 'icons/obj/abductor.dmi'
|
||||
icon_state = "camera_target"
|
||||
// The Xenobio Console does not trigger the AI Detector
|
||||
ai_detector_visible = FALSE
|
||||
/// Area that the xenobio camera eye is allowed to travel
|
||||
var/allowed_area = null
|
||||
|
||||
/mob/camera/ai_eye/remote/xenobio/Initialize(mapload)
|
||||
. = ..()
|
||||
var/area/A = get_area(loc)
|
||||
allowed_area = A.name
|
||||
|
||||
/mob/camera/ai_eye/remote/xenobio/setLoc(t)
|
||||
var/area/new_area = get_area(t)
|
||||
if(!new_area)
|
||||
return
|
||||
if(new_area.name != allowed_area && !new_area.xenobiology_compatible)
|
||||
return
|
||||
return ..()
|
||||
|
||||
/*
|
||||
* # Slime Management Console
|
||||
*
|
||||
@@ -54,6 +31,10 @@
|
||||
if(!connected_recycler)
|
||||
locate_recycler()
|
||||
|
||||
/obj/machinery/computer/camera_advanced/xenobio/CreateEye()
|
||||
eyeobj = new /mob/camera/eye/xenobio(loc, name, src, current_user)
|
||||
give_eye_control(current_user)
|
||||
|
||||
/obj/machinery/computer/camera_advanced/xenobio/proc/locate_recycler()
|
||||
for(var/obj/machinery/monkey_recycler/recycler in GLOB.monkey_recyclers)
|
||||
if(get_area(recycler) == get_area(loc))
|
||||
@@ -79,14 +60,6 @@
|
||||
stored_slimes -= A
|
||||
return ..()
|
||||
|
||||
/obj/machinery/computer/camera_advanced/xenobio/CreateEye()
|
||||
eyeobj = new /mob/camera/ai_eye/remote/xenobio(get_turf(src))
|
||||
eyeobj.origin = src
|
||||
eyeobj.visible_icon = TRUE
|
||||
eyeobj.acceleration = FALSE
|
||||
eyeobj.icon = 'icons/obj/abductor.dmi'
|
||||
eyeobj.icon_state = "camera_target"
|
||||
|
||||
/obj/machinery/computer/camera_advanced/xenobio/GrantActions(mob/living/carbon/user)
|
||||
..()
|
||||
|
||||
@@ -223,13 +196,13 @@
|
||||
if(!target || !ishuman(owner))
|
||||
return
|
||||
var/mob/living/carbon/human/C = owner
|
||||
var/mob/camera/ai_eye/remote/xenobio/remote_eye = C.remote_control
|
||||
var/mob/camera/eye/xenobio/remote_eye = C.remote_control
|
||||
var/obj/machinery/computer/camera_advanced/xenobio/X = target
|
||||
|
||||
if(iswallturf(remote_eye.loc))
|
||||
to_chat(owner, "You can't place slime here.")
|
||||
return
|
||||
else if(GLOB.cameranet.checkTurfVis(remote_eye.loc))
|
||||
else if(GLOB.cameranet.check_turf_vis(remote_eye.loc))
|
||||
for(var/mob/living/simple_animal/slime/S in X.stored_slimes)
|
||||
X.release_slime(S, remote_eye.loc)
|
||||
else
|
||||
@@ -243,10 +216,10 @@
|
||||
if(!target || !ishuman(owner))
|
||||
return
|
||||
var/mob/living/carbon/human/C = owner
|
||||
var/mob/camera/ai_eye/remote/xenobio/remote_eye = C.remote_control
|
||||
var/mob/camera/eye/xenobio/remote_eye = C.remote_control
|
||||
var/obj/machinery/computer/camera_advanced/xenobio/X = target
|
||||
|
||||
if(GLOB.cameranet.checkTurfVis(remote_eye.loc))
|
||||
if(GLOB.cameranet.check_turf_vis(remote_eye.loc))
|
||||
for(var/mob/living/simple_animal/slime/S in remote_eye.loc)
|
||||
if(length(X.stored_slimes) >= X.max_slimes)
|
||||
break
|
||||
@@ -265,11 +238,11 @@
|
||||
if(!target || !ishuman(owner))
|
||||
return
|
||||
var/mob/living/carbon/human/C = owner
|
||||
var/mob/camera/ai_eye/remote/xenobio/remote_eye = C.remote_control
|
||||
var/mob/camera/eye/xenobio/remote_eye = C.remote_control
|
||||
var/obj/machinery/computer/camera_advanced/xenobio/X = target
|
||||
var/obj/machinery/monkey_recycler/recycler = X.connected_recycler
|
||||
|
||||
if(GLOB.cameranet.checkTurfVis(remote_eye.loc))
|
||||
if(GLOB.cameranet.check_turf_vis(remote_eye.loc))
|
||||
if(LAZYLEN(SSmobs.cubemonkeys) >= GLOB.configuration.general.monkey_cube_cap)
|
||||
to_chat(owner, "<span class='warning'>Bluespace harmonics prevent the spawning of more than [GLOB.configuration.general.monkey_cube_cap] monkeys on the station at one time!</span>")
|
||||
return
|
||||
@@ -309,14 +282,14 @@
|
||||
if(!target || !ishuman(owner))
|
||||
return
|
||||
var/mob/living/carbon/human/C = owner
|
||||
var/mob/camera/ai_eye/remote/xenobio/remote_eye = C.remote_control
|
||||
var/mob/camera/eye/xenobio/remote_eye = C.remote_control
|
||||
var/obj/machinery/computer/camera_advanced/xenobio/X = target
|
||||
var/obj/machinery/monkey_recycler/recycler = X.connected_recycler
|
||||
|
||||
if(!recycler)
|
||||
to_chat(owner, "<span class='notice'>There is no connected monkey recycler. Use a multitool to link one.</span>")
|
||||
return
|
||||
if(GLOB.cameranet.checkTurfVis(remote_eye.loc))
|
||||
if(GLOB.cameranet.check_turf_vis(remote_eye.loc))
|
||||
for(var/mob/living/carbon/human/M in remote_eye.loc)
|
||||
if(issmall(M) && M.stat)
|
||||
M.visible_message("[M] vanishes as [M.p_theyre()] reclaimed for recycling!")
|
||||
@@ -334,9 +307,9 @@
|
||||
if(!target || !isliving(owner))
|
||||
return
|
||||
var/mob/living/C = owner
|
||||
var/mob/camera/ai_eye/remote/xenobio/remote_eye = C.remote_control
|
||||
var/mob/camera/eye/xenobio/remote_eye = C.remote_control
|
||||
|
||||
if(GLOB.cameranet.checkTurfVis(remote_eye.loc))
|
||||
if(GLOB.cameranet.check_turf_vis(remote_eye.loc))
|
||||
for(var/mob/living/simple_animal/slime/S in remote_eye.loc)
|
||||
slime_scan(S, C)
|
||||
else
|
||||
@@ -351,14 +324,14 @@
|
||||
return
|
||||
|
||||
var/mob/living/carbon/human/C = owner
|
||||
var/mob/camera/ai_eye/remote/xenobio/remote_eye = C.remote_control
|
||||
var/mob/camera/eye/xenobio/remote_eye = C.remote_control
|
||||
var/obj/machinery/computer/camera_advanced/xenobio/X = target
|
||||
|
||||
if(QDELETED(X.current_potion))
|
||||
to_chat(owner, "<span class='warning'>No potion loaded.</span>")
|
||||
return
|
||||
|
||||
if(GLOB.cameranet.checkTurfVis(remote_eye.loc))
|
||||
if(GLOB.cameranet.check_turf_vis(remote_eye.loc))
|
||||
for(var/mob/living/simple_animal/slime/S in remote_eye.loc)
|
||||
X.current_potion.attack__legacy__attackchain(S, C)
|
||||
break
|
||||
@@ -416,22 +389,22 @@
|
||||
|
||||
// Scans slime
|
||||
/obj/machinery/computer/camera_advanced/xenobio/proc/XenoSlimeClickCtrl(mob/living/user, mob/living/simple_animal/slime/S)
|
||||
if(!GLOB.cameranet.checkTurfVis(S.loc))
|
||||
if(!GLOB.cameranet.check_turf_vis(S.loc))
|
||||
to_chat(user, "<span class='warning'>Target is not near a camera. Cannot proceed.</span>")
|
||||
return
|
||||
var/mob/living/C = user
|
||||
var/mob/camera/ai_eye/remote/xenobio/E = C.remote_control
|
||||
var/mob/camera/eye/xenobio/E = C.remote_control
|
||||
var/area/mobarea = get_area(S.loc)
|
||||
if(mobarea.name == E.allowed_area || mobarea.xenobiology_compatible)
|
||||
slime_scan(S, C)
|
||||
|
||||
//Feeds a potion to slime
|
||||
/obj/machinery/computer/camera_advanced/xenobio/proc/XenoSlimeClickAlt(mob/living/user, mob/living/simple_animal/slime/S)
|
||||
if(!GLOB.cameranet.checkTurfVis(S.loc))
|
||||
if(!GLOB.cameranet.check_turf_vis(S.loc))
|
||||
to_chat(user, "<span class='warning'>Target is not near a camera. Cannot proceed.</span>")
|
||||
return
|
||||
var/mob/living/C = user
|
||||
var/mob/camera/ai_eye/remote/xenobio/E = C.remote_control
|
||||
var/mob/camera/eye/xenobio/E = C.remote_control
|
||||
var/obj/machinery/computer/camera_advanced/xenobio/X = E.origin
|
||||
var/area/mobarea = get_area(S.loc)
|
||||
if(!X.current_potion)
|
||||
@@ -442,11 +415,11 @@
|
||||
|
||||
//Picks up slime
|
||||
/obj/machinery/computer/camera_advanced/xenobio/proc/XenoSlimeClickShift(mob/living/user, mob/living/simple_animal/slime/S)
|
||||
if(!GLOB.cameranet.checkTurfVis(S.loc))
|
||||
if(!GLOB.cameranet.check_turf_vis(S.loc))
|
||||
to_chat(user, "<span class='warning'>Target is not near a camera. Cannot proceed.</span>")
|
||||
return
|
||||
var/mob/living/C = user
|
||||
var/mob/camera/ai_eye/remote/xenobio/E = C.remote_control
|
||||
var/mob/camera/eye/xenobio/E = C.remote_control
|
||||
var/obj/machinery/computer/camera_advanced/xenobio/X = E.origin
|
||||
var/area/mobarea = get_area(S.loc)
|
||||
if(mobarea.name == E.allowed_area || mobarea.xenobiology_compatible)
|
||||
@@ -463,11 +436,11 @@
|
||||
|
||||
//Place slimes
|
||||
/obj/machinery/computer/camera_advanced/xenobio/proc/XenoTurfClickShift(mob/living/user, turf/T)
|
||||
if(!GLOB.cameranet.checkTurfVis(T))
|
||||
if(!GLOB.cameranet.check_turf_vis(T))
|
||||
to_chat(user, "<span class='warning'>Target is not near a camera. Cannot proceed.</span>")
|
||||
return
|
||||
var/mob/living/C = user
|
||||
var/mob/camera/ai_eye/remote/xenobio/E = C.remote_control
|
||||
var/mob/camera/eye/xenobio/E = C.remote_control
|
||||
var/obj/machinery/computer/camera_advanced/xenobio/X = E.origin
|
||||
var/area/turfarea = get_area(T)
|
||||
if(iswallturf(T))
|
||||
@@ -479,11 +452,11 @@
|
||||
|
||||
//Place monkey
|
||||
/obj/machinery/computer/camera_advanced/xenobio/proc/XenoTurfClickCtrl(mob/living/user, turf/T)
|
||||
if(!GLOB.cameranet.checkTurfVis(T))
|
||||
if(!GLOB.cameranet.check_turf_vis(T))
|
||||
to_chat(user, "<span class='warning'>Target is not near a camera. Cannot proceed.</span>")
|
||||
return
|
||||
var/mob/living/C = user
|
||||
var/mob/camera/ai_eye/remote/xenobio/E = C.remote_control
|
||||
var/mob/camera/eye/xenobio/E = C.remote_control
|
||||
var/obj/machinery/computer/camera_advanced/xenobio/X = E.origin
|
||||
var/obj/machinery/monkey_recycler/recycler = X.connected_recycler
|
||||
var/area/turfarea = get_area(T)
|
||||
@@ -513,11 +486,11 @@
|
||||
|
||||
//Pick up monkey
|
||||
/obj/machinery/computer/camera_advanced/xenobio/proc/XenoMonkeyClickCtrl(mob/living/user, mob/living/carbon/human/M)
|
||||
if(!GLOB.cameranet.checkTurfVis(M.loc))
|
||||
if(!GLOB.cameranet.check_turf_vis(M.loc))
|
||||
to_chat(user, "<span class='warning'>Target is not near a camera. Cannot proceed.</span>")
|
||||
return
|
||||
var/mob/living/C = user
|
||||
var/mob/camera/ai_eye/remote/xenobio/E = C.remote_control
|
||||
var/mob/camera/eye/xenobio/E = C.remote_control
|
||||
var/obj/machinery/computer/camera_advanced/xenobio/X = E.origin
|
||||
var/area/mobarea = get_area(M.loc)
|
||||
var/obj/machinery/monkey_recycler/recycler = X.connected_recycler
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user