Chef Produce Console, for cases where there are no botanists (#57298)

This commit is contained in:
tralezab
2021-03-02 19:16:27 -08:00
committed by GitHub
parent 3f8f7e777d
commit c63f696f30
13 changed files with 621 additions and 9 deletions

View File

@@ -76247,6 +76247,10 @@
/obj/item/clipboard,
/obj/item/toy/figure/chef,
/obj/effect/turf_decal/bot,
/obj/item/food/mint,
/obj/item/reagent_containers/food/condiment/enzyme{
pixel_y = 5
},
/turf/open/floor/iron,
/area/service/kitchen)
"khj" = (
@@ -93125,12 +93129,10 @@
/turf/open/floor/iron,
/area/science/misc_lab/range)
"qhn" = (
/obj/structure/table/reinforced,
/obj/item/food/mint,
/obj/item/reagent_containers/food/condiment/enzyme{
pixel_y = 5
},
/obj/effect/turf_decal/bot,
/obj/machinery/computer/chef_order{
dir = 1
},
/turf/open/floor/iron,
/area/service/kitchen)
"qhE" = (

View File

@@ -49286,6 +49286,12 @@
},
/turf/open/floor/iron,
/area/engineering/atmos)
"sTS" = (
/obj/machinery/computer/chef_order{
dir = 4
},
/turf/open/floor/iron/cafeteria,
/area/service/kitchen)
"sUk" = (
/obj/effect/decal/cleanable/dirt,
/obj/effect/decal/cleanable/dirt,
@@ -95009,7 +95015,7 @@ dfW
mjA
rLD
nUo
nUo
sTS
nUo
nUo
tIN

View File

@@ -65525,6 +65525,10 @@
/obj/item/food/dough,
/obj/item/kitchen/rollingpin,
/obj/item/kitchen/rollingpin,
/obj/item/paper/crumpled{
info = "Hey whoever designed this shithole didn't give us space to install the produce computer so it's in maintenance near the theatre.";
name = "hastily written note"
},
/turf/open/floor/iron/dark,
/area/service/kitchen)
"jAY" = (
@@ -90726,6 +90730,15 @@
},
/turf/open/floor/iron/dark,
/area/cargo/qm)
"xwt" = (
/obj/effect/decal/cleanable/dirt,
/obj/machinery/computer/chef_order{
dir = 8
},
/turf/open/floor/plating{
icon_state = "platingdmg3"
},
/area/maintenance/central)
"xww" = (
/obj/structure/closet/secure_closet/personal/cabinet,
/obj/machinery/newscaster{
@@ -124428,7 +124441,7 @@ aox
aox
buB
ajq
akM
xwt
uuQ
sox
ref

View File

@@ -36431,6 +36431,9 @@
dir = 8
},
/obj/effect/decal/cleanable/dirt,
/obj/machinery/computer/chef_order{
dir = 1
},
/turf/open/floor/iron,
/area/hallway/secondary/service)
"fDd" = (

View File

@@ -45,6 +45,7 @@ SUBSYSTEM_DEF(shuttle)
var/list/discoveredPlants = list() //Typepaths for unusual plants we've already sent CentCom, associated with their potencies
var/list/supply_packs = list()
var/list/chef_groceries = list()
var/list/shoppinglist = list()
var/list/requestlist = list()
var/list/orderhistory = list()

View File

@@ -0,0 +1,123 @@
/obj/machinery/computer/chef_order
name = "Produce Orders Console"
desc = "An interface for ordering fresh produce and other. A far more expensive option than the botanists, but oh well."
icon_screen = "request"
icon_keyboard = "generic_key"
circuit = /obj/item/circuitboard/computer/chef_order
light_color = LIGHT_COLOR_ORANGE
COOLDOWN_DECLARE(order_cooldown)
var/static/list/order_datums = list()
var/list/grocery_list = list()
var/obj/item/radio/radio
var/radio_channel = RADIO_CHANNEL_SUPPLY
/obj/machinery/computer/chef_order/Initialize()
. = ..()
radio = new(src)
radio.frequency = FREQ_SUPPLY
radio.subspace_transmission = TRUE
radio.canhear_range = 0
radio.recalculateChannels()
if(!order_datums.len)
for(var/path in subtypesof(/datum/orderable_item))
order_datums += new path
/obj/machinery/computer/chef_order/Destroy()
QDEL_NULL(radio)
. = ..()
/obj/machinery/computer/chef_order/proc/get_total_cost()
. = 0
for(var/datum/orderable_item/item as anything in grocery_list)
for(var/i in 1 to grocery_list[item]) //for how many times we bought it
. += item.cost_per_order //add its price
/obj/machinery/computer/chef_order/ui_interact(mob/user, datum/tgui/ui)
ui = SStgui.try_update_ui(user, src, ui)
if(!ui)
ui = new(user, src, "ProduceConsole", name)
ui.open()
/obj/machinery/computer/chef_order/ui_data(mob/user)
. = ..()
.["off_cooldown"] = COOLDOWN_FINISHED(src, order_cooldown)
/obj/machinery/computer/chef_order/ui_static_data(mob/user)
. = ..()
.["total_cost"] = get_total_cost()
.["order_datums"] = list()
for(var/datum/orderable_item/item as anything in order_datums)
.["order_datums"] += list(list(
"name" = item.name,
"desc" = item.desc,
"cat" = item.category_index,
"ref" = REF(item),
"cost" = item.cost_per_order,
"amt" = grocery_list[item]
))
/obj/machinery/computer/chef_order/ui_act(action, params)
. = ..()
if(.)
return
if(!isliving(usr))
return
var/mob/living/chef = usr
//this is null if the action doesn't need it (purchase, quickpurchase)
var/datum/orderable_item/wanted_item = locate(params["target"]) in order_datums
switch(action)
if("cart_set")
grocery_list[wanted_item] = params["amt"]
if(!grocery_list[wanted_item])
grocery_list -= wanted_item
update_static_data(chef)
if("purchase")
if(!grocery_list.len || !COOLDOWN_FINISHED(src, order_cooldown))
return
var/obj/item/card/id/chef_card = chef.get_idcard(TRUE)
if(!chef_card || !chef_card.registered_account)
say("No bank account detected!")
return
var/final_cost = get_total_cost()
if(!chef_card.registered_account.adjust_money(-final_cost))
say("Sorry, but you do not have enough money.")
return
say("Thank you for your purchase! It will arrive on the next cargo shuttle!")
var/message = "The kitchen has ordered groceries which will arrive on the cargo shuttle! Please make sure it gets to them as soon as possible!"
radio.talk_into(src, message, radio_channel)
COOLDOWN_START(src, order_cooldown, 60 SECONDS)
for(var/datum/orderable_item/ordered_item in grocery_list)
if(ordered_item in SSshuttle.chef_groceries)
SSshuttle.chef_groceries[ordered_item] += grocery_list[ordered_item]
else
SSshuttle.chef_groceries[ordered_item] = grocery_list[ordered_item]
grocery_list.Cut()
update_static_data(chef)
if("express")
if(!grocery_list.len || !COOLDOWN_FINISHED(src, order_cooldown))
return
var/obj/item/card/id/chef_card = chef.get_idcard(TRUE)
if(!chef_card || !chef_card.registered_account)
say("No bank account detected!")
return
var/final_cost = get_total_cost()
final_cost *= 2
if(!chef_card.registered_account.adjust_money(-final_cost))
say("Sorry, but you do not have enough money. Remember, Express upcharges the cost!")
return
say("Thank you for your purchase! Please note: The charge of this purchase and machine cooldown has been doubled!")
COOLDOWN_START(src, order_cooldown, 120 SECONDS)
var/obj/structure/closet/supplypod/bluespacepod/pod = new()
pod.explosionSize = list(0,0,0,0)
for(var/datum/orderable_item/item as anything in grocery_list)//every order
for(var/amt in 1 to grocery_list[item])//every order amount
new item.item_instance.type(pod)
var/turf/landing_location = get_turf(chef)
new /obj/effect/pod_landingzone(landing_location, pod)
grocery_list.Cut()
update_static_data(chef)
. = TRUE

View File

@@ -0,0 +1,169 @@
#define CATEGORY_FRUITS_VEGGIES 1
#define CATEGORY_MILK_EGGS 2
#define CATEGORY_SAUCES_REAGENTS 3
///A datum for chef ordering options from the chef's computer.
/datum/orderable_item
var/name = "Orderable Item Name"
//description set automatically unless it's hard set by the subtype
var/desc
var/category_index = CATEGORY_FRUITS_VEGGIES
var/obj/item/item_instance
var/cost_per_order = 10
/datum/orderable_item/New()
. = ..()
if(type == /datum/orderable_item)
return
if(!item_instance)
CRASH("[type] orderable item datum has NO ITEM PATH!")
item_instance = new item_instance
if(!desc)
desc = item_instance.desc
/datum/orderable_item/Destroy(force, ...)
. = ..()
qdel(item_instance)
//Fruits and Veggies
/datum/orderable_item/potato
name = "Potato"
category_index = CATEGORY_FRUITS_VEGGIES
item_instance = /obj/item/food/grown/potato
/datum/orderable_item/tomato
name = "Tomato"
category_index = CATEGORY_FRUITS_VEGGIES
item_instance = /obj/item/food/grown/tomato
/datum/orderable_item/carrot
name = "Carrot"
category_index = CATEGORY_FRUITS_VEGGIES
item_instance = /obj/item/food/grown/carrot
/datum/orderable_item/eggplant
name = "Eggplant"
category_index = CATEGORY_FRUITS_VEGGIES
item_instance = /obj/item/food/grown/eggplant
/datum/orderable_item/mushroom
name = "Plump Helmet"
desc = "Plumus Hellmus: Plump, soft and s-so inviting~"
category_index = CATEGORY_FRUITS_VEGGIES
item_instance = /obj/item/food/grown/mushroom/plumphelmet
/datum/orderable_item/cabbage
name = "Cabbage"
category_index = CATEGORY_FRUITS_VEGGIES
item_instance = /obj/item/food/grown/cabbage
/datum/orderable_item/beets
name = "Onion"
category_index = CATEGORY_FRUITS_VEGGIES
item_instance = /obj/item/food/grown/onion
/datum/orderable_item/apple
name = "Apple"
category_index = CATEGORY_FRUITS_VEGGIES
item_instance =/obj/item/food/grown/apple
/datum/orderable_item/pumpkin
name = "Pumpkin"
category_index = CATEGORY_FRUITS_VEGGIES
item_instance =/obj/item/food/grown/pumpkin
/datum/orderable_item/watermelon
name = "Watermelon"
category_index = CATEGORY_FRUITS_VEGGIES
item_instance =/obj/item/food/grown/watermelon
/datum/orderable_item/corn
name = "Corn"
category_index = CATEGORY_FRUITS_VEGGIES
item_instance = /obj/item/food/grown/corn
/datum/orderable_item/soybean
name = "Soybeans"
category_index = CATEGORY_FRUITS_VEGGIES
item_instance = /obj/item/food/grown/soybeans
/datum/orderable_item/garlic
name = "Garlic"
category_index = CATEGORY_FRUITS_VEGGIES
item_instance = /obj/item/food/grown/garlic
/datum/orderable_item/cherries
name = "Cherries"
category_index = CATEGORY_FRUITS_VEGGIES
item_instance = /obj/item/food/grown/cherries
//Milk and Eggs
/datum/orderable_item/milk
name = "Milk"
category_index = CATEGORY_MILK_EGGS
item_instance = /obj/item/reagent_containers/food/condiment/milk
cost_per_order = 30
/datum/orderable_item/soymilk
name = "Soy Milk"
category_index = CATEGORY_MILK_EGGS
item_instance = /obj/item/reagent_containers/food/condiment/soymilk
cost_per_order = 30
/datum/orderable_item/eggs
name = "Egg Carton"
category_index = CATEGORY_MILK_EGGS
item_instance = /obj/item/storage/fancy/egg_box
cost_per_order = 40
/datum/orderable_item/fillet
name = "Fish Fillet"
category_index = CATEGORY_MILK_EGGS
item_instance = /obj/item/food/fishmeat
cost_per_order = 12
/datum/orderable_item/spider_eggs
name = "Spider Eggs"
category_index = CATEGORY_MILK_EGGS
item_instance = /obj/item/food/spidereggs
//Reagents
/datum/orderable_item/flour
name = "Flour Sack"
category_index = CATEGORY_SAUCES_REAGENTS
item_instance = /obj/item/reagent_containers/food/condiment/flour
cost_per_order = 30
/datum/orderable_item/sugar
name = "Sugar Sack"
category_index = CATEGORY_SAUCES_REAGENTS
item_instance = /obj/item/reagent_containers/food/condiment/sugar
cost_per_order = 30
/datum/orderable_item/enzyme
name = "Universal Enzyme"
category_index = CATEGORY_SAUCES_REAGENTS
item_instance = /obj/item/reagent_containers/food/condiment/enzyme
cost_per_order = 40
/datum/orderable_item/salt
name = "Salt Shaker"
category_index = CATEGORY_SAUCES_REAGENTS
item_instance = /obj/item/reagent_containers/food/condiment/saltshaker
cost_per_order = 15
/datum/orderable_item/pepper
name = "Pepper Mill"
category_index = CATEGORY_SAUCES_REAGENTS
item_instance = /obj/item/reagent_containers/food/condiment/peppermill
cost_per_order = 15
/datum/orderable_item/soysauce
name = "Soy Sauce"
category_index = CATEGORY_SAUCES_REAGENTS
item_instance = /obj/item/reagent_containers/food/condiment/soysauce
cost_per_order = 15

View File

@@ -459,6 +459,11 @@
//Service
/obj/item/circuitboard/computer/chef_order
name = "Produce Orders Console (Computer Board)"
icon_state = "supply"
build_path = /obj/machinery/computer/chef_order
//Supply
/obj/item/circuitboard/computer/cargo

View File

@@ -82,6 +82,7 @@
var/datum/bank_account/D = SSeconomy.get_dep_account(ACCOUNT_CAR)
if(D)
data["points"] = D.account_balance
data["grocery"] = SSshuttle.chef_groceries.len
data["away"] = SSshuttle.supply.getDockedId() == "supply_away"
data["self_paid"] = self_paid
data["docked"] = SSshuttle.supply.mode == SHUTTLE_IDLE

View File

@@ -92,8 +92,6 @@ GLOBAL_LIST_INIT(blacklisted_cargo_types, typecacheof(list(
var/list/obj/miscboxes = list() //miscboxes are combo boxes that contain all goody orders grouped
var/list/misc_order_num = list() //list of strings of order numbers, so that the manifest can show all orders in a box
var/list/misc_contents = list() //list of lists of items that each box will contain
if(!SSshuttle.shoppinglist.len)
return
var/list/empty_turfs = list()
for(var/place in shuttle_areas)
@@ -103,6 +101,21 @@ GLOBAL_LIST_INIT(blacklisted_cargo_types, typecacheof(list(
continue
empty_turfs += T
//quickly and greedily handle chef's grocery runs first, there are a few reasons why this isn't attached to the rest of cargo...
//but the biggest reason is that the chef requires produce to cook and do their job, and if they are using this system they
//already got let down by the botanists. So to open a new chance for cargo to also screw them over any more than is necessary is bad.
if(SSshuttle.chef_groceries.len)
var/obj/structure/closet/crate/freezer/grocery_crate = new(pick_n_take(empty_turfs))
grocery_crate.name = "kitchen produce freezer"
investigate_log("Chef's [SSshuttle.chef_groceries.len] sized produce order arrived. Cost was deducted from orderer, not cargo.", INVESTIGATE_CARGO)
for(var/datum/orderable_item/item as anything in SSshuttle.chef_groceries)//every order
for(var/amt in 1 to SSshuttle.chef_groceries[item])//every order amount
new item.item_instance.type(grocery_crate)
SSshuttle.chef_groceries.Cut() //This lets the console know it can order another round.
if(!SSshuttle.shoppinglist.len)
return
var/value = 0
var/purchases = 0
var/list/goodies_by_buyer = list() // if someone orders more than GOODY_FREE_SHIPPING_MAX goodies, we upcharge to a normal crate so they can't carry around 20 combat shotties

View File

@@ -944,6 +944,8 @@
#include "code\game\machinery\computer\station_alert.dm"
#include "code\game\machinery\computer\teleporter.dm"
#include "code\game\machinery\computer\warrant.dm"
#include "code\game\machinery\computer\chef_orders\chef_order.dm"
#include "code\game\machinery\computer\chef_orders\order_datum.dm"
#include "code\game\machinery\computer\prisoner\_prisoner.dm"
#include "code\game\machinery\computer\prisoner\gulag_teleporter.dm"
#include "code\game\machinery\computer\prisoner\management.dm"

View File

@@ -73,6 +73,7 @@ export const CargoContent = (props, context) => {
const CargoStatus = (props, context) => {
const { act, data } = useBackend(context);
const {
grocery,
away,
docked,
loan,
@@ -98,7 +99,10 @@ const CargoStatus = (props, context) => {
<LabeledList.Item label="Shuttle">
{docked && !requestonly && can_send &&(
<Button
color={grocery && "orange" || "green"}
content={location}
tooltip={grocery && "The chef is waiting on their grocery supplies." || ""}
tooltipPosition="right"
onClick={() => act('send')} />
) || location}
</LabeledList.Item>

View File

@@ -0,0 +1,270 @@
import { multiline } from 'common/string';
import { useBackend, useLocalState } from '../backend';
import { Box, Button, Dimmer, Divider, Icon, NumberInput, Section, Stack } from '../components';
import { Window } from '../layouts';
const buttonWidth = 2;
const TAB2NAME = [
{
component: () => ShoppingTab,
},
{
component: () => CheckoutTab,
},
];
const ShoppingTab = (props, context) => {
const { data, act } = useBackend(context);
const {
order_datums,
} = data;
const [
shopIndex,
setShopIndex,
] = useLocalState(context, 'shop-index', 1);
const mapped_food = order_datums.filter(food => (
food && food.cat === shopIndex
));
return (
<Stack fill vertical>
<Section mb={-0.9}>
<Stack.Item>
<Stack textAlign="center">
<Stack.Item grow>
<Button
fluid
color="green"
content="Fruits and Veggies"
onClick={() => setShopIndex(1)} />
</Stack.Item>
<Stack.Item grow>
<Button
fluid
color="white"
content="Milk and Eggs"
onClick={() => setShopIndex(2)} />
</Stack.Item>
<Stack.Item grow>
<Button
fluid
color="olive"
content="Sauces and Reagents"
onClick={() => setShopIndex(3)} />
</Stack.Item>
</Stack>
</Stack.Item>
</Section>
<Stack.Item grow>
<Section fill scrollable>
<Stack vertical mt={-2}>
<Divider />
{mapped_food.map(item => (
<Stack.Item key={item}>
<Stack>
<Stack.Item grow>
{item.name}
</Stack.Item>
<Stack.Item mt={-1} color="label" fontSize="10px">
{"\""+item.desc+"\""}
<br />
<Box textAlign="right">
{item.name+" costs "+item.cost+" per order."}
</Box>
</Stack.Item>
<Stack.Item mt={-0.5}>
<NumberInput
animated
value={item.amt && item.amt || 0}
width="41px"
minValue={0}
maxValue={20}
onChange={(e, value) => act('cart_set', {
target: item.ref,
amt: value,
})} />
</Stack.Item>
</Stack>
<Divider />
</Stack.Item>
))}
</Stack>
</Section>
</Stack.Item>
</Stack>
);
};
const CheckoutTab = (props, context) => {
const { data, act } = useBackend(context);
const {
order_datums,
total_cost,
} = data;
const checkout_list = order_datums.filter(food => (
food && food.amt
));
return (
<Stack vertical fill>
<Stack.Item grow>
<Section fill scrollable>
<Stack vertical fill>
<Stack.Item textAlign="center">
Checkout list:
</Stack.Item>
<Divider />
{!checkout_list.length && (
<>
<Box align="center" mt="15%" fontSize="40px">
Nothing!
</Box>
<br />
<Box align="center" mt={2} fontSize="15px">
(Go order something, will ya?)
</Box>
</>
)}
<Stack.Item grow>
{checkout_list.map(item => (
<Stack.Item key={item}>
<Stack>
<Stack.Item grow>
{item.name}
</Stack.Item>
<Stack.Item mt={-1} color="label" fontSize="10px">
{"\""+item.desc+"\""}
<br />
<Box textAlign="right">
{item.name+" costs "+item.cost+" per order."}
</Box>
</Stack.Item>
<Stack.Item mt={-0.5}>
<NumberInput
value={item.amt && item.amt || 0}
width="41px"
minValue={0}
maxValue={item.cost > 10 && 50 || 10}
onChange={(e, value) => act('cart_set', {
target: item.ref,
amt: value,
})} />
</Stack.Item>
</Stack>
<Divider />
</Stack.Item>
))}
</Stack.Item>
</Stack>
</Section>
</Stack.Item>
<Stack.Item>
<Section>
<Stack>
<Stack.Item grow mt={0.5}>
Total Cost: {total_cost}
</Stack.Item>
<Stack.Item grow textAlign="center">
<Button
fluid
icon="plane-departure"
content="Purchase"
tooltip={multiline`
Your groceries will arrive at cargo,
and hopefully get delivered by them.
`}
tooltipPosition="top"
onClick={() => act('purchase')} />
</Stack.Item>
<Stack.Item grow textAlign="center">
<Button
fluid
icon="parachute-box"
color="yellow"
content="Express"
tooltip={multiline`
Sends the ingredients instantly,
and locks the console longer. Doubles the price!
`}
tooltipPosition="top-left"
onClick={() => act('express')} />
</Stack.Item>
</Stack>
</Section>
</Stack.Item>
</Stack>
);
};
const OrderSent = (props, context) => {
const { act, data } = useBackend(context);
return (
<Dimmer>
<Stack vertical>
<Stack.Item>
<Icon
ml="28%"
color="green"
name="plane-arrival"
size={10}
/>
</Stack.Item>
<Stack.Item fontSize="18px" color="green">
Order sent! Machine on cooldown...
</Stack.Item>
</Stack>
</Dimmer>
);
};
export const ProduceConsole = (props, context) => {
const { act, data } = useBackend(context);
const {
off_cooldown,
} = data;
const [
tabIndex,
setTabIndex,
] = useLocalState(context, 'tab-index', 1);
const TabComponent = TAB2NAME[tabIndex-1].component();
return (
<Window
title="Produce Orders"
width={500}
height={400}>
<Window.Content>
{!off_cooldown && (
<OrderSent />
)}
<Stack vertical fill>
<Stack.Item>
<Section fill>
<Stack textAlign="center">
<Stack.Item grow={3}>
<Button
fluid
color="green"
lineHeight={buttonWidth}
icon="cart-plus"
content="Shopping"
onClick={() => setTabIndex(1)} />
</Stack.Item>
<Stack.Item grow>
<Button
fluid
color="green"
lineHeight={buttonWidth}
icon="dollar-sign"
content="Checkout"
onClick={() => setTabIndex(2)} />
</Stack.Item>
</Stack>
</Section>
</Stack.Item>
<Stack.Item grow>
<TabComponent />
</Stack.Item>
</Stack>
</Window.Content>
</Window>
);
};