diff --git a/code/modules/modular_computers/computers/item/pda.dm b/code/modules/modular_computers/computers/item/pda.dm
index c375fe9a5c1..1fea772b85e 100644
--- a/code/modules/modular_computers/computers/item/pda.dm
+++ b/code/modules/modular_computers/computers/item/pda.dm
@@ -328,7 +328,6 @@
starting_programs = list(
/datum/computer_file/program/filemanager,
/datum/computer_file/program/robotact,
- /datum/computer_file/program/borg_monitor,
/datum/computer_file/program/atmosscan,
/datum/computer_file/program/crew_manifest,
)
diff --git a/code/modules/modular_computers/file_system/programs/robotact.dm b/code/modules/modular_computers/file_system/programs/robotact.dm
index c213790b80a..927e09c044a 100644
--- a/code/modules/modular_computers/file_system/programs/robotact.dm
+++ b/code/modules/modular_computers/file_system/programs/robotact.dm
@@ -23,6 +23,20 @@
program_open_overlay = "command-syndicate"
return TRUE
return FALSE
+/**
+ * Checks if we should see a specific cyborg on our "network". Arguments are our borg, and another borg
+ *
+ * Intended to allow borgs with the same AI to see eachother, syndicate borgs (scrambledcodes) with no AI to see eachother
+ * and not-syndicate borgs with no AI to see no one. Syndicate borgs connected to an AI will no longer see other syndicate
+ * borgs except ones also slaved to the same AI.
+ */
+/datum/computer_file/program/robotact/proc/evaluate_borg(mob/living/silicon/robot/this_borg, mob/living/silicon/robot/other_borg)
+ if(this_borg.connected_ai != other_borg.connected_ai)
+ return FALSE
+ if(this_borg.scrambledcodes && other_borg.scrambledcodes)
+ return TRUE
+ if(this_borg.connected_ai)
+ return TRUE
/datum/computer_file/program/robotact/ui_data(mob/user)
var/list/data = list()
@@ -34,9 +48,11 @@
var/mob/living/silicon/robot/cyborg = tablet.silicon_owner
- data["name"] = cyborg.name
+ data["borgName"] = cyborg.name
data["designation"] = cyborg.model
- data["masterAI"] = cyborg.connected_ai //Master AI
+ data["masterAI"] = cyborg.connected_ai
+ data["MasterAI_connected"] = !!cyborg.connected_ai //Need a bool for this on the other side
+ data["masterAI_online"] = (cyborg.connected_ai?.stat == CONSCIOUS)
var/charge = 0
var/maxcharge = 1
@@ -56,6 +72,34 @@
data["thrustersStatus"] = "[cyborg.ionpulse_on?"ACTIVE":"DISABLED"]" //Feedback for thruster status
data["selfDestructAble"] = (cyborg.emagged || istype(cyborg, /mob/living/silicon/robot/model/syndicate))
+ data["cyborg_groups"] = list()
+ if(data["masterAI_online"] || (!data["MasterAI_connected"] && cyborg.scrambledcodes)) //If a borg isn't connected, we can just skip this all
+ var/list/borggroup = list() //temporary list for holding groups of borgs
+ for(var/mob/living/silicon/robot/other_borg in GLOB.silicon_mobs)
+ if(!evaluate_borg(cyborg,other_borg))
+ continue
+
+ var/shell = FALSE
+ if(other_borg.shell && !other_borg.ckey)
+ shell = TRUE
+
+ var/list/cyborg_data = list(
+ "otherBorgName" = other_borg.name,
+ "integ" = round((other_borg.health + 100) / 2), //mob heath is -100 to 100, we want to scale that to 0 - 100
+ "locked_down" = other_borg.lockcharge,
+ "status" = other_borg.stat,
+ "shell_discon" = shell,
+ "charge" = other_borg.cell ? round(other_borg.cell.percent()) : null,
+ "module" = other_borg.model ? "[other_borg.model.name]" : "None",
+ "ref" = REF(other_borg)
+ )
+ borggroup += list(cyborg_data)
+ if(length(borggroup) == 4) //grouping borgs in packs of four, since I can't do it later in js
+ data["cyborg_groups"] += list(borggroup)
+ borggroup = list()
+ if(length(borggroup)) //and any remainders
+ data["cyborg_groups"] += list(borggroup)
+
//Cover, TRUE for locked
data["cover"] = "[cyborg.locked? "LOCKED":"UNLOCKED"]"
//Ability to move. FAULT if lockdown wire is cut, DISABLED if borg locked, ENABLED otherwise
diff --git a/tgui/packages/tgui/interfaces/NtosRobotact.jsx b/tgui/packages/tgui/interfaces/NtosRobotact.jsx
index 71afb4db1ba..ecf27b3cf76 100644
--- a/tgui/packages/tgui/interfaces/NtosRobotact.jsx
+++ b/tgui/packages/tgui/interfaces/NtosRobotact.jsx
@@ -5,11 +5,15 @@ import {
AnimatedNumber,
Box,
Button,
+ Divider,
Flex,
LabeledList,
+ NoticeBox,
ProgressBar,
Section,
Slider,
+ Stack,
+ StackDivider,
Tabs,
} from '../components';
import { formatEnergy } from '../format';
@@ -49,8 +53,11 @@ export const NtosRobotactContent = (props) => {
thrustersInstalled,
thrustersStatus,
selfDestructAble,
+ cyborg_groups = [],
+ masterAI_online,
+ MasterAI_connected,
} = data;
- const borgName = data.name || [];
+ const borgName = data.borgName || [];
const borgType = data.designation || [];
const masterAI = data.masterAI || [];
const laws = data.Laws || [];
@@ -77,6 +84,14 @@ export const NtosRobotactContent = (props) => {
>
Logs
+ setTab_main(3)}
+ >
+ Network
+
{tab_main === 1 && (
@@ -332,6 +347,111 @@ export const NtosRobotactContent = (props) => {
)}
+ {tab_main === 3 && (
+
+
+
+
+
+ {!MasterAI_connected
+ ? 'No Conection'
+ : masterAI_online
+ ? 'Online'
+ : 'Unresponsive'}
+
+
+
+
+
+
+ {cyborg_groups.map((borggroup) => (
+
+
+ {borggroup.map((cyborg) => (
+
+
+
+
+
+ {cyborg.status
+ ? 'Not Responding'
+ : cyborg.locked_down
+ ? 'Locked Down'
+ : cyborg.shell_discon
+ ? 'Nominal/Disconnected'
+ : 'Nominal'}
+
+
+
+
+ {cyborg.integ === 0
+ ? 'Hard Fault'
+ : cyborg.integ <= 25
+ ? 'Functionality Disrupted'
+ : cyborg.integ <= 75
+ ? 'Functionality Impaired'
+ : 'Operational'}
+
+
+
+
+ {typeof cyborg.charge === 'number'
+ ? cyborg.charge + '%'
+ : 'No Cell'}
+
+
+
+ {cyborg.module}
+
+
+
+
+ ))}
+
+
+
+ ))}
+
+
+ {!!!cyborg_groups.length && (
+
+
+ CONNECTION UNAVAILABLE -- NETWORK STATUS UNKNOWN
+
+
+ )}
+
+ )}
);
};