aboutsummaryrefslogtreecommitdiff
path: root/data/recipes/default.js
diff options
context:
space:
mode:
Diffstat (limited to 'data/recipes/default.js')
-rw-r--r--data/recipes/default.js289
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()
+