From ca50656a51a4658bae9b1ea80c6668921cca5113 Mon Sep 17 00:00:00 2001 From: Aylong <69762909+AyIong@users.noreply.github.com> Date: Sat, 9 Nov 2024 10:04:53 +0200 Subject: [PATCH] [TGUI] Loadout (#27026) * [TGUI] Loadout * Loadout Tweaks * Cleanup * Almost there * Allow to sort alphabetical * UX tweaks * Note and remove tweaks from scarf * Oh fuck * Ooops * Sorting features * Global search * Rebuild * Sure * Rebuildo and some review changes * TGUI REBUILDO! --------- Co-authored-by: ROdenFL Co-authored-by: Burzah <116982774+Burzah@users.noreply.github.com> --- code/__DEFINES/preferences_defines.dm | 5 +- code/__HELPERS/global_lists.dm | 51 ++- code/game/jobs/job/job.dm | 4 +- code/modules/client/preference/character.dm | 4 +- .../client/preference/link_processing.dm | 33 +- .../client/preference/loadout/gear_tweaks.dm | 108 ++--- .../client/preference/loadout/loadout.dm | 21 +- .../client/preference/loadout/loadout_tgui.dm | 61 +++ code/modules/client/preference/preferences.dm | 70 +-- code/modules/ruins/ghost_bar.dm | 4 +- paradise.dme | 1 + tgui/packages/tgui/components/ImageButton.tsx | 29 +- tgui/packages/tgui/interfaces/Loadout.tsx | 398 ++++++++++++++++++ .../packages/tgui/interfaces/PrizeCounter.tsx | 3 +- .../tgui/styles/components/Dimmer.scss | 2 +- .../tgui/styles/components/Tooltip.scss | 2 +- .../tgui/styles/interfaces/Loadout.scss | 13 + tgui/packages/tgui/styles/main.scss | 1 + tgui/public/tgui-panel.bundle.css | 2 +- tgui/public/tgui-panel.bundle.js | 2 +- tgui/public/tgui.bundle.css | 2 +- tgui/public/tgui.bundle.js | 30 +- 22 files changed, 611 insertions(+), 235 deletions(-) create mode 100644 code/modules/client/preference/loadout/loadout_tgui.dm create mode 100644 tgui/packages/tgui/interfaces/Loadout.tsx create mode 100644 tgui/packages/tgui/styles/interfaces/Loadout.scss diff --git a/code/__DEFINES/preferences_defines.dm b/code/__DEFINES/preferences_defines.dm index c4f3905028a..fd0a1d7d7bf 100644 --- a/code/__DEFINES/preferences_defines.dm +++ b/code/__DEFINES/preferences_defines.dm @@ -162,9 +162,8 @@ #define TAB_CHAR 0 #define TAB_GAME 1 #define TAB_ANTAG 2 -#define TAB_GEAR 3 -#define TAB_KEYS 4 -#define TAB_TOGGLES 5 +#define TAB_KEYS 3 +#define TAB_TOGGLES 4 // Colourblind modes #define COLOURBLIND_MODE_NONE "None" diff --git a/code/__HELPERS/global_lists.dm b/code/__HELPERS/global_lists.dm index b17e430f0f8..1dfd5633387 100644 --- a/code/__HELPERS/global_lists.dm +++ b/code/__HELPERS/global_lists.dm @@ -75,35 +75,46 @@ GLOB.pai_software_by_key[P.id] = P // Setup loadout gear - for(var/geartype in subtypesof(/datum/gear)) - var/datum/gear/G = geartype + for(var/gear_type in subtypesof(/datum/gear)) + var/datum/gear/gear = gear_type - var/use_category = initial(G.sort_category) - - if(G == initial(G.main_typepath)) + if(gear == initial(gear.main_typepath)) continue - if(!initial(G.display_name)) - stack_trace("Loadout - Missing display name: [G]") + if(!initial(gear.display_name)) + stack_trace("Loadout - Missing display name: [gear]") continue - if(!initial(G.cost)) - stack_trace("Loadout - Missing cost: [G]") + if(!initial(gear.cost)) + stack_trace("Loadout - Missing cost: [gear]") continue - if(!initial(G.path)) - stack_trace("Loadout - Missing path definition: [G]") + if(!initial(gear.path)) + stack_trace("Loadout - Missing path definition: [gear]") continue - if(!GLOB.loadout_categories[use_category]) - GLOB.loadout_categories[use_category] = new /datum/loadout_category(use_category) - var/datum/loadout_category/LC = GLOB.loadout_categories[use_category] - GLOB.gear_datums[geartype] = new geartype - LC.gear[geartype] = GLOB.gear_datums[geartype] + gear = new gear_type + var/obj/gear_item = gear.path + var/list/tweaks = list() + for(var/datum/gear_tweak/tweak as anything in gear.gear_tweaks) + tweaks[tweak.type] += list(list( + "name" = tweak.display_type, + "icon" = tweak.fa_icon, + "tooltip" = tweak.info, + )) - GLOB.loadout_categories = sortAssoc(GLOB.loadout_categories) - for(var/loadout_category in GLOB.loadout_categories) - var/datum/loadout_category/LC = GLOB.loadout_categories[loadout_category] - LC.gear = sortAssoc(LC.gear) + GLOB.gear_tgui_info[gear.sort_category] += list( + "[gear_type]" = list( + "name" = gear.display_name, + "desc" = gear.description, + "icon" = gear_item.icon, + "icon_state" = gear_item.icon_state, + "cost" = gear.cost, + "gear_tier" = gear.donator_tier, + "allowed_roles" = gear.allowed_roles, + "tweaks" = tweaks, + ) + ) + GLOB.gear_datums[gear_type] = gear // Setup a list of robolimbs GLOB.basic_robolimb = new() diff --git a/code/game/jobs/job/job.dm b/code/game/jobs/job/job.dm index 7ad8749098b..85defcc14f3 100644 --- a/code/game/jobs/job/job.dm +++ b/code/game/jobs/job/job.dm @@ -208,7 +208,7 @@ continue if(G.slot) - if(H.equip_to_slot_or_del(G.spawn_item(H), G.slot, TRUE)) + if(H.equip_to_slot_or_del(G.spawn_item(H, H.client.prefs.active_character.get_gear_metadata(G)), G.slot, TRUE)) to_chat(H, "Equipping you with [G.display_name]!") else gear_leftovers += G @@ -228,7 +228,7 @@ if(length(gear_leftovers)) for(var/datum/gear/G in gear_leftovers) - var/atom/placed_in = H.equip_or_collect(G.spawn_item(null, H.client.prefs.active_character.loadout_gear[G.display_name])) + var/atom/placed_in = H.equip_or_collect(G.spawn_item(null, H.client.prefs.active_character.get_gear_metadata(G))) if(istype(placed_in)) if(isturf(placed_in)) to_chat(H, "Placing [G.display_name] on [placed_in]!") diff --git a/code/modules/client/preference/character.dm b/code/modules/client/preference/character.dm index 1a598016a8f..da5520d2f6f 100644 --- a/code/modules/client/preference/character.dm +++ b/code/modules/client/preference/character.dm @@ -1565,10 +1565,10 @@ #undef ICON_SHIFT_XY /datum/character_save/proc/get_gear_metadata(datum/gear/G) // NYI - . = loadout_gear[G.type] + . = loadout_gear["[G]"] if(!.) . = list() - loadout_gear[G.type] = . + loadout_gear["[G]"] = . /datum/character_save/proc/get_tweak_metadata(datum/gear/G, datum/gear_tweak/tweak) var/list/metadata = get_gear_metadata(G) diff --git a/code/modules/client/preference/link_processing.dm b/code/modules/client/preference/link_processing.dm index 7e51f38c49f..4bf35546b5c 100644 --- a/code/modules/client/preference/link_processing.dm +++ b/code/modules/client/preference/link_processing.dm @@ -85,34 +85,6 @@ active_character.gen_record = genmsg active_character.SetRecords(user) - if(href_list["preference"] == "gear") - if(href_list["toggle_gear"]) - var/datum/gear/TG = GLOB.gear_datums[text2path(href_list["toggle_gear"])] - if(TG && (TG.type in active_character.loadout_gear)) - active_character.loadout_gear -= TG.type - else - if(TG.donator_tier && user.client.donator_level < TG.donator_tier) - to_chat(user, "That gear is only available at a higher donation tier than you are on.") - return - build_loadout(TG) - - else if(href_list["gear"] && href_list["tweak"]) // NYI - var/datum/gear/gear = GLOB.gear_datums[text2path(href_list["gear"])] - var/datum/gear_tweak/tweak = locate(href_list["tweak"]) - if(!tweak || !istype(gear) || !(tweak in gear.gear_tweaks)) - return - var/metadata = tweak.get_metadata(user, active_character.get_tweak_metadata(gear, tweak)) - if(!metadata) - return - active_character.set_tweak_metadata(gear, tweak, metadata) - else if(href_list["select_category"]) - gear_tab = href_list["select_category"] - else if(href_list["clear_loadout"]) - active_character.loadout_gear.Cut() - - ShowChoices(user) - return - switch(href_list["task"]) if("random") var/datum/robolimb/robohead @@ -698,6 +670,11 @@ if(new_backbag) active_character.backbag = new_backbag + if("loadout") + var/datum/ui_module/loadout/loadout = new() + loadout.ui_interact(user) + return FALSE + if("nt_relation") var/new_relation = tgui_input_list(user, "Choose your relation to NT. Note that this represents what others can find out about your character by researching your background, not what your character actually thinks.", "Character Preference", list("Loyal", "Supportive", "Neutral", "Skeptical", "Opposed")) if(new_relation) diff --git a/code/modules/client/preference/loadout/gear_tweaks.dm b/code/modules/client/preference/loadout/gear_tweaks.dm index 37f90fb753c..9759f3cf7c3 100644 --- a/code/modules/client/preference/loadout/gear_tweaks.dm +++ b/code/modules/client/preference/loadout/gear_tweaks.dm @@ -1,5 +1,10 @@ -/datum/gear_tweak/proc/get_contents(metadata) - return +/datum/gear_tweak + /// Displayed in TGUI name + var/display_type + /// Font Awesome icon + var/fa_icon + /// Explains what is this do in TGUI tooltip + var/info /datum/gear_tweak/proc/get_metadata(user, metadata) return @@ -10,102 +15,51 @@ /datum/gear_tweak/proc/tweak_gear_data(metadata, datum/gear_data) return -/datum/gear_tweak/proc/tweak_item(obj/item/I, metadata) +/datum/gear_tweak/proc/tweak_item(obj/item/gear, metadata) return -/* -* Color adjustment -*/ - +// MARK: Color /datum/gear_tweak/color + display_type = "Color" + fa_icon = "palette" + info = "Recolorable" var/list/valid_colors /datum/gear_tweak/color/New(list/colors) valid_colors = colors ..() -/datum/gear_tweak/color/get_contents(metadata) - return "Color: " - /datum/gear_tweak/color/get_default() return valid_colors ? valid_colors[1] : COLOR_GRAY /datum/gear_tweak/color/get_metadata(user, metadata) if(valid_colors) - return input(user, "Choose an item color.", "Character Preference", metadata) as null|anything in valid_colors + return tgui_input_list(user, "Choose an item color.", "Recolor Gear", valid_colors, metadata) return tgui_input_color(user, "Choose an item color.", "Global Preference", metadata) -/datum/gear_tweak/color/tweak_item(obj/item/I, metadata) - if(valid_colors && !(metadata in valid_colors)) +/datum/gear_tweak/color/tweak_item(obj/item/gear, metadata) + if((valid_colors && !(metadata in valid_colors)) || !metadata) return - I.color = metadata -/* -* Path adjustment -*/ + gear.color = metadata -/datum/gear_tweak/path - var/list/valid_paths +// MARK: Rename +/datum/gear_tweak/rename + display_type = "Name" + fa_icon = "edit" + info = "Renameable" -/datum/gear_tweak/path/New(list/paths) - valid_paths = paths - ..() +/datum/gear_tweak/rename/get_default() + return "" -/datum/gear_tweak/path/get_contents(metadata) - return "Type: [metadata]" +/datum/gear_tweak/rename/get_metadata(user, metadata) + var/new_name = tgui_input_text(user, "Rename an object. Enter empty line for stock name", "Rename Gear", metadata, MAX_NAME_LEN) + if(isnull(new_name)) + return metadata + return new_name -/datum/gear_tweak/path/get_default() - return valid_paths[1] - -/datum/gear_tweak/path/get_metadata(user, metadata) - return input(user, "Choose a type.", "Character Preference", metadata) as null|anything in valid_paths - -/datum/gear_tweak/path/tweak_gear_data(metadata, datum/gear_data/gear_data) - if(!(metadata in valid_paths)) +/datum/gear_tweak/rename/tweak_item(obj/item/gear, metadata) + if(!metadata) return - gear_data.path = valid_paths[metadata] -/* -* Content adjustment -*/ - -/datum/gear_tweak/contents - var/list/valid_contents - -/datum/gear_tweak/contents/New() - valid_contents = args.Copy() - ..() - -/datum/gear_tweak/contents/get_contents(metadata) - return "Contents: [english_list(metadata, and_text = ", ")]" - -/datum/gear_tweak/contents/get_default() - . = list() - for(var/i = 1 to length(valid_contents)) - . += "Random" - -/datum/gear_tweak/contents/get_metadata(user, list/metadata) - . = list() - for(var/i = length(metadata) to length(valid_contents)) - metadata += "Random" - for(var/i = 1 to length(valid_contents)) - var/entry = input(user, "Choose an entry.", "Character Preference", metadata[i]) as null|anything in (valid_contents[i] + list("Random", "None")) - if(entry) - . += entry - else - return metadata - -/datum/gear_tweak/contents/tweak_item(obj/item/I, list/metadata) - if(length(metadata) != length(valid_contents)) - return - for(var/i = 1 to length(valid_contents)) - var/path - var/list/contents = valid_contents[i] - if(metadata[i] == "Random") - path = pick(contents) - path = contents[path] - else if(metadata[i] == "None") - continue - else - path = contents[metadata[i]] - new path(I) + gear.name = metadata diff --git a/code/modules/client/preference/loadout/loadout.dm b/code/modules/client/preference/loadout/loadout.dm index eff55feedee..2eaf2a612c1 100644 --- a/code/modules/client/preference/loadout/loadout.dm +++ b/code/modules/client/preference/loadout/loadout.dm @@ -1,14 +1,5 @@ -GLOBAL_LIST_EMPTY(loadout_categories) GLOBAL_LIST_EMPTY(gear_datums) -/datum/loadout_category - var/category = "" - var/list/gear = list() - -/datum/loadout_category/New(cat) - category = cat - ..() - /datum/gear /// Displayed name of the item listing. var/display_name @@ -48,10 +39,10 @@ GLOBAL_LIST_EMPTY(gear_datums) location = nlocation /datum/gear/proc/spawn_item(location, metadata) - var/datum/gear_data/gd = new(path, location) - for(var/datum/gear_tweak/gt in gear_tweaks) - gt.tweak_gear_data(metadata["[gt]"], gd) - var/item = new gd.path(gd.location) - for(var/datum/gear_tweak/gt in gear_tweaks) - gt.tweak_item(item, metadata["[gt]"]) + var/datum/gear_data/gear_data = new(path, location) + for(var/datum/gear_tweak/tweak in gear_tweaks) + tweak.tweak_gear_data(metadata["[tweak]"], gear_data) + var/item = new gear_data.path(gear_data.location) + for(var/datum/gear_tweak/tweak in gear_tweaks) + tweak.tweak_item(item, metadata["[tweak]"]) return item diff --git a/code/modules/client/preference/loadout/loadout_tgui.dm b/code/modules/client/preference/loadout/loadout_tgui.dm new file mode 100644 index 00000000000..c4be848b9b1 --- /dev/null +++ b/code/modules/client/preference/loadout/loadout_tgui.dm @@ -0,0 +1,61 @@ +GLOBAL_LIST_EMPTY(gear_tgui_info) + +/datum/ui_module/loadout + name = "Loadout" + +/datum/ui_module/loadout/ui_state(mob/user) + return GLOB.always_state + +/datum/ui_module/loadout/ui_interact(mob/user, datum/tgui/ui) + ui = SStgui.try_update_ui(user, src, ui) + if(!ui) + ui = new(user, src, "Loadout", name) + ui.set_autoupdate(FALSE) + ui.open() + +/datum/ui_module/loadout/ui_data(mob/user) + var/list/data = list() + data["gear_slots"] = user?.client?.prefs.build_loadout() + data["selected_gears"] = user?.client?.prefs?.active_character?.loadout_gear + return data + +/datum/ui_module/loadout/ui_static_data(mob/user) + var/list/data = list() + data["gears"] = GLOB.gear_tgui_info + data["max_gear_slots"] = user?.client?.prefs?.max_gear_slots + data["user_tier"] = user?.client?.donator_level + return data + +/datum/ui_module/loadout/ui_act(action, list/params) + if(..()) + return + . = TRUE + + var/mob/user = usr + var/datum/character_save/active_character = user.client.prefs.active_character + switch(action) + if("toggle_gear") + var/datum/gear/gear = GLOB.gear_datums[text2path(params["gear"])] + if(gear && ("[gear]" in active_character.loadout_gear)) + active_character.loadout_gear -= "[gear]" + return TRUE + + if(gear.donator_tier && user.client.donator_level < gear.donator_tier) + to_chat(user, "That gear is only available at a higher donation tier than you are on.") + return FALSE + + user.client.prefs.build_loadout(gear) + return TRUE + + if("set_tweak") + if(!(params["gear"] in active_character.loadout_gear)) + return FALSE + + var/datum/gear/gear = GLOB.gear_datums[text2path(params["gear"])] + var/datum/gear_tweak/tweak = locate(text2path(params["tweak"])) in gear.gear_tweaks + active_character.set_tweak_metadata(gear, tweak, tweak.get_metadata(user, active_character.get_tweak_metadata(gear, tweak))) + return TRUE + + if("clear_loadout") + active_character.loadout_gear.Cut() + return TRUE diff --git a/code/modules/client/preference/preferences.dm b/code/modules/client/preference/preferences.dm index 88c8c8ee463..ca058c397a9 100644 --- a/code/modules/client/preference/preferences.dm +++ b/code/modules/client/preference/preferences.dm @@ -171,7 +171,6 @@ GLOBAL_LIST_INIT(special_role_times, list( dat += "Character Settings" dat += "Game Preferences" dat += "Antagonists" - dat += "Loadout" dat += "Key Bindings" dat += "General Preferences" dat += "" @@ -391,7 +390,8 @@ GLOBAL_LIST_INIT(special_role_times, list( dat += "Undershirt: [active_character.undershirt]
" if(S.clothing_flags & HAS_SOCKS) dat += "Socks: [active_character.socks]
" - dat += "Backpack Type: [active_character.backbag]
" + dat += "Backpack Type: [active_character.backbag]

" + dat += "Open Loadout
" var/datum/species/myspecies = GLOB.all_species[active_character.species] if(!isnull(myspecies)) @@ -512,53 +512,6 @@ GLOBAL_LIST_INIT(special_role_times, list( dat += "Your [EXP_TYPE_CREW] playtime is [user.client.get_exp_type(EXP_TYPE_CREW)]
" dat += "" - if(TAB_GEAR) - var/total_cost = build_loadout() - - var/fcolor = "#3366CC" - if(total_cost < max_gear_slots) - fcolor = "#E67300" - dat += "" - dat += "" - dat += "" - - var/datum/loadout_category/LC = GLOB.loadout_categories[gear_tab] - dat += "" - dat += "" - dat += "" - for(var/gear_name in LC.gear) - var/datum/gear/G = LC.gear[gear_name] - var/ticked = (G.type in active_character.loadout_gear) - if(G.donator_tier > user.client.donator_level) - dat += "" - else - dat += "" - dat += "" - if(ticked) - . += "" - dat += "
[total_cost]/[max_gear_slots] loadout points spent. \[Clear Loadout\]
" - - var/firstcat = 1 - for(var/category in GLOB.loadout_categories) - if(firstcat) - firstcat = 0 - else - dat += " |" - if(category == gear_tab) - dat += " [category] " - else - dat += " [category] " - dat += "

[LC.category]

[G.display_name]
[G.display_name][G.cost]" - if(G.allowed_roles) - dat += "Restrictions: " - for(var/role in G.allowed_roles) - dat += role + " " - dat += "" - dat += "[G.description]
" - for(var/datum/gear_tweak/tweak in G.gear_tweaks) - . += " [tweak.get_contents(active_character.get_tweak_metadata(G, tweak))]" - . += "
" - if(TAB_KEYS) dat += "
All Key Bindings: " dat += "Reset to Default " @@ -772,25 +725,24 @@ GLOBAL_LIST_INIT(special_role_times, list( var/list/loadout_cache = active_character.loadout_gear.Copy() active_character.loadout_gear.Cut() if(new_item) - loadout_cache += new_item.type + loadout_cache += "[new_item]" - for(var/I in loadout_cache) - var/datum/gear/G = GLOB.gear_datums[text2path(I) || I] - if(!G) + for(var/item in loadout_cache) + var/datum/gear/gear = text2path(item) || item + if(!gear || !(gear.type in GLOB.gear_datums)) continue - var/added_cost = G.cost - if(!G.subtype_selection_cost) // If listings of the same subtype shouldn't have their cost added. - if(G.main_typepath in type_blacklist) + var/added_cost = gear.cost + if(!gear.subtype_selection_cost) // If listings of the same subtype shouldn't have their cost added. + if(gear.main_typepath in type_blacklist) added_cost = 0 else - type_blacklist += G.main_typepath + type_blacklist += gear.main_typepath if((total_cost + added_cost) > max_gear_slots) continue // If the final cost is too high, don't add the item. - active_character.loadout_gear += G.type + active_character.loadout_gear[item] = loadout_cache[item] ? loadout_cache[item] : list() total_cost += added_cost return total_cost - /datum/preferences/proc/init_keybindings(overrides, raw) if(raw) try diff --git a/code/modules/ruins/ghost_bar.dm b/code/modules/ruins/ghost_bar.dm index a89755e820c..b3066244a79 100644 --- a/code/modules/ruins/ghost_bar.dm +++ b/code/modules/ruins/ghost_bar.dm @@ -52,10 +52,10 @@ GLOBAL_LIST_EMPTY(occupants_by_key) if(G.allowed_roles) // Fix due to shitty HUD code continue if(G.slot) - if(H.equip_to_slot_or_del(G.spawn_item(H), G.slot, TRUE)) + if(H.equip_to_slot_or_del(G.spawn_item(H, save_to_load.get_gear_metadata(G)), G.slot, TRUE)) to_chat(H, "Equipping you with [G.display_name]!") else - H.equip_or_collect(G.spawn_item(null, save_to_load.loadout_gear[G.display_name])) + H.equip_or_collect(G.spawn_item(null, save_to_load.get_gear_metadata(G))) if(!H.w_uniform) equip_item(H, /obj/item/clothing/under/color/random, SLOT_HUD_JUMPSUIT) if(!H.shoes) diff --git a/paradise.dme b/paradise.dme index 6b5a1211936..3837342fe40 100644 --- a/paradise.dme +++ b/paradise.dme @@ -1726,6 +1726,7 @@ #include "code\modules\client\preference\loadout\loadout_racial.dm" #include "code\modules\client\preference\loadout\loadout_shoes.dm" #include "code\modules\client\preference\loadout\loadout_suit.dm" +#include "code\modules\client\preference\loadout\loadout_tgui.dm" #include "code\modules\client\preference\loadout\loadout_uniform.dm" #include "code\modules\clothing\chameleon.dm" #include "code\modules\clothing\clothing.dm" diff --git a/tgui/packages/tgui/components/ImageButton.tsx b/tgui/packages/tgui/components/ImageButton.tsx index f7b41229d30..37f0eb637d3 100644 --- a/tgui/packages/tgui/components/ImageButton.tsx +++ b/tgui/packages/tgui/components/ImageButton.tsx @@ -27,8 +27,11 @@ type Props = Partial<{ * Example: `buttons={}` */ buttons: InfernoNode; - /** Enables alternate buttons container. Disables pointer-events on buttons if non-fluid. */ - buttonsAlt: boolean; + /** + * Same as buttons, but. Have disabled pointer-events on content inside if non-fluid. + * Fluid version have humburger layout. + */ + buttonsAlt: InfernoNode; /** Content under image. Or on the right if fluid. */ children: InfernoNode; /** Applies a CSS class to the element. */ @@ -183,20 +186,36 @@ export const ImageButton = (props: Props) => {
{buttons}
)} + {buttonsAlt && ( +
+ {buttonsAlt} +
+ )}
); }; diff --git a/tgui/packages/tgui/interfaces/Loadout.tsx b/tgui/packages/tgui/interfaces/Loadout.tsx new file mode 100644 index 00000000000..a779cc53354 --- /dev/null +++ b/tgui/packages/tgui/interfaces/Loadout.tsx @@ -0,0 +1,398 @@ +import { createSearch } from 'common/string'; +import { useBackend, useLocalState } from '../backend'; +import { + Box, + Dimmer, + Dropdown, + ImageButton, + Button, + Input, + Section, + Tabs, + ProgressBar, + Stack, + LabeledList, +} from '../components'; +import { Window } from '../layouts'; + +type Data = { + user_tier: number; + gear_slots: number; + max_gear_slots: number; + selected_gears: string[]; + gears: Record>; +}; + +type Gear = { + name: string; + desc: string; + icon: string; + icon_state: string; + cost: number; + gear_tier: number; + allowed_roles: string[]; + tweaks: Record; +}; + +type Tweak = { + name: string; + icon: string; + tooltip: string; +}; + +const sortTypes = { + 'Default': (a, b) => a.gear.gear_tier - b.gear.gear_tier, + 'Alphabetical': (a, b) => a.gear.name.toLowerCase().localeCompare(b.gear.name.toLowerCase()), + 'Cost': (a, b) => a.gear.cost - b.gear.cost, +}; + +export const Loadout = (props, context) => { + const { act, data } = useBackend(context); + const [search, setSearch] = useLocalState(context, 'search', false); + const [searchText, setSearchText] = useLocalState(context, 'searchText', ''); + const [category, setCategory] = useLocalState(context, 'category', Object.keys(data.gears)[0]); + const [tweakedGear, setTweakedGear] = useLocalState(context, 'tweakedGear', ''); + + return ( + + {tweakedGear && } + + + + + + + + + + + + + + + + + + + ); +}; + +const LoadoutCategories = (props, context) => { + const { act, data } = useBackend(context); + const { category, setCategory } = props; + return ( + + {Object.keys(data.gears).map((cat) => ( + setCategory(cat)} + > + {cat} + + ))} + + ); +}; + +const LoadoutGears = (props, context) => { + const { act, data } = useBackend(context); + const { user_tier, gear_slots, max_gear_slots } = data; + const { category, search, setSearch, searchText, setSearchText } = props; + + const [sortType, setSortType] = useLocalState(context, 'sortType', 'Default'); + const [sortReverse, setsortReverse] = useLocalState(context, 'sortReverse', false); + const testSearch = createSearch(searchText, (gear) => gear.name); + + let contents; + if (searchText.length > 2) { + contents = Object.entries(data.gears) + .reduce((a, [key, gears]) => { + return a.concat(Object.entries(gears).map(([key, gear]) => ({ key, gear }))); + }, []) + .filter(({ gear }) => { + return testSearch(gear); + }); + } else { + contents = Object.entries(data.gears[category]).map(([key, gear]) => ({ key, gear })); + } + + contents.sort(sortTypes[sortType]); + if (sortReverse) { + contents = contents.reverse(); + } + + return ( +
+ + setSortType(value)} + /> + + +
+ } + tooltipPosition="left" + /> + )} + {Object.entries(gear.tweaks).map(([key, tweaks]: [string, Tweak[]]) => + tweaks.map((tweak) => ( +