aboutsummaryrefslogtreecommitdiff
path: root/worldbuilding_guide
diff options
context:
space:
mode:
Diffstat (limited to 'worldbuilding_guide')
-rw-r--r--worldbuilding_guide/recipes.md328
1 files changed, 154 insertions, 174 deletions
diff --git a/worldbuilding_guide/recipes.md b/worldbuilding_guide/recipes.md
index 335a6cc..e442c8c 100644
--- a/worldbuilding_guide/recipes.md
+++ b/worldbuilding_guide/recipes.md
@@ -1,36 +1,52 @@
# The House of Icarus - World Building Guide
-## Recipes
+## Crafting
-Recipes define how items are processed on stations to produce new items. They are the foundation for cooking, smithing, crafting, and fletching.
+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.
-Recipe files live in `data/recipes/<type>/<id>.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
+### Craft YAML Reference
| Field | Type | Description |
| -------------- | -------------- | ----------------------------------------------- |
-| `id` | string | Unique recipe identifier |
-| `type` | string | Recipe type (cooking, smithing, crafting, etc.) |
-| `skill` | string | Skill checked for success |
+| `type` | string | Craft type (pharmacy, smithing, cooking, smelting, crafting, fletching, construction, clean, or "" for skill-less) |
+| `skill` | string | Skill checked (defaults to type if omitted) |
| `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 |
+| `wait` | float64 | Ticks per craft cycle |
+| `station` | []string | Station object IDs required (optional) |
+| `tool` | string | Required tool_type (optional) |
| `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 |
+| `steps` | []CraftStep | Multi-step messages at tick intervals (optional)|
| `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`.
+The output is the item itself — no `output` field needed. The item ID IS the craft ID.
+
+### 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
+ consume:
+ - 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!"
+ message: "You assemble the map!"
+```
### ConsumeEntry — Multi-Item Ingredient Slots
@@ -51,199 +67,153 @@ consume:
quantity: 1
byproducts: [empty_bucket, ""] # bucket returns empty, vial is consumed entirely
- items: [herb]
- quantity: 1 # no byproducts — herb is consumed entirely
+ 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.
+### Skill-Based Production
```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 ...
+# data/items/consumables/stim_potion.yaml
+craft:
+ type: pharmacy
+ skill: pharmacy
+ level: 3
+ xp: 25
+ wait: 4
+ consume:
+ - items: [guam_potion_unf]
+ quantity: 1
+ - items: [eye_of_newt]
+ quantity: 1
+ message: "You mix a stim potion."
```
-**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)
+### Station-Based Production
```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."
+# data/items/materials/bronze_bar.yaml
+craft:
+ type: smelting
+ skill: smithing
+ level: 1
+ xp: 6
+ wait: 4
+ station: [furnace]
+ consume:
+ - items: [copper_ore]
+ quantity: 1
+ - items: [tin_ore]
+ quantity: 1
+ message: "You smelt a bronze bar."
```
-### 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."
+# data/items/equipment/bronze_dagger.yaml
+craft:
+ type: smithing
+ skill: smithing
+ level: 1
+ xp: 12
+ wait: 4
+ station: [anvil]
+ consume:
+ - items: [bronze_bar]
+ quantity: 1
+ message: "You hammer out a bronze dagger."
```
-### Smelting recipe (ore to bar at a furnace)
-
-Smelting recipes use `type: smelting` and `station: [furnace]`. The `smelt` command or `use <ore> on furnace` triggers them. Multi-ore recipes use `qty` on consume entries.
+For stackable outputs, use `output_qty`:
```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."
+# data/items/ammo/bronze_nails.yaml
+craft:
+ type: smithing
+ skill: smithing
+ level: 4
+ xp: 12
+ wait: 4
+ station: [anvil]
+ consume:
+ - items: [bronze_bar]
+ quantity: 1
+ output_qty: 15
+ message: "You hammer out some bronze nails."
```
-Iron smelting uses a `success` formula for its 50% failure rate:
+### Tool-Based Production
```yaml
-success:
- base: 0.5
- per_level: 0
- cap: 0.5
+# data/items/ammo/arrow_shafts.yaml
+craft:
+ type: fletching
+ level: 1
+ xp: 5
+ wait: 3
+ tool: knife
+ consume:
+ - items: [logs, oak_logs, willow_logs]
+ quantity: 1
+ output_qty: 15
```
-### Smithing recipe (bar to item at an anvil)
-
-Smithing recipes use `type: smithing` and `station: [anvil]`. The `smith` command or `use <bar> on anvil` triggers them. Requires a hammer (`tool_type: hammer`) in inventory.
+The `tool` field requires the player to have an item with that `tool_type` equipped or in inventory. The tool is NOT consumed.
-**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.
+### Skill-Less Combinations (Item-on-Item)
-The individual format is also supported:
+Omit `type` (or leave it empty) for combinations with no skill check, no XP, and 100% success:
```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."
+# data/items/consumables/bucket_of_water.yaml
+craft:
+ wait: 0
+ consume:
+ - items: [vial_of_water, jug_of_water]
+ quantity: 1
+ byproducts: [empty_vial, empty_jug]
+ - items: [empty_bucket]
+ quantity: 1
+ message: "You pour water into the bucket."
```
-For stackable outputs, use `output_qty`:
+### Multi-Piece Assembly (3+ items → 1)
```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."
+# data/items/quest/ancient_map.yaml
+craft:
+ wait: 0
+ consume:
+ - 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!"
+ message: "You assemble the ancient map."
```
-### MadeFrom — Item-on-item combinations
+### Clean Recipes
-Item-on-item combinations are defined directly on the output item via the `made_from` field. No recipe file needed.
+Clean herb recipes use `type: clean` and are handled as background actions (one herb per cycle, directly mutating inventory):
```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
+# data/items/materials/guam.yaml (clean guam)
+craft:
+ type: clean
+ skill: pharmacy
+ level: 3
+ xp: 3
+ wait: 2
+ consume:
+ - items: [grimy_guam]
+ quantity: 1
+ message: "You clean the grimy guam leaf."
```
-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.
@@ -257,3 +227,13 @@ value: 5
heal_value: 5
eat_message: "You eat the bread. Warm and satisfying."
```
+
+### Architecture
+
+The `CraftIndex` (`internal/game/craft_index.go`) is built once at startup from all item YAMLs that have a `craft:` block. It provides `O(1)` lookups by type, input item, and station. All crafting commands query the CraftIndex — no runtime file scanning.
+
+**Indexes:**
+- `byType["pharmacy"]` → all pharmacy-craftable items (used by `mix`)
+- `byInput["guam"]` → all items that consume 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 consume entries