# The House of Icarus - World Building Guide ## Crafting Crafting information lives on the **output item's YAML file** via the `craft:` block. There is no separate recipe directory. To find out how to make `bronze_dagger`, open `data/items/equipment/bronze_dagger.yaml` and look for the `craft:` block. (The item's **filename is its ID** — `bronze_dagger.yaml` → `bronze_dagger`; there is no `id:` field. `ingredients`/output entries reference items by filename.) ### Craft YAML Reference | Field | Type | Description | | -------------- | -------------- | ----------------------------------------------- | | `type` | string | Craft type (smithing, cooking, crafting, fletching, pharmacy, construction, combine, or "" for skill-less). Always matches a player skill name. | | `subtype` | string | Production method override (`smelt` for furnace recipes, `clean` for herb cleaning). Defaults empty (no override). | | `level` | int | Required skill level | | `xp` | int | XP awarded on success | | `wait` | float64 | Ticks per craft cycle | | `station` | []string | Station object IDs required (optional) | | `tool` | string | Required tool_type (optional) | | `ingredients` | []IngredientEntry | Ingredients consumed (see below) | | `output_qty` | int | Quantity produced (default 1, for stackables) | | `fail` | string | ItemID produced on failure (optional) | | `success_message` | string | Success message per cycle (optional, see message defaults) | | `fail_message` | string | Failure message (optional, empty = silent fail) | | `start_message`| string | Message when action begins (optional, see message defaults) | | `end_message` | string | Message when action completes (optional, see message defaults) | | `steps` | []CraftStep | Multi-step messages at tick intervals (optional)| | `success` | SuccessFormula | Optional skill check formula (see Behaviors) | The output is the item itself — no `output` field needed. The item ID IS the craft ID. ### Message Variables All message fields (`success_message`, `fail_message`, `start_message`, `end_message`, and `steps[].message`) support variables that expand to colorized item names: | Variable | Expands to | | -------- | ----------------------------------------------- | | `%n` | Output item name (colored, e.g. "stim potion") | | `%i1` | 1st ingredient entry's matched item (colored) | | `%i2` | 2nd ingredient entry's matched item (colored) | | `%b1` | 1st byproduct item name (colored, success only) | | `%b2` | 2nd byproduct item name (colored, success only) | Numbering follows YAML ingredient/byproduct order. If an ingredient entry has multiple alternative items (`items: [a, b]`), the variable expands to whichever the player actually possesses, colored with that item's `color:` field. Variables work alongside inline color tags (`{C4}text{/}`) which are expanded after variable substitution. ### Message Defaults If a message field is omitted from the YAML, the game uses a skill-level default based on the craft `type`: | Type | Default `success_message` | Default `start_message` | |------|-------------------|------------------------| | `cooking` | `"Cooked to perfection. %n looks great!"` | `"You start cooking %i1."` | | `smelt` | `"You remove a white hot %n!"` | `"You place the %i1 into the furnace."` | | `smithing` | `"You smith a %n."` | `"You begin smithing %i1."` | | `crafting` | `"You craft a %n."` | `"You begin crafting %i1."` | | `fletching` | `"You fletch a %n."` | `"You begin fletching %i1."` | | `pharmacy` | `"You mix a %n."` | `"You start mixing %i1."` | | `construction` | `"You construct a %n."` | `"You begin constructing %i1."` | | `clean` | `"You clean the %i1."` | `"You begin cleaning herbs."` | | (unset) | `"You produce %n."` | `"You start %i1."` | Default messages are keyed by `subtype` when set, otherwise by `type`. For skills that never fail (smithing, crafting, fletching, pharmacy, construction), `fail_message` defaults to empty — no message is shown on failure. ### CraftStep — Multi-Step Messages Optional interim messages fired at specific tick offsets during the craft cycle. The `tick` is the number of ticks elapsed since the start of the cycle. ```yaml craft: type: "" wait: 6 ingredients: - items: [map_piece_1] quantity: 1 - items: [map_piece_2] quantity: 1 - items: [map_piece_3] quantity: 1 steps: - tick: 1 message: "You try to puzzle how the pieces fit together." - tick: 3 message: "Aha, this edge lines up here!" success_message: "You assemble the map!" ``` ### IngredientEntry — Multi-Item Ingredient Slots Each ingredient entry defines an ingredient slot with multiple valid items. The first matching item found in the player's inventory is consumed. ```yaml ingredients: - 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 ingredients: - 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 ``` ### Skill-Based Production ```yaml # data/items/consumables/stim_potion.yaml craft: type: pharmacy level: 3 xp: 25 wait: 4 ingredients: - items: [guam_potion_unf] quantity: 1 - items: [eye_of_newt] quantity: 1 success_message: "You mix a %n." # %n expands to "stim potion" colored ``` ### Station-Based Production ```yaml # data/items/materials/bronze_bar.yaml craft: type: smithing subtype: smelt level: 1 xp: 6 wait: 4 station: [furnace] ingredients: - items: [copper_ore] quantity: 1 - items: [tin_ore] quantity: 1 success_message: "You smelt a %n." # default is "You remove a white hot %n!" # overridden here for simpler flavor ``` ```yaml # data/items/equipment/bronze_dagger.yaml craft: type: smithing level: 1 xp: 12 wait: 4 station: [anvil] ingredients: - items: [bronze_bar] quantity: 1 # success_message omitted — uses default "You smith a %n." ``` For stackable outputs, use `output_qty`: ```yaml # data/items/ammo/bronze_nails.yaml craft: type: smithing level: 4 xp: 12 wait: 4 station: [anvil] ingredients: - items: [bronze_bar] quantity: 1 output_qty: 15 # success_message omitted — uses default "You smith a %n." ``` ### Tool-Based Production ```yaml # data/items/ammo/arrow_shafts.yaml craft: type: fletching level: 1 xp: 5 wait: 3 tool: knife ingredients: - items: [logs, oak_logs, willow_logs] quantity: 1 output_qty: 15 ``` The `tool` field requires the player to have an item with that `tool_type` equipped or in inventory. The tool is NOT consumed. ### Skill-Less Combinations (Item-on-Item) Omit `type` (or leave it empty) for combinations with no skill check, no XP, and 100% success: ```yaml # data/items/consumables/bucket_of_water.yaml craft: wait: 0 ingredients: - items: [vial_of_water, jug_of_water] quantity: 1 byproducts: [empty_vial, empty_jug] - items: [empty_bucket] quantity: 1 success_message: "You pour the %i1 into the %i2." # %i1 = water source, %i2 = bucket ``` ### Multi-Piece Assembly (3+ items → 1) ```yaml # data/items/quest/ancient_map.yaml craft: wait: 0 ingredients: - items: [torn_page_1] quantity: 1 - items: [torn_page_2] quantity: 1 - items: [torn_page_3] quantity: 1 steps: - tick: 1 message: "You try to puzzle how the pieces fit together." - tick: 3 message: "Aha, this edge lines up here!" success_message: "You assemble the %n." ``` ### Clean Recipes Clean herb recipes use `type: pharmacy` with `subtype: clean` and are handled as background actions (one herb per cycle, directly mutating inventory): ```yaml # data/items/materials/guam.yaml (clean guam) craft: type: pharmacy subtype: clean level: 3 xp: 3 wait: 2 ingredients: - items: [grimy_guam] quantity: 1 # success_message omitted — uses default "You clean the %i1." # %i1 expands to the grimy herb name with its color ``` ### Food/Healing Items Items with `heal_value` and `eat_message` can be consumed via the `eat` command. ```yaml name: bread color: "DE" 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." ``` ### Architecture The `CraftIndex` (`internal/game/production_index.go`) is built once at startup from all item YAMLs that have a `craft:` block. It provides `O(1)` lookups by type, subtype, input item, and station. All crafting commands query the CraftIndex — no runtime file scanning. **Indexes:** - `byType["pharmacy"]` → all pharmacy-craftable items (used by `mix`) - `bySubtype["clean"]` → all items with subtype `clean` (grimy herb cleaning) - `bySubtype["smelt"]` → all items with subtype `smelt` (furnace smelting) - `byInput["guam"]` → all items that use guam (used by `use` to find combinations) - `byStation["anvil"]` → all items craftable at an anvil (used by `use bar on anvil`) - `FindByTwoInputs(a, b)` → items consuming both inputs in different ingredient entries