diff --git a/code/game/machinery/computer/abnormality_auxiliary.dm b/code/game/machinery/computer/abnormality_auxiliary.dm
index df085e37c143..d388610c5fae 100644
--- a/code/game/machinery/computer/abnormality_auxiliary.dm
+++ b/code/game/machinery/computer/abnormality_auxiliary.dm
@@ -16,6 +16,9 @@
)
var/datum/suppression/selected_core_type = null
+ // toggles if the window being opened is TGUI or UI, players can toggle it in case TGUI fails to load
+ var/TGUI_mode = TRUE
+
/obj/machinery/computer/abnormality_auxiliary/Initialize()
. = ..()
GLOB.lobotomy_devices += src
@@ -25,8 +28,25 @@
GLOB.lobotomy_devices -= src
..()
-/obj/machinery/computer/abnormality_auxiliary/ui_interact(mob/user)
+/obj/machinery/computer/abnormality_auxiliary/AltClick(mob/user) // toggles if the UI is using TGUI or not
+ . = ..()
+ // If we dont close them, some things can be weird
+ SStgui.close_uis(src)
+ TGUI_mode = !TGUI_mode
+ say("[TGUI_mode ? "Turned on" : "Turned off"] TGUI mode")
+ playsound(get_turf(src), 'sound/machines/terminal_prompt_confirm.ogg', 50, TRUE)
+
+/obj/machinery/computer/abnormality_auxiliary/ui_interact(mob/user, datum/tgui/ui)
. = ..()
+ if(TGUI_mode)
+ ui = SStgui.try_update_ui(user, src, ui)
+ if(!ui)
+ to_chat(user, span_notice("If TGUI is failing to load, you can alt+click the console to switch to UI mode"))
+ ui = new(user, src, "AuxiliaryManagerConsole")
+ ui.open()
+ ui.set_autoupdate(TRUE)
+ return
+
var/dat
for(var/p in all_pages)
dat += "[p == page ? "[p]" : "[p]"]"
@@ -81,6 +101,7 @@
. = ..()
if(.)
return .
+
if(ishuman(usr))
usr.set_machine(src)
add_fingerprint(usr)
@@ -135,3 +156,345 @@
#undef CORE_SUPPRESSIONS
#undef FACILITY_UPGRADES
+
+// TGUI stuff onwards, all beware ye who enter
+
+// gather all the assets needed for optional decorative stuff
+/datum/asset/simple/sephirah
+ assets = list(
+ // upper layer
+
+ "SEPHIRAH.yellow.png" = icon('icons/obj/plushes.dmi', "malkuth"),
+ "SEPHIRAH.purple.png" = icon('icons/obj/plushes.dmi', "yesod"),
+ "SEPHIRAH.green.png" = icon('icons/obj/plushes.dmi', "netzach"),
+ "SEPHIRAH.orange.png" = icon('icons/obj/plushes.dmi', "hod"),
+
+ // middle layer
+
+ // command overriden
+ "SEPHIRAH.blue.png" = icon('icons/obj/plushes.dmi', "chesed"),
+ "SEPHIRAH.red.png" = icon('icons/obj/plushes.dmi', "gebura"),
+
+ // lower layer
+
+ // extraction overriden
+ "SEPHIRAH.white.png" = icon('icons/obj/plushes.dmi', "hokma"),
+
+ // icon overrides
+
+ "SEPHIRAH.AYIN.png" = icon('icons/obj/plushes.dmi', "ayin"), // fuck you *turns ayin into a sephirah*
+ "SEPHIRAH.TWINS.png" = icon('icons/obj/plushes.dmi', "lisa"),
+ "SEPHIRAH.BINAH.png" = icon('icons/obj/plushes.dmi', "binah"),
+
+ )
+
+/obj/machinery/computer/abnormality_auxiliary/ui_assets(mob/user)
+ return list(
+ get_asset_datum(/datum/asset/simple/sephirah),
+ )
+
+/obj/machinery/computer/abnormality_auxiliary/ui_data(mob/user)
+ . = ..()
+ var/list/data = list()
+
+ // start facility upgrade info
+ data["Upgrade_points"] = round(SSlobotomy_corp.lob_points, 0.1)
+
+ // preferably this would be in static, but the cost and avaibility needs to be updated whenever an action is performed
+
+ var/list/bullet_upgrades = list()
+ var/list/real_bullet_upgrades = list()
+ var/list/agent_upgrades = list()
+ var/list/abnormality_upgrades = list()
+ var/list/you_didnt_give_it_a_proper_category_dammit_upgrades = list()
+
+ for(var/thing in SSlobotomy_corp.upgrades)
+ var/datum/facility_upgrade/upgrade = thing
+ if(!upgrade.CanShowUpgrade())
+ continue
+
+ var/available = TRUE
+ if(upgrade.value >= upgrade.max_value)
+ available = FALSE
+
+ var/modified_upgrade_name
+ if(upgrade.value == 0) // if the upgrade is just a toggle, there's no point in showing its value now, is there?
+ modified_upgrade_name = upgrade.name
+ else
+ modified_upgrade_name = "[upgrade.name] ([upgrade.value])"
+
+
+ var/list/upgrade_data = list(list(
+ "name" = modified_upgrade_name,
+ "ref" = REF(upgrade),
+ "cost" = upgrade.cost,
+ "available" = available,
+ ))
+
+
+ var/upgrade_category = upgrade.category
+ switch(upgrade_category) // sort them into different lists depending on what category they fit in
+ if("Bullets")
+ bullet_upgrades += upgrade_data
+
+ if("Bullet Upgrades")
+ real_bullet_upgrades += upgrade_data
+
+ if("Agent")
+ agent_upgrades += upgrade_data
+
+ if("Abnormalities")
+ abnormality_upgrades += upgrade_data
+
+ else
+ you_didnt_give_it_a_proper_category_dammit_upgrades += upgrade_data
+
+ data["bullet_upgrades"] = bullet_upgrades
+ data["real_bullet_upgrades"] = real_bullet_upgrades
+ data["agent_upgrades"] = agent_upgrades
+ data["abnormality_upgrades"] = abnormality_upgrades
+ data["misc_upgrades"] = you_didnt_give_it_a_proper_category_dammit_upgrades
+ // end facility upgrade info
+
+ return data
+
+
+/obj/machinery/computer/abnormality_auxiliary/ui_static_data(mob/user)
+ . = ..()
+ var/list/data = list()
+
+ // start core suppression info
+ data["current_suppression"] = FALSE // if the type check fails, we send FALSE instead
+ if(istype(SSlobotomy_corp.core_suppression))
+ var/core_suppression_name = SSlobotomy_corp.core_suppression.name
+
+ data["current_suppression"] = core_suppression_name
+ data["selected_core_color"] = "red"
+ var/icon_override = FALSE // normally the assets are fetched via the color of the core being supressed, this overrides it
+ switch(core_suppression_name) // we choose the core's color once its locked in place here, the mother of all switches
+ // upper layer
+ if(CONTROL_CORE_SUPPRESSION)
+ data["selected_core_color"] = "yellow"
+
+ if(INFORMATION_CORE_SUPPRESSION)
+ data["selected_core_color"] = "purple"
+
+ if(SAFETY_CORE_SUPPRESSION)
+ data["selected_core_color"] = "green"
+
+ if(TRAINING_CORE_SUPPRESSION)
+ data["selected_core_color"] = "orange"
+
+ // middle layer
+
+ if(COMMAND_CORE_SUPPRESSION)
+ data["selected_core_color"] = "yellow"
+ icon_override = "TWINS"
+
+ if(WELFARE_CORE_SUPPRESSION)
+ data["selected_core_color"] = "blue"
+
+ if(DISCIPLINARY_CORE_SUPPRESSION)
+ data["selected_core_color"] = "red"
+
+ // bottom layer
+ if(EXTRACTION_CORE_SUPPRESSION)
+ data["selected_core_color"] = "yellow"
+ icon_override = "BINAH"
+
+ if(RECORDS_CORE_SUPPRESSION)
+ data["selected_core_color"] = "white"
+
+ // literal hell layer
+
+ // should divide them and give them colors later, but no clue what they could have for now
+ if(DAY46_CORE_SUPPRESSION, DAY47_CORE_SUPPRESSION, DAY48_CORE_SUPPRESSION, DAY49_CORE_SUPPRESSION, DAY50_CORE_SUPPRESSION)
+ data["selected_core_color"] = "white"
+ icon_override = "AYIN"
+
+ // you didnt set a proper core layer
+ else
+ data["selected_core_color"] = "red"
+
+ if(icon_override)
+ data["selected_core_icon"] = "SEPHIRAH.[icon_override].png"
+ else
+ data["selected_core_icon"] = "SEPHIRAH.[data["selected_core_color"]].png"
+
+ if(ispath(selected_core_type))
+ data["selected_core_name"] = initial(selected_core_type.name)
+ data["selected_core_description"] = initial(selected_core_type.desc)
+ data["selected_core_goal"] = initial(selected_core_type.goal_text)
+ data["selected_core_reward"] = initial(selected_core_type.reward_text)
+
+ var/list/available_suppressions = list()
+ for(var/core_type in SSlobotomy_corp.available_core_suppressions)
+ var/datum/suppression/core_suppression = core_type
+ available_suppressions += list(list(
+ "name" = core_suppression.name,
+ "ref" = REF(core_suppression),
+ ))
+
+ data["available_suppressions"] = available_suppressions
+
+ var/list/pre_made_core_suppressions = subtypesof(/datum/suppression)
+ var/list/all_core_suppressions = list()
+ for(var/core_type in pre_made_core_suppressions)
+ var/datum/suppression/core_suppression = core_type
+ all_core_suppressions += list(list(
+ "name" = core_suppression.name,
+ "ref" = REF(core_suppression),
+ ))
+
+ data["all_core_suppressions"] = all_core_suppressions
+ // end core suppression info
+
+ var/is_admin
+ if(user.client.holder)
+ is_admin = TRUE
+ else
+ is_admin = FALSE
+
+ data["is_admin"] = is_admin // used to determine if we unlock special admin-only options
+
+ return data
+
+
+/obj/machinery/computer/abnormality_auxiliary/ui_act(action, list/params)
+ . = ..()
+ if(. && !usr.client.holder) // the usr.client.holder check allows admins to bypass the typical TGUI proximity checks
+ return
+
+ switch(action)
+ if("Select Core Suppression") // selects a core suppression
+ var/core_suppression = locate(params["selected_core"]) in SSlobotomy_corp.available_core_suppressions
+ if(!ispath(core_suppression) || !(core_suppression in SSlobotomy_corp.available_core_suppressions))
+ return
+
+ selected_core_type = core_suppression
+ say("[initial(selected_core_type.name)] has been selected!")
+ playsound(get_turf(src), 'sound/machines/terminal_prompt_confirm.ogg', 50, TRUE)
+ update_static_data_for_all_viewers()
+
+ if("Activate Core Suppression") // activates the currently selected core suppression
+ if(!ispath(selected_core_type) || !(selected_core_type in SSlobotomy_corp.available_core_suppressions))
+ return
+ if(istype(SSlobotomy_corp.core_suppression))
+ CRASH("[src] has attempted to activate a core suppression via TGUI whilst its not possible!")
+
+ log_action(usr,
+ message_override = "[usr] has started the [initial(selected_core_type.name)] core suppression"
+ )
+
+ say("[initial(selected_core_type.name)] protocol activated, good luck manager.")
+ SSlobotomy_corp.core_suppression = new selected_core_type
+ SSlobotomy_corp.core_suppression.legitimate = TRUE
+ SSlobotomy_corp.available_core_suppressions = list()
+ selected_core_type = null
+ playsound(get_turf(src), 'sound/machines/terminal_prompt_confirm.ogg', 50, TRUE)
+ addtimer(CALLBACK(SSlobotomy_corp.core_suppression, TYPE_PROC_REF(/datum/suppression, Run)), 2 SECONDS)
+ update_static_data_for_all_viewers()
+
+ if("Buy Upgrade") // Buys an upgrade, looking for a parameter that is given to the upgrade thats being bought on the TGUI side
+ var/datum/facility_upgrade/U = locate(params["selected_upgrade"]) in SSlobotomy_corp.upgrades
+ if(!istype(U) || !U.CanUpgrade())
+ return
+
+ log_action(usr,
+ message_override = "[usr] has purchased the [U.name] facility upgrade"
+ )
+ U.Upgrade()
+ playsound(get_turf(src), 'sound/machines/terminal_prompt_confirm.ogg', 50, TRUE)
+
+ // admin-only actions, remember to put a if(!log_action) check with a proper return
+ if("Unlock Core Suppressions")
+ if(!log_action(usr, admin_action = TRUE,
+ message_override = "[usr] has used admin powers to manipulate the available cores in the auxiliary console"
+ ))
+ update_static_data_for_all_viewers()
+ return
+
+ var/core_to_unlock = params["core_unlock"]
+
+ if(core_to_unlock != 1)
+ var/list/all_cores = subtypesof(/datum/suppression)
+ var/selected_core = locate(params["core_unlock"]) in all_cores
+
+ SSlobotomy_corp.available_core_suppressions += selected_core
+
+ else // unlock all of them if the core to unlock is not specified
+ SSlobotomy_corp.available_core_suppressions = subtypesof(/datum/suppression)
+
+ update_static_data_for_all_viewers()
+
+ if("Disable Core Suppression")
+ if(istype(SSlobotomy_corp.core_suppression) || !LAZYLEN(SSlobotomy_corp.available_core_suppressions))
+ message_admins("[usr] has tried to disable all core suppressions but there were none, all admins laugh at them!")
+ return
+
+ if(!log_action(usr, admin_action = TRUE,
+ message_override = "[usr] has used admin powers to disable all core suppressions!"
+ ))
+ update_static_data_for_all_viewers()
+ return
+
+ SSlobotomy_corp.ResetPotentialSuppressions()
+ update_static_data_for_all_viewers()
+
+ if("End Core Suppression")
+ if(!log_action(usr, admin_action = TRUE,
+ message_override = "[usr] has used admin powers to end the current core suppression (persistence not saved)"
+ ))
+ update_static_data_for_all_viewers()
+ return
+
+ SSlobotomy_corp.core_suppression.legitimate = FALSE // let admins mess around without worrying about persistence
+ SSlobotomy_corp.core_suppression.End()
+ update_static_data_for_all_viewers()
+
+ if("Change LOB Points")
+ var/amount = params["LOB_amount"]
+ if(!log_action(usr, admin_action = TRUE,
+ message_override = "[usr] has used admin powers to [amount > 0 ? "add" : "remove"] [amount] LOB point[(amount > 1 || amount < -1) ? "s" : ""] in the auxiliary console"
+ ))
+ update_static_data_for_all_viewers()
+ return
+
+ SSlobotomy_corp.lob_points += amount
+
+ else // something bad happened, refresh the data and it hopefully fixes itself
+ update_static_data_for_all_viewers()
+
+/**
+ * Logs interactions with the console
+ *
+ * arguments:
+ * (required) console_user = the user that is using the console (usr)
+ * (optional) admin_action = if the current action should be restricted for only admins
+ * (optional/required) message_override = if set on any value other than FALSE, the logging message will be replaced by it
+ */
+/obj/machinery/computer/abnormality_auxiliary/proc/log_action(mob/console_user, admin_action = FALSE, message_override = FALSE)
+ if(!console_user)
+ CRASH("user not provided in (/obj/machinery/computer/abnormality_auxiliary/proc/log_action)")
+
+ if(!admin_action)
+ if(message_override)
+ log_game(message_override)
+ message_admins(message_override)
+ return TRUE
+ else // if you are going to use it on non-admin actions, you need a message because we have actually no clue whats happening
+ CRASH("message_override not set up on a non-admin action within the TGUI auxiliary console whilst its mandatory!")
+
+ var/is_admin = console_user.client.holder
+ if(!is_admin)
+ message_admins("[usr] has used an admin-only option in the auxiliary console TGUI whilst not an admin!")
+ return FALSE
+
+ if(message_override)
+ log_game(message_override)
+ message_admins(message_override)
+ return TRUE
+
+ log_game("[usr] has used admin powers to trigger an admin-only action in the auxiliary console")
+ message_admins("[usr] has used admin powers to trigger an admin-only action in the auxiliary console")
+ return TRUE
diff --git a/code/modules/tgui/external.dm b/code/modules/tgui/external.dm
index fc1db4510fee..b6d02ddb81df 100644
--- a/code/modules/tgui/external.dm
+++ b/code/modules/tgui/external.dm
@@ -62,6 +62,17 @@
if(ui)
ui.send_full_update()
+/**
+ * public
+ *
+ * Will force an update on static data for all viewers.
+ * Should be done manually whenever something happens to
+ * change static data.
+ */
+/datum/proc/update_static_data_for_all_viewers()
+ for (var/datum/tgui/window as anything in SStgui.open_uis_by_src[REF(src)])
+ window.send_full_update()
+
/**
* public
*
diff --git a/tgui/packages/tgui/interfaces/AuxiliaryManagerConsole.js b/tgui/packages/tgui/interfaces/AuxiliaryManagerConsole.js
new file mode 100644
index 000000000000..b9b6b99b29d9
--- /dev/null
+++ b/tgui/packages/tgui/interfaces/AuxiliaryManagerConsole.js
@@ -0,0 +1,511 @@
+// THIS IS A LOBOTOMYCORPORATION UI FILE
+
+import { resolveAsset } from '../assets';
+import { useBackend, useLocalState } from '../backend';
+import { Box, Button, LabeledList, NoticeBox, Section, Tabs, Collapsible } from '../components';
+import { Window } from '../layouts';
+
+export const AuxiliaryManagerConsole = (props, context) => {
+ const [tab, setTab] = useLocalState(context, 'tab', 1);
+
+ return (
+
+
+
+ setTab(1)}>
+ Facility Upgrade system
+
+ setTab(2)}>
+ Core Suppression system
+
+
+ {tab === 1 && }
+ {tab === 2 && }
+
+
+ );
+};
+
+const FacilityUpgrades = (props, context) => {
+ const { act, data } = useBackend(context);
+ const { Upgrade_points, is_admin } = data;
+
+ return (
+
+ {is_admin === 1 && (
+
+ !! Due to being adminned,
+ your proximity and living checks are bypassed !!
+
+ )}
+ {is_admin === 1 && (
+
+ (ADMIN ONLY) Add/Subtract LOB points:
+
+ )}
+
+
+ {Upgrade_points}
+
+
+ {/*
+ All of the upgrade parts are basically the same,
+ except they have different mapping variables so we can sort out categories
+ Surelly there's a better way to do this
+ */}
+
+ Available unlockable bullets:
+
+
+
+
+ Available bullet upgrades:
+
+
+
+
+ Available agent upgrades:
+
+
+
+
+ Available abnormality cell upgrades:
+
+
+
+
+ Available uncategorized upgrades:
+
+
+
+ );
+};
+
+const CoreSuppressionSelector = (props, context) => {
+ const { act, data } = useBackend(context);
+ const {
+ is_admin,
+ current_suppression,
+ available_suppressions,
+ selected_core_name,
+ selected_core_description,
+ selected_core_goal,
+ selected_core_reward,
+ selected_core_color,
+ selected_core_icon,
+ } = data;
+
+ if (current_suppression) {
+ return (
+
+ {is_admin === 1 && (
+ act('End Core Suppression')}
+ />
+ )}
+
+ WARNING WARNING WARNING
+ WARNING WARNING WARNING
+ WARNING WARNING WARNING
+
+
+
+ {current_suppression} in progress!
+
+
+
+ WARNING WARNING WARNING
+ WARNING WARNING WARNING
+ WARNING WARNING WARNING
+
+
+ );
+ }
+
+ return (
+
+ {is_admin === 1 && (
+
+ !! Due to being adminned,
+ your proximity and living checks are bypassed !!
+
+ )}
+ {is_admin === 1 && (
+
+
+ act('Unlock Core Suppressions', {
+ core_unlock: 1,
+ })}
+ />
+ act('Disable Core Suppression')}
+ />
+
+ )}
+ {is_admin === 1 && (
+
+
+
+ )}
+ {available_suppressions.length > 0 && (
+
+ {available_suppressions.map(available_suppressions => (
+
+ act('Select Core Suppression', {
+ selected_core: available_suppressions.ref,
+ })}
+ />
+ }
+ />
+ ))}
+
+ )}
+ {available_suppressions.length === 0 && (
+
+ Core suppressions not available!
+
+ )}
+ {selected_core_name && (
+
+
+ {selected_core_name}
+
+
+ {selected_core_description}
+
+
+ {selected_core_goal}
+
+
+ {selected_core_reward}
+
+ act('Activate Core Suppression')}
+ />
+
+ )}
+
+ );
+};
+
+/**
+ * Tons of copy paste down below
+ */
+
+const BulletUpgrades = (props, context) => {
+ const { act, data } = useBackend(context);
+ const { Upgrade_points, bullet_upgrades } = data;
+
+ if (bullet_upgrades.length < 1) {
+ return;
+ }
+
+ return (
+
+ {bullet_upgrades.map(bullet_upgrades => (
+ = bullet_upgrades.cost
+ && bullet_upgrades.available === 1
+ ? 'green'
+ : 'red'
+ }
+ onClick={() =>
+ act('Buy Upgrade', {
+ selected_upgrade: bullet_upgrades.ref,
+ })}
+ />
+ }
+ />
+ ))}
+
+ );
+};
+
+const MoreBulletUpgrades = (props, context) => {
+ const { act, data } = useBackend(context);
+ const { Upgrade_points, real_bullet_upgrades } = data;
+
+ if (real_bullet_upgrades.length < 1) {
+ return;
+ }
+
+ return (
+
+ {real_bullet_upgrades.map(real_bullet_upgrades => (
+ = real_bullet_upgrades.cost
+ && real_bullet_upgrades.available === 1
+ ? 'green'
+ : 'red'
+ }
+ onClick={() =>
+ act('Buy Upgrade', {
+ selected_upgrade: real_bullet_upgrades.ref,
+ })}
+ />
+ }
+ />
+ ))}
+
+ );
+};
+
+const AgentUpgrades = (props, context) => {
+ const { act, data } = useBackend(context);
+ const { Upgrade_points, agent_upgrades } = data;
+
+ if (agent_upgrades.length < 1) {
+ return;
+ }
+
+ return (
+
+ {agent_upgrades.map(agent_upgrades => (
+ = agent_upgrades.cost
+ && agent_upgrades.available === 1
+ ? 'green'
+ : 'red'
+ }
+ onClick={() =>
+ act('Buy Upgrade', {
+ selected_upgrade: agent_upgrades.ref,
+ })}
+ />
+ }
+ />
+ ))}
+
+ );
+};
+
+const AbnormalityUpgrades = (props, context) => {
+ const { act, data } = useBackend(context);
+ const { Upgrade_points, abnormality_upgrades } = data;
+
+ if (abnormality_upgrades.length < 1) {
+ return;
+ }
+
+ return (
+
+ {abnormality_upgrades.map(abnormality_upgrades => (
+ = abnormality_upgrades.cost
+ && abnormality_upgrades.available === 1
+ ? 'green'
+ : 'red'
+ }
+ onClick={() =>
+ act('Buy Upgrade', {
+ selected_upgrade: abnormality_upgrades.ref,
+ })}
+ />
+ }
+ />
+ ))}
+
+ );
+};
+
+const MiscUpgrades = (props, context) => {
+ const { act, data } = useBackend(context);
+ const { Upgrade_points, misc_upgrades } = data;
+
+ if (misc_upgrades.length < 1) {
+ return;
+ }
+
+ return (
+
+ {misc_upgrades.map(misc_upgrades => (
+ = misc_upgrades.cost
+ && misc_upgrades.available === 1
+ ? 'green'
+ : 'red'
+ }
+ onClick={() =>
+ act('Buy Upgrade', {
+ selected_upgrade: misc_upgrades.ref,
+ })}
+ />
+ }
+ />
+ ))}
+
+ );
+};
+
+const AllCores = (props, context) => {
+ const { act, data } = useBackend(context);
+ const { all_core_suppressions } = data;
+
+ if (all_core_suppressions.length < 1) {
+ return;
+ }
+
+ return (
+
+ {all_core_suppressions.map(all_core_suppressions => (
+
+ act('Unlock Core Suppressions', {
+ core_unlock: all_core_suppressions.ref,
+ })}
+ />
+ }
+ />
+ ))}
+
+ );
+};