Files
Bubberstation/code/datums/components/gps.dm
Bloop fd1bc8f9d0 Fixes PAIs not being able to send messages or turn the GPS off (#89279)
## About The Pull Request

Fixes https://github.com/NovaSector/NovaSector/issues/4826

Since https://github.com/tgstation/tgstation/pull/88651 PAIs have been
blanket barred from being able to pass any `can_perform_action()` check.

From the pr:


![image](https://github.com/user-attachments/assets/67842da5-7208-4c43-b71f-4ba5c0c2f7af)

## Why It's Good For The Game

As it turns out there are a few things that it makes sense for them to
be able to interact with. Now you can again!

## Changelog

🆑
fix: fixed PAIs not being able to send or reply to messages using their
digital messenger app.
fix: fixed PAIs not being able to turn off the GPS tracking using their
gpa app.
/🆑
2025-01-30 13:41:09 +01:00

189 lines
5.9 KiB
Plaintext

///Global GPS_list. All GPS components get saved in here for easy reference.
GLOBAL_LIST_EMPTY(GPS_list)
///GPS component. Atoms that have this show up on gps. Pretty simple stuff.
/datum/component/gps
var/gpstag = "COM0"
var/tracking = TRUE
var/emped = FALSE
/datum/component/gps/Initialize(_gpstag = "COM0")
if(!isatom(parent))
return COMPONENT_INCOMPATIBLE
gpstag = _gpstag
GLOB.GPS_list += src
/datum/component/gps/Destroy()
GLOB.GPS_list -= src
return ..()
/datum/component/gps/kheiral_cuffs
/datum/component/gps/kheiral_cuffs/Initialize(_gpstag = "COM0")
. = ..()
RegisterSignal(parent, COMSIG_ITEM_DROPPED, PROC_REF(deactivate_kheiral_cuffs))
/datum/component/gps/kheiral_cuffs/proc/deactivate_kheiral_cuffs(datum/source)
SIGNAL_HANDLER
qdel(src)
///GPS component subtype. Only gps/item's can be used to open the UI.
/datum/component/gps/item
var/updating = TRUE //Automatic updating of GPS list. Can be set to manual by user.
var/global_mode = TRUE //If disabled, only GPS signals of the same Z level are shown
/// UI state of GPS, altering when it can be used.
var/datum/ui_state/state = null
/datum/component/gps/item/Initialize(_gpstag = "COM0", emp_proof = FALSE, state = null, overlay_state = "working")
. = ..()
if(. == COMPONENT_INCOMPATIBLE || !isitem(parent))
return COMPONENT_INCOMPATIBLE
if(isnull(state))
state = GLOB.default_state
src.state = state
var/atom/A = parent
if(overlay_state)
A.add_overlay(overlay_state)
A.name = "[initial(A.name)] ([gpstag])"
RegisterSignal(parent, COMSIG_ITEM_ATTACK_SELF, PROC_REF(interact))
if(!emp_proof)
RegisterSignal(parent, COMSIG_ATOM_EMP_ACT, PROC_REF(on_emp_act))
RegisterSignal(parent, COMSIG_ATOM_EXAMINE, PROC_REF(on_examine))
RegisterSignal(parent, COMSIG_CLICK_ALT, PROC_REF(on_click_alt))
///Called on COMSIG_ITEM_ATTACK_SELF
/datum/component/gps/item/proc/interact(datum/source, mob/user)
SIGNAL_HANDLER
if(user)
INVOKE_ASYNC(src, PROC_REF(ui_interact), user)
///Called on COMSIG_ATOM_EXAMINE
/datum/component/gps/item/proc/on_examine(datum/source, mob/user, list/examine_list)
SIGNAL_HANDLER
examine_list += span_notice("Alt-click to switch it [tracking ? "off":"on"].")
///Called on COMSIG_ATOM_EMP_ACT
/datum/component/gps/item/proc/on_emp_act(datum/source, severity, protection)
SIGNAL_HANDLER
if(protection & EMP_PROTECT_SELF)
return
emped = TRUE
var/atom/A = parent
A.cut_overlay("working")
A.add_overlay("emp")
addtimer(CALLBACK(src, PROC_REF(reboot)), 300, TIMER_UNIQUE|TIMER_OVERRIDE) //if a new EMP happens, remove the old timer so it doesn't reactivate early
SStgui.close_uis(src) //Close the UI control if it is open.
///Restarts the GPS after getting turned off by an EMP.
/datum/component/gps/item/proc/reboot()
emped = FALSE
var/atom/A = parent
A.cut_overlay("emp")
A.add_overlay("working")
///Calls toggletracking
/datum/component/gps/item/proc/on_click_alt(datum/source, mob/user)
SIGNAL_HANDLER
toggletracking(user)
return CLICK_ACTION_SUCCESS
///Toggles the tracking for the gps
/datum/component/gps/item/proc/toggletracking(mob/user)
if(!user.can_perform_action(parent, ALLOW_RESTING | ALLOW_PAI))
return //user not valid to use gps
if(emped)
to_chat(user, span_warning("It's busted!"))
return
var/atom/A = parent
if(tracking)
A.cut_overlay("working")
to_chat(user, span_notice("[parent] is no longer tracking, or visible to other GPS devices."))
tracking = FALSE
else
A.add_overlay("working")
to_chat(user, span_notice("[parent] is now tracking, and visible to other GPS devices."))
tracking = TRUE
/datum/component/gps/item/ui_interact(mob/user, datum/tgui/ui)
if(emped)
to_chat(user, span_hear("[parent] fizzles weakly."))
return
ui = SStgui.try_update_ui(user, src, ui)
if(!ui)
ui = new(user, src, "Gps")
ui.open()
ui.set_autoupdate(updating)
/datum/component/gps/item/ui_state(mob/user)
return state
/datum/component/gps/item/ui_data(mob/user)
var/list/data = list()
data["power"] = tracking
data["tag"] = gpstag
data["updating"] = updating
data["globalmode"] = global_mode
if(!tracking || emped) //Do not bother scanning if the GPS is off or EMPed
return data
var/turf/curr = get_turf(parent)
data["currentArea"] = "[get_area_name(curr, TRUE)]"
data["currentCoords"] = "[curr.x], [curr.y], [curr.z]"
var/list/signals = list()
data["signals"] = list()
for(var/datum/component/gps/gps as anything in GLOB.GPS_list)
if(gps == src || gps.emped || !gps.tracking)
continue
var/turf/pos = get_turf(gps.parent)
if(!pos || (!global_mode && pos.z != curr.z))
continue
var/list/signal = list()
signal["entrytag"] = gps.gpstag //Name or 'tag' of the GPS
signal["coords"] = "[pos.x], [pos.y], [pos.z]"
// Distance is calculated for the same z-level only, and direction is calculated for crosslinked/neighboring and same z-levels.
if(pos.z == curr.z)
signal["dist"] = max(get_dist(curr, pos), 0) //Distance between the src and remote GPS turfs
signal["degrees"] = round(get_angle(curr, pos)) //0-360 degree directional bearing, for more precision.
else
var/angle = get_linked_z_angle(curr.z, pos.z)
if(!isnull(angle))
signal["degrees"] = angle
signals += list(signal) //Add this signal to the list of signals
data["signals"] = signals
return data
/datum/component/gps/item/ui_act(action, list/params, datum/tgui/ui, datum/ui_state/state)
. = ..()
if(.)
return
switch(action)
if("rename")
var/atom/parentasatom = parent
var/a = tgui_input_text(usr, "Enter the desired tag", "GPS Tag", gpstag, max_length = 20)
if (QDELETED(ui) || ui.status != UI_INTERACTIVE)
return
if (!a)
return
gpstag = a
. = TRUE
usr.log_message("renamed [parentasatom] to \"[initial(parentasatom.name)] ([gpstag])\".", LOG_GAME)
parentasatom.name = "[initial(parentasatom.name)] ([gpstag])"
if("power")
toggletracking(usr)
. = TRUE
if("updating")
updating = !updating
. = TRUE
if("globalmode")
global_mode = !global_mode
. = TRUE