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:
asciodev
2025-01-17 18:22:43 +00:00
committed by GitHub
co-authored by Luc GDN Drsmail
parent dac57002ff
commit 93ed0f096d
107 changed files with 912 additions and 822 deletions
+3 -3
View File
@@ -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))
+1 -1
View File
@@ -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)
+1 -1
View File
@@ -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)
+1 -1
View File
@@ -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))
+1 -1
View File
@@ -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)
+6 -6
View File
@@ -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)
+1 -1
View File
@@ -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()
+1 -1
View File
@@ -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
+14 -14
View File
@@ -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)
+16 -103
View File
@@ -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'>&#09;[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))
+1 -1
View File
@@ -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()
+1 -1
View File
@@ -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)
+15 -8
View File
@@ -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
+1 -1
View File
@@ -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)
+1 -1
View File
@@ -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.
+1 -1
View File
@@ -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
+4 -4
View File
@@ -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>")
+2 -2
View File
@@ -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
+1 -1
View File
@@ -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
+12 -7
View File
@@ -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 ---
+1 -1
View File
@@ -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>")
+4 -4
View File
@@ -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
+2 -2
View File
@@ -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.
+1 -1
View File
@@ -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
+2 -2
View File
@@ -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)
+1 -1
View File
@@ -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)
+4 -4
View File
@@ -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(..())
+2 -2
View File
@@ -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