diff --git a/code/_onclick/hud/_defines.dm b/code/_onclick/hud/_defines.dm
index a3b7a7e3269..47df75473b5 100644
--- a/code/_onclick/hud/_defines.dm
+++ b/code/_onclick/hud/_defines.dm
@@ -164,6 +164,7 @@
#define ui_pai_state_laws "SOUTH:6,WEST+8"
#define ui_pai_pda_send "SOUTH:6,WEST+9"
#define ui_pai_pda_log "SOUTH:6,WEST+10"
+#define ui_pai_internal_gps "SOUTH:6,WEST+11"
#define ui_pai_take_picture "SOUTH:6,WEST+12"
#define ui_pai_view_images "SOUTH:6,WEST+13"
diff --git a/code/_onclick/hud/pai.dm b/code/_onclick/hud/pai.dm
index 86256d9ce0e..9b7016da21a 100644
--- a/code/_onclick/hud/pai.dm
+++ b/code/_onclick/hud/pai.dm
@@ -136,6 +136,20 @@
var/mob/living/silicon/pai/pAI = usr
pAI.cmd_show_message_log(usr)
+/atom/movable/screen/pai/internal_gps
+ name = "Internal GPS"
+ icon_state = "internal_gps"
+ required_software = "internal gps"
+
+/atom/movable/screen/pai/internal_gps/Click()
+ . = ..()
+ if(!.)
+ return
+ var/mob/living/silicon/pai/pAI = usr
+ if(!pAI.internal_gps)
+ pAI.internal_gps = new(pAI)
+ pAI.internal_gps.attack_self(pAI)
+
/atom/movable/screen/pai/image_take
name = "Take Image"
icon_state = "take_picture"
@@ -233,6 +247,11 @@
using.screen_loc = ui_pai_pda_log
static_inventory += using
+// Internal GPS
+ using = new /atom/movable/screen/pai/internal_gps()
+ using.screen_loc = ui_pai_internal_gps
+ static_inventory += using
+
// Take image
using = new /atom/movable/screen/pai/image_take()
using.screen_loc = ui_pai_take_picture
diff --git a/code/datums/components/gps.dm b/code/datums/components/gps.dm
index 433d967bf8e..2c13a6860e3 100644
--- a/code/datums/components/gps.dm
+++ b/code/datums/components/gps.dm
@@ -20,11 +20,18 @@ GLOBAL_LIST_EMPTY(GPS_list)
/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)
+/datum/component/gps/item/Initialize(_gpstag = "COM0", emp_proof = FALSE, state = null)
. = ..()
if(. == COMPONENT_INCOMPATIBLE || !isitem(parent))
return COMPONENT_INCOMPATIBLE
+
+ if(isnull(state))
+ state = GLOB.default_state
+ src.state = state
+
var/atom/A = parent
A.add_overlay("working")
A.name = "[initial(A.name)] ([gpstag])"
@@ -98,6 +105,9 @@ GLOBAL_LIST_EMPTY(GPS_list)
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
diff --git a/code/game/objects/items/devices/gps.dm b/code/game/objects/items/devices/gps.dm
index a7bc794a145..31875ac5a90 100644
--- a/code/game/objects/items/devices/gps.dm
+++ b/code/game/objects/items/devices/gps.dm
@@ -13,6 +13,10 @@
/obj/item/gps/Initialize()
. = ..()
+ add_gps_component()
+
+/// Adds the GPS component to this item.
+/obj/item/gps/proc/add_gps_component()
AddComponent(/datum/component/gps/item, gpstag)
/obj/item/gps/spaceruin
@@ -45,6 +49,15 @@
gpstag = "MINER"
desc = "A positioning system helpful for rescuing trapped or injured miners, keeping one on you at all times while mining might just save your life."
+/*
+ * GPS for pAIS, which only allows access if it's contained within the user.
+ */
+/obj/item/gps/pai
+ gpstag = "PAI0"
+
+/obj/item/gps/pai/add_gps_component()
+ AddComponent(/datum/component/gps/item, gpstag, state = GLOB.inventory_state)
+
/obj/item/gps/visible_debug
name = "visible GPS"
gpstag = "ADMIN"
diff --git a/code/modules/mob/living/silicon/pai/pai.dm b/code/modules/mob/living/silicon/pai/pai.dm
index f95a1de03ae..92dd0c5066e 100644
--- a/code/modules/mob/living/silicon/pai/pai.dm
+++ b/code/modules/mob/living/silicon/pai/pai.dm
@@ -66,6 +66,9 @@
var/obj/machinery/newscaster //pAI Newscaster
var/obj/item/healthanalyzer/hostscan //pAI healthanalyzer
+ /// Internal pAI GPS, enabled if pAI downloads GPS software, and then uses it.
+ var/obj/item/gps/pai/internal_gps = null
+
var/encryptmod = FALSE
var/holoform = FALSE
var/canholo = TRUE
@@ -103,6 +106,8 @@
signaler = null
if(A == hostscan)
hostscan = null
+ if(A == internal_gps)
+ internal_gps = null
return ..()
/mob/living/silicon/pai/Destroy()
@@ -111,6 +116,7 @@
QDEL_NULL(newscaster)
QDEL_NULL(signaler)
QDEL_NULL(hostscan)
+ QDEL_NULL(internal_gps)
if(!QDELETED(card) && loc != card)
card.forceMove(drop_location())
card.pai = null //these are otherwise handled by paicard/handle_atom_del()
diff --git a/code/modules/mob/living/silicon/pai/software.dm b/code/modules/mob/living/silicon/pai/software.dm
index 27a354839b1..272f37d4516 100644
--- a/code/modules/mob/living/silicon/pai/software.dm
+++ b/code/modules/mob/living/silicon/pai/software.dm
@@ -22,6 +22,7 @@
"security HUD" = 20,
"loudness booster" = 20,
"newscaster" = 20,
+ "internal gps" = 35,
"door jack" = 25,
"encryption keys" = 25,
"universal translator" = 35
@@ -283,6 +284,11 @@
if(subscreen == 1) // Open Instrument
internal_instrument.interact(src)
+ if("internalgps")
+ if(!internal_gps)
+ internal_gps = new(src)
+ internal_gps.attack_self(src)
+
paiInterface()
// MENUS
@@ -315,6 +321,9 @@
dat += "Remote Signaller
"
if(s == "loudness booster")
dat += "Loudness Booster
"
+ if(s == "internal gps")
+ dat += "Internal GPS
"
+
dat += "
"
// Advanced
diff --git a/icons/hud/screen_pai.dmi b/icons/hud/screen_pai.dmi
index 4868d26cc08..a8856712fad 100644
Binary files a/icons/hud/screen_pai.dmi and b/icons/hud/screen_pai.dmi differ