Skip to content

Commit

Permalink
Refactors AI / camera eyes and slows holopad holograms to walk speed (#…
Browse files Browse the repository at this point in the history
…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>
  • Loading branch information
4 people authored Jan 17, 2025
1 parent dac5700 commit 93ed0f0
Show file tree
Hide file tree
Showing 107 changed files with 913 additions and 823 deletions.
4 changes: 2 additions & 2 deletions code/__DEFINES/mob_defines.dm
Original file line number Diff line number Diff line change
Expand Up @@ -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))
Expand All @@ -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))
Expand Down
2 changes: 1 addition & 1 deletion code/__HELPERS/unsorted.dm
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand Down
12 changes: 6 additions & 6 deletions code/_onclick/ai_onclick.dm
Original file line number Diff line number Diff line change
Expand Up @@ -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

Expand Down Expand Up @@ -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
Expand Down
4 changes: 2 additions & 2 deletions code/_onclick/hud/ai_hud.dm
Original file line number Diff line number Diff line change
Expand Up @@ -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()

Expand Down Expand Up @@ -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))
Expand Down
2 changes: 1 addition & 1 deletion code/_onclick/hud/alert.dm
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
2 changes: 1 addition & 1 deletion code/controllers/subsystem/SSshuttles.dm
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
2 changes: 1 addition & 1 deletion code/controllers/subsystem/tickets/SStickets.dm
Original file line number Diff line number Diff line change
Expand Up @@ -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()
Expand Down
6 changes: 3 additions & 3 deletions code/datums/diseases/magnitis.dm
Original file line number Diff line number Diff line change
Expand Up @@ -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))
Expand All @@ -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++)
Expand All @@ -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++)
Expand Down
2 changes: 1 addition & 1 deletion code/datums/emote.dm
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
56 changes: 24 additions & 32 deletions code/datums/holocall.dm
Original file line number Diff line number Diff line change
@@ -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
Expand Down Expand Up @@ -49,7 +48,7 @@
user.remote_control = null

if(!QDELETED(eye))
eye.RemoveImages()
eye.remove_images()
QDEL_NULL(eye)

if(connected_holopad && !QDELETED(hologram))
Expand Down Expand Up @@ -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)
Expand All @@ -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)
Expand All @@ -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
Expand All @@ -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
Expand All @@ -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"
Expand Down
4 changes: 2 additions & 2 deletions code/datums/keybindings/ai_keybinds.dm
Original file line number Diff line number Diff line change
Expand Up @@ -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"
Expand Down Expand Up @@ -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"
Expand Down
2 changes: 1 addition & 1 deletion code/datums/mind.dm
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand Down
2 changes: 1 addition & 1 deletion code/datums/station_traits/positive_traits.dm
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
6 changes: 3 additions & 3 deletions code/game/atoms_movable.dm
Original file line number Diff line number Diff line change
Expand Up @@ -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))
Expand Down
2 changes: 1 addition & 1 deletion code/game/data_huds.dm
Original file line number Diff line number Diff line change
Expand Up @@ -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]"
Expand Down
2 changes: 1 addition & 1 deletion code/game/gamemodes/autotraitor/autotraitor.dm
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand Down
10 changes: 5 additions & 5 deletions code/game/gamemodes/malfunction/Malf_Modules.dm
Original file line number Diff line number Diff line change
Expand Up @@ -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

Expand Down Expand Up @@ -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)
Expand Down Expand Up @@ -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
Expand Down
Loading

0 comments on commit 93ed0f0

Please sign in to comment.