aboutsummaryrefslogtreecommitdiff
path: root/building_guide/recipes.md
blob: 96bf0f93bf099593bdd03fe254ebf56ea8c0ea97 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
# 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 <verb> %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