Q: iron_smelt (iron_ore + wood → iron_ingot) and gold_smelt (gold + wood → gold_ingot) recipes added at Smelter, using the existing ingredient2 buffer mechanism. New TYPE_IRON_INGOT and TYPE_GOLD_INGOT item types (procedural hue-hash draw for now). R: new Recipe.target_workbench field (StringName, empty = any matching skill) round-trips through to_dict/from_dict. Workbench bill picker filters by both required_skill AND target_workbench vs lower-cased label_text. plank → carpenter, stone_block/iron_smelt/gold_smelt → smelter, flour → millstone. Cooking-only recipes (bread, meal) stay unrestricted since Hearth is the only cooking workbench. 9 recipes total now, 4 distinct workbench routes. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
182 lines
6.4 KiB
GDScript
182 lines
6.4 KiB
GDScript
class_name RecipeCatalog
|
||
## Static registry of all recipes. Each method returns a fresh Recipe instance
|
||
## configured for that product. Extend here as new workbenches land.
|
||
##
|
||
## Phase 6 — two recipes:
|
||
## plank() — wood → plank (Carpenter's bench, Crafting)
|
||
## stone_block() — stone → stone_block (Smelter, Crafting)
|
||
##
|
||
## Phase 7 — cooking chain (grain → flour → bread, vegetable → meal):
|
||
## flour() — grain → flour (Millstone, Crafting)
|
||
## bread() — flour → bread (Hearth, Cooking)
|
||
## meal_from_vegetables() — vegetable → meal (Hearth, Cooking)
|
||
##
|
||
## The full ~22-recipe list per docs/design.md continues in Phase 8+.
|
||
|
||
|
||
static func plank() -> Recipe:
|
||
var r := Recipe.new()
|
||
r.id = &"plank"
|
||
r.label = "Wood plank"
|
||
r.ingredient_type = Item.TYPE_WOOD
|
||
r.output_type = Item.TYPE_PLANK
|
||
r.work_ticks = 60 # ~3 sim seconds at 1× (20 Hz × 3 s = 60 ticks)
|
||
r.required_skill = Recipe.SKILL_CRAFTING
|
||
r.skill_threshold = 0
|
||
r.target_workbench = &"carpenter"
|
||
return r
|
||
|
||
|
||
static func stone_block() -> Recipe:
|
||
var r := Recipe.new()
|
||
r.id = &"stone_block"
|
||
r.label = "Stone block"
|
||
r.ingredient_type = Item.TYPE_STONE
|
||
r.output_type = Item.TYPE_STONE_BLOCK
|
||
r.work_ticks = 80 # ~4 sim seconds at 1×
|
||
r.required_skill = Recipe.SKILL_CRAFTING
|
||
r.skill_threshold = 0
|
||
r.target_workbench = &"smelter"
|
||
return r
|
||
|
||
|
||
# ── Phase 7 — cooking chain ───────────────────────────────────────────────────
|
||
|
||
static func flour() -> Recipe:
|
||
## Step 1 of the grain→flour→bread chain.
|
||
## Ingredient: grain. Output: flour. Worked at the Millstone (accepted_skill = crafting).
|
||
## Any crafter can do this — no culinary expertise required for grinding.
|
||
var r := Recipe.new()
|
||
r.id = &"flour"
|
||
r.label = "Flour"
|
||
r.ingredient_type = Item.TYPE_GRAIN
|
||
r.output_type = Item.TYPE_FLOUR
|
||
r.work_ticks = 50 # ~2.5 sim seconds at 1× — quick grinding pass
|
||
r.required_skill = Recipe.SKILL_CRAFTING
|
||
r.skill_threshold = 0
|
||
r.target_workbench = &"millstone"
|
||
return r
|
||
|
||
|
||
static func bread() -> Recipe:
|
||
## Step 2 of the grain→flour→bread chain.
|
||
## Ingredient: flour. Output: bread. Worked at the Hearth (accepted_skill = cooking).
|
||
var r := Recipe.new()
|
||
r.id = &"bread"
|
||
r.label = "Bread"
|
||
r.ingredient_type = Item.TYPE_FLOUR
|
||
r.output_type = Item.TYPE_BREAD
|
||
r.work_ticks = 90 # ~4.5 sim seconds at 1× — baking takes longer
|
||
r.required_skill = Recipe.SKILL_COOKING
|
||
r.skill_threshold = 0
|
||
return r
|
||
|
||
|
||
static func meal_from_vegetables() -> Recipe:
|
||
## Single-step cooking: vegetable → meal. Worked at the Hearth (accepted_skill = cooking).
|
||
## Parallel path so harvested produce (potatoes, etc.) can reach the belly
|
||
## without going through the grain chain.
|
||
var r := Recipe.new()
|
||
r.id = &"meal_veg"
|
||
r.label = "Veggie meal"
|
||
r.ingredient_type = Item.TYPE_VEGETABLE
|
||
r.output_type = Item.TYPE_MEAL
|
||
r.work_ticks = 80 # ~4 sim seconds at 1×
|
||
r.required_skill = Recipe.SKILL_COOKING
|
||
r.skill_threshold = 0
|
||
return r
|
||
|
||
|
||
# ── Phase 14 — Death + cremation ─────────────────────────────────────────────
|
||
|
||
static func cremate_corpse() -> Recipe:
|
||
## Cremation recipe. Primary ingredient: 1 corpse (TYPE_CORPSE).
|
||
## Secondary ingredient: 5 wood (ingredient2_type / ingredient2_count) — see
|
||
## recipe.gd for the Phase 14 extension fields.
|
||
## Output: 1 ash item (TYPE_ASH). Work time: 60 ticks (~3 sim seconds at 1×).
|
||
## No Quality roll — cremation is binary. accepted_skill = manual_labor;
|
||
## any laborer can operate the pyre.
|
||
##
|
||
## Stub gap: CraftingProvider's ingredient-pickup step only handles the
|
||
## primary ingredient (ingredient_type = TYPE_CORPSE). The 5-wood secondary
|
||
## requirement is recorded in ingredient2_type/ingredient2_count but is NOT
|
||
## enforced at runtime until CraftingProvider is extended (Phase 14 follow-up).
|
||
var r := Recipe.new()
|
||
r.id = &"cremate_corpse"
|
||
r.label = "Cremate corpse"
|
||
r.ingredient_type = Item.TYPE_CORPSE
|
||
r.ingredient2_type = Item.TYPE_WOOD
|
||
r.ingredient2_count = 5
|
||
r.output_type = Item.TYPE_ASH
|
||
r.work_ticks = 60 # ~3 sim seconds at 1×
|
||
r.required_skill = &"manual_labor"
|
||
r.skill_threshold = 0
|
||
return r
|
||
|
||
|
||
## Quarry workbench — no input, produces 1 stone per work cycle. Used by the
|
||
## QuarryWorkbench placed on a BigRockNode for renewable stone supply.
|
||
static func quarry_stone() -> Recipe:
|
||
var r := Recipe.new()
|
||
r.id = &"quarry_stone"
|
||
r.label = "Quarry stone"
|
||
r.ingredient_type = &"" # no input
|
||
r.output_type = Item.TYPE_STONE
|
||
r.work_ticks = 300
|
||
r.required_skill = &"manual_labor"
|
||
r.skill_threshold = 0
|
||
return r
|
||
|
||
|
||
# ── Phase 19 — iron/gold smelting ────────────────────────────────────────────
|
||
|
||
static func iron_smelt() -> Recipe:
|
||
## Iron ore → iron ingot. Worked at the Smelter (accepted_skill = crafting).
|
||
## Secondary fuel ingredient (wood) is recorded but not yet enforced at
|
||
## runtime — CraftingProvider only checks the primary ingredient today.
|
||
var r := Recipe.new()
|
||
r.id = &"iron_smelt"
|
||
r.label = "Smelt iron ingot"
|
||
r.ingredient_type = Item.TYPE_IRON_ORE
|
||
r.ingredient2_type = Item.TYPE_WOOD
|
||
r.ingredient2_count = 1
|
||
r.output_type = Item.TYPE_IRON_INGOT
|
||
r.work_ticks = 200 # ~10 sim seconds at 1× — slower than stone-block
|
||
r.required_skill = Recipe.SKILL_CRAFTING
|
||
r.skill_threshold = 0
|
||
r.target_workbench = &"smelter"
|
||
return r
|
||
|
||
|
||
static func gold_smelt() -> Recipe:
|
||
## Gold ore → gold ingot. Same smelting chain as iron.
|
||
var r := Recipe.new()
|
||
r.id = &"gold_smelt"
|
||
r.label = "Smelt gold ingot"
|
||
r.ingredient_type = Item.TYPE_GOLD
|
||
r.ingredient2_type = Item.TYPE_WOOD
|
||
r.ingredient2_count = 1
|
||
r.output_type = Item.TYPE_GOLD_INGOT
|
||
r.work_ticks = 200 # ~10 sim seconds at 1×
|
||
r.required_skill = Recipe.SKILL_CRAFTING
|
||
r.skill_threshold = 0
|
||
r.target_workbench = &"smelter"
|
||
return r
|
||
|
||
|
||
## Returns one fresh instance of every recipe in the catalog. Used by UI
|
||
## recipe-pickers to enumerate available bills; callers filter by
|
||
## `recipe.required_skill` and `recipe.target_workbench` against the
|
||
## workbench's `accepted_skill` and `label_text`.
|
||
static func all() -> Array[Recipe]:
|
||
return [
|
||
plank(),
|
||
stone_block(),
|
||
flour(),
|
||
bread(),
|
||
meal_from_vegetables(),
|
||
cremate_corpse(),
|
||
quarry_stone(),
|
||
iron_smelt(),
|
||
gold_smelt(),
|
||
]
|