From 3cfde345be128b95c20336d2d557990577b01c6b Mon Sep 17 00:00:00 2001
From: zxaber <37497534+zxaber@users.noreply.github.com>
Date: Sun, 3 Nov 2024 22:10:07 -0800
Subject: [PATCH] Removes SiliConnect from borg PDAs, expands their self-status
app instead (#87350)
## About The Pull Request
- SiliConnect is no longer a default app for cyborgs.
- RoboTact, the borg self-status app now has a Network tab, which lists
other borgs' status.
- The Network tab will only list borgs connected to the same AI as you.
If your AI goes down, you lose connection to other borgs' status info.
- Your AI is also listed on the Network tab, with their own status in a
very binary good/bad form.
- Syndicate borgs are able to see other syndicate borgs on the Network
list, even though they lack an AI.
## Why It's Good For The Game
SiliConnect was recently added to the default borg apps list. But it has
a lot of features that borgs can't actually use, and so feels rather
messy. It was added with the goal of letting borgs see eachother's
status, and so I've ported that functionality into RoboTact. SiliConnect
is no longer a default borg app (though it *can* be installed if a borg
and human really want it to be).
Showing the AI's status is certainly a balance choice. But it's not
really that much of a secret when the AI dying already adjusts the
monitors across the station to a BSOD image. On the flip side, we get to
shut off borg status sharing when the AI goes offline, which is neat.
## Changelog
:cl:
del: SiliConnect, a tool meant for Roboticists, is no longer included by
default on borgs.
add: RoboTact, the borg self-status app, now shows the status of other
borgs synced to the same AI. Syndicate borgs can likewise see
eachother's status, even without an AI.
balance: RoboTact also shows their synced AI's very basic status of
functional or offline.
/:cl:
UI Pictures:

Dead AI:

Syndicate borgs do not see station borg status, but can see eachother's

~~Drafting because I need to do edge-case testing, and the AI box isn't
quite functioning correctly when the borg has no AI master.~~
---
.../modular_computers/computers/item/pda.dm | 1 -
.../file_system/programs/robotact.dm | 48 ++++++-
.../packages/tgui/interfaces/NtosRobotact.jsx | 122 +++++++++++++++++-
3 files changed, 167 insertions(+), 4 deletions(-)
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
+
+
+ )}
+
+ )}
);
};