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: +
+ ); +}; + +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 && ( +
+ ); + } + + return ( +
+ {is_admin === 1 && ( + + !! Due to being adminned, + your proximity and living checks are bypassed !! + + )} + {is_admin === 1 && ( + +
+ ); +}; + +/** + * 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, + })} + /> + } + /> + ))} + + ); +};