diff --git a/code/game/machinery/camera/tracking.dm b/code/game/machinery/camera/tracking.dm
index f7fd84eca7..60541e0fe3 100644
--- a/code/game/machinery/camera/tracking.dm
+++ b/code/game/machinery/camera/tracking.dm
@@ -152,11 +152,11 @@
cameraFollow = null
/mob/living/silicon/ai/proc/ai_actual_track(mob/living/target as mob)
- if(!istype(target)) return
+ if(!istype(target)) return FALSE
var/mob/living/silicon/ai/U = usr
if(target == U.cameraFollow)
- return
+ return TRUE
if(U.cameraFollow)
U.ai_cancel_tracking()
@@ -185,6 +185,8 @@
return
sleep(10)
+ return TRUE
+
/obj/machinery/camera/attack_ai(var/mob/living/silicon/ai/user as mob)
if (!istype(user))
return
diff --git a/code/modules/mob/living/silicon/ai/ai.dm b/code/modules/mob/living/silicon/ai/ai.dm
index 61f0be1a95..22707c6dbb 100644
--- a/code/modules/mob/living/silicon/ai/ai.dm
+++ b/code/modules/mob/living/silicon/ai/ai.dm
@@ -483,6 +483,19 @@ var/list/ai_verbs_default = list(
else
to_chat(src, "System error. Cannot locate [html_decode(href_list["trackname"])].")
return
+
+ if(href_list["trackbot"])
+ var/mob/living/bot/target = locate(href_list["trackbot"]) in mob_list
+ if(target)
+ ai_actual_track(target)
+ else
+ to_chat(src, "Target is not on or near any active cameras on the station.")
+ return
+
+ if(href_list["open"])
+ var/mob/target = locate(href_list["open"]) in mob_list
+ if(target)
+ open_nearest_door(target)
return
@@ -825,6 +838,39 @@ var/list/ai_verbs_default = list(
/mob/living/silicon/ai/proc/is_in_chassis()
return istype(loc, /turf)
+/mob/living/silicon/ai/proc/open_nearest_door(mob/living/target) // Rykka ports AI opening doors
+ if(!istype(target))
+ return
+
+ if(target && ai_actual_track(target))
+ var/obj/machinery/door/airlock/A = null
+
+ var/dist = -1
+ for(var/obj/machinery/door/airlock/D in range(3, target))
+ if(!D.density)
+ continue
+
+ var/curr_dist = get_dist(D, target)
+
+ if(dist < 0)
+ dist = curr_dist
+ A = D
+ else if(dist > curr_dist)
+ dist = curr_dist
+ A = D
+
+ if(istype(A))
+ switch(alert(src, "Do you want to open \the [A] for [target]?", "Doorknob_v2a.exe", "Yes", "No"))
+ if("Yes")
+ A.AIShiftClick()
+ to_chat(src, "You open \the [A] for [target].")
+ else
+ to_chat(src, "You deny the request.")
+ else
+ to_chat(src, "Unable to locate an airlock near [target].")
+
+ else
+ to_chat(src, "Target is not on or near any active cameras on the station.")
/mob/living/silicon/ai/ex_act(var/severity)
if(severity == 1.0)
@@ -906,15 +952,20 @@ var/list/ai_verbs_default = list(
jobname = "Unknown"
var/track = ""
- if(changed_voice)
- if(impersonating)
+ if(changed_voice) // They have a fake name
+ if(impersonating) // And we found a mob with that name above, track them instead
track = "[speaker_name] ([jobname])"
- else
+ track += "\[OPEN\]" // Rykka ports AI opening doors
+ else // We couldn't find a mob with their fake name, don't track at all
track = "[speaker_name] ([jobname])"
- else
- track = "[speaker_name] ([jobname])"
+ else // Not faking their name
+ if(istype(speaker, /mob/living/bot)) // It's a bot, and no fake name! (That'd be kinda weird.) :p
+ track = "[speaker_name] ([jobname])"
+ else // It's not a bot, and no fake name!
+ track = "[speaker_name] ([jobname])"
+ track += "\[OPEN\]" // Rykka ports AI opening doors
- return track
+ return track // Feed variable back to AI
/mob/living/silicon/ai/proc/relay_speech(mob/living/M, list/message_pieces, verb)
var/message = combine_message(message_pieces, verb, M)