You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
249 lines
5.5 KiB
249 lines
5.5 KiB
import { MenuItemState } from "./enums.js"; |
|
import { assert } from "./utils.js"; |
|
|
|
/** |
|
* @typedef {Object} SuppliesBase |
|
* @property {number} flour |
|
* @property {number} eggs |
|
* @property {number} oil |
|
* @property {number} butter |
|
* @property {number} milk |
|
* @property {number} yeast |
|
* @property {number} chocolate |
|
* @property {number} fruit |
|
* @property {number} sugar |
|
*/ |
|
|
|
/** @typedef {SuppliesBase & {[key: string]: number}} Supplies */ |
|
|
|
/** |
|
* @typedef {'enabled' | 'disabled'} MenuItemStateValue |
|
*/ |
|
|
|
/** |
|
* @typedef {Object} MenuItem |
|
* @property {Partial<Supplies>} ingredients |
|
* @property {number} oven_slots |
|
* @property {number} base_demand |
|
* @property {MenuItemStateValue} state |
|
*/ |
|
|
|
/** |
|
* @typedef {'bread' | 'sweet_rolls' | 'vanilla_cake' | 'cookies' | 'fruit_muffins' | 'croissants' | 'chocolate_cookies' | 'chocolate_cake' | 'fruit_tart'} MenuItemName |
|
*/ |
|
|
|
/** |
|
* @typedef {Object} GameState |
|
* @property {number} player_money |
|
* @property {{ day: number, phase: string, elapsed_ms: number, day_length_ms: number, tick_ms: number }} time |
|
* @property {Supplies} supplies |
|
* @property {Record<MenuItemName, MenuItem>} menu |
|
* @property {Supplies} store |
|
* @property {{ capacity: number, used: number, queue: string[] }} oven |
|
* @property {Record<MenuItemName, number>} prices |
|
*/ |
|
|
|
/** |
|
* @typedef {Object} Command |
|
* @property {(game_state: GameState) => GameState} execute |
|
*/ |
|
|
|
/** |
|
* Creates a new game state with default values |
|
* @returns {GameState} |
|
*/ |
|
function init_game_state() { |
|
return { |
|
player_money: 0, |
|
time: { |
|
day: 1, |
|
phase: "planning", |
|
elapsed_ms: 0, |
|
day_length_ms: 30000, |
|
tick_ms: 250, |
|
}, |
|
supplies: { |
|
flour: 0, |
|
eggs: 0, |
|
oil: 0, |
|
butter: 0, |
|
milk: 0, |
|
yeast: 0, |
|
chocolate: 0, |
|
fruit: 0, |
|
sugar: 0, |
|
}, |
|
menu: { |
|
bread: { |
|
ingredients: { |
|
flour: 2, |
|
yeast: 1, |
|
milk: 1, |
|
}, |
|
oven_slots: 1, |
|
base_demand: 40, |
|
state: MenuItemState.ENABLED, |
|
}, |
|
sweet_rolls: { |
|
ingredients: { |
|
flour: 2, |
|
sugar: 1, |
|
butter: 1, |
|
milk: 1, |
|
}, |
|
oven_slots: 1, |
|
base_demand: 35, |
|
state: MenuItemState.ENABLED, |
|
}, |
|
vanilla_cake: { |
|
ingredients: { |
|
flour: 2, |
|
eggs: 2, |
|
sugar: 2, |
|
milk: 1, |
|
oil: 1, |
|
}, |
|
oven_slots: 2, |
|
base_demand: 25, |
|
state: MenuItemState.ENABLED, |
|
}, |
|
cookies: { |
|
ingredients: { |
|
flour: 1, |
|
eggs: 1, |
|
sugar: 1, |
|
butter: 1, |
|
}, |
|
oven_slots: 2, |
|
base_demand: 40, |
|
state: MenuItemState.ENABLED, |
|
}, |
|
fruit_muffins: { |
|
ingredients: { |
|
flour: 2, |
|
eggs: 1, |
|
sugar: 1, |
|
fruit: 1, |
|
}, |
|
oven_slots: 2, |
|
base_demand: 30, |
|
state: MenuItemState.ENABLED, |
|
}, |
|
croissants: { |
|
ingredients: { |
|
flour: 2, |
|
butter: 2, |
|
milk: 1, |
|
yeast: 1, |
|
}, |
|
oven_slots: 3, |
|
base_demand: 20, |
|
state: MenuItemState.ENABLED, |
|
}, |
|
chocolate_cookies: { |
|
ingredients: { |
|
flour: 1, |
|
eggs: 1, |
|
sugar: 1, |
|
butter: 1, |
|
chocolate: 1, |
|
}, |
|
oven_slots: 2, |
|
base_demand: 35, |
|
state: MenuItemState.ENABLED, |
|
}, |
|
chocolate_cake: { |
|
ingredients: { |
|
flour: 2, |
|
eggs: 2, |
|
sugar: 2, |
|
butter: 1, |
|
chocolate: 2, |
|
milk: 1, |
|
}, |
|
oven_slots: 3, |
|
base_demand: 12, |
|
state: MenuItemState.ENABLED, |
|
}, |
|
fruit_tart: { |
|
ingredients: { |
|
flour: 2, |
|
butter: 2, |
|
sugar: 1, |
|
eggs: 1, |
|
fruit: 2, |
|
}, |
|
oven_slots: 4, |
|
base_demand: 15, |
|
state: MenuItemState.ENABLED, |
|
}, |
|
}, |
|
store: { |
|
flour: 0.6, |
|
sugar: 0.4, |
|
yeast: 0.3, |
|
oil: 0.7, |
|
milk: 0.8, |
|
eggs: 0.9, |
|
butter: 1.2, |
|
fruit: 1.3, |
|
chocolate: 1.5, |
|
}, |
|
oven: { |
|
capacity: 4, |
|
used: 0, |
|
queue: [], |
|
}, |
|
prices: { |
|
bread: 4.0, |
|
sweet_rolls: 5.0, |
|
vanilla_cake: 9.0, |
|
cookies: 6.0, |
|
fruit_muffins: 6.5, |
|
croissants: 7.5, |
|
chocolate_cookies: 7.0, |
|
chocolate_cake: 14.0, |
|
fruit_tart: 12.0, |
|
}, |
|
}; |
|
} |
|
|
|
/** |
|
* Bakes an item if supplies and oven capacity allow |
|
* @param {GameState} game_state - The current game state |
|
* @param {MenuItemName} item_name - The name of the item to bake |
|
* @returns {GameState} The updated game state |
|
*/ |
|
function bake_items(game_state, item_name) { |
|
const menu_item = game_state.menu[item_name]; |
|
const oven_slots = menu_item.oven_slots; |
|
const canFitInOven = |
|
game_state.oven.used + oven_slots <= game_state.oven.capacity; |
|
|
|
assert(canFitInOven, "oven must have capacity before baking"); |
|
assert(!!game_state, "game_state must be defined"); |
|
assert( |
|
game_state.menu[item_name].state === MenuItemState.ENABLED, |
|
"item must be bakeable with current supplies", |
|
); |
|
|
|
// supplies update |
|
const updated_supplies = { |
|
...game_state.supplies, |
|
}; |
|
|
|
for (const ingredient in menu_item.ingredients) { |
|
updated_supplies[ingredient] -= menu_item.ingredients[ingredient] ?? 0; |
|
} |
|
|
|
return { |
|
...game_state, |
|
supplies: updated_supplies, |
|
oven: { |
|
...game_state.oven, |
|
used: game_state.oven.used + oven_slots, |
|
}, |
|
}; |
|
} |
|
|
|
export { init_game_state, bake_items };
|
|
|