From 4fcda892765c4199abd3b607fcb94fb8e37ba37c Mon Sep 17 00:00:00 2001
From: SkyratBot <59378654+SkyratBot@users.noreply.github.com>
Date: Fri, 8 Jan 2021 02:22:13 +0100
Subject: [PATCH] [MIRROR] Fixes AIs being unable to access their local APC
when out of power (#2564)
* Fixes AIs being unable to access their own APC interface when power is off (#55977)
When an AI runs out of power, they get a short fluff text story about hacking into their own APC through the powernet or whatever, before having the APC's interface open. The intention is that an AI can re-enable their own breaker after a bit if something flipped it off. However, one of the many checks in TGUI will fail if the AI has no power (specifically, if incapacitated() returns TRUE), making this whole feature not work. In fact, it's probably been broken since TGUI APCs were done. I have fixed it by adding a check in the very same proc to return UI_INTERACTIVE if the UI's source object is the same object referenced in the AIs apc_override variable. Closes #52548
The apc_override variable is now an APC object reference rather than a boolean. It is set to the AI's local APC when the hack flufftext completes, and is null'd when power is restored. This reference is used by the above, so that the AI only gets access to this one APC rather than any APC in general.
AIs now also get a hyperlink in their chatbox, allowing them to open the APC interface should they have closed it. If they have had power restored, the apc_override reference var will be null, and using the hyperlink will simply result in text stating the backdoor to the APC is closed.
If the AI reconnects into a state where it has no power and apc_override is set, it will get a hyperlink to the APC, in case the AI player had been reconnecting when the window would have popped up or otherwise does not have the link for whatever reason.
* Fixes AIs being unable to access their local APC when out of power
Co-authored-by: zxaber <37497534+zxaber@users.noreply.github.com>
---
code/modules/mob/living/silicon/ai/ai.dm | 18 +++++++++++++++---
code/modules/mob/living/silicon/ai/life.dm | 9 ++++++---
code/modules/mob/living/silicon/ai/login.dm | 2 ++
code/modules/tgui/states.dm | 2 ++
4 files changed, 25 insertions(+), 6 deletions(-)
diff --git a/code/modules/mob/living/silicon/ai/ai.dm b/code/modules/mob/living/silicon/ai/ai.dm
index 04368ee333a..6a1e4d20737 100644
--- a/code/modules/mob/living/silicon/ai/ai.dm
+++ b/code/modules/mob/living/silicon/ai/ai.dm
@@ -74,7 +74,7 @@
var/turf/waypoint //Holds the turf of the currently selected waypoint.
var/waypoint_mode = FALSE //Waypoint mode is for selecting a turf via clicking.
var/call_bot_cooldown = 0 //time of next call bot command
- var/apc_override = FALSE //hack for letting the AI use its APC even when visionless
+ var/obj/machinery/power/apc/apc_override //Ref of the AI's APC, used when the AI has no power in order to access their APC.
var/nuking = FALSE
var/obj/machinery/doomsday_device/doomsday_device
@@ -210,6 +210,7 @@
Bot = null
controlled_mech = null
linked_core = null
+ apc_override = null
return ..()
/// Removes all malfunction-related abilities from the AI
@@ -391,8 +392,19 @@
/mob/living/silicon/ai/Topic(href, href_list)
..()
- if(usr != src || incapacitated())
+ if(usr != src)
return
+
+ if(href_list["emergencyAPC"]) //This check comes before incapacitated() because the only time it would be useful is when we have no power.
+ if(!apc_override)
+ to_chat(src, "APC backdoor is no longer available.")
+ return
+ apc_override.ui_interact(src)
+ return
+
+ if(incapacitated())
+ return
+
if (href_list["mach_close"])
if (href_list["mach_close"] == "aialerts")
viewalerts = 0
@@ -812,7 +824,7 @@
if(isturf(loc)) //AI in core, check if on cameras
//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
- return (GLOB.cameranet && GLOB.cameranet.checkTurfVis(get_turf_pixel(A))) || apc_override
+ return ((GLOB.cameranet && GLOB.cameranet.checkTurfVis(get_turf_pixel(A))) || (A == 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)
diff --git a/code/modules/mob/living/silicon/ai/life.dm b/code/modules/mob/living/silicon/ai/life.dm
index 028b574353c..68977d4045d 100644
--- a/code/modules/mob/living/silicon/ai/life.dm
+++ b/code/modules/mob/living/silicon/ai/life.dm
@@ -144,9 +144,9 @@
sleep(50)
to_chat(src, "Receiving control information from APC.")
sleep(2)
- apc_override = 1
- theAPC.ui_interact(src)
- apc_override = 0
+ to_chat(src, "APC ready for connection.")
+ apc_override = theAPC
+ apc_override.ui_interact(src)
setAiRestorePowerRoutine(POWER_RESTORATION_APC_FOUND)
sleep(50)
theAPC = null
@@ -155,10 +155,13 @@
if(aiRestorePowerRoutine)
if(aiRestorePowerRoutine == POWER_RESTORATION_APC_FOUND)
to_chat(src, "Alert cancelled. Power has been restored.")
+ if(apc_override)
+ to_chat(src, "APC backdoor has been closed.") //Fluff for why we have to hack every time.
else
to_chat(src, "Alert cancelled. Power has been restored without our assistance.")
setAiRestorePowerRoutine(POWER_RESTORATION_OFF)
set_blindness(0)
+ apc_override = null
update_sight()
/mob/living/silicon/ai/proc/ai_lose_power()
diff --git a/code/modules/mob/living/silicon/ai/login.dm b/code/modules/mob/living/silicon/ai/login.dm
index aff19f69d4b..03989573fbd 100644
--- a/code/modules/mob/living/silicon/ai/login.dm
+++ b/code/modules/mob/living/silicon/ai/login.dm
@@ -8,6 +8,8 @@
O.mode = 1
O.emotion = "Neutral"
O.update()
+ if(lacks_power() && apc_override) //Placing this in Login() in case the AI doesn't have this link for whatever reason.
+ to_chat(usr, "Main power is unavailable, backup power in use. Diagnostics scan complete. Local APC ready for connection.")
set_eyeobj_visible(TRUE)
if(multicam_on)
end_multicam()
diff --git a/code/modules/tgui/states.dm b/code/modules/tgui/states.dm
index 62cb2ded81d..73c053254d8 100644
--- a/code/modules/tgui/states.dm
+++ b/code/modules/tgui/states.dm
@@ -78,6 +78,8 @@
/mob/living/silicon/ai/shared_ui_interaction(src_object)
// Disable UIs if the AI is unpowered.
+ if(apc_override == src_object) //allows AI to (eventually) use the interface for their own APC even when out of power
+ return UI_INTERACTIVE
if(lacks_power())
return UI_DISABLED
return ..()