diff options
Diffstat (limited to 'data/recipes')
-rw-r--r-- | data/recipes/default.ts | 298 |
1 files changed, 157 insertions, 141 deletions
diff --git a/data/recipes/default.ts b/data/recipes/default.ts index 33b433a6..5ff17030 100644 --- a/data/recipes/default.ts +++ b/data/recipes/default.ts @@ -20,8 +20,8 @@ export interface Recipe { tile?: string, - inputs: (string | null)[], - outputs: (string | null)[], + inputs: (Item | null | undefined)[], + outputs: (Item | null | undefined)[], action: "instant" | "passive" | "active" | "demand" | "demand" duration?: number revert_duration?: number, @@ -29,184 +29,200 @@ export interface Recipe { 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<string>() -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] - }) - } -} - +const all_items = new Set<Item>() +const all_recipes = new Set<Recipe>() 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")}`); + all_recipes.add(r); +} +export function finish() { + const k = new Set<string>() + for (const r of all_recipes) { + let s = `- action: !${r.action}\n` + s += ` inputs: [${r.inputs.map(e => e!.toString()).join(",")}]\n` + s += ` outputs: [${r.outputs.map(e => e!.toString()).join(",")}]\n` + if (r.warn) s += ` warn: true\n` + if (r.duration) s += ` duration: ${r.duration}\n` + if (r.revert_duration) s += ` revert_duration: ${r.revert_duration}\n` + if (r.points) s += ` points: ${r.points}\n` + if (r.tile) s += ` tile: ${r.tile}\n` + k.add(s) + } + for (const r of k) + console.log(r); +} +function auto_trash() { + for (const i of all_items) { + if (i instanceof Container) continue + if (!i.container) out({ action: "instant", inputs: [i], outputs: [], tile: "trash" }) + else { + out({ action: "instant", inputs: [i], outputs: [i.container.dispose ?? i.container], tile: "trash" }) + } + } } -export function edible(item: string) { - let i = item - if (!item.endsWith("-plate") && !item.endsWith("-glass")) { - i += "-plate" - out({ action: "instant", inputs: [item], outputs: [i] }) +class Item { + constructor( + public name: string, + public container?: Container + ) { } + as(s: string) { this.name = s; return this } + tr(container?: Container) { + const o = new Item(this.name, container) + if (this.container) out({ action: "instant", inputs: [this, container], outputs: [this.container, o] }) + else out({ action: "instant", inputs: [container, this], outputs: [o] }) + return o + } + toString() { + return this.name + (this.container ? "-" + this.container : "") } - 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] }) +class Container extends Item { constructor(name: string, public dispose?: Item) { super(name) } } +const FP = new Container("foodprocessor") +const POT = new Container("pot") +const PL = new Container("plate", new Container("dirty-plate")) +const GL = new Container("glass") + +function crate(s: string): Item { + const item = new Item(s); + out({ action: "instant", inputs: [], outputs: [item], tile: `${s}-crate`, points: -1 }) + return item } -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 }) +function cut(s: Item, two?: boolean): Item { + const o = new Item(`sliced-${s.name}`, s.container) + out({ action: "active", inputs: [s], outputs: [o, two ? o : null], tile: "cuttingboard", duration: 2 }) + return o } -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] }) +function cook(s: Item): Item { + const o = new Item(`cooked-${s.name}`, s.container) + out({ action: "passive", duration: 25, tile: "stove", inputs: [s], outputs: [o] }) + out({ action: "passive", duration: 15, revert_duration: 20, tile: "stove", inputs: [o], outputs: [new Item("burned", POT)], warn: true }) + return 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 }) +function bake(s: Item): Item { + const o = new Item(`sliced-${s.name}`, s.container) + out({ action: "passive", duration: 25, tile: "oven", inputs: [s], outputs: [o] }) + out({ action: "passive", duration: 15, revert_duration: 20, tile: "oven", inputs: [o], outputs: [new Item("burned")], warn: true }) + return o } -export function crate(item: string) { - out({ action: "instant", tile: item + "-crate", inputs: [], outputs: [item], points: -1 }) +function freeze(s: Item): Item { + const o = new Item(`frozen-${s.name}`, s.container) + out({ action: "passive", duration: 25, tile: "freezer", inputs: [s], outputs: [o] }) + return o } - -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] +function process(s: Item): Item { + const o = new Item(`processed-${s.name}`, s.container) + out({ action: "passive", duration: 5, inputs: [s], outputs: [o] }) + return o } - -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] - }) +function instant(a: Item, b: Item): Item { + if (a.container && b.container) throw new Error("Instant recipe can have at most one containerized item"); + const cont = a.container ?? b.container + const o = new Item("!!!") + out({ action: "instant", inputs: [a, b], outputs: [o, cont] }) + return o +} +function combine(c: Container, ...items: Item[]): Item { + const open = items.map(i => (i.tr(c), [i.name])) const seen = new Set<string>() + let result 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 + for (const new_item of items) { + if (cur.includes(new_item.name)) continue + const rkey = cur.join("-") + "#" + new_item + if (seen.has(rkey)) continue seen.add(rkey) - const parts = [...cur, i] + const parts = [...cur, new_item.name] parts.sort() - const o = parts.join("-") + "-" + container open.push(parts) + const i = new Item(cur.join("-"), c) + const o = new Item(parts.join("-"), c) + if (parts.length == items.length) result = o out({ action: "instant", - inputs: [c, ifull], - outputs: [o, ic] + inputs: [i, new_item], + outputs: [o, new_item.container] }) } } + return result! +} +function edible(...items: Item[]) { + for (const i of items) { + out({ action: "demand", inputs: [i], outputs: [i.container?.dispose ?? i.container], duration: 10 }) + } +} +function either(a: Item, b: Item) { + if (a.name != b.name) throw new Error("either options are named differently"); + if (a.container != b.container) throw new Error("either options are contained differently"); + return a +} +function sink_fill(c: Container) { + const o = new Item("water", c) + out({ action: "instant", inputs: [c], outputs: [o], tile: "sink" }) + return o } +out({ action: "active", duration: 2, tile: "sink", inputs: [new Container("dirty-plate")], outputs: [PL] }) -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") +const tomato = crate("tomato") +const raw_steak = crate("raw-steak") +const flour = crate("flour") +const leek = crate("leek") +const rice = crate("rice") +const fish = crate("fish") +const coconut = crate("coconut") +const strawberry = crate("strawberry") - 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 }) +// Bread +const dough = process(flour.tr(FP)).as("dough").tr() +const bread = bake(dough).as("bread") +const bread_slice = cut(bread, true).as("bread-slice") +edible(bread) - crate("rice") - crate("fish") - crate("coconut") - crate("strawberry") +// Burger +const steak_pot = cook(raw_steak.tr(POT)).as("steak") +const sliced_tomato = cut(tomato).as("sliced-tomato") +const burger = combine(PL, steak_pot, sliced_tomato, bread_slice) +const tomato_toast = combine(PL, sliced_tomato, bread_slice) +edible(burger, tomato_toast) - // Rice and nigiri - cut("fish") - cook("rice") - out({ action: "instant", inputs: ["sliced-fish", "cooked-rice-pot"], outputs: ["nigiri", "pot"] }) +// Soup +const tomato_juice = process(tomato.tr(FP)).as("tomato-juice") +const leek_tj_pot = combine(POT, leek, tomato_juice) +const tomato_soup_plate = cook(leek_tj_pot).as("tomato-soup").tr(PL) +edible(tomato_soup_plate) - out({ action: "instant", inputs: ["plate", "cooked-rice-pot"], outputs: ["cooked-rice-plate", "pot"] }) - edible("cooked-rice-plate") - edible("nigiri") +// Rice and nigiri +const nigiri = instant(cut(fish), cook(rice.tr(POT))).as("nigiri").tr(PL) +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") +// coconut milk and strawberry puree +const strawberry_puree = process(strawberry.tr(FP)).as("strawberry-puree") +const milk = process(coconut.tr(FP)).as("milk") +const strawberry_shake = either( + process(instant(milk, strawberry).as("strawberry-milk")).as("strawberry-shake"), + process(instant(strawberry_puree, coconut).as("strawberry-milk")).as("strawberry-shake") +) - // 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") +// icecream +const strawberry_icecream = freeze(strawberry_shake).as("strawberry-icecream").tr(PL) +edible(strawberry_icecream) - // 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"] }) +// drinks +edible( + strawberry_shake.tr(GL), + sink_fill(GL) +) - edible("water-glass") - edible("strawberrymilk-glass") +auto_trash() +finish() - auto_trash() -} |