mirror of
https://github.com/yogstation13/Yogstation.git
synced 2025-02-26 09:04:50 +00:00
Fix the vending machine chef's compartment (#18626)
* Make the vending chef compartment work again * Fix vending load access check * Fix missing table wrapper * Apply eslint fixes & fix button disable check * Add icons to custom vending items * Appease the linter * Rename "dispense" to "vend_custom" * Refactor vending code out into procs Reduces code duplication significantly * Remove stray vend_ready set * Fix proper/improper names not dispensing * Remove empty stocks from listing Bibby --------- Co-authored-by: ynot01 <ynot000001@gmail.com>
This commit is contained in:
@@ -37,6 +37,26 @@ IF YOU MODIFY THE PRODUCTS LIST OF A MACHINE, MAKE SURE TO UPDATE ITS RESUPPLY C
|
||||
///List of items that have been returned to the vending machine.
|
||||
var/list/returned_products
|
||||
|
||||
/**
|
||||
* # User-inserted custom product
|
||||
* A datum that represents a custom product that is vendable
|
||||
*/
|
||||
/datum/data/vending_custom_product
|
||||
///Name of the stored item
|
||||
name = "generic"
|
||||
///Unstripped name of the item, includes article
|
||||
var/full_name = ""
|
||||
///Icon of the item
|
||||
var/asset = null
|
||||
///How many are stored currently
|
||||
var/amount = 0
|
||||
|
||||
/datum/data/vending_custom_product/New(obj/item/I)
|
||||
name = format_text(I.name)
|
||||
full_name = I.name
|
||||
var/icon/icon = icon(I.icon, I.icon_state, SOUTH, 1)
|
||||
asset = icon2base64(icon) // costly? probably. less costly than sending the entire spritesheet? also probably
|
||||
|
||||
/**
|
||||
* # vending machines
|
||||
*
|
||||
@@ -136,6 +156,7 @@ IF YOU MODIFY THE PRODUCTS LIST OF A MACHINE, MAKE SURE TO UPDATE ITS RESUPPLY C
|
||||
var/obj/item/coin/coin
|
||||
///Bills we accept?
|
||||
var/obj/item/stack/spacecash/bill
|
||||
///Custom item price
|
||||
var/chef_price = 10
|
||||
///Default price of items if not overridden
|
||||
var/default_price = 25
|
||||
@@ -152,6 +173,7 @@ IF YOU MODIFY THE PRODUCTS LIST OF A MACHINE, MAKE SURE TO UPDATE ITS RESUPPLY C
|
||||
///ID's that can load this vending machine wtih refills
|
||||
var/list/canload_access_list
|
||||
|
||||
///Custom item stock
|
||||
var/list/vending_machine_input = list()
|
||||
///Display header on the input view
|
||||
var/input_display_header = "Custom Compartment"
|
||||
@@ -601,10 +623,12 @@ GLOBAL_LIST_EMPTY(vending_products)
|
||||
LAZYADD(product_datum.returned_products, I)
|
||||
return
|
||||
|
||||
if(vending_machine_input[format_text(I.name)])
|
||||
vending_machine_input[format_text(I.name)]++
|
||||
else
|
||||
vending_machine_input[format_text(I.name)] = 1
|
||||
var/name = format_text(I.name)
|
||||
if(!vending_machine_input[name])
|
||||
vending_machine_input[name] = new /datum/data/vending_custom_product(I)
|
||||
|
||||
var/datum/data/vending_custom_product/P = vending_machine_input[name]
|
||||
P.amount++
|
||||
loaded_items++
|
||||
|
||||
/obj/machinery/vending/exchange_parts(mob/user, obj/item/storage/part_replacer/W)
|
||||
@@ -669,6 +693,9 @@ GLOBAL_LIST_EMPTY(vending_products)
|
||||
. = list()
|
||||
.["onstation"] = onstation
|
||||
.["department"] = payment_department
|
||||
.["chef"] = list() // "chef compartment" i.e. player-added stock
|
||||
.["chef"]["title"] = input_display_header
|
||||
.["chef"]["price"] = chef_price
|
||||
.["product_records"] = list()
|
||||
for (var/datum/data/vending_product/R in product_records)
|
||||
var/list/data = list(
|
||||
@@ -733,6 +760,11 @@ GLOBAL_LIST_EMPTY(vending_products)
|
||||
for (var/datum/data/vending_product/R in product_records + coin_records + hidden_records)
|
||||
.["stock"][R.name] = R.amount
|
||||
.["extended_inventory"] = extended_inventory
|
||||
// extra items that have been placed in custom stock
|
||||
.["custom_stock"] = list()
|
||||
for (var/name in vending_machine_input)
|
||||
var/datum/data/vending_custom_product/P = vending_machine_input[name]
|
||||
.["custom_stock"][P.name] = list(amount = P.amount, img = P.asset)
|
||||
|
||||
/obj/machinery/vending/ui_act(action, params)
|
||||
. = ..()
|
||||
@@ -770,25 +802,26 @@ GLOBAL_LIST_EMPTY(vending_products)
|
||||
flick(icon_deny,src)
|
||||
vend_ready = TRUE
|
||||
return
|
||||
var/mob/living/L
|
||||
if(isliving(usr))
|
||||
L = usr
|
||||
|
||||
if(onstation && ishuman(usr) && (L && !L.ignores_capitalism))
|
||||
if(coin_records.Find(R) || hidden_records.Find(R))
|
||||
price_to_use = R.custom_premium_price ? R.custom_premium_price : extra_price
|
||||
|
||||
if(LAZYLEN(R.returned_products))
|
||||
price_to_use = 0 //returned items are free
|
||||
|
||||
if(!charge_user(price_to_use, R.name))
|
||||
vend_ready = TRUE
|
||||
return
|
||||
|
||||
if(onstation && ishuman(usr))
|
||||
var/mob/living/carbon/human/H = usr
|
||||
var/obj/item/card/id/C = H.get_idcard(TRUE)
|
||||
|
||||
// this should really be caught by charge_user above, just extra safety
|
||||
if(!C)
|
||||
say("No card found.")
|
||||
flick(icon_deny,src)
|
||||
vend_ready = TRUE
|
||||
return
|
||||
else if (!C.registered_account)
|
||||
say("No account found.")
|
||||
flick(icon_deny,src)
|
||||
vend_ready = TRUE
|
||||
return
|
||||
else if(age_restrictions && R.age_restricted && (!C.registered_age || C.registered_age < AGE_MINOR))
|
||||
|
||||
if(age_restrictions && R.age_restricted && (!C.registered_age || C.registered_age < AGE_MINOR))
|
||||
say("You are not of legal age to purchase [R.name].")
|
||||
if(!(usr in GLOB.narcd_underages))
|
||||
alertradio.set_frequency(FREQ_SECURITY)
|
||||
@@ -797,29 +830,10 @@ GLOBAL_LIST_EMPTY(vending_products)
|
||||
flick(icon_deny,src)
|
||||
vend_ready = TRUE
|
||||
return
|
||||
var/datum/bank_account/account = C.registered_account
|
||||
if(account.account_job && account.account_job.paycheck_department == payment_department)
|
||||
price_to_use = 0
|
||||
if(coin_records.Find(R) || hidden_records.Find(R))
|
||||
price_to_use = R.custom_premium_price ? R.custom_premium_price : extra_price
|
||||
if(LAZYLEN(R.returned_products))
|
||||
price_to_use = 0 //returned items are free
|
||||
if(price_to_use && !account.adjust_money(-price_to_use))
|
||||
say("You do not possess the funds to purchase [R.name].")
|
||||
flick(icon_deny,src)
|
||||
vend_ready = TRUE
|
||||
return
|
||||
var/datum/bank_account/D = SSeconomy.get_dep_account(payment_department)
|
||||
if(D)
|
||||
D.adjust_money(price_to_use)
|
||||
if(last_shopper != usr || purchase_message_cooldown < world.time)
|
||||
say("Thank you for shopping with [src]!")
|
||||
purchase_message_cooldown = world.time + 5 SECONDS
|
||||
last_shopper = usr
|
||||
use_power(5)
|
||||
if(icon_vend) //Show the vending animation if needed
|
||||
flick(icon_vend,src)
|
||||
playsound(src, 'sound/machines/machine_vend.ogg', 50, TRUE, extrarange = -3)
|
||||
|
||||
thank_user("Thank you for shopping with [src]!")
|
||||
finish_vend()
|
||||
|
||||
var/obj/item/vended_item
|
||||
if(!LAZYLEN(R.returned_products)) //always give out free returned stuff first, e.g. to avoid walling a traitor objective in a bag behind paid items
|
||||
vended_item = new R.product_path(get_turf(src))
|
||||
@@ -830,6 +844,88 @@ GLOBAL_LIST_EMPTY(vending_products)
|
||||
R.amount--
|
||||
SSblackbox.record_feedback("nested tally", "vending_machine_usage", 1, list("[type]", "[R.product_path]"))
|
||||
vend_ready = TRUE
|
||||
if("vend_custom")
|
||||
. = TRUE
|
||||
if(!vend_ready)
|
||||
return
|
||||
if(panel_open)
|
||||
to_chat(usr, span_warning("The vending machine cannot dispense products while its service panel is open!"))
|
||||
return
|
||||
var/N = params["item"]
|
||||
var/datum/data/vending_custom_product/P = vending_machine_input[N]
|
||||
if(!P || P.amount <= 0) // don't dispense none item with left beef
|
||||
return
|
||||
vend_ready = FALSE //One thing at a time!!
|
||||
|
||||
// Charge the user
|
||||
if (!charge_user(chef_price, P.full_name))
|
||||
vend_ready = TRUE
|
||||
return
|
||||
|
||||
thank_user("Thank you for shopping local and buying \the [P.full_name]!")
|
||||
finish_vend()
|
||||
|
||||
P.amount = max(P.amount - 1, 0)
|
||||
for(var/obj/item/I in contents)
|
||||
if(format_text(I.name) == N)
|
||||
I.forceMove(get_turf(src))
|
||||
break
|
||||
if(P.amount <= 0) // If there's no more left, clear it from the records
|
||||
vending_machine_input[N] = null
|
||||
qdel(P)
|
||||
vend_ready = TRUE
|
||||
|
||||
/**
|
||||
* Charge the user during a vend
|
||||
* Returns false if the user could not buy this item
|
||||
*/
|
||||
/obj/machinery/vending/proc/charge_user(price, item_name)
|
||||
var/mob/living/L
|
||||
if(isliving(usr))
|
||||
L = usr
|
||||
|
||||
if(onstation && ishuman(usr) && (L && !L.ignores_capitalism))
|
||||
var/mob/living/carbon/human/H = usr
|
||||
var/obj/item/card/id/C = H.get_idcard(TRUE)
|
||||
|
||||
if(!C)
|
||||
say("No card found.")
|
||||
flick(icon_deny,src)
|
||||
return FALSE
|
||||
else if (!C.registered_account)
|
||||
say("No account found.")
|
||||
flick(icon_deny,src)
|
||||
return FALSE
|
||||
var/datum/bank_account/account = C.registered_account
|
||||
if(account.account_job && account.account_job.paycheck_department == payment_department)
|
||||
price = 0
|
||||
if(price && !account.adjust_money(-price))
|
||||
say("You do not possess the funds to purchase \the [item_name].")
|
||||
flick(icon_deny,src)
|
||||
return FALSE
|
||||
var/datum/bank_account/D = SSeconomy.get_dep_account(payment_department)
|
||||
if(D)
|
||||
D.adjust_money(price)
|
||||
|
||||
return TRUE
|
||||
|
||||
/**
|
||||
* Thank the user for the purchase
|
||||
*/
|
||||
/obj/machinery/vending/proc/thank_user(message)
|
||||
if(last_shopper != usr || purchase_message_cooldown < world.time)
|
||||
say(message)
|
||||
purchase_message_cooldown = world.time + 5 SECONDS
|
||||
last_shopper = usr
|
||||
|
||||
/**
|
||||
* Finish a vend by consuming power, playing animations & playing sounds
|
||||
*/
|
||||
/obj/machinery/vending/proc/finish_vend()
|
||||
use_power(5)
|
||||
if(icon_vend) //Show the vending animation if needed
|
||||
flick(icon_vend,src)
|
||||
playsound(src, 'sound/machines/machine_vend.ogg', 50, TRUE, extrarange = -3)
|
||||
|
||||
/obj/machinery/vending/process(delta_time)
|
||||
if(stat & (BROKEN|NOPOWER))
|
||||
@@ -965,21 +1061,26 @@ GLOBAL_LIST_EMPTY(vending_products)
|
||||
if(!canload_access_list)
|
||||
return TRUE
|
||||
else
|
||||
var/do_you_have_access = FALSE
|
||||
var/req_access_txt_holder = req_access_txt
|
||||
for(var/i in canload_access_list)
|
||||
req_access_txt = i
|
||||
if(!allowed(user) && !(obj_flags & EMAGGED) && scan_id)
|
||||
continue
|
||||
else
|
||||
do_you_have_access = TRUE
|
||||
break //you passed don't bother looping anymore
|
||||
req_access_txt = req_access_txt_holder // revert to normal (before the proc ran)
|
||||
if(do_you_have_access)
|
||||
if((obj_flags & EMAGGED) || !scan_id)
|
||||
return TRUE
|
||||
else
|
||||
to_chat(user, span_warning("[src]'s input compartment blinks red: Access denied."))
|
||||
return FALSE
|
||||
|
||||
if(ishuman(user))
|
||||
var/mob/living/carbon/human/H = user
|
||||
var/obj/item/card/id/C = H.get_idcard(TRUE)
|
||||
if(!C)
|
||||
to_chat(user, span_warning("[src]'s input compartment blinks red: No card found."))
|
||||
return FALSE
|
||||
|
||||
var/A = C.GetAccess()
|
||||
// This is checking like `req_one_access` does (need any in list)
|
||||
// The only thing that uses this is the chef compartment which only has one access in the list anyway
|
||||
// If you add another, you may need to alter this behaviour
|
||||
for(var/req in canload_access_list)
|
||||
if(req in A)
|
||||
return TRUE
|
||||
|
||||
to_chat(user, span_warning("[src]'s input compartment blinks red: Access denied."))
|
||||
return FALSE
|
||||
|
||||
/obj/machinery/vending/onTransitZ()
|
||||
return
|
||||
|
||||
@@ -41,13 +41,6 @@
|
||||
S.forceMove(get_turf(src))
|
||||
return ..()
|
||||
|
||||
/obj/machinery/vending/snack/proc/food_load(obj/item/reagent_containers/food/snacks/S)
|
||||
if(vending_machine_input[S.name])
|
||||
vending_machine_input[S.name]++
|
||||
else
|
||||
vending_machine_input[S.name] = 1
|
||||
sortList(vending_machine_input)
|
||||
|
||||
/obj/machinery/vending/snack/random
|
||||
name = "\improper Random Snackies"
|
||||
icon_state = "random_snack"
|
||||
|
||||
@@ -24,12 +24,24 @@ const VendingRow = (props, context) => {
|
||||
|| data.ignores_capitalism
|
||||
// yogs end
|
||||
);
|
||||
|
||||
const customFree = (
|
||||
!data.onstation
|
||||
|| (
|
||||
data.user
|
||||
&& data.department
|
||||
&& data.department === data.user.department
|
||||
)
|
||||
|| data.ignores_capitalism
|
||||
);
|
||||
|
||||
return (
|
||||
<Table.Row>
|
||||
<Table.Cell collapsing>
|
||||
{product.base64 ? (
|
||||
<img
|
||||
src={`data:image/jpeg;base64,${product.img}`}
|
||||
className="icon"
|
||||
style={{
|
||||
'vertical-align': 'middle',
|
||||
'horizontal-align': 'middle',
|
||||
@@ -51,8 +63,7 @@ const VendingRow = (props, context) => {
|
||||
</Table.Cell>
|
||||
<Table.Cell collapsing textAlign="center">
|
||||
<Box
|
||||
color={custom
|
||||
? 'good'
|
||||
color={custom ? (productStock > 0 ? 'good' : 'bad')
|
||||
: productStock <= 0
|
||||
? 'bad'
|
||||
: productStock <= (product.max_amount / 2)
|
||||
@@ -65,8 +76,13 @@ const VendingRow = (props, context) => {
|
||||
{custom && (
|
||||
<Button
|
||||
fluid
|
||||
content={data.access ? 'FREE' : product.price + ' cr'}
|
||||
onClick={() => act('dispense', {
|
||||
disabled={(
|
||||
productStock === 0
|
||||
|| !data.user
|
||||
|| (!free && product.price > data.user.cash)
|
||||
)}
|
||||
content={customFree ? 'FREE' : product.price + ' cr'}
|
||||
onClick={() => act('vend_custom', {
|
||||
'item': product.name,
|
||||
})} />
|
||||
) || (
|
||||
@@ -93,13 +109,10 @@ export const Vending = (props, context) => {
|
||||
const { act, data } = useBackend(context);
|
||||
const {
|
||||
product_ad,
|
||||
chef,
|
||||
} = data;
|
||||
let inventory;
|
||||
let custom = false;
|
||||
if (data.vending_machine_input) {
|
||||
inventory = data.vending_machine_input;
|
||||
custom = true;
|
||||
} else if (data.extended_inventory) {
|
||||
if (data.extended_inventory) {
|
||||
inventory = [
|
||||
...data.product_records,
|
||||
...data.coin_records,
|
||||
@@ -111,6 +124,17 @@ export const Vending = (props, context) => {
|
||||
...data.coin_records,
|
||||
];
|
||||
}
|
||||
|
||||
const customInventory = Object.keys(data.custom_stock).map(itemName => ({
|
||||
product: {
|
||||
name: itemName,
|
||||
price: chef.price,
|
||||
base64: true,
|
||||
img: data.custom_stock[itemName].img,
|
||||
},
|
||||
productStock: data.custom_stock[itemName].amount,
|
||||
}));
|
||||
|
||||
return (
|
||||
<Window
|
||||
title="Vending Machine"
|
||||
@@ -140,12 +164,24 @@ export const Vending = (props, context) => {
|
||||
)}
|
||||
</Section>
|
||||
)}
|
||||
{!!customInventory.length &&
|
||||
<Section title={chef.title} >
|
||||
<Table>
|
||||
{customInventory.map(customItem => (
|
||||
<VendingRow
|
||||
key={customItem.product.name}
|
||||
custom
|
||||
product={customItem.product}
|
||||
productStock={customItem.productStock}
|
||||
/>
|
||||
))}
|
||||
</Table>
|
||||
</Section>}
|
||||
<Section title="Products" >
|
||||
<Table>
|
||||
{inventory.map(product => (
|
||||
<VendingRow
|
||||
key={product.name}
|
||||
custom={custom}
|
||||
product={product}
|
||||
productStock={data.stock[product.name]} />
|
||||
))}
|
||||
|
||||
Reference in New Issue
Block a user