From a05eb411266bbac4c998b421b9526cae02b3a6f1 Mon Sep 17 00:00:00 2001 From: SkyratBot <59378654+SkyratBot@users.noreply.github.com> Date: Thu, 20 Apr 2023 03:25:55 +0200 Subject: [PATCH] [MIRROR] Produce consoles now grey out their buttons if the cost criteria aren't met & have dynamic window sizes. [MDB IGNORE] (#20653) * Produce consoles now grey out their buttons if the cost criteria aren't met & have dynamic window sizes. (#74773) ## About The Pull Request Fixes #74645 Fixes #72536 If your total order is less than 200 credits/mining points then the purchase button is greyed out telling you just that ![Screenshot (169)](https://user-images.githubusercontent.com/110812394/232320295-bb8a3c14-1f4d-4823-ba7d-3557011166fe.png) Bonus. If your cart is empty then the express button is also greyed out telling you to order atleast 1 item ![Screenshot (170)](https://user-images.githubusercontent.com/110812394/232320326-8fd59734-c3fe-4a5e-9655-bdf62288456d.png) Even more bonus, the width of the window is dynamically adjusted based on the number of order categories so golem mining console is no longer obscured ![Screenshot (171)](https://user-images.githubusercontent.com/110812394/232320401-f6ac65f6-0f93-4426-9ca6-7b4398c613f0.png) Code changes 1. `var/cargo_cost_multiplier` : as the name implies is now the cost applied to all stuff ordered through cargo. it takes top priority(because we assume it will always be cheaper than express) and all item costs are multiplied with this before being displayed on the UI. So mining console has this value as 0.65 as intended 2. `proc/retrive_points()` : is used to retrieve the type of points this console is dealing with from the mobs id card, so for mining it returns the card's mining point's, for others it returns the card's cash, if you want to introduce a new currency type and make your own console for it, make sure you override this proc 3. `proc/subtract_points()` : is used to subtract these points(money, mining points) from the id card after the order is confirmed, return true if it was successful, false otherwise to cancel the order ## Changelog :cl: fix: order consoles cancelling order's less than 200 but still subtracting money, mining points from the player code: multiplier for all shipments made through cargo refactor: 2 new procs retrive_points() & subtract_points() to dela with different types /:cl: * Produce consoles now grey out their buttons if the cost criteria aren't met & have dynamic window sizes. --------- Co-authored-by: SyncIt21 <110812394+SyncIt21@users.noreply.github.com> --- .../orders/order_computer/mining_order.dm | 37 +------ .../orders/order_computer/order_computer.dm | 58 +++++++--- .../{ProduceConsole.js => ProduceConsole.tsx} | 101 +++++++++++++----- 3 files changed, 119 insertions(+), 77 deletions(-) rename tgui/packages/tgui/interfaces/{ProduceConsole.js => ProduceConsole.tsx} (80%) diff --git a/code/game/machinery/computer/orders/order_computer/mining_order.dm b/code/game/machinery/computer/orders/order_computer/mining_order.dm index 4048d9b151f..527e917fa61 100644 --- a/code/game/machinery/computer/orders/order_computer/mining_order.dm +++ b/code/game/machinery/computer/orders/order_computer/mining_order.dm @@ -1,5 +1,3 @@ -#define MINING_SHIPPING_MULTIPLIER 0.65 -#define GET_MINING_SHIPPING_MULTIPLIER(cost) round(cost * MINING_SHIPPING_MULTIPLIER, 5) #define CREDIT_TYPE_MINING "mp" /obj/machinery/computer/order_console/mining @@ -10,14 +8,13 @@ icon_keyboard = null icon_screen = null circuit = /obj/item/circuitboard/computer/order_console/mining - cooldown_time = 10 SECONDS //just time to let you know your order went through. + cargo_cost_multiplier = 0.65 express_cost_multiplier = 1 purchase_tooltip = @{"Your purchases will arrive at cargo, and hopefully get delivered by them. 35% cheaper than express delivery."} express_tooltip = @{"Sends your purchases instantly."} - credit_type = CREDIT_TYPE_MINING order_categories = list( @@ -28,15 +25,10 @@ ) blackbox_key = "mining" -/obj/machinery/computer/order_console/mining/purchase_items(obj/item/card/id/card, express = FALSE) - var/final_cost = get_total_cost() - var/failure_message = "Sorry, but you do not have enough mining points." - if(!express) - final_cost = GET_MINING_SHIPPING_MULTIPLIER(final_cost) +/obj/machinery/computer/order_console/mining/subtract_points(final_cost, obj/item/card/id/card) if(final_cost <= card.registered_account.mining_points) card.registered_account.mining_points -= final_cost return TRUE - say(failure_message) return FALSE /obj/machinery/computer/order_console/mining/order_groceries(mob/living/purchaser, obj/item/card/id/card, list/groceries) @@ -67,33 +59,14 @@ radio.talk_into(src, "A shaft miner has ordered equipment which will arrive on the cargo shuttle! Please make sure it gets to them as soon as possible!", radio_channel) SSshuttle.shopping_list += new_order -/obj/machinery/computer/order_console/mining/ui_data(mob/user) - var/list/data = ..() - var/cost = get_total_cost() - data["total_cost"] = "[GET_MINING_SHIPPING_MULTIPLIER(cost)] (Express: [cost]) " - if(!isliving(user)) - return data - var/mob/living/living_user = user - var/obj/item/card/id/id_card = living_user.get_idcard(TRUE) - if(id_card) - data["points"] = id_card.registered_account.mining_points - - return data +/obj/machinery/computer/order_console/mining/retrive_points(obj/item/card/id/id_card) + return FLOOR(id_card.registered_account.mining_points, 1) /obj/machinery/computer/order_console/mining/ui_act(action, params) . = ..() if(!.) flick("mining-deny", src) -/obj/machinery/computer/order_console/mining/ui_static_data(mob/user) - var/list/data = ..() - for(var/list/order in data["order_datums"]) - var/cost = order["cost"] - if(isnull(cost)) //sanity check - continue - order["cost"] = GET_MINING_SHIPPING_MULTIPLIER(cost) // change costs to reflect mining shipping instead - return data - /obj/machinery/computer/order_console/mining/attackby(obj/item/weapon, mob/user, params) if(istype(weapon, /obj/item/mining_voucher)) redeem_voucher(weapon, user) @@ -215,5 +188,3 @@ #undef CREDIT_TYPE_MINING #undef TO_POINT_CARD #undef TO_USER_ID -#undef MINING_SHIPPING_MULTIPLIER -#undef GET_MINING_SHIPPING_MULTIPLIER diff --git a/code/game/machinery/computer/orders/order_computer/order_computer.dm b/code/game/machinery/computer/orders/order_computer/order_computer.dm index 7d54ee86a76..5e38e354c00 100644 --- a/code/game/machinery/computer/orders/order_computer/order_computer.dm +++ b/code/game/machinery/computer/orders/order_computer/order_computer.dm @@ -28,7 +28,9 @@ GLOBAL_LIST_EMPTY(order_console_products) var/credit_type = CREDIT_TYPE_CREDIT ///Whether the console can only use express mode ONLY var/forced_express = FALSE - ///Multiplied cost to use express mode + ///Multiplied cost to use for cargo mode + var/cargo_cost_multiplier = 1 + ///Multiplied cost to use for express mode var/express_cost_multiplier = 2 ///The categories of orderable items this console can view and purchase. var/list/order_categories = list() @@ -69,10 +71,17 @@ GLOBAL_LIST_EMPTY(order_console_products) ui = new(user, src, "ProduceConsole", name) ui.open() +/** + * points is any type of currency this machine accepts(money, mining points etc) which is displayed on the ui + * Args: + * card - The ID card we retrive these points from + */ +/obj/machinery/computer/order_console/proc/retrive_points(obj/item/card/id/id_card) + return FLOOR(id_card.registered_account?.account_balance, 1) + /obj/machinery/computer/order_console/ui_data(mob/user) var/list/data = list() - var/cost = get_total_cost() - data["total_cost"] = "[cost] (Express: [cost * express_cost_multiplier])" + data["total_cost"] = get_total_cost() data["off_cooldown"] = COOLDOWN_FINISHED(src, order_cooldown) if(!isliving(user)) @@ -80,7 +89,7 @@ GLOBAL_LIST_EMPTY(order_console_products) var/mob/living/living_user = user var/obj/item/card/id/id_card = living_user.get_idcard(TRUE) if(id_card) - data["points"] = id_card.registered_account?.account_balance + data["points"] = retrive_points(id_card) for(var/datum/orderable_item/item as anything in GLOB.order_console_products) if(!(item.category_index in order_categories)) continue @@ -97,17 +106,21 @@ GLOBAL_LIST_EMPTY(order_console_products) data["express_tooltip"] = express_tooltip data["purchase_tooltip"] = purchase_tooltip data["forced_express"] = forced_express + data["cargo_value"] = CARGO_CRATE_VALUE + data["cargo_cost_multiplier"] = cargo_cost_multiplier + data["express_cost_multiplier"] = express_cost_multiplier data["order_categories"] = order_categories data["order_datums"] = list() for(var/datum/orderable_item/item as anything in GLOB.order_console_products) if(!(item.category_index in order_categories)) continue + data["order_datums"] += list(list( "name" = item.name, "desc" = item.desc, "cat" = item.category_index, "ref" = REF(item), - "cost" = item.cost_per_order, + "cost" = FLOOR(item.cost_per_order * cargo_cost_multiplier, 1), "product_icon" = icon2base64(getFlatIcon(image(icon = initial(item.item_path.icon), icon_state = initial(item.item_path.icon_state)), no_anim=TRUE)) )) return data @@ -136,21 +149,20 @@ GLOBAL_LIST_EMPTY(order_console_products) grocery_list[wanted_item] = clamp(params["amt"], 0, 20) if(!grocery_list[wanted_item]) grocery_list -= wanted_item - if("purchase", "ltsrbt_deliver") + if("purchase") if(!grocery_list.len || !COOLDOWN_FINISHED(src, order_cooldown)) return if(forced_express) return ui_act(action = "express") + //So miners cant spam buy crates for a very low price + if(get_total_cost() < CARGO_CRATE_VALUE) + return var/obj/item/card/id/used_id_card = living_user.get_idcard(TRUE) if(!used_id_card || !used_id_card.registered_account) say("No bank account detected!") return if(!purchase_items(used_id_card)) return - //So miners cant spam buy crates for a very low price - if(get_total_cost() < CARGO_CRATE_VALUE) - say("For the delivery order needs to cost more or equal to [CARGO_CRATE_VALUE] points!") - return if(blackbox_key) SSblackbox.record_feedback("tally", "non_express_[blackbox_key]_order", 1, name) order_groceries(living_user, used_id_card, grocery_list) @@ -197,16 +209,30 @@ GLOBAL_LIST_EMPTY(order_console_products) * returns TRUE if we can afford, FALSE otherwise. */ /obj/machinery/computer/order_console/proc/purchase_items(obj/item/card/id/card, express = FALSE) - var/final_cost = get_total_cost() - var/failure_message = "Sorry, but you do not have enough money." - if(express) - final_cost *= express_cost_multiplier - failure_message += " Remember, Express upcharges the cost!" - if(card.registered_account.adjust_money(-final_cost, "[name]: Purchase")) + var/final_cost = get_total_cost() * (express ? express_cost_multiplier : cargo_cost_multiplier) + var/failure_message = !express ? "Sorry, but you do not have enough [credit_type]." : " Remember, Express upcharges the cost!" + if(subtract_points(final_cost, card)) return TRUE say(failure_message) return FALSE +/** + * whatever type of points was retrived in retrive_points() subtract those type of points from the card upon confirming order + * Args: + * final_cost - amount of points to subtract from this card + * card - The ID card to subtract these points from + * returns TRUE if successfull + */ +/obj/machinery/computer/order_console/proc/subtract_points(final_cost, obj/item/card/id/card) + return card.registered_account.adjust_money(-final_cost, "[name]: Purchase") + +/** + * start of the shipment of your order + * Args: + * purchaser - The mob who is making this purchase + * card - The card used to place this order + * groceries - the list of orders to be placed + */ /obj/machinery/computer/order_console/proc/order_groceries(mob/living/purchaser, obj/item/card/id/card, list/groceries) return diff --git a/tgui/packages/tgui/interfaces/ProduceConsole.js b/tgui/packages/tgui/interfaces/ProduceConsole.tsx similarity index 80% rename from tgui/packages/tgui/interfaces/ProduceConsole.js rename to tgui/packages/tgui/interfaces/ProduceConsole.tsx index 99d718e68e9..a467beceb55 100644 --- a/tgui/packages/tgui/interfaces/ProduceConsole.js +++ b/tgui/packages/tgui/interfaces/ProduceConsole.tsx @@ -1,3 +1,4 @@ +import { BooleanLike } from 'common/react'; import { capitalize, createSearch } from 'common/string'; import { useBackend, useLocalState } from '../backend'; import { Box, Button, Dimmer, Divider, Icon, Input, NumberInput, Section, Stack, Tabs } from '../components'; @@ -5,6 +6,36 @@ import { Window } from '../layouts'; const buttonWidth = 2; +type OrderDatum = { + name: string; + desc: number; + cat: string; + ref: string; + cost: number; + product_icon: string; +}; + +type Item = { + name: string; + amt: number; +}; + +type Data = { + credit_type: string; + off_cooldown: BooleanLike; + points: number; + express_tooltip: string; + purchase_tooltip: string; + forced_express: string; + cargo_value: number; + cargo_cost_multiplier: number; + express_cost_multiplier: number; + order_categories: string[]; + order_datums: OrderDatum[]; + item_amts: Item[]; + total_cost: number; +}; + const TAB2NAME = [ { component: () => ShoppingTab, @@ -20,34 +51,41 @@ const findAmount = (item_amts, name) => { }; const ShoppingTab = (props, context) => { - const { data, act } = useBackend(context); + const { data, act } = useBackend(context); const { credit_type, order_categories, order_datums, item_amts } = data; - const [shopIndex, setShopIndex] = useLocalState(context, 'shop-index', 1); - const [condensed, setCondensed] = useLocalState(context, 'condensed', false); + const [shopCategory, setShopCategory] = useLocalState( + context, + 'shopCategory', + order_categories[0] + ); + const [condensed] = useLocalState(context, 'condensed', false); const [searchItem, setSearchItem] = useLocalState(context, 'searchItem', ''); - const search = createSearch(searchItem, (order_datums) => order_datums.name); + const search = createSearch( + searchItem, + (order_datums) => order_datums.name + ); let goods = searchItem.length > 0 - ? data.order_datums.filter(search) - : order_datums.filter((item) => item && item.cat === shopIndex); + ? order_datums.filter((item) => search(item) && item.cat === shopCategory) + : order_datums.filter((item) => item && item.cat === shopCategory); return (
- {order_categories.map((item, key) => ( + {order_categories.map((category) => ( { - setShopIndex(item); + setShopCategory(category); if (searchItem.length > 0) { setSearchItem(''); } }}> - {item} + {category} ))} @@ -60,10 +98,6 @@ const ShoppingTab = (props, context) => { value={searchItem} onInput={(e, value) => { setSearchItem(value); - - if (value.length > 0) { - setShopIndex(1); - } }} fluid /> @@ -75,8 +109,8 @@ const ShoppingTab = (props, context) => {
- {goods.map((item) => ( - + {goods.map((item, key) => ( + { }; const CheckoutTab = (props, context) => { - const { data, act } = useBackend(context); + const { data, act } = useBackend(context); const { credit_type, purchase_tooltip, express_tooltip, forced_express, + cargo_value, order_datums, total_cost, + cargo_cost_multiplier, + express_cost_multiplier, item_amts, } = data; - + const total_cargo_cost = Math.floor(total_cost * cargo_cost_multiplier); const checkout_list = order_datums.filter( (food) => food && (findAmount(item_amts, food.name) || 0) ); @@ -187,8 +224,8 @@ const CheckoutTab = (props, context) => { )} - {checkout_list.map((item) => ( - + {checkout_list.map((item, key) => ( + {capitalize(item.name)} @@ -228,7 +265,8 @@ const CheckoutTab = (props, context) => {
- Total Cost: {total_cost} + Total Cost:{total_cargo_cost}(Express: + {total_cost * express_cost_multiplier}) {!forced_express && ( @@ -236,7 +274,12 @@ const CheckoutTab = (props, context) => { fluid icon="plane-departure" content="Purchase" - tooltip={purchase_tooltip} + disabled={total_cargo_cost < cargo_value} + tooltip={ + total_cargo_cost < cargo_value + ? `Total Cost must be above or equal to ${cargo_value}` + : purchase_tooltip + } tooltipPosition="top" onClick={() => act('purchase')} /> @@ -248,7 +291,10 @@ const CheckoutTab = (props, context) => { icon="parachute-box" color="yellow" content="Express" - tooltip={express_tooltip} + disabled={total_cost <= 0} + tooltip={ + total_cost <= 0 ? 'Order atleast 1 item' : express_tooltip + } tooltipPosition="top-start" onClick={() => act('express')} /> @@ -261,7 +307,6 @@ const CheckoutTab = (props, context) => { }; const OrderSent = (props, context) => { - const { act, data } = useBackend(context); return ( @@ -277,13 +322,13 @@ const OrderSent = (props, context) => { }; export const ProduceConsole = (props, context) => { - const { act, data } = useBackend(context); - const { points, off_cooldown } = data; + const { data } = useBackend(context); + const { points, off_cooldown, order_categories } = data; const [tabIndex, setTabIndex] = useLocalState(context, 'tab-index', 1); const [condensed, setCondensed] = useLocalState(context, 'condensed', false); const TabComponent = TAB2NAME[tabIndex - 1].component(); return ( - + {!off_cooldown && }