Files
Bubberstation/code/modules/tgui/states.dm
zxaber 9885e1753d 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.
2021-01-07 22:17:07 -03:00

124 lines
3.4 KiB
Plaintext

/*!
* Base state and helpers for states. Just does some sanity checks,
* implement a proper state for in-depth checks.
*
* Copyright (c) 2020 Aleksej Komarov
* SPDX-License-Identifier: MIT
*/
/**
* public
*
* Checks the UI state for a mob.
*
* required user mob The mob who opened/is using the UI.
* required state datum/ui_state The state to check.
*
* return UI_state The state of the UI.
*/
/datum/proc/ui_status(mob/user, datum/ui_state/state)
var/src_object = ui_host(user)
. = UI_CLOSE
if(!state)
return
if(isobserver(user))
// If they turn on ghost AI control, admins can always interact.
if(isAdminGhostAI(user))
. = max(., UI_INTERACTIVE)
// Regular ghosts can always at least view if in range.
if(user.client)
var/clientviewlist = getviewsize(user.client.view)
if(get_dist(src_object, user) < max(clientviewlist[1], clientviewlist[2]))
. = max(., UI_UPDATE)
// Check if the state allows interaction
var/result = state.can_use_topic(src_object, user)
. = max(., result)
/**
* private
*
* Checks if a user can use src_object's UI, and returns the state.
* Can call a mob proc, which allows overrides for each mob.
*
* required src_object datum The object/datum which owns the UI.
* required user mob The mob who opened/is using the UI.
*
* return UI_state The state of the UI.
*/
/datum/ui_state/proc/can_use_topic(src_object, mob/user)
// Don't allow interaction by default.
return UI_CLOSE
/**
* public
*
* Standard interaction/sanity checks. Different mob types may have overrides.
*
* return UI_state The state of the UI.
*/
/mob/proc/shared_ui_interaction(src_object)
// Close UIs if mindless.
if(!client)
return UI_CLOSE
// Disable UIs if unconcious.
else if(stat)
return UI_DISABLED
// Update UIs if incapicitated but concious.
else if(incapacitated())
return UI_UPDATE
return UI_INTERACTIVE
/mob/living/shared_ui_interaction(src_object)
. = ..()
if(!(mobility_flags & MOBILITY_UI) && . == UI_INTERACTIVE)
return UI_UPDATE
/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 ..()
/mob/living/silicon/robot/shared_ui_interaction(src_object)
// Disable UIs if the object isn't installed in the borg AND the borg is either locked, has a dead cell, or no cell.
var/atom/device = src_object
if((istype(device) && device.loc != src) && (!cell || cell.charge <= 0 || lockcharge))
return UI_DISABLED
return ..()
/**
* public
*
* Distance versus interaction check.
*
* required src_object atom/movable The object which owns the UI.
*
* return UI_state The state of the UI.
*/
/mob/living/proc/shared_living_ui_distance(atom/movable/src_object, viewcheck = TRUE)
// If the object is obscured, close it.
if(viewcheck && !(src_object in view(src)))
return UI_CLOSE
var/dist = get_dist(src_object, src)
// Open and interact if 1-0 tiles away.
if(dist <= 1)
return UI_INTERACTIVE
// View only if 2-3 tiles away.
else if(dist <= 2)
return UI_UPDATE
// Disable if 5 tiles away.
else if(dist <= 5)
return UI_DISABLED
// Otherwise, we got nothing.
return UI_CLOSE
/mob/living/carbon/human/shared_living_ui_distance(atom/movable/src_object, viewcheck = TRUE)
if(dna.check_mutation(TK) && tkMaxRangeCheck(src, src_object))
return UI_INTERACTIVE
return ..()