diff --git a/code/__DEFINES/machines.dm b/code/__DEFINES/machines.dm
index a48202a4e30..0c554b3139e 100644
--- a/code/__DEFINES/machines.dm
+++ b/code/__DEFINES/machines.dm
@@ -84,6 +84,12 @@
#define PROGRAM_STATE_KILLED 0
#define PROGRAM_STATE_BACKGROUND 1
#define PROGRAM_STATE_ACTIVE 2
+//Program categories
+#define PROGRAM_CATEGORY_CREW "Crew"
+#define PROGRAM_CATEGORY_ENGI "Engineering"
+#define PROGRAM_CATEGORY_ROBO "Robotics"
+#define PROGRAM_CATEGORY_SUPL "Supply"
+#define PROGRAM_CATEGORY_MISC "Other"
#define FIREDOOR_OPEN 1
#define FIREDOOR_CLOSED 2
diff --git a/code/modules/modular_computers/file_system/program.dm b/code/modules/modular_computers/file_system/program.dm
index 699ccb0947b..751332c8623 100644
--- a/code/modules/modular_computers/file_system/program.dm
+++ b/code/modules/modular_computers/file_system/program.dm
@@ -15,6 +15,8 @@
var/filedesc = "Unknown Program"
/// Short description of this program's function.
var/extended_desc = "N/A"
+ /// Category in the NTDownloader.
+ var/category = PROGRAM_CATEGORY_MISC
/// Program-specific screen icon state
var/program_icon_state = null
/// Set to 1 for program to require nonstop NTNet connection to run. If NTNet connection is lost program crashes.
diff --git a/code/modules/modular_computers/file_system/programs/airestorer.dm b/code/modules/modular_computers/file_system/programs/airestorer.dm
index 8e3bbb20f56..eafbcb6126d 100644
--- a/code/modules/modular_computers/file_system/programs/airestorer.dm
+++ b/code/modules/modular_computers/file_system/programs/airestorer.dm
@@ -1,6 +1,7 @@
/datum/computer_file/program/aidiag
filename = "aidiag"
filedesc = "NT FRK"
+ category = PROGRAM_CATEGORY_ROBO
program_icon_state = "generic"
extended_desc = "Firmware Restoration Kit, capable of reconstructing damaged AI systems. Requires direct AI connection via intellicard slot."
size = 12
diff --git a/code/modules/modular_computers/file_system/programs/alarm.dm b/code/modules/modular_computers/file_system/programs/alarm.dm
index 646d9892ba4..8ef71a93067 100644
--- a/code/modules/modular_computers/file_system/programs/alarm.dm
+++ b/code/modules/modular_computers/file_system/programs/alarm.dm
@@ -1,6 +1,7 @@
/datum/computer_file/program/alarm_monitor
filename = "alarmmonitor"
filedesc = "Canary"
+ category = PROGRAM_CATEGORY_ENGI
ui_header = "alarm_green.gif"
program_icon_state = "alert-green"
extended_desc = "This program provides visual interface for a station's alarm system."
diff --git a/code/modules/modular_computers/file_system/programs/antagonist/contract_uplink.dm b/code/modules/modular_computers/file_system/programs/antagonist/contract_uplink.dm
index 8709526de68..5d2090f2bde 100644
--- a/code/modules/modular_computers/file_system/programs/antagonist/contract_uplink.dm
+++ b/code/modules/modular_computers/file_system/programs/antagonist/contract_uplink.dm
@@ -1,6 +1,7 @@
/datum/computer_file/program/contract_uplink
filename = "contractor uplink"
filedesc = "Syndicate Contractor Uplink"
+ category = PROGRAM_CATEGORY_MISC
program_icon_state = "assign"
extended_desc = "A standard, Syndicate issued system for handling important contracts while on the field."
size = 10
diff --git a/code/modules/modular_computers/file_system/programs/antagonist/dos.dm b/code/modules/modular_computers/file_system/programs/antagonist/dos.dm
index 6bab999facd..c76f85143e3 100644
--- a/code/modules/modular_computers/file_system/programs/antagonist/dos.dm
+++ b/code/modules/modular_computers/file_system/programs/antagonist/dos.dm
@@ -1,6 +1,7 @@
/datum/computer_file/program/ntnet_dos
filename = "ntn_dos"
filedesc = "DoS Traffic Generator"
+ category = PROGRAM_CATEGORY_MISC
program_icon_state = "hostile"
extended_desc = "This advanced script can perform denial of service attacks against NTNet quantum relays. The system administrator will probably notice this. Multiple devices can run this program together against same relay for increased effect"
size = 20
diff --git a/code/modules/modular_computers/file_system/programs/antagonist/revelation.dm b/code/modules/modular_computers/file_system/programs/antagonist/revelation.dm
index ba24a5ab3e0..829f9ccef8c 100644
--- a/code/modules/modular_computers/file_system/programs/antagonist/revelation.dm
+++ b/code/modules/modular_computers/file_system/programs/antagonist/revelation.dm
@@ -1,6 +1,7 @@
/datum/computer_file/program/revelation
filename = "revelation"
filedesc = "Revelation"
+ category = PROGRAM_CATEGORY_MISC
program_icon_state = "hostile"
extended_desc = "This virus can destroy hard drive of system it is executed on. It may be obfuscated to look like another non-malicious program. Once armed, it will destroy the system upon next execution."
size = 13
diff --git a/code/modules/modular_computers/file_system/programs/atmosscan.dm b/code/modules/modular_computers/file_system/programs/atmosscan.dm
index f718977d5b2..b6c040741e0 100644
--- a/code/modules/modular_computers/file_system/programs/atmosscan.dm
+++ b/code/modules/modular_computers/file_system/programs/atmosscan.dm
@@ -1,6 +1,7 @@
/datum/computer_file/program/atmosscan
filename = "atmosscan"
filedesc = "AtmoZphere"
+ category = PROGRAM_CATEGORY_ENGI
program_icon_state = "air"
extended_desc = "A small built-in sensor reads out the atmospheric conditions around the device."
size = 4
diff --git a/code/modules/modular_computers/file_system/programs/borg_monitor.dm b/code/modules/modular_computers/file_system/programs/borg_monitor.dm
index 6fa36fed96a..4b350051030 100644
--- a/code/modules/modular_computers/file_system/programs/borg_monitor.dm
+++ b/code/modules/modular_computers/file_system/programs/borg_monitor.dm
@@ -1,6 +1,7 @@
/datum/computer_file/program/borg_monitor
filename = "siliconnect"
filedesc = "SiliConnect"
+ category = PROGRAM_CATEGORY_ROBO
ui_header = "borg_mon.gif"
program_icon_state = "generic"
extended_desc = "This program allows for remote monitoring of station cyborgs."
@@ -97,6 +98,7 @@
/datum/computer_file/program/borg_monitor/syndicate
filename = "roboverlord"
filedesc = "Roboverlord"
+ category = PROGRAM_CATEGORY_ROBO
ui_header = "borg_mon.gif"
program_icon_state = "generic"
extended_desc = "This program allows for remote monitoring of mission-assigned cyborgs."
diff --git a/code/modules/modular_computers/file_system/programs/bounty_board.dm b/code/modules/modular_computers/file_system/programs/bounty_board.dm
index 9c42a28a9bc..d008d5e72be 100644
--- a/code/modules/modular_computers/file_system/programs/bounty_board.dm
+++ b/code/modules/modular_computers/file_system/programs/bounty_board.dm
@@ -1,6 +1,7 @@
/datum/computer_file/program/bounty_board
filename = "bountyboard"
filedesc = "Bounty Board Request Network"
+ category = PROGRAM_CATEGORY_SUPL
program_icon_state = "bountyboard"
extended_desc = "A multi-platform network for placing requests across the station, with payment across the network being possible.."
requires_ntnet = TRUE
diff --git a/code/modules/modular_computers/file_system/programs/budgetordering.dm b/code/modules/modular_computers/file_system/programs/budgetordering.dm
index b42c6812938..307483c209b 100644
--- a/code/modules/modular_computers/file_system/programs/budgetordering.dm
+++ b/code/modules/modular_computers/file_system/programs/budgetordering.dm
@@ -1,8 +1,9 @@
/datum/computer_file/program/budgetorders
filename = "orderapp"
- filedesc = "Nanotrasen Internal Requisition Network (NIRN)"
+ filedesc = "NT IRN"
+ category = PROGRAM_CATEGORY_SUPL
program_icon_state = "request"
- extended_desc = "A request network that utilizes the Nanotrasen Ordering network to purchase supplies using a department budget account."
+ extended_desc = "Nanotrasen Internal Requisition Network interface for supply purchasing using a department budget account."
requires_ntnet = TRUE
transfer_access = ACCESS_HEADS
usage_flags = PROGRAM_LAPTOP | PROGRAM_TABLET
diff --git a/code/modules/modular_computers/file_system/programs/card.dm b/code/modules/modular_computers/file_system/programs/card.dm
index e9c8fd9110d..37629269292 100644
--- a/code/modules/modular_computers/file_system/programs/card.dm
+++ b/code/modules/modular_computers/file_system/programs/card.dm
@@ -9,6 +9,7 @@
/datum/computer_file/program/card_mod
filename = "plexagonidwriter"
filedesc = "Plexagon Access Management"
+ category = PROGRAM_CATEGORY_CREW
program_icon_state = "id"
extended_desc = "Program for programming employee ID cards to access parts of the station."
transfer_access = ACCESS_HEADS
diff --git a/code/modules/modular_computers/file_system/programs/cargoship.dm b/code/modules/modular_computers/file_system/programs/cargoship.dm
index 89a3b3247db..6393a5c3b1c 100644
--- a/code/modules/modular_computers/file_system/programs/cargoship.dm
+++ b/code/modules/modular_computers/file_system/programs/cargoship.dm
@@ -1,6 +1,7 @@
/datum/computer_file/program/shipping
filename = "shipping"
filedesc = "GrandArk Exporter"
+ category = PROGRAM_CATEGORY_SUPL
program_icon_state = "shipping"
extended_desc = "A combination printer/scanner app that enables modular computers to print barcodes for easy scanning and shipping."
size = 6
diff --git a/code/modules/modular_computers/file_system/programs/crewmanifest.dm b/code/modules/modular_computers/file_system/programs/crewmanifest.dm
index 08e5df04bc6..99483d4e789 100644
--- a/code/modules/modular_computers/file_system/programs/crewmanifest.dm
+++ b/code/modules/modular_computers/file_system/programs/crewmanifest.dm
@@ -1,6 +1,7 @@
/datum/computer_file/program/crew_manifest
filename = "plexagoncrew"
filedesc = "Plexagon Crew List"
+ category = PROGRAM_CATEGORY_CREW
program_icon_state = "id"
extended_desc = "Program for viewing and printing the current crew manifest"
transfer_access = ACCESS_HEADS
diff --git a/code/modules/modular_computers/file_system/programs/jobmanagement.dm b/code/modules/modular_computers/file_system/programs/jobmanagement.dm
index 3f21d2cf2c2..4df92541b35 100644
--- a/code/modules/modular_computers/file_system/programs/jobmanagement.dm
+++ b/code/modules/modular_computers/file_system/programs/jobmanagement.dm
@@ -1,6 +1,7 @@
/datum/computer_file/program/job_management
filename = "plexagoncore"
filedesc = "Plexagon HR Core"
+ category = PROGRAM_CATEGORY_CREW
program_icon_state = "id"
extended_desc = "Program for viewing and changing job slot avalibility."
transfer_access = ACCESS_HEADS
diff --git a/code/modules/modular_computers/file_system/programs/ntdownloader.dm b/code/modules/modular_computers/file_system/programs/ntdownloader.dm
index f3fa6df2b3a..56283e3c8be 100644
--- a/code/modules/modular_computers/file_system/programs/ntdownloader.dm
+++ b/code/modules/modular_computers/file_system/programs/ntdownloader.dm
@@ -22,6 +22,13 @@
var/emagged = FALSE
var/list/main_repo
var/list/antag_repo
+ var/list/show_categories = list(
+ PROGRAM_CATEGORY_CREW,
+ PROGRAM_CATEGORY_ENGI,
+ PROGRAM_CATEGORY_ROBO,
+ PROGRAM_CATEGORY_SUPL,
+ PROGRAM_CATEGORY_MISC,
+ )
/datum/computer_file/program/ntnetdownload/run_program()
. = ..()
@@ -146,39 +153,29 @@
var/obj/item/computer_hardware/hard_drive/hard_drive = my_computer.all_components[MC_HDD]
data["disk_size"] = hard_drive.max_capacity
data["disk_used"] = hard_drive.used_capacity
- var/list/all_entries[0]
- for(var/A in main_repo)
- var/datum/computer_file/program/P = A
- // Only those programs our user can run will show in the list
- if(hard_drive.find_file_by_name(P.filename))
- continue
- all_entries.Add(list(list(
+ data["emagged"] = emagged
+
+ var/list/repo = antag_repo | main_repo
+ var/list/program_categories = list()
+
+ for(var/I in repo)
+ var/datum/computer_file/program/P = I
+ if(!(P.category in program_categories))
+ program_categories.Add(P.category)
+ data["programs"] += list(list(
+ "icon" = P.program_icon,
"filename" = P.filename,
"filedesc" = P.filedesc,
"fileinfo" = P.extended_desc,
- "compatibility" = check_compatibility(P),
+ "category" = P.category,
+ "installed" = !!hard_drive.find_file_by_name(P.filename),
+ "compatible" = check_compatibility(P),
"size" = P.size,
- "access" = P.can_run(user,transfer = 1, access = access)
- )))
- data["hackedavailable"] = FALSE
- if(emagged) // If we are running on emagged computer we have access to some "bonus" software
- var/list/hacked_programs[0]
- for(var/S in antag_repo)
- var/datum/computer_file/program/P = S
- if(hard_drive.find_file_by_name(P.filename))
- continue
- data["hackedavailable"] = TRUE
- hacked_programs.Add(list(list(
- "filename" = P.filename,
- "filedesc" = P.filedesc,
- "fileinfo" = P.extended_desc,
- "compatibility" = check_compatibility(P),
- "size" = P.size,
- "access" = TRUE,
- )))
- data["hacked_programs"] = hacked_programs
+ "access" = emagged && P.available_on_syndinet ? TRUE : P.can_run(user,transfer = 1, access = access),
+ "verifiedsource" = P.available_on_ntnet,
+ ))
- data["downloadable_programs"] = all_entries
+ data["categories"] = show_categories & program_categories
return data
@@ -186,8 +183,8 @@
var/hardflag = computer.hardware_flag
if(P?.is_supported_by_hardware(hardflag,0))
- return "Compatible"
- return "Incompatible!"
+ return TRUE
+ return FALSE
/datum/computer_file/program/ntnetdownload/kill_program(forced)
abort_file_download()
diff --git a/code/modules/modular_computers/file_system/programs/ntmonitor.dm b/code/modules/modular_computers/file_system/programs/ntmonitor.dm
index b39fcad572d..d508317008a 100644
--- a/code/modules/modular_computers/file_system/programs/ntmonitor.dm
+++ b/code/modules/modular_computers/file_system/programs/ntmonitor.dm
@@ -1,6 +1,7 @@
/datum/computer_file/program/ntnetmonitor
filename = "wirecarp"
filedesc = "WireCarp"
+ category = PROGRAM_CATEGORY_MISC
program_icon_state = "comm_monitor"
extended_desc = "This program monitors stationwide NTNet network, provides access to logging systems, and allows for configuration changes"
size = 12
diff --git a/code/modules/modular_computers/file_system/programs/ntnrc_client.dm b/code/modules/modular_computers/file_system/programs/ntnrc_client.dm
index 19172f130ab..b4e48d0e79a 100644
--- a/code/modules/modular_computers/file_system/programs/ntnrc_client.dm
+++ b/code/modules/modular_computers/file_system/programs/ntnrc_client.dm
@@ -1,6 +1,7 @@
/datum/computer_file/program/chatclient
filename = "ntnrc_client"
filedesc = "Chat Client"
+ category = PROGRAM_CATEGORY_MISC
program_icon_state = "command"
extended_desc = "This program allows communication over NTNRC network"
size = 8
diff --git a/code/modules/modular_computers/file_system/programs/powermonitor.dm b/code/modules/modular_computers/file_system/programs/powermonitor.dm
index 78a14ff1ad8..933c9410a27 100644
--- a/code/modules/modular_computers/file_system/programs/powermonitor.dm
+++ b/code/modules/modular_computers/file_system/programs/powermonitor.dm
@@ -3,6 +3,7 @@
/datum/computer_file/program/power_monitor
filename = "ampcheck"
filedesc = "AmpCheck"
+ category = PROGRAM_CATEGORY_ENGI
program_icon_state = "power_monitor"
extended_desc = "This program connects to sensors around the station to provide information about electrical systems"
ui_header = "power_norm.gif"
diff --git a/code/modules/modular_computers/file_system/programs/radar.dm b/code/modules/modular_computers/file_system/programs/radar.dm
index 9f570fe6a4c..31142b37291 100644
--- a/code/modules/modular_computers/file_system/programs/radar.dm
+++ b/code/modules/modular_computers/file_system/programs/radar.dm
@@ -1,6 +1,7 @@
/datum/computer_file/program/radar //generic parent that handles most of the process
filename = "genericfinder"
filedesc = "debug_finder"
+ category = PROGRAM_CATEGORY_CREW
ui_header = "borg_mon.gif" //DEBUG -- new icon before PR
program_icon_state = "radarntos"
requires_ntnet = TRUE
@@ -258,6 +259,7 @@
/datum/computer_file/program/radar/fission360
filename = "fission360"
filedesc = "Fission360"
+ category = PROGRAM_CATEGORY_MISC
program_icon_state = "radarsyndicate"
extended_desc = "This program allows for tracking of nuclear authorization disks and warheads."
requires_ntnet = FALSE
diff --git a/code/modules/modular_computers/file_system/programs/robocontrol.dm b/code/modules/modular_computers/file_system/programs/robocontrol.dm
index 8c41ea6c380..7fe5a09ab2a 100644
--- a/code/modules/modular_computers/file_system/programs/robocontrol.dm
+++ b/code/modules/modular_computers/file_system/programs/robocontrol.dm
@@ -2,6 +2,7 @@
/datum/computer_file/program/robocontrol
filename = "botkeeper"
filedesc = "BotKeeper"
+ category = PROGRAM_CATEGORY_ROBO
program_icon_state = "robot"
extended_desc = "A remote controller used for giving basic commands to non-sentient robots."
transfer_access = null
diff --git a/code/modules/modular_computers/file_system/programs/robotact.dm b/code/modules/modular_computers/file_system/programs/robotact.dm
index 34156015ed7..1bb1da54fcd 100644
--- a/code/modules/modular_computers/file_system/programs/robotact.dm
+++ b/code/modules/modular_computers/file_system/programs/robotact.dm
@@ -1,6 +1,7 @@
/datum/computer_file/program/robotact
filename = "robotact"
filedesc = "RoboTact"
+ category = PROGRAM_CATEGORY_ROBO
extended_desc = "A built-in app for cyborg self-management and diagnostics."
ui_header = "robotact.gif" //DEBUG -- new icon before PR
program_icon_state = "command"
diff --git a/code/modules/modular_computers/file_system/programs/secureeye.dm b/code/modules/modular_computers/file_system/programs/secureeye.dm
index 92275b1e8b6..d2d7590cb18 100644
--- a/code/modules/modular_computers/file_system/programs/secureeye.dm
+++ b/code/modules/modular_computers/file_system/programs/secureeye.dm
@@ -3,6 +3,7 @@
/datum/computer_file/program/secureye
filename = "secureye"
filedesc = "SecurEye"
+ category = PROGRAM_CATEGORY_MISC
ui_header = "borg_mon.gif"
program_icon_state = "generic"
extended_desc = "This program allows access to standard security camera networks."
diff --git a/code/modules/modular_computers/file_system/programs/sm_monitor.dm b/code/modules/modular_computers/file_system/programs/sm_monitor.dm
index 799a4eb3ebf..f0ee46e23ae 100644
--- a/code/modules/modular_computers/file_system/programs/sm_monitor.dm
+++ b/code/modules/modular_computers/file_system/programs/sm_monitor.dm
@@ -1,6 +1,7 @@
/datum/computer_file/program/supermatter_monitor
filename = "ntcims"
filedesc = "NT CIMS"
+ category = PROGRAM_CATEGORY_ENGI
ui_header = "smmon_0.gif"
program_icon_state = "smmon_0"
extended_desc = "Crystal Integrity Monitoring System, connects to specially calibrated supermatter sensors to provide information on the status of supermatter-based engines."
diff --git a/tgui/packages/tgui/interfaces/NtosNetDownloader.js b/tgui/packages/tgui/interfaces/NtosNetDownloader.js
index ae9e6b94c75..88e7062a7fb 100644
--- a/tgui/packages/tgui/interfaces/NtosNetDownloader.js
+++ b/tgui/packages/tgui/interfaces/NtosNetDownloader.js
@@ -1,5 +1,8 @@
-import { useBackend } from '../backend';
-import { Box, Button, Flex, Icon, LabeledList, NoticeBox, ProgressBar, Section } from '../components';
+import { scale, toFixed } from 'common/math';
+import { useBackend, useLocalState } from '../backend';
+import { Box, Button, Stack, Icon, LabeledList, NoticeBox, ProgressBar, Section, Tabs } from '../components';
+import { flow } from 'common/fp';
+import { filter, sortBy } from 'common/collections';
import { NtosWindow } from '../layouts';
export const NtosNetDownloader = (props, context) => {
@@ -8,16 +11,43 @@ export const NtosNetDownloader = (props, context) => {
PC_device_theme,
disk_size,
disk_used,
- downloadable_programs = [],
+ downloadcompletion,
+ downloading,
+ downloadname,
+ downloadsize,
error,
- hacked_programs = [],
- hackedavailable,
+ emagged,
+ categories,
+ programs,
} = data;
+ const all_categories = ['All'].concat(categories);
+ const downloadpercentage = toFixed(
+ scale(downloadcompletion, 0, downloadsize) * 100
+ );
+ const [
+ selectedCategory,
+ setSelectedCategory,
+ ] = useLocalState(context, 'category', all_categories[0]);
+ const items = flow([
+ // This filters the list to only contain programs with category
+ selectedCategory !== all_categories[0]
+ && filter(program => program.category === selectedCategory),
+ // This filters the list to only contain verified programs
+ (!emagged && PC_device_theme === "ntos")
+ && filter(program => program.verifiedsource === 1),
+ // This sorts all programs in the lists by name and compatibility
+ sortBy(
+ program => -program.compatible,
+ program => program.filedesc),
+ ])(programs);
+ const disk_free_space = downloading
+ ? disk_size - toFixed(disk_used + downloadcompletion)
+ : disk_size - disk_used;
return (
+ width={600}
+ height={600}>
{!!error && (
@@ -31,45 +61,55 @@ export const NtosNetDownloader = (props, context) => {
)}
-
+
+ ) || (!!downloadname && (
+
+ ))}>
- {`${disk_used} GQ / ${disk_size} GQ`}
+
+ {`${disk_free_space} GQ free of ${disk_size} GQ`}
+
-
- {downloadable_programs
- .filter(program => program.access)
- .map(program => (
+
+
+
+ {all_categories.map(category => (
+ setSelectedCategory(category)}>
+ {category}
+
+ ))}
+
+
+
+ {items?.map(program => (
))}
- {downloadable_programs
- .filter(program => !program.access)
- .map(program => (
-
- ))}
-
- {!!hackedavailable && (
-
-
- Please note that Nanotrasen does not recommend download
- of software from non-official servers.
-
- {hacked_programs.map(program => (
-
- ))}
-
- )}
+
+
);
@@ -79,65 +119,74 @@ const Program = (props, context) => {
const { program } = props;
const { act, data } = useBackend(context);
const {
+ PC_device_theme,
disk_size,
disk_used,
- downloadcompletion,
downloading,
downloadname,
- downloadsize,
+ downloadcompletion,
} = data;
const disk_free = disk_size - disk_used;
return (
-
-
-
+
+
+
+
{program.filedesc}
-
-
+
+
{program.size} GQ
-
-
- {program.filename === downloadname && (
+
+
+ {(downloading && program.filename === downloadname) && (
) || (
-
-
- {program.compatibility !== 'Compatible' && (
-
-
- Incompatible!
-
- )}
- {!(program.access) && (
-
-
- Invalid credentials loaded!
-
- )}
- {program.size > disk_free && (
-
-
- Not enough disk space!
-
- )}
-
+
+
+
{program.fileinfo}
-
+ {(!program.verifiedsource && PC_device_theme === "ntos") && (
+
+ Unverified source. Please note that Nanotrasen does not recommend
+ download and usage of software from non-official servers.
+
+ )}
+
);
};