diff options
Diffstat (limited to 'data/recipes/default.js')
-rw-r--r-- | data/recipes/default.js | 289 |
1 files changed, 289 insertions, 0 deletions
diff --git a/data/recipes/default.js b/data/recipes/default.js new file mode 100644 index 00000000..c1c72714 --- /dev/null +++ b/data/recipes/default.js @@ -0,0 +1,289 @@ +/* + 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 <https://www.gnu.org/licenses/>. + +*/ + +//? Is this a good idea? Probably not. + +// export interface Recipe { +// tile?: string, +// inputs: (Item | null | undefined)[], +// outputs: (Item | null | undefined)[], +// action: "instant" | "passive" | "active" | "demand" | "demand" +// duration?: number +// revert_duration?: number, +// warn?: boolean, +// points?: number, +// } + +const all_items = new Set() +const all_recipes = new Set() +export function out(r) { + 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) + all_recipes.add(r); +} +export function finish() { + const k = new Set() + for (const r of all_recipes) { + let s = `- action: !${r.action}\n` + s += ` inputs: [${r.inputs.map(e => JSON.stringify(e.toString())).join(",")}]\n` + s += ` outputs: [${r.outputs.map(e => JSON.stringify(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: i.container.dispose_tile ?? "trash" + }) + } + } +} +function auto_burn() { + for (const i of [...all_items]) { + if (i instanceof Container) continue + if (i.container || i.name == "burned") continue + else { + out({ + action: "passive", + inputs: [i], + outputs: [new Item("burned")], + duration: 1.5, + revert_duration: 1.5, + warn: true, + tile: "stove" + }) + } + } +} + +class Item { + constructor(name, container) { this.name = name; this.container = container } + as(s) { this.name = s; return this } + tr(container) { + const o = new Item(this.name, container) + if (this.container == container) return o + 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.container ? this.container + ":" : "") + this.name + } +} + +class Container extends Item { + constructor(name, dispose, dispose_tile) { + super(name); this.dispose = dispose; this.dispose_tile = dispose_tile; + } +} +const FP = new Container("foodprocessor") +const POT = new Container("pot") +const PAN = new Container("pan") +const PL = new Container("plate", new Container("dirty-plate")) +const GL = new Container("glass", undefined, "sink") + +function crate(s) { + const item = new Item(s); + out({ action: "instant", inputs: [], outputs: [item], tile: `${s}-crate`, points: -1 }) + out({ action: "instant", inputs: [item], outputs: [], tile: `${s}-crate`, points: 1 }) + return item +} +function cut(s, two) { + 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 +} +function cook(s, duration = 20) { + const o = new Item(`cooked-${s.name}`, s.container) + out({ action: "passive", duration, revert_duration: duration * 2, tile: "stove", inputs: [s], outputs: [o] }) + out({ action: "passive", duration: duration / 3, revert_duration: duration / 2, tile: "stove", inputs: [o], outputs: [new Item("burned", POT)], warn: true }) + return o +} +function sear(s, duration = 15) { + s = s.tr(PAN) + const o = new Item(`seared-${s.name}`, s.container) + out({ action: "passive", duration, revert_duration: duration * 2, tile: "stove", inputs: [s], outputs: [o] }) + out({ action: "passive", duration: duration / 3, revert_duration: duration / 3, tile: "stove", inputs: [o], outputs: [new Item("burned", PAN)], warn: true }) + return o +} +function bake(s, duration = 25) { + const o = new Item(`sliced-${s.name}`, s.container) + out({ action: "passive", duration, revert_duration: duration * 2, tile: "oven", inputs: [s], outputs: [o] }) + out({ action: "passive", duration: duration / 2, revert_duration: duration / 4, tile: "oven", inputs: [o], outputs: [new Item("burned")], warn: true }) + return o +} +function freeze(s) { + const o = new Item(`frozen-${s.name}`, s.container) + out({ action: "passive", duration: 25, tile: "freezer", inputs: [s], outputs: [o] }) + return o +} +function process(s) { + const o = new Item(`processed-${s.name}`, s.container) + out({ action: "passive", duration: 5, inputs: [s], outputs: [o] }) + return o +} +function container_add(base, add) { + const o = new Item("!!!", base.container) + out({ action: "instant", inputs: [base, add], outputs: [o, add.container] }) + return o +} +function combine(c, ...items) { + if (items.length == 1) return items[0].tr(c) + const open = items.map(i => (i.tr(c), [i.name])) + const seen = new Set() + let result + while (1) { + const cur = open.pop() + if (!cur) break; + 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, new_item.name] + parts.sort() + 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: [i, new_item], + outputs: [o, new_item.container] + }) + } + } + return result +} +function edible(...items) { + for (const i of items) { + out({ action: "demand", inputs: [i], outputs: [i.container?.dispose ?? i.container], duration: 10 }) + } +} +function either(a, b) { + 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) { + const o = new Item("water", c) + out({ action: "active", inputs: [c], outputs: [o], tile: "sink", duration: 1 }) + return o +} + +out({ action: "active", duration: 2, tile: "sink", inputs: [new Container("dirty-plate")], outputs: [PL] }) + +const tomato = crate("tomato") +const steak = crate("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") +const cheese = crate("cheese") +const lettuce = crate("lettuce") + +// Buns +const dough = process(flour.tr(FP)).as("dough").tr() +const bun = bake(dough).as("bun") +edible(bun.tr(PL)) + +// Steak +const seared_steak = sear(steak) +edible( + combine(PL, seared_steak, bun), + combine(PL, seared_steak), +) + +// Salad +edible( + combine(PL, cut(tomato), cut(lettuce)), + combine(PL, cut(lettuce)), +) + +// Burger +const b_patty = sear(cut(steak).as("patty")) +edible( + combine(PL, cut(bun), b_patty, cut(cheese)), + combine(PL, cut(bun), b_patty, cut(cheese), cut(lettuce)), + combine(PL, cut(bun), b_patty, cut(tomato), cut(lettuce)), + combine(PL, cut(bun), b_patty, cut(cheese), cut(tomato)), + combine(PL, cut(bun), cut(cheese), cut(lettuce), cut(tomato)), + combine(PL, cut(bun), cut(lettuce), cut(tomato)), +) + +// 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) + +// Rice and nigiri +const nigiri = container_add(cut(fish), cook(rice.tr(POT))).as("nigiri").tr(PL) +edible(nigiri) + +// 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(container_add(milk, strawberry).as("milk,strawberry")).as("strawberry-shake"), + process(container_add(strawberry_puree, coconut).as("coconut,strawberry-puree")).as("strawberry-shake") +) + +// Icecream +edible(freeze(strawberry_shake).as("strawberry-icecream").tr(PL)) + +// Mochi +const rice_flour = process(rice.tr(FP)).as("rice-flour") +const mochi_dough = cook(rice_flour.tr(POT), 5).as("mochi-dough") +const strawberry_mochi = container_add(strawberry, mochi_dough).as("strawberry-mochi") +edible(strawberry_mochi) + +// Drinks +edible( + strawberry_shake.tr(GL), + tomato_juice.tr(GL), + sink_fill(GL) +) + +// Curry +const curry_with_rice = combine(PL, cook(rice.tr(POT)), cook(combine(POT, milk, tomato, leek)).as("curry")) +edible(curry_with_rice) + +auto_trash() +auto_burn() +finish() + |