# The House of Icarus - World Building Guide ## Recipes Recipes define how items are processed on stations to produce new items. They are the foundation for cooking, smithing, crafting, and fletching. Recipe files live in `data/recipes//.yaml`. Two formats are supported: **individual** (one recipe per file) and **consolidated** (multiple related recipes per file). Consolidated format is preferred when many recipes share the same type, station, and materials (e.g., all bronze smithing products in one file). ### Recipe vs MadeFrom - **Recipes** (`data/recipes/`) use a station (fire, range, furnace, anvil, etc.). The player must be near the station object. - **MadeFrom** (on the item YAML directly) is for item-on-item combinations that need no station. The player combines ingredients from their inventory. ### Recipe YAML Reference | Field | Type | Description | | -------------- | -------------- | ----------------------------------------------- | | `id` | string | Unique recipe identifier | | `type` | string | Recipe type (cooking, smithing, crafting, etc.) | | `skill` | string | Skill checked for success | | `level` | int | Required skill level | | `xp` | int | XP awarded on success | | `wait` | float64 | Ticks per craft cycle (default 6) | | `station` | []string | Station object IDs required | | `consume` | []ConsumeEntry | Ingredients consumed (see below) | | `output` | string | ItemID produced on success | | `output_qty` | int | Quantity produced (default 1, for stackables) | | `fail` | string | ItemID produced on failure (optional) | | `message` | string | Success message | | `fail_message` | string | Failure message | | `success` | SuccessFormula | Optional skill check formula (see Behaviors) | The recipe's name in menus comes from the output item's `name` field, colored using the output item's `color`. ### ConsumeEntry — Multi-Item Ingredient Slots Each consume entry defines an ingredient slot with multiple valid items. The first matching item found in the player's inventory is consumed. ```yaml consume: - items: [item_id, alternative_id, ...] quantity: 1 byproducts: [byproduct_for_item, byproduct_for_alt, ...] ``` `byproducts` is optional. When present, it matches the `items` list by index — consuming `items[0]` returns `byproducts[0]` to inventory. Use `""` for items with no byproduct: ```yaml consume: - items: [bucket_of_water, vial_of_water] quantity: 1 byproducts: [empty_bucket, ""] # bucket returns empty, vial is consumed entirely - items: [herb] quantity: 1 # no byproducts — herb is consumed entirely ``` ### Consolidated Format For recipe categories where many recipes share the same `type`, `station`, and `wait` (e.g., smithing all bronze items from bronze bars, fletching all arrow shafts from logs), use a **consolidated** file. Shared fields are set once at the top level; each product entry provides only the fields that differ. **Loader behavior:** At load time, the loader expands each `products` entry into an individual `RecipeDef` with the same shape as the individual format. The production engine sees no difference — all lookup, matching, and execution code works identically. **Inheritance:** Child fields override parent. `consume` at the top level provides a default ingredient list; any product with different `consume` (e.g., a platebody needing 5 bars instead of 1) specifies its own. `output_qty`, `message`, `fail`, and `level` are per-product. ```yaml # data/recipes/smithing/bronze.yaml — consolidated: 8 products in one file type: smithing # shared by all products station: [anvil] # shared by all products wait: 4 # shared by all products consume: # default ingredient list — overridden per-product if needed - items: [bronze_bar] quantity: 1 products: - id: smith_bronze_dagger output: bronze_dagger level: 1 xp: 12 # inherits consume: 1 bronze_bar from parent - id: smith_bronze_nails output: bronze_nails level: 4 xp: 12 output_qty: 15 # stackable output, 15 per cycle - id: smith_bronze_full_helm output: bronze_full_helm level: 7 xp: 25 consume: # overrides parent — 2 bars instead of 1 - items: [bronze_bar] quantity: 2 - id: smith_bronze_platebody output: bronze_platebody level: 18 xp: 62 consume: # overrides parent — 5 bars - items: [bronze_bar] quantity: 5 # ... dagger, sword, med_helm, arrowtips, bolts_unf ... ``` **Use consolidated files when:** - Many recipes share the same `type`, `station`, and `material` - Adding a new tier means copy-pasting identical consume/station/wait fields - The relationship between recipes is easier to understand as a group **Use individual files when:** - The recipe is unique and doesn't share structure with others (e.g., compound smelting recipes with different ore ratios) - You want fine-grained version control on a single recipe - The recipe is complex enough that a consolidated file would be harder to read Individual and consolidated files coexist — the loader handles both transparently. ### Station-based recipe (cooking on a fire) ```yaml id: cook_trout type: cooking skill: cooking level: 15 xp: 70 wait: 6 station: [fire, cooking_range] consume: - items: [raw_trout] quantity: 1 output: trout fail: burnt_fish message: "Cooked to perfection. It looks great!" fail_message: "You accidentally burn the trout." ``` ### Station-specific recipe (range only, not fire) ```yaml id: cook_bread type: cooking skill: cooking level: 1 xp: 40 wait: 6 station: [cooking_range] consume: - items: [bread_dough] quantity: 1 output: bread fail: burnt_meat message: "You bake the dough into a fresh loaf of bread." fail_message: "You burn the bread to a crisp." ``` ### Smelting recipe (ore to bar at a furnace) Smelting recipes use `type: smelting` and `station: [furnace]`. The `smelt` command or `use on furnace` triggers them. Multi-ore recipes use `qty` on consume entries. ```yaml id: smelt_steel type: smelting skill: smithing level: 40 xp: 17 wait: 4 station: [furnace] consume: - items: [iron_ore] quantity: 1 - items: [coal] quantity: 2 output: steel_bar message: "You remove a white hot steel bar!" fail_message: "You fail to smelt a usable bar." ``` Iron smelting uses a `success` formula for its 50% failure rate: ```yaml success: base: 0.5 per_level: 0 cap: 0.5 ``` ### Smithing recipe (bar to item at an anvil) Smithing recipes use `type: smithing` and `station: [anvil]`. The `smith` command or `use on anvil` triggers them. Requires a hammer (`tool_type: hammer`) in inventory. **Recommended:** Use consolidated format (one file per metal type) since all products for a given metal share the same bar, station, and wait. See [Consolidated Format](#consolidated-format) above. The individual format is also supported: ```yaml id: smith_steel_platebody type: smithing skill: smithing level: 48 xp: 187 wait: 4 station: [anvil] consume: - items: [steel_bar] quantity: 5 output: steel_platebody message: "You hammer out a steel platebody." ``` For stackable outputs, use `output_qty`: ```yaml id: smith_iron_nails type: smithing skill: smithing level: 24 xp: 25 wait: 4 station: [anvil] consume: - items: [iron_bar] quantity: 1 output: iron_nails output_qty: 15 message: "You hammer out some iron nails." ``` ### MadeFrom — Item-on-item combinations Item-on-item combinations are defined directly on the output item via the `made_from` field. No recipe file needed. ```yaml # data/items/bread_dough.yaml id: bread_dough name: bread dough color: "222" made_from: - items: [pot_of_flour] quantity: 1 - items: [bucket_of_water, pitcher_of_water, vial_of_water] quantity: 1 ``` The player uses `use flour on water` to combine them. The system finds that `bread_dough` can be made from these ingredients and produces it. ### Food/Healing Items Items with `heal_value` and `eat_message` can be consumed via the `eat` command. ```yaml id: bread name: bread color: "222" description: "A fresh loaf of bread, still warm from the oven." value: 5 heal_value: 5 eat_message: "You eat the bread. Warm and satisfying." ```