From 735230d642b25d05ee44d3d63fc1919a3ef8d0a7 Mon Sep 17 00:00:00 2001 From: ShadowLarkens Date: Mon, 7 Sep 2020 16:52:38 -0700 Subject: [PATCH] TGUI Metal Menu (Travis stop it) --- code/game/objects/items/stacks/stack.dm | 151 +++++++++----------- tgui/packages/tgui/interfaces/Stack.js | 174 +++++++++++++++++++++++ tgui/packages/tgui/public/tgui.bundle.js | 14 +- 3 files changed, 251 insertions(+), 88 deletions(-) create mode 100644 tgui/packages/tgui/interfaces/Stack.js diff --git a/code/game/objects/items/stacks/stack.dm b/code/game/objects/items/stacks/stack.dm index ad187265c2f..0c2cf539610 100644 --- a/code/game/objects/items/stacks/stack.dm +++ b/code/game/objects/items/stacks/stack.dm @@ -66,63 +66,81 @@ else . += "There is enough charge for [get_amount()]." -/obj/item/stack/attack_self(mob/user as mob) - list_recipes(user) +/obj/item/stack/attack_self(mob/user) + tgui_interact(user) -/obj/item/stack/proc/list_recipes(mob/user as mob, recipes_sublist) - if (!recipes) - return - if (!src || get_amount() <= 0) - user << browse(null, "window=stack") - user.set_machine(src) //for correct work of onclose - var/list/recipe_list = recipes - if (recipes_sublist && recipe_list[recipes_sublist] && istype(recipe_list[recipes_sublist], /datum/stack_recipe_list)) - var/datum/stack_recipe_list/srl = recipe_list[recipes_sublist] - recipe_list = srl.recipes - var/t1 = text("Constructions from []Amount Left: []
", src, src.get_amount()) - for(var/i=1;i<=recipe_list.len,i++) - var/E = recipe_list[i] - if (isnull(E)) - t1 += "
" - continue +/obj/item/stack/tgui_interact(mob/user, datum/tgui/ui, datum/tgui/parent_ui) + ui = SStgui.try_update_ui(user, src, ui) + if(!ui) + ui = new(user, src, "Stack", name) + ui.open() - if (i>1 && !isnull(recipe_list[i-1])) - t1+="
" +/obj/item/stack/tgui_data(mob/user, datum/tgui/ui, datum/tgui_state/state) + var/list/data = ..() + + data["amount"] = get_amount() - if (istype(E, /datum/stack_recipe_list)) - var/datum/stack_recipe_list/srl = E - t1 += "[srl.title]" + return data - if (istype(E, /datum/stack_recipe)) - var/datum/stack_recipe/R = E - var/max_multiplier = round(src.get_amount() / R.req_amount) - var/title as text - var/can_build = 1 - can_build = can_build && (max_multiplier>0) - if (R.res_amount>1) - title+= "[R.res_amount]x [R.title]\s" - else - title+= "[R.title]" - title+= " ([R.req_amount] [src.singular_name]\s)" - if (can_build) - t1 += text("[title] ") - else - t1 += text("[]", title) - continue - if (R.max_res_amount>1 && max_multiplier>1) - max_multiplier = min(max_multiplier, round(R.max_res_amount/R.res_amount)) - t1 += " |" - var/list/multipliers = list(5,10,25) - for (var/n in multipliers) - if (max_multiplier>=n) - t1 += " [n*R.res_amount]x" - if (!(max_multiplier in multipliers)) - t1 += " [max_multiplier*R.res_amount]x" +/obj/item/stack/tgui_static_data(mob/user, datum/tgui/ui, datum/tgui_state/state) + var/list/data = ..() - t1 += "
" - user << browse(t1, "window=stack") - onclose(user, "stack") - return + data["recipes"] = recursively_build_recipes(recipes) + + return data + +/obj/item/stack/proc/recursively_build_recipes(list/recipe_to_iterate) + var/list/L = list() + for(var/recipe in recipe_to_iterate) + if(istype(recipe, /datum/stack_recipe_list)) + var/datum/stack_recipe_list/R = recipe + L["[R.title]"] = recursively_build_recipes(R.recipes) + if(istype(recipe, /datum/stack_recipe)) + var/datum/stack_recipe/R = recipe + L["[R.title]"] = build_recipe(R) + + return L + +/obj/item/stack/proc/build_recipe(datum/stack_recipe/R) + return list( + "res_amount" = R.res_amount, + "max_res_amount" = R.max_res_amount, + "req_amount" = R.req_amount, + "ref" = "\ref[R]", + ) + +/obj/item/stack/tgui_state(mob/user) + return GLOB.tgui_hands_state + +/obj/item/stack/tgui_act(action, list/params, datum/tgui/ui, datum/tgui_state/state) + if(..()) + return TRUE + + switch(action) + if("make") + if(get_amount() < 1) + qdel(src) + return + + var/datum/stack_recipe/R = locate(params["ref"]) + if(!is_valid_recipe(R, recipes)) //href exploit protection + return FALSE + var/multiplier = text2num(params["multiplier"]) + if(!multiplier || (multiplier <= 0)) //href exploit protection + return + produce_recipe(R, multiplier, usr) + return TRUE + +/obj/item/stack/proc/is_valid_recipe(datum/stack_recipe/R, list/recipe_list) + for(var/S in recipe_list) + if(S == R) + return TRUE + if(istype(S, /datum/stack_recipe_list)) + var/datum/stack_recipe_list/L = S + if(is_valid_recipe(R, L.recipes)) + return TRUE + + return FALSE /obj/item/stack/proc/produce_recipe(datum/stack_recipe/recipe, var/quantity, mob/user) var/required = quantity*recipe.req_amount @@ -177,35 +195,6 @@ else O.color = color -/obj/item/stack/Topic(href, href_list) - ..() - if ((usr.restrained() || usr.stat || usr.get_active_hand() != src)) - return - - if (href_list["sublist"] && !href_list["make"]) - list_recipes(usr, text2num(href_list["sublist"])) - - if (href_list["make"]) - if (src.get_amount() < 1) qdel(src) //Never should happen - - var/list/recipes_list = recipes - if (href_list["sublist"]) - var/datum/stack_recipe_list/srl = recipes_list[text2num(href_list["sublist"])] - recipes_list = srl.recipes - - var/datum/stack_recipe/R = recipes_list[text2num(href_list["make"])] - var/multiplier = text2num(href_list["multiplier"]) - if (!multiplier || (multiplier <= 0)) //href exploit protection - return - - src.produce_recipe(R, multiplier, usr) - - if (src && usr.machine==src) //do not reopen closed window - spawn( 0 ) - src.interact(usr) - return - return - //Return 1 if an immediate subsequent call to use() would succeed. //Ensures that code dealing with stacks uses the same logic /obj/item/stack/proc/can_use(var/used) diff --git a/tgui/packages/tgui/interfaces/Stack.js b/tgui/packages/tgui/interfaces/Stack.js new file mode 100644 index 00000000000..d1e5c48fd5a --- /dev/null +++ b/tgui/packages/tgui/interfaces/Stack.js @@ -0,0 +1,174 @@ +import { round } from 'common/math'; +import { Fragment } from 'inferno'; +import { useBackend } from "../backend"; +import { Box, Button, Flex, Icon, LabeledList, ProgressBar, Section, Collapsible, Table, Divider } from "../components"; +import { Window } from "../layouts"; +import { logger } from '../logging'; + +export const Stack = (props, context) => { + const { act, data } = useBackend(context); + + const { + amount, + recipes, + } = data; + + return ( + + +
+ +
+
+
+ ); +}; + +const RecipeList = (props, context) => { + const { act, data } = useBackend(context); + + const { + recipes, + } = props; + + let sortedKeys = Object.keys(recipes).sort(); + + // Shunt all categories to the top. + // We're not using this for now, keeping it here in case someone really hates color coding later. + // let nonCategories = sortedKeys.filter(item => recipes[item].ref !== undefined); + // let categories = sortedKeys.filter(item => recipes[item].ref === undefined); + + // categories.unshift("--DIVIDER--"); + + // let newSortedKeys = nonCategories.concat(categories); + + return sortedKeys.map(title => { + // if (title === "--DIVIDER--") { + // return ( + // + // + // + // ); + // } + let recipe = recipes[title]; + if (recipe.ref === undefined) { + return ( + + + + + + ); + } else { + return ( + + ); + } + }); +}; + +const buildMultiplier = (recipe, amount) => { + if (recipe.req_amount > amount) { + return 0; + } + + return Math.floor(amount / recipe.req_amount); +}; + +const Multipliers = (props, context) => { + const { act, data } = useBackend(context); + + const { + recipe, + maxMultiplier, + } = props; + + let maxM = Math.min(maxMultiplier, Math.floor(recipe.max_res_amount / recipe.res_amount)); + + let multipliers = [5, 10, 25]; + + let finalResult = []; + + for (let multiplier of multipliers) { + if (maxM >= multiplier) { + finalResult.push(( +