From 4aad465e5f5d4e6559ebfbc243f389e6c5c489d2 Mon Sep 17 00:00:00 2001 From: Couls Date: Fri, 27 Aug 2021 03:28:41 -0400 Subject: [PATCH] tgui: Autolathe (#60800) Moves autolathe over to TGUI Features include: - Dropdown Materials list, with colorcoded materials(Bananium has a yellow bar!) - Categories are now easier to switch through as the autolathe all fits on one scrollable page - You can now see the most you can make with your materials of any design, rather than just stacks - Can now print a specific amount Co-authored-by: Aleksej Komarov --- code/game/machinery/autolathe.dm | 366 +++++++++------------ tgui/packages/tgui/interfaces/Autolathe.js | 203 ++++++++++++ 2 files changed, 365 insertions(+), 204 deletions(-) create mode 100644 tgui/packages/tgui/interfaces/Autolathe.js diff --git a/code/game/machinery/autolathe.dm b/code/game/machinery/autolathe.dm index c838fed5883..b6721566fb4 100644 --- a/code/game/machinery/autolathe.dm +++ b/code/game/machinery/autolathe.dm @@ -31,8 +31,7 @@ var/datum/design/being_built var/datum/techweb/stored_research var/list/datum/design/matching_designs - var/selected_category - var/screen = 1 + var/selected_category = "None" var/base_price = 25 var/hacked_price = 50 @@ -61,27 +60,175 @@ QDEL_NULL(wires) return ..() -/obj/machinery/autolathe/ui_interact(mob/user) - . = ..() +/obj/machinery/autolathe/ui_interact(mob/user, datum/tgui/ui) if(!is_operational) return if(shocked && !(machine_stat & NOPOWER)) shock(user,50) + ui = SStgui.try_update_ui(user, src, ui) + if(!ui) + ui = new(user, src, "Autolathe") + ui.open() - var/dat +/obj/machinery/autolathe/ui_data(mob/user) + var/list/data = list() + data["materials"] = list() + var/datum/component/material_container/materials = GetComponent(/datum/component/material_container) + data["materialtotal"] = materials.total_amount + data["materialsmax"] = materials.max_amount + data["categories"] = categories + data["designs"] = list() + data["active"] = busy - switch(screen) - if(AUTOLATHE_MAIN_MENU) - dat = main_win(user) - if(AUTOLATHE_CATEGORY_MENU) - dat = category_win(user,selected_category) - if(AUTOLATHE_SEARCH_MENU) - dat = search_win(user) + for(var/mat_id in materials.materials) + var/datum/material/M = mat_id + var/mineral_count = materials.materials[mat_id] + var/list/material_data = list( + name = M.name, + mineral_amount = mineral_count, + matcolour = M.greyscale_colors, + ) + data["materials"] += list(material_data) + if(selected_category != "None" && !length(matching_designs)) + data["designs"] = handle_designs(stored_research.researched_designs, TRUE) + else + data["designs"] = handle_designs(matching_designs, FALSE) + return data - var/datum/browser/popup = new(user, "autolathe", name, 400, 500) - popup.set_content(dat) - popup.open() +/obj/machinery/autolathe/proc/handle_designs(list/designs, categorycheck) + var/list/output = list() + for(var/v in designs) + var/datum/design/D = categorycheck ? SSresearch.techweb_design_by_id(v) : v + if(categorycheck) + if(!(selected_category in D.category)) + continue + var/unbuildable = FALSE // we can't build the design currently + var/m10 = FALSE // 10x mult + var/m25 = FALSE // 25x mult + var/m50 = FALSE // 50x mult + var/m5 = FALSE // 5x mult + var/sheets = FALSE // sheets or no? + if(disabled || !can_build(D)) + unbuildable = TRUE + var/max_multiplier = unbuildable ? 0 : 1 + if(ispath(D.build_path, /obj/item/stack)) + sheets = TRUE + if(!unbuildable) + var/datum/component/material_container/mats = GetComponent(/datum/component/material_container) + for(var/datum/material/mat in D.materials) + max_multiplier = min(D.maxstack, round(mats.get_material_amount(mat)/D.materials[mat])) + if (max_multiplier>10 && !disabled) + m10 = TRUE + if (max_multiplier>25 && !disabled) + m25 = TRUE + else + if(!unbuildable) + if(!disabled && can_build(D, 5)) + m5 = TRUE + if(!disabled && can_build(D, 10)) + m10 = TRUE + var/datum/component/material_container/mats = GetComponent(/datum/component/material_container) + for(var/datum/material/mat in D.materials) + max_multiplier = min(50, round(mats.get_material_amount(mat)/(D.materials[mat] * creation_efficiency))) + + var/list/design = list( + name = D.name, + id = D.id, + ref = REF(src), + cost = get_design_cost(D), + buildable = unbuildable, + mult5 = m5, + mult10 = m10, + mult25 = m25, + mult50 = m50, + sheet = sheets, + maxmult = max_multiplier, + ) + output += list(design) + return output + +/obj/machinery/autolathe/ui_act(action, params) + . = ..() + if(.) + return + if(action == "menu") + selected_category = null + matching_designs.Cut() + . = TRUE + + if(action == "category") + selected_category = params["selectedCategory"] + matching_designs.Cut() + . = TRUE + + if(action == "search") + matching_designs.Cut() + + for(var/v in stored_research.researched_designs) + var/datum/design/D = SSresearch.techweb_design_by_id(v) + if(findtext(D.name,params["to_search"])) + matching_designs.Add(D) + . = TRUE + + if(action == "make") + if (!busy) + ///////////////// + //href protection + being_built = stored_research.isDesignResearchedID(params["id"]) + if(!being_built) + return + + var/multiplier = text2num(params["multiplier"]) + if(!multiplier) + to_chat(usr, "[src] only accepts a numerical multiplier!") + return + var/is_stack = ispath(being_built.build_path, /obj/item/stack) + multiplier = clamp(round(multiplier),1,50) + + ///////////////// + + var/coeff = (is_stack ? 1 : creation_efficiency) //stacks are unaffected by production coefficient + var/total_amount = 0 + + for(var/MAT in being_built.materials) + total_amount += being_built.materials[MAT] + + var/power = max(2000, (total_amount)*multiplier/5) //Change this to use all materials + + var/datum/component/material_container/materials = GetComponent(/datum/component/material_container) + + var/list/materials_used = list() + var/list/custom_materials = list() //These will apply their material effect, This should usually only be one. + + for(var/MAT in being_built.materials) + var/datum/material/used_material = MAT + var/amount_needed = being_built.materials[MAT] * coeff * multiplier + if(istext(used_material)) //This means its a category + var/list/list_to_show = list() + for(var/i in SSmaterials.materials_by_category[used_material]) + if(materials.materials[i] > 0) + list_to_show += i + + used_material = input("Choose [used_material]", "Custom Material") as null|anything in sortList(list_to_show, /proc/cmp_typepaths_asc) + if(!used_material) + return //Didn't pick any material, so you can't build shit either. + custom_materials[used_material] += amount_needed + + materials_used[used_material] = amount_needed + + if(materials.has_materials(materials_used)) + busy = TRUE + to_chat(usr, "You print [multiplier] item(s) from the [src]") + use_power(power) + icon_state = "autolathe_n" + var/time = is_stack ? 32 : (32 * coeff * multiplier) ** 0.8 + addtimer(CALLBACK(src, .proc/make_item, power, materials_used, custom_materials, multiplier, coeff, is_stack, usr), time) + . = TRUE + else + to_chat(usr, "Not enough materials for this operation.") + else + to_chat(usr, "The autolathe is busy. Please wait for completion of previous operation.") /obj/machinery/autolathe/on_deconstruction() var/datum/component/material_container/materials = GetComponent(/datum/component/material_container) @@ -93,7 +240,6 @@ return TRUE if(default_deconstruction_screwdriver(user, "autolathe_t", "autolathe", O)) - updateUsrDialog() return TRUE if(default_deconstruction_crowbar(O)) @@ -134,86 +280,6 @@ flick("autolathe_o", src)//plays metal insertion animation use_power(min(1000, amount_inserted / 100)) - updateUsrDialog() - -/obj/machinery/autolathe/Topic(href, href_list) - if(..()) - return - if (!busy) - if(href_list["menu"]) - screen = text2num(href_list["menu"]) - updateUsrDialog() - - if(href_list["category"]) - selected_category = href_list["category"] - updateUsrDialog() - - if(href_list["make"]) - - ///////////////// - //href protection - being_built = stored_research.isDesignResearchedID(href_list["make"]) - if(!being_built) - return - - var/multiplier = text2num(href_list["multiplier"]) - var/is_stack = ispath(being_built.build_path, /obj/item/stack) - multiplier = clamp(multiplier,1,50) - - ///////////////// - - var/coeff = (is_stack ? 1 : creation_efficiency) //stacks are unaffected by production coefficient - var/total_amount = 0 - - for(var/MAT in being_built.materials) - total_amount += being_built.materials[MAT] - - var/power = max(2000, (total_amount)*multiplier/5) //Change this to use all materials - - var/datum/component/material_container/materials = GetComponent(/datum/component/material_container) - - var/list/materials_used = list() - var/list/custom_materials = list() //These will apply their material effect, This should usually only be one. - - for(var/MAT in being_built.materials) - var/datum/material/used_material = MAT - var/amount_needed = being_built.materials[MAT] * coeff * multiplier - if(istext(used_material)) //This means its a category - var/list/list_to_show = list() - for(var/i in SSmaterials.materials_by_category[used_material]) - if(materials.materials[i] > 0) - list_to_show += i - - used_material = input("Choose [used_material]", "Custom Material") as null|anything in sortList(list_to_show, /proc/cmp_typepaths_asc) - if(!used_material) - return //Didn't pick any material, so you can't build shit either. - custom_materials[used_material] += amount_needed - - materials_used[used_material] = amount_needed - - if(materials.has_materials(materials_used)) - busy = TRUE - use_power(power) - icon_state = "autolathe_n" - var/time = is_stack ? 32 : (32 * coeff * multiplier) ** 0.8 - addtimer(CALLBACK(src, .proc/make_item, power, materials_used, custom_materials, multiplier, coeff, is_stack, usr), time) - else - to_chat(usr, "Not enough materials for this operation.") - - if(href_list["search"]) - matching_designs.Cut() - - for(var/v in stored_research.researched_designs) - var/datum/design/D = SSresearch.techweb_design_by_id(v) - if(findtext(D.name,href_list["to_search"])) - matching_designs.Add(D) - updateUsrDialog() - else - to_chat(usr, "The autolathe is busy. Please wait for completion of previous operation.") - - updateUsrDialog() - - return /obj/machinery/autolathe/proc/make_item(power, list/materials_used, list/picked_materials, multiplier, coeff, is_stack, mob/user) var/datum/component/material_container/materials = GetComponent(/datum/component/material_container) @@ -241,7 +307,6 @@ icon_state = "autolathe" busy = FALSE - updateDialog() /obj/machinery/autolathe/RefreshParts() var/mat_capacity = 0 @@ -261,113 +326,6 @@ if(in_range(user, src) || isobserver(user)) . += span_notice("The status display reads: Storing up to [materials.max_amount] material units.
Material consumption at [creation_efficiency*100]%.") -/obj/machinery/autolathe/proc/main_win(mob/user) - var/dat = "

Autolathe Menu:


" - dat += materials_printout() - - dat += "
\ - \ - \ - \ - \ - \ -

" - - var/line_length = 1 - dat += "" - - for(var/C in categories) - if(line_length > 2) - dat += "" - line_length = 1 - - dat += "" - line_length++ - - dat += "
[C]
" - return dat - -/obj/machinery/autolathe/proc/category_win(mob/user,selected_category) - var/dat = "Return to main menu" - dat += "

Browsing [selected_category]:


" - dat += materials_printout() - - for(var/v in stored_research.researched_designs) - var/datum/design/D = SSresearch.techweb_design_by_id(v) - if(!(selected_category in D.category)) - continue - - if(disabled || !can_build(D)) - dat += "[D.name]" - else - dat += "[D.name]" - - if(ispath(D.build_path, /obj/item/stack)) - var/datum/component/material_container/materials = GetComponent(/datum/component/material_container) - var/max_multiplier - for(var/datum/material/mat in D.materials) - max_multiplier = min(D.maxstack, round(materials.get_material_amount(mat)/D.materials[mat])) - if (max_multiplier>10 && !disabled) - dat += " x10" - if (max_multiplier>25 && !disabled) - dat += " x25" - if(max_multiplier > 0 && !disabled) - dat += " x[max_multiplier]" - else - if(!disabled && can_build(D, 5)) - dat += " x5" - if(!disabled && can_build(D, 10)) - dat += " x10" - - dat += "[get_design_cost(D)]
" - - dat += "
" - return dat - -/obj/machinery/autolathe/proc/search_win(mob/user) - var/dat = "Return to main menu" - dat += "

Search results:


" - dat += materials_printout() - - for(var/v in matching_designs) - var/datum/design/D = v - if(disabled || !can_build(D)) - dat += "[D.name]" - else - dat += "[D.name]" - - if(ispath(D.build_path, /obj/item/stack)) - var/datum/component/material_container/materials = GetComponent(/datum/component/material_container) - var/max_multiplier - for(var/datum/material/mat in D.materials) - max_multiplier = min(D.maxstack, round(materials.get_material_amount(mat)/D.materials[mat])) - if (max_multiplier>10 && !disabled) - dat += " x10" - if (max_multiplier>25 && !disabled) - dat += " x25" - if(max_multiplier > 0 && !disabled) - dat += " x[max_multiplier]" - else - if(!disabled && can_build(D, 5)) - dat += " x5" - if(!disabled && can_build(D, 10)) - dat += " x10" - - dat += "[get_design_cost(D)]
" - - dat += "
" - return dat - -/obj/machinery/autolathe/proc/materials_printout() - var/datum/component/material_container/materials = GetComponent(/datum/component/material_container) - var/dat = "Total amount: [materials.total_amount] / [materials.max_amount] cm3
" - for(var/mat_id in materials.materials) - var/datum/material/M = mat_id - var/mineral_amount = materials.materials[mat_id] - if(mineral_amount > 0) - dat += "[M.name] amount: [mineral_amount] cm3
" - return dat - /obj/machinery/autolathe/proc/can_build(datum/design/D, amount = 1) if(D.make_reagents.len) return FALSE diff --git a/tgui/packages/tgui/interfaces/Autolathe.js b/tgui/packages/tgui/interfaces/Autolathe.js new file mode 100644 index 00000000000..56322da3d9e --- /dev/null +++ b/tgui/packages/tgui/interfaces/Autolathe.js @@ -0,0 +1,203 @@ +import { useBackend, useLocalState } from '../backend'; +import { Button, LabeledList, Section, ProgressBar, Flex, Box, Table, Collapsible, Input, Dimmer, Icon } from '../components'; +import { Window } from '../layouts'; +import { capitalize } from "common/string"; + +export const Autolathe = (props, context) => { + const { act, data } = useBackend(context); + // Extract `health` and `color` variables from the `data` object. + const { + materialtotal, + materialsmax, + materials = [], + categories = [], + designs = [], + active, + } = data; + const [ + current_category, + setCategory, + ] = useLocalState(context, 'current_category', "None"); + const filteredmaterials = materials.filter(material => + material.mineral_amount > 0); + return ( + + +
+ + + + {materialtotal + '/' + materialsmax + ' cm³'} + + + + {filteredmaterials.length > 0 && ( + + + {filteredmaterials.map(filteredmaterial => ( + + +
{filteredmaterial.mineral_amount + ' cm³'}
+
+
+ ))} +
+
)} +
+
+
+
+ { + if (value.length) { + act('search', { + to_search: value, + }); + setCategory('results for "' + value + '"'); + } + }} /> +
+
+ + {categories.map(category => ( + // eslint-disable-next-line react/jsx-key +
+ {current_category.toString() !== "None" && ( +
{ + act('menu'); + setCategory("None"); + }} /> + )}> + {active === 1 && ( + + + {'Building items...'} + + )} + + + {designs.length + && (designs.map(design => ( + + +
+
+
+ )} +
+
+ ); +};