mirror of
https://github.com/Bubberstation/Bubberstation.git
synced 2026-08-31 00:58:26 +01:00
General maintenance for vending machines (#91987)
## About The Pull Request **1. Code Improvements** - Removed unused vars `coin`, `bill` & other stuff - Removed duplicate definition of `on_deconstruction()` - Autodoc for a lot of procs - Merged smaller procs into larger ones to avoid scrolling in the code editor & reduced overhead - Split the vending machine file into several smaller files for easy code management **2. Qol** - Implemented vending machine ads. They now display random stuff on the UI https://github.com/user-attachments/assets/9720ea60-f268-4ca2-940d-243e3d0ac75f - More error messages for custom & normal vendors as to why an item could not be loaded - Custom vending machines can be deconstructed safely via crowbar without any explosion only after unlinking your account from the machine else you get the same explosion. Upon deconstruction all loaded items are moved into its restock canister meaning the machine can be safely moved with all its products just like a regular vending machine to a new location **3. Fixes** - Fixes #81917. Any returned items in the vending machine now show up as free in the UI & won't cost credits to buy them - Fixes #87416. Custom & normal vendors now keep track of products removed via `Exited()` so the UI gets always updated - Fixes #83151. Items with different names & custom prices now show up in unique rows - Fixes #92170 Custom vendors now show the correct icon for inserted items - Closes #80010. From the above fix this situation is impossible so it's safe to close this as a duplicate - Closes #78016 same problem as above with `Exited()` duplicate - Custom vendors can now actually be used by players who are not the owner instead of locking down the UI - Vending machines keep track of `max_amount` of stocked items by hand as well & not just RPED **4. Refactor** - Separates custom vending machine code from normal vending machine code. This prime Marely focus on the `vending_machine_input` list which now only exists inside the custom vending machine - Compressed the UI code for vending machine so both custom & normal vending machines can send the same data instead of separating the 2. Overall less code - Moved attack chain from `attackby()` to `item_interaction()` for loading items ## Changelog 🆑 code: cleaned up vending machine code qol: vending machines now have more product slogans you never heard before qol: custom & normal vending machines now have more feedback on why an item could not be loaded qol: vending machines now display random ads on the UI qol: custom vending machines can be deconstructed via crowbar safely only after unlinking your account from the machine. qol: upon deconstructing a custom vendor all its products are moved into its refill canister & it will be restored when reconstructing the machine elsewhere fix: Returned items to the vending machine now show up as free in the UI and won't be greyed out if you don't have credits to get them back fix: items that leave the vending machine by any means will update the UI in all cases fix: loading items by hand to the vending machine now respects the max_amount for that category fix: custom vendors can now actually be used by players who are not the owner thus enabling them to transfer credits to the owner during purchases & basically they do their job again fix: custom vendors now show the correct icon for inserted items fix: Items with different names & custom prices now show up in unique rows in custom vendors refactor: separated custom & normal vending machine code. Reduced UI code & improved attack chain /🆑 --------- Co-authored-by: MrMelbert <51863163+MrMelbert@users.noreply.github.com>
This commit is contained in:
+181
@@ -0,0 +1,181 @@
|
||||
///Helper to create a typepath to be used in the UI
|
||||
#define SANITIZED_PATH(path)(replacetext(replacetext("[path]", "/obj/item/", ""), "/", "-"))
|
||||
|
||||
/obj/machinery/vending/ui_assets(mob/user)
|
||||
return list(
|
||||
get_asset_datum(/datum/asset/spritesheet_batched/vending),
|
||||
)
|
||||
|
||||
/obj/machinery/vending/ui_interact(mob/user, datum/tgui/ui)
|
||||
ui = SStgui.try_update_ui(user, src, ui)
|
||||
if(!ui)
|
||||
ui = new(user, src, "Vending", name)
|
||||
ui.open()
|
||||
|
||||
|
||||
/**
|
||||
* Returns a list of given product records of the vendor to be used in UI.
|
||||
* arguments:
|
||||
* records - list of records available
|
||||
* categories - list of categories available
|
||||
* premium - bool of whether a record should be priced by a custom/premium price or not
|
||||
*/
|
||||
/obj/machinery/vending/proc/collect_records_for_static_data(list/records, list/categories, premium)
|
||||
PROTECTED_PROC(TRUE)
|
||||
|
||||
var/static/list/default_category = list(
|
||||
"name" = "Products",
|
||||
"icon" = "cart-shopping",
|
||||
)
|
||||
|
||||
var/list/out_records = list()
|
||||
|
||||
for (var/datum/data/vending_product/record as anything in records)
|
||||
var/list/static_record = list(
|
||||
path = SANITIZED_PATH(record.product_path),
|
||||
name = record.name,
|
||||
price = record.price,
|
||||
ref = REF(record),
|
||||
colorable = record.colorable,
|
||||
)
|
||||
|
||||
var/atom/printed = record.product_path
|
||||
// If it's not GAGS and has no innate colors we have to care about, we use DMIcon
|
||||
if(ispath(printed, /atom) \
|
||||
&& (!initial(printed.greyscale_config) || !initial(printed.greyscale_colors)) \
|
||||
&& !initial(printed.color) \
|
||||
)
|
||||
static_record["icon"] = initial(printed.icon)
|
||||
static_record["icon_state"] = initial(printed.icon_state)
|
||||
|
||||
var/list/category = record.category || default_category
|
||||
if (!isnull(category))
|
||||
if (!(category["name"] in categories))
|
||||
categories[category["name"]] = list("icon" = category["icon"])
|
||||
|
||||
static_record["category"] = category["name"]
|
||||
|
||||
if (premium)
|
||||
static_record["premium"] = TRUE
|
||||
|
||||
out_records += list(static_record)
|
||||
|
||||
return out_records
|
||||
|
||||
/obj/machinery/vending/ui_static_data(mob/user)
|
||||
var/list/data = list()
|
||||
data["onstation"] = onstation
|
||||
if(ad_list.len)
|
||||
data["ad"] = ad_list[rand(1, ad_list.len)]
|
||||
data["all_products_free"] = all_products_free
|
||||
data["department"] = payment_department
|
||||
data["jobDiscount"] = DEPARTMENT_DISCOUNT
|
||||
data["product_records"] = list()
|
||||
data["displayed_currency_icon"] = displayed_currency_icon
|
||||
data["displayed_currency_name"] = displayed_currency_name
|
||||
|
||||
var/list/categories = list()
|
||||
|
||||
data["product_records"] = collect_records_for_static_data(product_records, categories)
|
||||
data["coin_records"] = collect_records_for_static_data(coin_records, categories, premium = TRUE)
|
||||
data["hidden_records"] = collect_records_for_static_data(hidden_records, categories, premium = TRUE)
|
||||
|
||||
data["categories"] = categories
|
||||
|
||||
return data
|
||||
|
||||
|
||||
/**
|
||||
* Returns the balance that the vendor will use for proceeding payment. Most vendors would want to use the user's
|
||||
* card's account credits balance.
|
||||
* arguments:
|
||||
* passed_id - the id card that will be billed for the product
|
||||
*/
|
||||
/obj/machinery/vending/proc/fetch_balance_to_use(obj/item/card/id/passed_id)
|
||||
PROTECTED_PROC(TRUE)
|
||||
|
||||
return passed_id.registered_account.account_balance
|
||||
|
||||
/obj/machinery/vending/ui_data(mob/user)
|
||||
. = list()
|
||||
|
||||
var/obj/item/card/id/card_used
|
||||
var/held_cash = 0
|
||||
if(isliving(user))
|
||||
var/mob/living/living_user = user
|
||||
card_used = living_user.get_idcard(TRUE)
|
||||
held_cash = living_user.tally_physical_credits()
|
||||
|
||||
var/list/user_data = null
|
||||
if(card_used?.registered_account)
|
||||
user_data = list()
|
||||
user_data["name"] = card_used.registered_account.account_holder
|
||||
user_data["cash"] = fetch_balance_to_use(card_used) + held_cash
|
||||
if(card_used.registered_account.account_job)
|
||||
user_data["job"] = card_used.registered_account.account_job.title
|
||||
user_data["department"] = card_used.registered_account.account_job.paycheck_department
|
||||
else
|
||||
user_data["job"] = "No Job"
|
||||
user_data["department"] = DEPARTMENT_UNASSIGNED
|
||||
.["user"] = user_data
|
||||
|
||||
.["stock"] = list()
|
||||
for (var/datum/data/vending_product/product_record as anything in product_records + coin_records + hidden_records)
|
||||
.["stock"][SANITIZED_PATH(product_record.product_path)] = list(
|
||||
amount = product_record.amount,
|
||||
free = length(product_record.returned_products)
|
||||
)
|
||||
|
||||
if(prob(10) && ad_list.len)
|
||||
.["ad"] = ad_list[rand(1, ad_list.len)]
|
||||
|
||||
.["extended_inventory"] = extended_inventory
|
||||
|
||||
/obj/machinery/vending/ui_act(action, list/params, datum/tgui/ui, datum/ui_state/state)
|
||||
. = ..()
|
||||
if(.)
|
||||
return
|
||||
|
||||
switch(action)
|
||||
if("vend")
|
||||
. = vend(params, ui.user)
|
||||
if("select_colors")
|
||||
var/datum/data/vending_product/product = locate(params["ref"])
|
||||
if(!istype(product))
|
||||
return FALSE
|
||||
var/atom/fake_atom = product.product_path
|
||||
var/config = initial(fake_atom.greyscale_config)
|
||||
if(!config)
|
||||
return FALSE
|
||||
|
||||
var/list/allowed_configs = list("[config]")
|
||||
if(ispath(fake_atom, /obj/item))
|
||||
var/obj/item/item = fake_atom
|
||||
if(initial(item.greyscale_config_worn))
|
||||
allowed_configs += "[initial(item.greyscale_config_worn)]"
|
||||
if(initial(item.greyscale_config_inhand_left))
|
||||
allowed_configs += "[initial(item.greyscale_config_inhand_left)]"
|
||||
if(initial(item.greyscale_config_inhand_right))
|
||||
allowed_configs += "[initial(item.greyscale_config_inhand_right)]"
|
||||
var/datum/greyscale_modify_menu/menu = new(
|
||||
src, ui.user, allowed_configs, CALLBACK(src, PROC_REF(_vend_greyscale), params, ui.user),
|
||||
starting_icon_state=initial(fake_atom.icon_state),
|
||||
starting_config = initial(fake_atom.greyscale_config),
|
||||
starting_colors = initial(fake_atom.greyscale_colors)
|
||||
)
|
||||
menu.ui_interact(ui.user)
|
||||
return TRUE
|
||||
|
||||
/**
|
||||
* Vends a greyscale modified item.
|
||||
* arguments:
|
||||
* menu - greyscale config menu that has been used to vend the item
|
||||
*/
|
||||
/obj/machinery/vending/proc/_vend_greyscale(list/params, mob/user, datum/greyscale_modify_menu/menu)
|
||||
PRIVATE_PROC(TRUE)
|
||||
|
||||
if(user != menu.user)
|
||||
return
|
||||
vend(params, user, menu.split_colors)
|
||||
|
||||
#undef SANITIZED_PATH
|
||||
Reference in New Issue
Block a user