/*
Hurry Curry! - a game about cooking
Copyright 2024 metamuffin
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU Affero General Public License as published by
the Free Software Foundation, version 3 of the License only.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Affero General Public License for more details.
You should have received a copy of the GNU Affero General Public License
along with this program. If not, see .
*/
//? Is is a good idea? Probably not.
export interface Recipe {
tile?: string,
inputs: (string | null)[],
outputs: (string | null)[],
action: "instant" | "passive" | "active" | "demand" | "demand"
duration?: number
revert_duration?: number,
warn?: boolean,
points?: number,
}
function trash_output(ifull: string) {
const [i, ic] = get_container(ifull)
if (i == "plate") return ifull
if (i == "glass") return ifull
if (i == "pot") return ifull
if (i == "foodprocessor") return ifull
if (i == "dirty") return ifull
if (ic == "glass") return "glass"
if (ic == "plate") return "dirty-plate"
return null
}
export const all_items = new Set()
export function auto_trash() {
for (const ifull of all_items) {
let [i, ic] = get_container(ifull)
if (i == "plate") continue
if (i == "glass") continue
if (i == "pot") continue
if (i == "foodprocessor") continue
if (i == "dirty") continue
if (ic == "glass") ic = "glass"
if (ic == "plate") ic = "dirty-plate"
out({
action: "instant",
tile: ic == "glass" ? "sink" : "trash",
inputs: [ifull],
outputs: [ic]
})
}
}
export function out(r: Recipe) {
r.inputs.forEach(i => i ? all_items.add(i) : void 0)
r.outputs.forEach(i => i ? all_items.add(i) : void 0)
r.inputs = r.inputs.filter(e => e)
r.outputs = r.outputs.filter(e => e)
console.log(`- ${JSON.stringify(r).replaceAll("\"active\"", "!active").replaceAll("\"passive\"", "!passive").replaceAll("\"instant\"", "!instant")}`);
}
export function edible(item: string) {
let i = item
if (!item.endsWith("-plate") && !item.endsWith("-glass")) {
i += "-plate"
out({ action: "instant", inputs: [item], outputs: [i] })
}
out({ action: "demand", inputs: [i], outputs: [trash_output(i)], duration: 10 })
}
export function cut(from: string, to?: string, to2?: string) {
out({ action: "active", duration: 2, tile: "cuttingboard", inputs: [from], outputs: [to ?? ("sliced-" + from), to2 ?? null] })
}
export function cook(from: string, to?: string) {
const i = from.endsWith("-pot") ? from : from + "-pot"
const o = (to ?? ("cooked-" + from)) + "-pot"
if (!from.endsWith("-pot")) out({ action: "instant", inputs: ["pot", from], outputs: [i] })
out({ action: "passive", duration: 20, revert_duration: 40, tile: "stove", inputs: [i], outputs: [o] })
out({ action: "passive", duration: 5, revert_duration: 10, tile: "stove", inputs: [o], outputs: ["burned-pot"], warn: true })
}
export function process(from: string, to?: string) {
const i = from.endsWith("-foodprocessor") ? from : from + "-foodprocessor"
const o = (to ?? (from + "-juice")) + "-foodprocessor"
if (!from.endsWith("-foodprocessor")) out({ action: "instant", inputs: ["foodprocessor", from], outputs: [i] })
out({ action: "passive", duration: 5, inputs: [i], outputs: [o] })
}
export function bake(from: string, to?: string) {
const o = (to ?? ("baked-" + from))
out({ action: "passive", duration: 25, tile: "oven", inputs: [from], outputs: [o] })
out({ action: "passive", duration: 15, revert_duration: 20, tile: "oven", inputs: [o], outputs: ["burned"], warn: true })
}
export function crate(item: string) {
out({ action: "instant", tile: item + "-crate", inputs: [], outputs: [item], points: -1 })
}
export function get_container(ifull: string): [string, string | null] {
const iparts = ifull.split("-")
const ic = iparts.pop()
if (ic && iparts.length && ["pot", "plate", "foodprocessor", "glass"].includes(ic)) return [iparts.join("-"), ic]
return [ifull, null]
}
export function combine(container: string, ...inputs: string[]) {
const open = inputs.map(ifull => {
const [i, ic] = get_container(ifull)
out({ action: "instant", inputs: [container, ifull], outputs: [i + "-" + container, ic] })
return [i]
})
const seen = new Set()
while (1) {
const cur = open.pop()
if (!cur) break;
const c = cur.join("-") + "-" + container
for (const ifull of inputs) {
const [i, ic] = get_container(ifull)
if (cur.includes(i)) continue
const rkey = cur.join("-") + "#" + i
if (seen.has(rkey)) continue
seen.add(rkey)
const parts = [...cur, i]
parts.sort()
const o = parts.join("-") + "-" + container
open.push(parts)
out({
action: "instant",
inputs: [c, ifull],
outputs: [o, ic]
})
}
}
}
if (import.meta.main) {
out({ action: "active", duration: 2, tile: "sink", inputs: ["dirty-plate"], outputs: ["plate"] })
crate("tomato")
crate("raw-steak")
crate("flour")
crate("leek")
cut("tomato")
cook("raw-steak", "steak")
// bread
process("flour", "dough")
out({ action: "instant", inputs: ["dough-foodprocessor"], outputs: ["foodprocessor", "dough"] })
bake("dough", "bread")
cut("bread", "bread-slice", "bread-slice")
// tomato soup
process("tomato")
combine("pot", "leek", "tomato-juice-foodprocessor")
cook("leek-tomato-juice-pot", "tomato-soup")
out({ action: "instant", inputs: ["tomato-soup-pot", "plate"], outputs: ["pot", "tomato-soup-plate"] })
combine("plate", "steak-pot", "sliced-tomato", "bread-slice")
edible("steak-plate")
edible("bread-slice-steak-plate")
edible("bread-slice-sliced-tomato-plate")
edible("bread-slice-sliced-tomato-steak-plate")
out({ action: "demand", inputs: ["bread"], outputs: [], duration: 0 })
crate("rice")
crate("fish")
crate("coconut")
crate("strawberry")
// Rice and nigiri
cut("fish")
cook("rice")
out({ action: "instant", inputs: ["sliced-fish", "cooked-rice-pot"], outputs: ["nigiri", "pot"] })
out({ action: "instant", inputs: ["plate", "cooked-rice-pot"], outputs: ["cooked-rice-plate", "pot"] })
edible("cooked-rice-plate")
edible("nigiri")
// coconut milk and strawberry puree
process("strawberry", "strawberry-puree")
process("coconut", "milk")
out({ action: "instant", inputs: ["milk-foodprocessor", "strawberry"], outputs: ["strawberry-milk-foodprocessor"] })
out({ action: "instant", inputs: ["strawberry-puree-foodprocessor", "coconut"], outputs: ["strawberry-milk-foodprocessor"] })
process("strawberry-milk-foodprocessor", "strawberrymilk")
process("coconut-strawberry-puree-foodprocessor", "strawberrymilk")
// icecream
out({ action: "passive", inputs: ["strawberrymilk-foodprocessor"], outputs: ["strawberry-icecream-foodprocessor"], tile: "freezer", duration: 20 })
out({ action: "instant", inputs: ["strawberry-icecream-foodprocessor", "plate"], outputs: ["foodprocessor", "strawberry-icecream-plate"] })
edible("strawberry-icecream-plate")
// drinks
out({ action: "instant", inputs: ["glass"], outputs: ["water-glass"], tile: "sink" })
out({ action: "instant", inputs: ["glass", "milk-foodprocessor"], outputs: ["milk-glass", "foodprocessor"] })
out({ action: "instant", inputs: ["glass", "strawberrymilk-foodprocessor"], outputs: ["strawberrymilk-glass", "foodprocessor"] })
edible("water-glass")
edible("strawberrymilk-glass")
auto_trash()
}