diff options
329 files changed, 4698 insertions, 2841 deletions
diff --git a/building_guide/items.md b/building_guide/items.md index 8f8d87d..eefdf9c 100644 --- a/building_guide/items.md +++ b/building_guide/items.md @@ -3,7 +3,7 @@ **The filename is the ID.** An item is looked up by its filename stem (`bronze_pickaxe.yaml` → `bronze_pickaxe`); the loader derives `ItemDef.ID` from it. Do not put an `id:` field in the file — it is ignored. Anything that references this item (drop -tables, craft `consume`, room `item_spawns`) uses that filename. +tables, craft `ingredients`, room `item_spawns`) uses that filename. ```yaml name: bronze pickaxe diff --git a/building_guide/recipes.md b/building_guide/recipes.md index 364d375..e865fa6 100644 --- a/building_guide/recipes.md +++ b/building_guide/recipes.md @@ -2,20 +2,20 @@ ## 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. `consume`/output entries reference items by filename.) +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 (pharmacy, smithing, cooking, smelting, crafting, fletching, construction, clean, or "" for skill-less) | -| `skill` | string | Skill checked (defaults to type if omitted) | +| `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) | -| `consume` | []ConsumeEntry | Ingredients consumed (see below) | +| `ingredients` | []IngredientEntry | Ingredients consumed (see below) | | `output_qty` | int | Quantity produced (default 1, for stackables) | | `fail` | string | ItemID produced on failure (optional) | | `message` | string | Success message per cycle (optional, see message defaults) | @@ -34,12 +34,12 @@ All message fields (`message`, `fail_message`, `start_message`, `end_message`, a | Variable | Expands to | | -------- | ----------------------------------------------- | | `%n` | Output item name (colored, e.g. "stim potion") | -| `%i1` | 1st consume entry's matched item (colored) | -| `%i2` | 2nd consume entry's matched item (colored) | +| `%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 consume/byproduct order. If a consume entry has multiple alternative items (`items: [a, b]`), the variable expands to whichever the player actually possesses, colored with that item's `color:` field. +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. @@ -50,7 +50,7 @@ If a message field is omitted from the YAML, the game uses a skill-level default | Type | Default `message` | Default `start_message` | |------|-------------------|------------------------| | `cooking` | `"Cooked to perfection. %n looks great!"` | `"You start cooking %i1."` | -| `smelting` | `"You remove a white hot %n!"` | `"You place the %i1 into the furnace."` | +| `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."` | @@ -59,7 +59,7 @@ If a message field is omitted from the YAML, the game uses a skill-level default | `clean` | `"You clean the %i1."` | `"You begin cleaning herbs."` | | (unset) | `"You produce %n."` | `"You start <verb> %i1."` | -Any of these can be overridden per-item by setting the field in YAML. For skills that never fail (smithing, crafting, fletching, pharmacy, construction), `fail_message` defaults to empty — no message is shown on failure. +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 @@ -69,7 +69,7 @@ Optional interim messages fired at specific tick offsets during the craft cycle. craft: type: "" wait: 6 - consume: + ingredients: - items: [map_piece_1] quantity: 1 - items: [map_piece_2] @@ -84,12 +84,12 @@ craft: message: "You assemble the map!" ``` -### ConsumeEntry — Multi-Item Ingredient Slots +### IngredientEntry — 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. +Each ingredient entry defines an ingredient slot with multiple valid items. The first matching item found in the player's inventory is consumed. ```yaml -consume: +ingredients: - items: [item_id, alternative_id, ...] quantity: 1 byproducts: [byproduct_for_item, byproduct_for_alt, ...] @@ -98,7 +98,7 @@ consume: `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: +ingredients: - items: [bucket_of_water, vial_of_water] quantity: 1 byproducts: [empty_bucket, ""] # bucket returns empty, vial is consumed entirely @@ -112,11 +112,10 @@ consume: # data/items/consumables/stim_potion.yaml craft: type: pharmacy - skill: pharmacy level: 3 xp: 25 wait: 4 - consume: + ingredients: - items: [guam_potion_unf] quantity: 1 - items: [eye_of_newt] @@ -129,13 +128,13 @@ craft: ```yaml # data/items/materials/bronze_bar.yaml craft: - type: smelting - skill: smithing + type: smithing + subtype: smelt level: 1 xp: 6 wait: 4 station: [furnace] - consume: + ingredients: - items: [copper_ore] quantity: 1 - items: [tin_ore] @@ -148,12 +147,11 @@ craft: # data/items/equipment/bronze_dagger.yaml craft: type: smithing - skill: smithing level: 1 xp: 12 wait: 4 station: [anvil] - consume: + ingredients: - items: [bronze_bar] quantity: 1 # message omitted — uses default "You smith a %n." @@ -165,12 +163,11 @@ For stackable outputs, use `output_qty`: # data/items/ammo/bronze_nails.yaml craft: type: smithing - skill: smithing level: 4 xp: 12 wait: 4 station: [anvil] - consume: + ingredients: - items: [bronze_bar] quantity: 1 output_qty: 15 @@ -187,7 +184,7 @@ craft: xp: 5 wait: 3 tool: knife - consume: + ingredients: - items: [logs, oak_logs, willow_logs] quantity: 1 output_qty: 15 @@ -203,7 +200,7 @@ Omit `type` (or leave it empty) for combinations with no skill check, no XP, and # data/items/consumables/bucket_of_water.yaml craft: wait: 0 - consume: + ingredients: - items: [vial_of_water, jug_of_water] quantity: 1 byproducts: [empty_vial, empty_jug] @@ -218,7 +215,7 @@ craft: # data/items/quest/ancient_map.yaml craft: wait: 0 - consume: + ingredients: - items: [torn_page_1] quantity: 1 - items: [torn_page_2] @@ -235,17 +232,17 @@ craft: ### Clean Recipes -Clean herb recipes use `type: clean` and are handled as background actions (one herb per cycle, directly mutating inventory): +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: clean - skill: pharmacy + type: pharmacy + subtype: clean level: 3 xp: 3 wait: 2 - consume: + ingredients: - items: [grimy_guam] quantity: 1 # message omitted — uses default "You clean the %i1." @@ -267,10 +264,12 @@ 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. +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`) -- `byInput["guam"]` → all items that consume guam (used by `use` to find combinations) +- `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 consume entries +- `FindByTwoInputs(a, b)` → items consuming both inputs in different ingredient entries diff --git a/data/.admin_history.json b/data/.admin_history.json index 364be38..8519fc5 100644 --- a/data/.admin_history.json +++ b/data/.admin_history.json @@ -1 +1 @@ -{"history":[{"time":"2026-06-30T14:29:37-04:00","description":"delete room 1014 (cleaned 0 exits)","file_path":"data/rooms/intro/1014.yaml","old_content":"id: 1014\nname: 'Room #1014'\ncolor: D5\ndescription: []\nexits:\n southwest:\n room: 1013\nobjects: []\nitem_spawns: []\nmobs: []\non_enter: []\nhazard: \"\"\nblock_transport: false\ntriggers: []\n","new_content":"","is_delete":true,"is_create":false},{"time":"2026-06-30T14:29:37-04:00","description":"delete room 1016 (cleaned 0 exits)","file_path":"data/rooms/intro/1016.yaml","old_content":"id: 1016\nname: New Room\ncolor: \"97\"\ndescription:\n - text: A featureless room.\nexits:\n down:\n room: 1017\n south:\n room: 1009\n southwest:\n room: 1005\nobjects: []\nitem_spawns: []\nmobs: []\non_enter: []\nhazard: \"\"\nblock_transport: false\ntriggers: []\n","new_content":"","is_delete":true,"is_create":false},{"time":"2026-06-30T14:29:38-04:00","description":"delete room 1015 (cleaned 0 exits)","file_path":"data/rooms/intro/1015.yaml","old_content":"id: 1015\nname: 'Room #1015'\ncolor: 0C\ndescription: []\nexits:\n northwest:\n room: 1018\nobjects: []\nitem_spawns: []\nmobs: []\non_enter: []\nhazard: \"\"\nblock_transport: false\ntriggers: []\n","new_content":"","is_delete":true,"is_create":false},{"time":"2026-06-30T14:29:39-04:00","description":"delete room 1017 (cleaned 0 exits)","file_path":"data/rooms/intro/1017.yaml","old_content":"id: 1017\nname: New Room\ncolor: \"\"\ndescription:\n - text: A featureless room.\nexits: {}\nobjects: []\nitem_spawns: []\nmobs: []\non_enter: []\nhazard: \"\"\nblock_transport: false\ntriggers: []\n","new_content":"","is_delete":true,"is_create":false},{"time":"2026-06-30T14:29:40-04:00","description":"delete room 1018 (cleaned 0 exits)","file_path":"data/rooms/intro/1018.yaml","old_content":"id: 1018\nname: 'Room #1018'\ncolor: D0\ndescription: []\nexits: {}\nobjects: []\nitem_spawns: []\nmobs: []\non_enter: []\nhazard: \"\"\nblock_transport: false\ntriggers: []\n","new_content":"","is_delete":true,"is_create":false},{"time":"2026-06-30T14:29:40-04:00","description":"delete room 1019 (cleaned 0 exits)","file_path":"data/rooms/intro/1019.yaml","old_content":"id: 1019\nname: 'Room #1019'\ncolor: \"\"\ndescription: []\nexits: {}\nobjects: []\nitem_spawns: []\nmobs: []\non_enter: []\nhazard: \"\"\nblock_transport: false\ntriggers: []\n","new_content":"","is_delete":true,"is_create":false},{"time":"2026-06-30T14:29:41-04:00","description":"delete room 1020 (cleaned 0 exits)","file_path":"data/rooms/intro/1020.yaml","old_content":"id: 1020\nname: 'Room #1020'\ncolor: \"\"\ndescription: []\nexits: {}\nobjects: []\nitem_spawns: []\nmobs: []\non_enter: []\nhazard: \"\"\nblock_transport: false\ntriggers: []\n","new_content":"","is_delete":true,"is_create":false},{"time":"2026-06-30T14:30:45-04:00","description":"delete room 1013 (cleaned 1 exits)","file_path":"data/rooms/intro/1013.yaml","old_content":"id: 1013\nname: 'Room #1013'\ncolor: \"72\"\ndescription: []\nexits:\n west:\n room: 1007\nobjects: []\nitem_spawns: []\nmobs: []\non_enter: []\nhazard: \"\"\nblock_transport: false\ntriggers: []\n","new_content":"","is_delete":true,"is_create":false},{"time":"2026-06-30T14:30:49-04:00","description":"delete room 1009 (cleaned 0 exits)","file_path":"data/rooms/intro/1009.yaml","old_content":"id: 1009\nname: New Room\ncolor: \"27\"\ndescription:\n - text: A featureless room.\nexits:\n northwest:\n room: 8\n southwest:\n room: 1006\n west:\n room: 1005\nobjects: []\nitem_spawns: []\nmobs:\n - id: man\n - id: man\non_enter: []\nhazard: \"\"\nblock_transport: false\ntriggers: []\n","new_content":"","is_delete":true,"is_create":false},{"time":"2026-06-30T14:30:51-04:00","description":"delete room 1007 (cleaned 1 exits)","file_path":"data/rooms/intro/1007.yaml","old_content":"id: 1007\nname: 'Room #1007'\ncolor: \"\"\ndescription: []\nexits:\n west:\n room: 2004\nobjects: []\nitem_spawns: []\nmobs: []\non_enter: []\nhazard: \"\"\nblock_transport: false\ntriggers: []\n","new_content":"","is_delete":true,"is_create":false},{"time":"2026-06-30T14:30:53-04:00","description":"delete room 1006 (cleaned 4 exits)","file_path":"data/rooms/intro/1006.yaml","old_content":"id: 1006\nname: New Room\ncolor: E2\ndescription:\n - text: A featureless room.\nexits:\n north:\n room: 1005\n northwest:\n room: 1008\n up:\n room: 1010\n west:\n room: 2003\nobjects: []\nitem_spawns: []\nmobs: []\non_enter: []\nhazard: \"\"\nblock_transport: false\ntriggers: []\n","new_content":"","is_delete":true,"is_create":false},{"time":"2026-06-30T14:30:59-04:00","description":"delete room 1010 (cleaned 1 exits)","file_path":"data/rooms/intro/1010.yaml","old_content":"id: 1010\nname: New Room\ncolor: \"\"\ndescription:\n - text: A featureless room.\nexits:\n north:\n room: 1011\nobjects: []\nitem_spawns: []\nmobs: []\non_enter: []\nhazard: \"\"\nblock_transport: false\ntriggers: []\n","new_content":"","is_delete":true,"is_create":false},{"time":"2026-06-30T14:31:00-04:00","description":"delete room 1011 (cleaned 0 exits)","file_path":"data/rooms/intro/1011.yaml","old_content":"id: 1011\nname: New Room\ncolor: \"\"\ndescription:\n - text: A featureless room.\nexits:\n east:\n room: 1012\nobjects: []\nitem_spawns: []\nmobs: []\non_enter: []\nhazard: \"\"\nblock_transport: false\ntriggers: []\n","new_content":"","is_delete":true,"is_create":false},{"time":"2026-06-30T14:31:01-04:00","description":"delete room 1012 (cleaned 0 exits)","file_path":"data/rooms/intro/1012.yaml","old_content":"id: 1012\nname: New Room\ncolor: \"\"\ndescription:\n - text: A featureless room.\nexits: {}\nobjects: []\nitem_spawns: []\nmobs: []\non_enter: []\nhazard: \"\"\nblock_transport: false\ntriggers: []\n","new_content":"","is_delete":true,"is_create":false},{"time":"2026-06-30T14:31:02-04:00","description":"delete room 1005 (cleaned 2 exits)","file_path":"data/rooms/intro/1005.yaml","old_content":"id: 1005\nname: New Room\ncolor: CC\ndescription:\n - text: A featureless room.\nexits:\n southwest:\n room: 2003\n west:\n room: 1008\nobjects: []\nitem_spawns: []\nmobs: []\non_enter: []\nhazard: \"\"\nblock_transport: false\ntriggers: []\n","new_content":"","is_delete":true,"is_create":false},{"time":"2026-06-30T14:31:03-04:00","description":"delete room 1008 (cleaned 1 exits)","file_path":"data/rooms/intro/1008.yaml","old_content":"id: 1008\nname: New Room\ncolor: A9\ndescription:\n - text: A featureless room.\nexits:\n north:\n room: 7\n south:\n room: 2003\nobjects: []\nitem_spawns: []\nmobs: []\non_enter: []\nhazard: \"\"\nblock_transport: false\ntriggers: []\n","new_content":"","is_delete":true,"is_create":false},{"time":"2026-06-30T14:32:29-04:00","description":"update room 2003 (add exit north to 1005)","file_path":"data/rooms/intro/2003.yaml","old_content":"id: 2003\nname: Test Room\ncolor: \"\"\ndescription:\n - text: It's a test room\nexits:\n south:\n room: 2004\n southwest:\n room: 2005\n west:\n room: 2002\nobjects: []\nitem_spawns: []\nmobs: []\non_enter: []\nhazard: \"\"\nblock_transport: false\ntriggers: []\n","new_content":"id: 2003\nname: Test Room\ncolor: \"\"\ndescription:\n - text: It's a test room\nexits:\n north:\n room: 1005\n south:\n room: 2004\n southwest:\n room: 2005\n west:\n room: 2002\nobjects: []\nitem_spawns: []\nmobs: []\non_enter: []\nhazard: \"\"\nblock_transport: false\ntriggers: []\n","is_delete":false,"is_create":false},{"time":"2026-06-30T14:32:29-04:00","description":"create room 1005","file_path":"data/rooms/intro/1005.yaml","old_content":"","new_content":"exits:\n south: 2003\nid: 1005\nname: 'Room #1005'\n","is_delete":false,"is_create":true},{"time":"2026-06-30T14:32:30-04:00","description":"update room 1005 (add exit east to 1006)","file_path":"data/rooms/intro/1005.yaml","old_content":"exits:\n south: 2003\nid: 1005\nname: 'Room #1005'\n","new_content":"id: 1005\nname: 'Room #1005'\ncolor: \"\"\ndescription: []\nexits:\n east:\n room: 1006\n south:\n room: 2003\nobjects: []\nitem_spawns: []\nmobs: []\non_enter: []\nhazard: \"\"\nblock_transport: false\ntriggers: []\n","is_delete":false,"is_create":false},{"time":"2026-06-30T14:32:30-04:00","description":"create room 1006","file_path":"data/rooms/intro/1006.yaml","old_content":"","new_content":"exits:\n west: 1005\nid: 1006\nname: 'Room #1006'\n","is_delete":false,"is_create":true},{"time":"2026-06-30T14:32:31-04:00","description":"update room 1006 (add exit south to 1007)","file_path":"data/rooms/intro/1006.yaml","old_content":"exits:\n west: 1005\nid: 1006\nname: 'Room #1006'\n","new_content":"id: 1006\nname: 'Room #1006'\ncolor: \"\"\ndescription: []\nexits:\n south:\n room: 1007\n west:\n room: 1005\nobjects: []\nitem_spawns: []\nmobs: []\non_enter: []\nhazard: \"\"\nblock_transport: false\ntriggers: []\n","is_delete":false,"is_create":false},{"time":"2026-06-30T14:32:31-04:00","description":"create room 1007","file_path":"data/rooms/intro/1007.yaml","old_content":"","new_content":"exits:\n north: 1006\nid: 1007\nname: 'Room #1007'\n","is_delete":false,"is_create":true},{"time":"2026-06-30T14:32:32-04:00","description":"update room 1007 (add exit east to 1008)","file_path":"data/rooms/intro/1007.yaml","old_content":"exits:\n north: 1006\nid: 1007\nname: 'Room #1007'\n","new_content":"id: 1007\nname: 'Room #1007'\ncolor: \"\"\ndescription: []\nexits:\n east:\n room: 1008\n north:\n room: 1006\nobjects: []\nitem_spawns: []\nmobs: []\non_enter: []\nhazard: \"\"\nblock_transport: false\ntriggers: []\n","is_delete":false,"is_create":false},{"time":"2026-06-30T14:32:32-04:00","description":"create room 1008","file_path":"data/rooms/intro/1008.yaml","old_content":"","new_content":"exits:\n west: 1007\nid: 1008\nname: 'Room #1008'\n","is_delete":false,"is_create":true},{"time":"2026-06-30T14:32:32-04:00","description":"update room 1008 (add exit north to 1009)","file_path":"data/rooms/intro/1008.yaml","old_content":"exits:\n west: 1007\nid: 1008\nname: 'Room #1008'\n","new_content":"id: 1008\nname: 'Room #1008'\ncolor: \"\"\ndescription: []\nexits:\n north:\n room: 1009\n west:\n room: 1007\nobjects: []\nitem_spawns: []\nmobs: []\non_enter: []\nhazard: \"\"\nblock_transport: false\ntriggers: []\n","is_delete":false,"is_create":false},{"time":"2026-06-30T14:32:32-04:00","description":"create room 1009","file_path":"data/rooms/intro/1009.yaml","old_content":"","new_content":"exits:\n south: 1008\nid: 1009\nname: 'Room #1009'\n","is_delete":false,"is_create":true},{"time":"2026-06-30T14:32:33-04:00","description":"update room 1009 (add exit north to 1010)","file_path":"data/rooms/intro/1009.yaml","old_content":"exits:\n south: 1008\nid: 1009\nname: 'Room #1009'\n","new_content":"id: 1009\nname: 'Room #1009'\ncolor: \"\"\ndescription: []\nexits:\n north:\n room: 1010\n south:\n room: 1008\nobjects: []\nitem_spawns: []\nmobs: []\non_enter: []\nhazard: \"\"\nblock_transport: false\ntriggers: []\n","is_delete":false,"is_create":false},{"time":"2026-06-30T14:32:33-04:00","description":"create room 1010","file_path":"data/rooms/intro/1010.yaml","old_content":"","new_content":"exits:\n south: 1009\nid: 1010\nname: 'Room #1010'\n","is_delete":false,"is_create":true},{"time":"2026-06-30T14:32:33-04:00","description":"update room 1010 (add exit east to 1011)","file_path":"data/rooms/intro/1010.yaml","old_content":"exits:\n south: 1009\nid: 1010\nname: 'Room #1010'\n","new_content":"id: 1010\nname: 'Room #1010'\ncolor: \"\"\ndescription: []\nexits:\n east:\n room: 1011\n south:\n room: 1009\nobjects: []\nitem_spawns: []\nmobs: []\non_enter: []\nhazard: \"\"\nblock_transport: false\ntriggers: []\n","is_delete":false,"is_create":false},{"time":"2026-06-30T14:32:33-04:00","description":"create room 1011","file_path":"data/rooms/intro/1011.yaml","old_content":"","new_content":"exits:\n west: 1010\nid: 1011\nname: 'Room #1011'\n","is_delete":false,"is_create":true},{"time":"2026-06-30T14:32:34-04:00","description":"update room 1011 (add exit south to 1012)","file_path":"data/rooms/intro/1011.yaml","old_content":"exits:\n west: 1010\nid: 1011\nname: 'Room #1011'\n","new_content":"id: 1011\nname: 'Room #1011'\ncolor: \"\"\ndescription: []\nexits:\n south:\n room: 1012\n west:\n room: 1010\nobjects: []\nitem_spawns: []\nmobs: []\non_enter: []\nhazard: \"\"\nblock_transport: false\ntriggers: []\n","is_delete":false,"is_create":false},{"time":"2026-06-30T14:32:34-04:00","description":"create room 1012","file_path":"data/rooms/intro/1012.yaml","old_content":"","new_content":"exits:\n north: 1011\nid: 1012\nname: 'Room #1012'\n","is_delete":false,"is_create":true},{"time":"2026-06-30T14:32:34-04:00","description":"update room 1012 (add exit south to 1013)","file_path":"data/rooms/intro/1012.yaml","old_content":"exits:\n north: 1011\nid: 1012\nname: 'Room #1012'\n","new_content":"id: 1012\nname: 'Room #1012'\ncolor: \"\"\ndescription: []\nexits:\n north:\n room: 1011\n south:\n room: 1013\nobjects: []\nitem_spawns: []\nmobs: []\non_enter: []\nhazard: \"\"\nblock_transport: false\ntriggers: []\n","is_delete":false,"is_create":false},{"time":"2026-06-30T14:32:34-04:00","description":"create room 1013","file_path":"data/rooms/intro/1013.yaml","old_content":"","new_content":"exits:\n north: 1012\nid: 1013\nname: 'Room #1013'\n","is_delete":false,"is_create":true},{"time":"2026-06-30T14:32:35-04:00","description":"delete room 1013 (cleaned 1 exits)","file_path":"data/rooms/intro/1013.yaml","old_content":"exits:\n north: 1012\nid: 1013\nname: 'Room #1013'\n","new_content":"","is_delete":true,"is_create":false},{"time":"2026-06-30T14:32:36-04:00","description":"delete room 1012 (cleaned 1 exits)","file_path":"data/rooms/intro/1012.yaml","old_content":"id: 1012\nname: 'Room #1012'\ncolor: \"\"\ndescription: []\nexits:\n north:\n room: 1011\nobjects: []\nitem_spawns: []\nmobs: []\non_enter: []\nhazard: \"\"\nblock_transport: false\ntriggers: []\n","new_content":"","is_delete":true,"is_create":false},{"time":"2026-06-30T14:32:37-04:00","description":"delete room 1011 (cleaned 1 exits)","file_path":"data/rooms/intro/1011.yaml","old_content":"id: 1011\nname: 'Room #1011'\ncolor: \"\"\ndescription: []\nexits:\n west:\n room: 1010\nobjects: []\nitem_spawns: []\nmobs: []\non_enter: []\nhazard: \"\"\nblock_transport: false\ntriggers: []\n","new_content":"","is_delete":true,"is_create":false},{"time":"2026-06-30T14:32:37-04:00","description":"delete room 1010 (cleaned 1 exits)","file_path":"data/rooms/intro/1010.yaml","old_content":"id: 1010\nname: 'Room #1010'\ncolor: \"\"\ndescription: []\nexits:\n south:\n room: 1009\nobjects: []\nitem_spawns: []\nmobs: []\non_enter: []\nhazard: \"\"\nblock_transport: false\ntriggers: []\n","new_content":"","is_delete":true,"is_create":false},{"time":"2026-06-30T14:32:38-04:00","description":"delete room 1009 (cleaned 1 exits)","file_path":"data/rooms/intro/1009.yaml","old_content":"id: 1009\nname: 'Room #1009'\ncolor: \"\"\ndescription: []\nexits:\n south:\n room: 1008\nobjects: []\nitem_spawns: []\nmobs: []\non_enter: []\nhazard: \"\"\nblock_transport: false\ntriggers: []\n","new_content":"","is_delete":true,"is_create":false},{"time":"2026-06-30T14:32:39-04:00","description":"delete room 1008 (cleaned 1 exits)","file_path":"data/rooms/intro/1008.yaml","old_content":"id: 1008\nname: 'Room #1008'\ncolor: \"\"\ndescription: []\nexits:\n west:\n room: 1007\nobjects: []\nitem_spawns: []\nmobs: []\non_enter: []\nhazard: \"\"\nblock_transport: false\ntriggers: []\n","new_content":"","is_delete":true,"is_create":false},{"time":"2026-06-30T14:32:40-04:00","description":"delete room 1007 (cleaned 1 exits)","file_path":"data/rooms/intro/1007.yaml","old_content":"id: 1007\nname: 'Room #1007'\ncolor: \"\"\ndescription: []\nexits:\n north:\n room: 1006\nobjects: []\nitem_spawns: []\nmobs: []\non_enter: []\nhazard: \"\"\nblock_transport: false\ntriggers: []\n","new_content":"","is_delete":true,"is_create":false},{"time":"2026-06-30T14:32:40-04:00","description":"delete room 1006 (cleaned 1 exits)","file_path":"data/rooms/intro/1006.yaml","old_content":"id: 1006\nname: 'Room #1006'\ncolor: \"\"\ndescription: []\nexits:\n west:\n room: 1005\nobjects: []\nitem_spawns: []\nmobs: []\non_enter: []\nhazard: \"\"\nblock_transport: false\ntriggers: []\n","new_content":"","is_delete":true,"is_create":false},{"time":"2026-06-30T14:32:41-04:00","description":"delete room 1005 (cleaned 1 exits)","file_path":"data/rooms/intro/1005.yaml","old_content":"id: 1005\nname: 'Room #1005'\ncolor: \"\"\ndescription: []\nexits:\n south:\n room: 2003\nobjects: []\nitem_spawns: []\nmobs: []\non_enter: []\nhazard: \"\"\nblock_transport: false\ntriggers: []\n","new_content":"","is_delete":true,"is_create":false},{"time":"2026-06-30T15:05:42-04:00","description":"update room 1001","file_path":"data/rooms/intro/1001.yaml","old_content":"id: 1001\nname: Inside Transport Shuttle\ncolor: \"\"\ndescription:\n - text: |-\n A dim, windowless shuttle interior with a few uncomfortable rows of steel seats facing forward. A large framed sign hangs next to the closed cockpit door. The piston-powered staircase is firmly closed at the rear of the craft.\n\n A dim, windowless shuttle interior with a few uncomfortable rows of steel seats facing forward. A large {11}framed sign{/} hangs next to the closed cockpit door. A piston-powered staircase leads down out the back of the small craft with a smiling attendant ready to help disembark.\nexits:\n down:\n room: 1002\n condition:\n flag: \"\"\n value: null\n not: false\n player_flag: 1001_touchdown\n has_item: \"\"\n min_credits: 0\n all_of: []\n any_of: []\n blocked_message: The piston-powered staircase is firmly closed.\n east:\n room: 2001\nobjects:\n - name: framed sign\n hidden: true\n description:\n - text: \"We hope you enjoy your trip on our shuttle! Your pilot is [TYLER].\\n\\nWhen you arrive at your final destination, please be aware of the following basic commands:\\n\\n{0B bold}Movement:{/} {0A}north{/}, {0A}south{/}, {0A}east{/}, {0A}west{/}, {0A}up{/}, {0A}down{/}\\n{0B bold}Look:{/} {0A}look{/}, {0A}look \u003citem/object/mob\u003e{/}, and {0A}map{/}\\n{0B bold}Items:{/} {0A}inv{/} to see your 28-slot inventory\\n {0A}get \u003citem\u003e{/}, {0A}drop \u003citem\u003e{/}, {0A}wear \u003citem\u003e{/}, {0A}remove \u003citem\u003e{/}\\n {0A}use \u003citem\u003e on \u003citem/object\u003e{/}\\n {0A}eq{/} for equiped gear\\n{0B bold}Comms:{/} {0A}talk \u003cmob\u003e{/} for NPC chat\\n {0A}say \u003cmsg\u003e{/} and {0A}global \u003cmsg\u003e{/} for human chat\\n{0B bold}Character:{/} {0A}score{/} and {0A}skills{/} for stats. \\n{0B bold}Combat{/} {0A}attack \u003cmob\u003e{/}\\n{0B bold}Skills{/} Many skills have shortcuts like {0A}mine{/}, {0A}fish{/}, or {0A}chop{/}\\n{0B bold}Options{/} {0A}options{/} for a list of account options\\n {0A}options \u003copt\u003e \u003cvalue\u003e{/} to change an option\\n\\nType {0C bold}what{/} for a list of possible common actions\\n\\nMake sure to check the {0A}help{/} pages, especially {0A}help newplayer{/}!\"\n on_look:\n set_flags: {}\n set_player_flags:\n 1001_look_sign: true\n give_item: \"\"\n take_item: \"\"\n teleport: 0\n heal: 0\n cost: 0\n shop: null\n assign_task: false\n skip_task: false\n extend_task: false\n reputation_cost: 0\n sawmill: false\n aps_node: false\n - name: door\n hidden: true\n description:\n - text: A sturdy, locked steel door that keeps passengers out of the cockpit. There is a tiny, thin window at eye level.\n - name: window\n hidden: true\n description:\n - text: A thick trim with rounded bolt heads frames the tiny window. It looks like it was cut into the door at some point, potentially as a simple replacement to computerized security systems. Inside the cockpit there's a pilot finishing up landing procedures on a large panel of analog instruments.\n - name: instrument panel\n aliases:\n - cockpit\n hidden: true\n description:\n - text: The cramped cockpit is surrounded by buttons, swiches, dials, and analog gauges. The parts are a mix of technologies from the last century. Part of the panel is obscured by a draped cloth as if to hide it from view. Odd.\n - name: pilot\n hidden: true\n description:\n - text: That's the guy who took you from the Passenger Barge Denali down here to Vesta. A middle-aged man in a neat white jumpsuit with a matching white sort of conductor's hat. He's following a written procedure checklist and seems to take his job seriously.\nitem_spawns: []\nmobs:\n - id: flight_attendant\non_enter:\n - message: '{0B bold}Welcome to The House of Icarus{/}'\n condition:\n flag: \"\"\n value: null\n not: true\n player_flag: 1001_welcome\n has_item: \"\"\n min_credits: 0\n all_of: []\n any_of: []\n delay: 5\n set_flags: {}\n set_player_flags: {}\n broadcast: \"\"\n broadcast_global: \"\"\n spawn_mob: null\n despawn_mob: \"\"\n give_item: \"\"\n take_item: \"\"\n teleport: 0\n heal: 0\n - message: '{0B}Type{/} {0A}look sign{/} {0B}or{/} {0A}talk attendant{/} {0B}to get started{/}'\n condition:\n flag: \"\"\n value: null\n not: true\n player_flag: 1001_welcome\n has_item: \"\"\n min_credits: 0\n all_of: []\n any_of: []\n delay: 7\n set_flags: {}\n set_player_flags:\n 1001_welcome: true\n broadcast: \"\"\n broadcast_global: \"\"\n spawn_mob: null\n despawn_mob: \"\"\n give_item: \"\"\n take_item: \"\"\n teleport: 0\n heal: 0\n - message: '{0B}Type{/} {0A}help newplayer{/} {0B}for the new player''s guide. That''s it. Explore and have fun.{/}'\n condition:\n flag: \"\"\n value: null\n not: true\n player_flag: 1001_welcome\n has_item: \"\"\n min_credits: 0\n all_of: []\n any_of: []\n delay: 7\n set_flags: {}\n set_player_flags: {}\n broadcast: \"\"\n broadcast_global: \"\"\n spawn_mob: null\n despawn_mob: \"\"\n give_item: \"\"\n take_item: \"\"\n teleport: 0\n heal: 0\nhazard: \"\"\nblock_transport: true\ntriggers:\n - id: \"\"\n on_player_flag: 1001_look_sign\n on_flag: \"\"\n value: null\n room: 0\n steps:\n - delay: 5\n message: The cabin shakes as the small craft touches down\n broadcast: \"\"\n broadcast_global: \"\"\n set_flags: {}\n set_player_flags: {}\n spawn_mob: null\n give_item: \"\"\n take_item: \"\"\n teleport: 0\n heal: 0\n despawn_mob: \"\"\n - delay: 5\n message: The pistons hiss as the rear staircase opens\n broadcast: \"\"\n broadcast_global: \"\"\n set_flags: {}\n set_player_flags: {}\n spawn_mob: null\n give_item: \"\"\n take_item: \"\"\n teleport: 0\n heal: 0\n despawn_mob: \"\"\n - delay: 0\n message: \"\"\n broadcast: \"\"\n broadcast_global: \"\"\n set_flags: {}\n set_player_flags:\n 1001_touchdown: true\n spawn_mob: null\n give_item: \"\"\n take_item: \"\"\n teleport: 0\n heal: 0\n despawn_mob: \"\"\n","new_content":"block_transport: true\ncolor: \"\"\ndescription:\n - text: |-\n A dim, windowless shuttle interior with a few uncomfortable rows of steel seats facing forward. A large framed sign hangs next to the closed cockpit door. The piston-powered staircase is firmly closed at the rear of the craft.\n\n A dim, windowless shuttle interior with a few uncomfortable rows of steel seats facing forward. A large {11}framed sign{/} hangs next to the closed cockpit door. A piston-powered staircase leads down out the back of the small craft with a smiling attendant ready to help disembark.\nexits:\n down:\n blocked_message: The piston-powered staircase is firmly closed.\n condition:\n all_of: []\n any_of: []\n flag: \"\"\n has_item: \"\"\n min_credits: 0\n not: false\n player_flag: 1001_touchdown\n value: null\n room: 1002\n east:\n room: 2001\nhazard: \"\"\nid: 1001\nitem_spawns: []\nmobs:\n - id: flight_attendant\nname: Inside Transport Shuttle\nobjects:\n - description:\n - text: \"We hope you enjoy your trip on our shuttle! Your pilot is [TYLER].\\n\\nWhen you arrive at your final destination, please be aware of the following basic commands:\\n\\n{0B bold}Movement:{/} {0A}north{/}, {0A}south{/}, {0A}east{/}, {0A}west{/}, {0A}up{/}, {0A}down{/}\\n{0B bold}Look:{/} {0A}look{/}, {0A}look \u003citem/object/mob\u003e{/}, and {0A}map{/}\\n{0B bold}Items:{/} {0A}inv{/} to see your 28-slot inventory\\n {0A}get \u003citem\u003e{/}, {0A}drop \u003citem\u003e{/}, {0A}wear \u003citem\u003e{/}, {0A}remove \u003citem\u003e{/}\\n {0A}use \u003citem\u003e on \u003citem/object\u003e{/}\\n {0A}eq{/} for equiped gear\\n{0B bold}Comms:{/} {0A}talk \u003cmob\u003e{/} for NPC chat\\n {0A}say \u003cmsg\u003e{/} and {0A}global \u003cmsg\u003e{/} for human chat\\n{0B bold}Character:{/} {0A}score{/} and {0A}skills{/} for stats. \\n{0B bold}Combat{/} {0A}attack \u003cmob\u003e{/}\\n{0B bold}Skills{/} Many skills have shortcuts like {0A}mine{/}, {0A}fish{/}, or {0A}chop{/}\\n{0B bold}Options{/} {0A}options{/} for a list of account options\\n {0A}options \u003copt\u003e \u003cvalue\u003e{/} to change an option\\n\\nType {0C bold}what{/} for a list of possible common actions\\n\\nMake sure to check the {0A}help{/} pages, especially {0A}help newplayer{/}!\"\n hidden: true\n name: framed sign\n on_look:\n aps_node: false\n assign_task: false\n cost: 0\n extend_task: false\n give_item: \"\"\n heal: 0\n reputation_cost: 0\n sawmill: false\n set_flags: {}\n set_player_flags:\n 1001_look_sign: true\n shop: null\n skip_task: false\n take_item: \"\"\n teleport: 0\n - description:\n - text: A sturdy, locked steel door that keeps passengers out of the cockpit. There is a tiny, thin window at eye level.\n hidden: true\n name: door\n - description:\n - text: A thick trim with rounded bolt heads frames the tiny window. It looks like it was cut into the door at some point, potentially as a simple replacement to computerized security systems. Inside the cockpit there's a pilot finishing up landing procedures on a large panel of analog instruments.\n hidden: true\n name: window\n - aliases:\n - cockpit\n description:\n - text: The cramped cockpit is surrounded by buttons, swiches, dials, and analog gauges. The parts are a mix of technologies from the last century. Part of the panel is obscured by a draped cloth as if to hide it from view. Odd.\n hidden: true\n name: instrument panel\n - aliases: []\n description:\n - text: That's the guy who took you from the Passenger Barge Denali down here to Vesta. A middle-aged man in a neat white jumpsuit with a matching white sort of conductor's hat. He's following a written procedure checklist and seems to take his job seriously.\n hidden: false\n name: pilot\non_enter:\n - broadcast: \"\"\n broadcast_global: \"\"\n condition:\n all_of: []\n any_of: []\n flag: \"\"\n has_item: \"\"\n min_credits: 0\n not: true\n player_flag: 1001_welcome\n value: null\n delay: 5\n despawn_mob: \"\"\n give_item: \"\"\n heal: 0\n message: '{0B bold}Welcome to The House of Icarus{/}'\n set_flags: {}\n set_player_flags: {}\n spawn_mob: null\n take_item: \"\"\n teleport: 0\n - broadcast: \"\"\n broadcast_global: \"\"\n condition:\n all_of: []\n any_of: []\n flag: \"\"\n has_item: \"\"\n min_credits: 0\n not: true\n player_flag: 1001_welcome\n value: null\n delay: 7\n despawn_mob: \"\"\n give_item: \"\"\n heal: 0\n message: '{0B}Type{/} {0A}look sign{/} {0B}or{/} {0A}talk attendant{/} {0B}to get started{/}'\n set_flags: {}\n set_player_flags:\n 1001_welcome: true\n spawn_mob: null\n take_item: \"\"\n teleport: 0\n - broadcast: \"\"\n broadcast_global: \"\"\n condition:\n all_of: []\n any_of: []\n flag: \"\"\n has_item: \"\"\n min_credits: 0\n not: true\n player_flag: 1001_welcome\n value: null\n delay: 7\n despawn_mob: \"\"\n give_item: \"\"\n heal: 0\n message: '{0B}Type{/} {0A}help newplayer{/} {0B}for the new player''s guide. That''s it. Explore and have fun.{/}'\n set_flags: {}\n set_player_flags: {}\n spawn_mob: null\n take_item: \"\"\n teleport: 0\ntriggers:\n - id: \"\"\n on_flag: \"\"\n on_player_flag: 1001_look_sign\n room: 0\n steps:\n - broadcast: \"\"\n broadcast_global: \"\"\n delay: 5\n despawn_mob: \"\"\n give_item: \"\"\n heal: 0\n message: The cabin shakes as the small craft touches down\n set_flags: {}\n set_player_flags: {}\n spawn_mob: null\n take_item: \"\"\n teleport: 0\n - broadcast: \"\"\n broadcast_global: \"\"\n delay: 5\n despawn_mob: \"\"\n give_item: \"\"\n heal: 0\n message: The pistons hiss as the rear staircase opens\n set_flags: {}\n set_player_flags: {}\n spawn_mob: null\n take_item: \"\"\n teleport: 0\n - broadcast: \"\"\n broadcast_global: \"\"\n delay: 0\n despawn_mob: \"\"\n give_item: \"\"\n heal: 0\n message: \"\"\n set_flags: {}\n set_player_flags:\n 1001_touchdown: true\n spawn_mob: null\n take_item: \"\"\n teleport: 0\n value: null\n","is_delete":false,"is_create":false},{"time":"2026-06-30T15:05:43-04:00","description":"update room 1001","file_path":"data/rooms/intro/1001.yaml","old_content":"block_transport: true\ncolor: \"\"\ndescription:\n - text: |-\n A dim, windowless shuttle interior with a few uncomfortable rows of steel seats facing forward. A large framed sign hangs next to the closed cockpit door. The piston-powered staircase is firmly closed at the rear of the craft.\n\n A dim, windowless shuttle interior with a few uncomfortable rows of steel seats facing forward. A large {11}framed sign{/} hangs next to the closed cockpit door. A piston-powered staircase leads down out the back of the small craft with a smiling attendant ready to help disembark.\nexits:\n down:\n blocked_message: The piston-powered staircase is firmly closed.\n condition:\n all_of: []\n any_of: []\n flag: \"\"\n has_item: \"\"\n min_credits: 0\n not: false\n player_flag: 1001_touchdown\n value: null\n room: 1002\n east:\n room: 2001\nhazard: \"\"\nid: 1001\nitem_spawns: []\nmobs:\n - id: flight_attendant\nname: Inside Transport Shuttle\nobjects:\n - description:\n - text: \"We hope you enjoy your trip on our shuttle! Your pilot is [TYLER].\\n\\nWhen you arrive at your final destination, please be aware of the following basic commands:\\n\\n{0B bold}Movement:{/} {0A}north{/}, {0A}south{/}, {0A}east{/}, {0A}west{/}, {0A}up{/}, {0A}down{/}\\n{0B bold}Look:{/} {0A}look{/}, {0A}look \u003citem/object/mob\u003e{/}, and {0A}map{/}\\n{0B bold}Items:{/} {0A}inv{/} to see your 28-slot inventory\\n {0A}get \u003citem\u003e{/}, {0A}drop \u003citem\u003e{/}, {0A}wear \u003citem\u003e{/}, {0A}remove \u003citem\u003e{/}\\n {0A}use \u003citem\u003e on \u003citem/object\u003e{/}\\n {0A}eq{/} for equiped gear\\n{0B bold}Comms:{/} {0A}talk \u003cmob\u003e{/} for NPC chat\\n {0A}say \u003cmsg\u003e{/} and {0A}global \u003cmsg\u003e{/} for human chat\\n{0B bold}Character:{/} {0A}score{/} and {0A}skills{/} for stats. \\n{0B bold}Combat{/} {0A}attack \u003cmob\u003e{/}\\n{0B bold}Skills{/} Many skills have shortcuts like {0A}mine{/}, {0A}fish{/}, or {0A}chop{/}\\n{0B bold}Options{/} {0A}options{/} for a list of account options\\n {0A}options \u003copt\u003e \u003cvalue\u003e{/} to change an option\\n\\nType {0C bold}what{/} for a list of possible common actions\\n\\nMake sure to check the {0A}help{/} pages, especially {0A}help newplayer{/}!\"\n hidden: true\n name: framed sign\n on_look:\n aps_node: false\n assign_task: false\n cost: 0\n extend_task: false\n give_item: \"\"\n heal: 0\n reputation_cost: 0\n sawmill: false\n set_flags: {}\n set_player_flags:\n 1001_look_sign: true\n shop: null\n skip_task: false\n take_item: \"\"\n teleport: 0\n - description:\n - text: A sturdy, locked steel door that keeps passengers out of the cockpit. There is a tiny, thin window at eye level.\n hidden: true\n name: door\n - description:\n - text: A thick trim with rounded bolt heads frames the tiny window. It looks like it was cut into the door at some point, potentially as a simple replacement to computerized security systems. Inside the cockpit there's a pilot finishing up landing procedures on a large panel of analog instruments.\n hidden: true\n name: window\n - aliases:\n - cockpit\n description:\n - text: The cramped cockpit is surrounded by buttons, swiches, dials, and analog gauges. The parts are a mix of technologies from the last century. Part of the panel is obscured by a draped cloth as if to hide it from view. Odd.\n hidden: true\n name: instrument panel\n - aliases: []\n description:\n - text: That's the guy who took you from the Passenger Barge Denali down here to Vesta. A middle-aged man in a neat white jumpsuit with a matching white sort of conductor's hat. He's following a written procedure checklist and seems to take his job seriously.\n hidden: false\n name: pilot\non_enter:\n - broadcast: \"\"\n broadcast_global: \"\"\n condition:\n all_of: []\n any_of: []\n flag: \"\"\n has_item: \"\"\n min_credits: 0\n not: true\n player_flag: 1001_welcome\n value: null\n delay: 5\n despawn_mob: \"\"\n give_item: \"\"\n heal: 0\n message: '{0B bold}Welcome to The House of Icarus{/}'\n set_flags: {}\n set_player_flags: {}\n spawn_mob: null\n take_item: \"\"\n teleport: 0\n - broadcast: \"\"\n broadcast_global: \"\"\n condition:\n all_of: []\n any_of: []\n flag: \"\"\n has_item: \"\"\n min_credits: 0\n not: true\n player_flag: 1001_welcome\n value: null\n delay: 7\n despawn_mob: \"\"\n give_item: \"\"\n heal: 0\n message: '{0B}Type{/} {0A}look sign{/} {0B}or{/} {0A}talk attendant{/} {0B}to get started{/}'\n set_flags: {}\n set_player_flags:\n 1001_welcome: true\n spawn_mob: null\n take_item: \"\"\n teleport: 0\n - broadcast: \"\"\n broadcast_global: \"\"\n condition:\n all_of: []\n any_of: []\n flag: \"\"\n has_item: \"\"\n min_credits: 0\n not: true\n player_flag: 1001_welcome\n value: null\n delay: 7\n despawn_mob: \"\"\n give_item: \"\"\n heal: 0\n message: '{0B}Type{/} {0A}help newplayer{/} {0B}for the new player''s guide. That''s it. Explore and have fun.{/}'\n set_flags: {}\n set_player_flags: {}\n spawn_mob: null\n take_item: \"\"\n teleport: 0\ntriggers:\n - id: \"\"\n on_flag: \"\"\n on_player_flag: 1001_look_sign\n room: 0\n steps:\n - broadcast: \"\"\n broadcast_global: \"\"\n delay: 5\n despawn_mob: \"\"\n give_item: \"\"\n heal: 0\n message: The cabin shakes as the small craft touches down\n set_flags: {}\n set_player_flags: {}\n spawn_mob: null\n take_item: \"\"\n teleport: 0\n - broadcast: \"\"\n broadcast_global: \"\"\n delay: 5\n despawn_mob: \"\"\n give_item: \"\"\n heal: 0\n message: The pistons hiss as the rear staircase opens\n set_flags: {}\n set_player_flags: {}\n spawn_mob: null\n take_item: \"\"\n teleport: 0\n - broadcast: \"\"\n broadcast_global: \"\"\n delay: 0\n despawn_mob: \"\"\n give_item: \"\"\n heal: 0\n message: \"\"\n set_flags: {}\n set_player_flags:\n 1001_touchdown: true\n spawn_mob: null\n take_item: \"\"\n teleport: 0\n value: null\n","new_content":"block_transport: true\ncolor: \"\"\ndescription:\n - text: |-\n A dim, windowless shuttle interior with a few uncomfortable rows of steel seats facing forward. A large framed sign hangs next to the closed cockpit door. The piston-powered staircase is firmly closed at the rear of the craft.\n\n A dim, windowless shuttle interior with a few uncomfortable rows of steel seats facing forward. A large {11}framed sign{/} hangs next to the closed cockpit door. A piston-powered staircase leads down out the back of the small craft with a smiling attendant ready to help disembark.\nexits:\n down:\n blocked_message: The piston-powered staircase is firmly closed.\n condition:\n all_of: []\n any_of: []\n flag: \"\"\n has_item: \"\"\n min_credits: 0\n not: false\n player_flag: 1001_touchdown\n value: null\n room: 1002\n east:\n room: 2001\nhazard: \"\"\nid: 1001\nitem_spawns: []\nmobs:\n - id: flight_attendant\nname: Inside Transport Shuttle\nobjects:\n - description:\n - text: \"We hope you enjoy your trip on our shuttle! Your pilot is [TYLER].\\n\\nWhen you arrive at your final destination, please be aware of the following basic commands:\\n\\n{0B bold}Movement:{/} {0A}north{/}, {0A}south{/}, {0A}east{/}, {0A}west{/}, {0A}up{/}, {0A}down{/}\\n{0B bold}Look:{/} {0A}look{/}, {0A}look \u003citem/object/mob\u003e{/}, and {0A}map{/}\\n{0B bold}Items:{/} {0A}inv{/} to see your 28-slot inventory\\n {0A}get \u003citem\u003e{/}, {0A}drop \u003citem\u003e{/}, {0A}wear \u003citem\u003e{/}, {0A}remove \u003citem\u003e{/}\\n {0A}use \u003citem\u003e on \u003citem/object\u003e{/}\\n {0A}eq{/} for equiped gear\\n{0B bold}Comms:{/} {0A}talk \u003cmob\u003e{/} for NPC chat\\n {0A}say \u003cmsg\u003e{/} and {0A}global \u003cmsg\u003e{/} for human chat\\n{0B bold}Character:{/} {0A}score{/} and {0A}skills{/} for stats. \\n{0B bold}Combat{/} {0A}attack \u003cmob\u003e{/}\\n{0B bold}Skills{/} Many skills have shortcuts like {0A}mine{/}, {0A}fish{/}, or {0A}chop{/}\\n{0B bold}Options{/} {0A}options{/} for a list of account options\\n {0A}options \u003copt\u003e \u003cvalue\u003e{/} to change an option\\n\\nType {0C bold}what{/} for a list of possible common actions\\n\\nMake sure to check the {0A}help{/} pages, especially {0A}help newplayer{/}!\"\n hidden: true\n name: framed sign\n on_look:\n aps_node: false\n assign_task: false\n cost: 0\n extend_task: false\n give_item: \"\"\n heal: 0\n reputation_cost: 0\n sawmill: false\n set_flags: {}\n set_player_flags:\n 1001_look_sign: true\n shop: null\n skip_task: false\n take_item: \"\"\n teleport: 0\n - description:\n - text: A sturdy, locked steel door that keeps passengers out of the cockpit. There is a tiny, thin window at eye level.\n hidden: true\n name: door\n - description:\n - text: A thick trim with rounded bolt heads frames the tiny window. It looks like it was cut into the door at some point, potentially as a simple replacement to computerized security systems. Inside the cockpit there's a pilot finishing up landing procedures on a large panel of analog instruments.\n hidden: true\n name: window\n - aliases:\n - cockpit\n description:\n - text: The cramped cockpit is surrounded by buttons, swiches, dials, and analog gauges. The parts are a mix of technologies from the last century. Part of the panel is obscured by a draped cloth as if to hide it from view. Odd.\n hidden: true\n name: instrument panel\n - aliases: []\n description:\n - text: That's the guy who took you from the Passenger Barge Denali down here to Vesta. A middle-aged man in a neat white jumpsuit with a matching white sort of conductor's hat. He's following a written procedure checklist and seems to take his job seriously.\n hidden: true\n name: pilot\non_enter:\n - broadcast: \"\"\n broadcast_global: \"\"\n condition:\n all_of: []\n any_of: []\n flag: \"\"\n has_item: \"\"\n min_credits: 0\n not: true\n player_flag: 1001_welcome\n value: null\n delay: 5\n despawn_mob: \"\"\n give_item: \"\"\n heal: 0\n message: '{0B bold}Welcome to The House of Icarus{/}'\n set_flags: {}\n set_player_flags: {}\n spawn_mob: null\n take_item: \"\"\n teleport: 0\n - broadcast: \"\"\n broadcast_global: \"\"\n condition:\n all_of: []\n any_of: []\n flag: \"\"\n has_item: \"\"\n min_credits: 0\n not: true\n player_flag: 1001_welcome\n value: null\n delay: 7\n despawn_mob: \"\"\n give_item: \"\"\n heal: 0\n message: '{0B}Type{/} {0A}look sign{/} {0B}or{/} {0A}talk attendant{/} {0B}to get started{/}'\n set_flags: {}\n set_player_flags:\n 1001_welcome: true\n spawn_mob: null\n take_item: \"\"\n teleport: 0\n - broadcast: \"\"\n broadcast_global: \"\"\n condition:\n all_of: []\n any_of: []\n flag: \"\"\n has_item: \"\"\n min_credits: 0\n not: true\n player_flag: 1001_welcome\n value: null\n delay: 7\n despawn_mob: \"\"\n give_item: \"\"\n heal: 0\n message: '{0B}Type{/} {0A}help newplayer{/} {0B}for the new player''s guide. That''s it. Explore and have fun.{/}'\n set_flags: {}\n set_player_flags: {}\n spawn_mob: null\n take_item: \"\"\n teleport: 0\ntriggers:\n - id: \"\"\n on_flag: \"\"\n on_player_flag: 1001_look_sign\n room: 0\n steps:\n - broadcast: \"\"\n broadcast_global: \"\"\n delay: 5\n despawn_mob: \"\"\n give_item: \"\"\n heal: 0\n message: The cabin shakes as the small craft touches down\n set_flags: {}\n set_player_flags: {}\n spawn_mob: null\n take_item: \"\"\n teleport: 0\n - broadcast: \"\"\n broadcast_global: \"\"\n delay: 5\n despawn_mob: \"\"\n give_item: \"\"\n heal: 0\n message: The pistons hiss as the rear staircase opens\n set_flags: {}\n set_player_flags: {}\n spawn_mob: null\n take_item: \"\"\n teleport: 0\n - broadcast: \"\"\n broadcast_global: \"\"\n delay: 0\n despawn_mob: \"\"\n give_item: \"\"\n heal: 0\n message: \"\"\n set_flags: {}\n set_player_flags:\n 1001_touchdown: true\n spawn_mob: null\n take_item: \"\"\n teleport: 0\n value: null\n","is_delete":false,"is_create":false},{"time":"2026-06-30T16:34:21-04:00","description":"update room 2001","file_path":"data/rooms/intro/2001.yaml","old_content":"block_transport: false\ncolor: \"\"\ndescription:\n - text: It's a test room\nexits:\n east:\n room: 2002\n south:\n room: 2006\n southeast:\n room: 2005\n west:\n room: 1001\nhazard: \"\"\nid: 2001\nitem_spawns: []\nmobs: []\nname: Test Room\nobjects: []\non_enter: []\ntriggers: []\n","new_content":"block_transport: false\ncolor: \"\"\ndescription:\n - text: It's a test room\nexits:\n east:\n room: 2002\n south:\n room: 2006\n southeast:\n room: 2005\n west:\n room: 1001\nhazard: \"\"\nid: 2001\nitem_spawns: []\nmobs: []\nname: Test Room\nobjects:\n - id: tree\non_enter: []\ntriggers: []\n","is_delete":false,"is_create":false},{"time":"2026-06-30T16:35:02-04:00","description":"update room 2001","file_path":"data/rooms/intro/2001.yaml","old_content":"block_transport: false\ncolor: \"\"\ndescription:\n - text: It's a test room\nexits:\n east:\n room: 2002\n south:\n room: 2006\n southeast:\n room: 2005\n west:\n room: 1001\nhazard: \"\"\nid: 2001\nitem_spawns: []\nmobs: []\nname: Test Room\nobjects:\n - id: tree\non_enter: []\ntriggers: []\n","new_content":"block_transport: false\ncolor: \"\"\ndescription:\n - text: It's a test room\nexits:\n east:\n room: 2002\n south:\n room: 2006\n southeast:\n room: 2005\n west:\n room: 1001\nhazard: \"\"\nid: 2001\nitem_spawns:\n - id: bronze_axe\n quantity: 1\n respawn_ticks: 0\nmobs: []\nname: Test Room\nobjects:\n - id: tree\non_enter: []\ntriggers: []\n","is_delete":false,"is_create":false},{"time":"2026-06-30T16:35:15-04:00","description":"update room 2001","file_path":"data/rooms/intro/2001.yaml","old_content":"block_transport: false\ncolor: \"\"\ndescription:\n - text: It's a test room\nexits:\n east:\n room: 2002\n south:\n room: 2006\n southeast:\n room: 2005\n west:\n room: 1001\nhazard: \"\"\nid: 2001\nitem_spawns:\n - id: bronze_axe\n quantity: 1\n respawn_ticks: 0\nmobs: []\nname: Test Room\nobjects:\n - id: tree\non_enter: []\ntriggers: []\n","new_content":"block_transport: false\ncolor: \"\"\ndescription:\n - text: It's a test room\nexits:\n east:\n room: 2002\n south:\n room: 2006\n southeast:\n room: 2005\n west:\n room: 1001\nhazard: \"\"\nid: 2001\nitem_spawns:\n - id: bronze_axe\n quantity: 1\n respawn_ticks: 1\nmobs: []\nname: Test Room\nobjects:\n - id: tree\non_enter: []\ntriggers: []\n","is_delete":false,"is_create":false},{"time":"2026-06-30T17:43:28-04:00","description":"Update object copper_rock","file_path":"data/objects/copper_rock.yaml","old_content":"color: \"B2\"\ngather:\n depleted_message: You don't see any ore in this rock.\n drops:\n - depletes: true\n item_id: copper_ore\n level: 1\n message: You manage to mine some {B2}copper ore{/}.\n weight: 90\n xp: 17\n - depletes: false\n message: You spot a glint of something valuable!\n table: gem_table\n weight: 10\n fail_message: You chip away but get nothing useful.\n gather_message: You swing your pickaxe at the rock...\n respawn_broadcast: A glint of copper catches your eye from some {name}.\n respawn_timer: 50\n skill: mining\n success:\n base: 0.5\n cap: 0.95\n per_level: 0.01\n tools:\n - pickaxe\nname: copper rock\n","new_content":"aliases: []\ncolor: B2\ndescription: \"\"\ngather:\n bait: \"\"\n deplete_timer: 0\n depleted_message: You don't see any ore in this rock.\n drops:\n - depletes: true\n item_id: copper_ore\n level: 1\n message: You manage to mine some {B2}copper ore{/}.\n quantity: 0\n table: \"\"\n weight: 90\n xp: 17\n - depletes: false\n item_id: \"\"\n level: 0\n message: You spot a glint of something valuable!\n quantity: 0\n table: gem_table\n weight: 10\n xp: 0\n exhausted_message: \"\"\n fail_message: You chip away but get nothing useful.\n gather_message: You swing your pickaxe at the rock...\n nest_chance: 0\n respawn_broadcast: A glint of copper catches your eye from some {name}.\n respawn_timer: 50\n skill: mining\n success:\n base: 0.5\n cap: 0.95\n per_level: 0.01\n tools:\n - pickaxe\nhidden: false\nid: copper_rock\ninroom_description: \"\"\nname: copper rock\nremoval_item: \"\"\n","is_delete":false,"is_create":false},{"time":"2026-06-30T17:43:45-04:00","description":"Update object copper_rock","file_path":"data/objects/copper_rock.yaml","old_content":"aliases: []\ncolor: B2\ndescription: \"\"\ngather:\n bait: \"\"\n deplete_timer: 0\n depleted_message: You don't see any ore in this rock.\n drops:\n - depletes: true\n item_id: copper_ore\n level: 1\n message: You manage to mine some {B2}copper ore{/}.\n quantity: 0\n table: \"\"\n weight: 90\n xp: 17\n - depletes: false\n item_id: \"\"\n level: 0\n message: You spot a glint of something valuable!\n quantity: 0\n table: gem_table\n weight: 10\n xp: 0\n exhausted_message: \"\"\n fail_message: You chip away but get nothing useful.\n gather_message: You swing your pickaxe at the rock...\n nest_chance: 0\n respawn_broadcast: A glint of copper catches your eye from some {name}.\n respawn_timer: 50\n skill: mining\n success:\n base: 0.5\n cap: 0.95\n per_level: 0.01\n tools:\n - pickaxe\nhidden: false\nid: copper_rock\ninroom_description: \"\"\nname: copper rock\nremoval_item: \"\"\n","new_content":"aliases: []\ncolor: B2\ndescription: \"\"\ngather:\n bait: \"\"\n deplete_timer: 0\n depleted_message: You don't see any ore in this rock.\n drops:\n - depletes: true\n item_id: copper_ore\n level: 1\n message: You manage to mine some {B2}copper ore{/}.\n quantity: 0\n table: \"\"\n weight: 90\n xp: 17\n - depletes: false\n item_id: \"\"\n level: 0\n message: You spot a glint of something valuable!\n quantity: 0\n table: gem_table\n weight: 10\n xp: 0\n exhausted_message: \"\"\n fail_message: You chip away but get nothing useful.\n gather_message: You swing your pickaxe at the rock...\n nest_chance: 0\n respawn_broadcast: A glint of copper catches your eye from some {name}.\n respawn_timer: 50\n skill: mining\n success:\n base: 0.55\n cap: 0.95\n per_level: 0.01\n tools:\n - pickaxe\nhidden: false\nid: copper_rock\ninroom_description: \"\"\nname: copper rock\nremoval_item: \"\"\n","is_delete":false,"is_create":false},{"time":"2026-06-30T17:43:55-04:00","description":"Update object copper_rock","file_path":"data/objects/copper_rock.yaml","old_content":"aliases: []\ncolor: B2\ndescription: \"\"\ngather:\n bait: \"\"\n deplete_timer: 0\n depleted_message: You don't see any ore in this rock.\n drops:\n - depletes: true\n item_id: copper_ore\n level: 1\n message: You manage to mine some {B2}copper ore{/}.\n quantity: 0\n table: \"\"\n weight: 90\n xp: 17\n - depletes: false\n item_id: \"\"\n level: 0\n message: You spot a glint of something valuable!\n quantity: 0\n table: gem_table\n weight: 10\n xp: 0\n exhausted_message: \"\"\n fail_message: You chip away but get nothing useful.\n gather_message: You swing your pickaxe at the rock...\n nest_chance: 0\n respawn_broadcast: A glint of copper catches your eye from some {name}.\n respawn_timer: 50\n skill: mining\n success:\n base: 0.55\n cap: 0.95\n per_level: 0.01\n tools:\n - pickaxe\nhidden: false\nid: copper_rock\ninroom_description: \"\"\nname: copper rock\nremoval_item: \"\"\n","new_content":"aliases: []\ncolor: B2\ndescription: \"\"\ngather:\n bait: \"\"\n deplete_timer: 0\n depleted_message: You don't see any ore in this rock.\n drops:\n - depletes: true\n item_id: copper_ore\n level: 1\n message: You manage to mine some {B2}copper ore{/}.\n quantity: 0\n table: \"\"\n weight: 90\n xp: 17\n - depletes: false\n item_id: \"\"\n level: 0\n message: You spot a glint of something valuable!\n quantity: 0\n table: gem_table\n weight: 10\n xp: 0\n exhausted_message: \"\"\n fail_message: You chip away but get nothing useful.\n gather_message: You swing your pickaxe at the rock...\n nest_chance: 0\n respawn_broadcast: A glint of copper catches your eye from some {name}.\n respawn_timer: 50\n skill: mining\n success:\n base: 0.5\n cap: 0.95\n per_level: 0.01\n tools:\n - pickaxe\nhidden: false\nid: copper_rock\ninroom_description: \"\"\nname: copper rock\nremoval_item: \"\"\n","is_delete":false,"is_create":false},{"time":"2026-06-30T17:45:35-04:00","description":"Update object copper_rock","file_path":"data/objects/copper_rock.yaml","old_content":"aliases: []\ncolor: B2\ndescription: \"\"\ngather:\n bait: \"\"\n deplete_timer: 0\n depleted_message: You don't see any ore in this rock.\n drops:\n - depletes: true\n item_id: copper_ore\n level: 1\n message: You manage to mine some {B2}copper ore{/}.\n quantity: 0\n table: \"\"\n weight: 90\n xp: 17\n - depletes: false\n item_id: \"\"\n level: 0\n message: You spot a glint of something valuable!\n quantity: 0\n table: gem_table\n weight: 10\n xp: 0\n exhausted_message: \"\"\n fail_message: You chip away but get nothing useful.\n gather_message: You swing your pickaxe at the rock...\n nest_chance: 0\n respawn_broadcast: A glint of copper catches your eye from some {name}.\n respawn_timer: 50\n skill: mining\n success:\n base: 0.5\n cap: 0.95\n per_level: 0.01\n tools:\n - pickaxe\nhidden: false\nid: copper_rock\ninroom_description: \"\"\nname: copper rock\nremoval_item: \"\"\n","new_content":"aliases: []\ncolor: B2\ndescription: \"\"\ngather:\n bait: \"\"\n deplete_timer: 0\n depleted_message: You don't see any ore in this rock.\n drops:\n - depletes: true\n item_id: copper_ore\n level: 1\n message: You manage to mine some {B2}copper ore{/}.\n quantity: 0\n table: \"\"\n weight: 90\n xp: 17\n - depletes: false\n item_id: \"\"\n level: 0\n message: You spot a glint of something valuable!\n quantity: 0\n table: gem_table\n weight: 10\n xp: 0\n exhausted_message: \"\"\n fail_message: You chip away but get nothing useful.\n gather_message: You swing your pickaxe at the rock...\n nest_chance: 0\n respawn_broadcast: A glint of copper catches your eye from some {name}.\n respawn_timer: 50\n skill: mining\n success:\n base: 0.55\n cap: 0.95\n per_level: 0.01\n tools:\n - pickaxe\nhidden: false\nid: copper_rock\ninroom_description: \"\"\nname: copper rock\nremoval_item: \"\"\n","is_delete":false,"is_create":false},{"time":"2026-06-30T17:45:40-04:00","description":"Update object copper_rock","file_path":"data/objects/copper_rock.yaml","old_content":"aliases: []\ncolor: B2\ndescription: \"\"\ngather:\n bait: \"\"\n deplete_timer: 0\n depleted_message: You don't see any ore in this rock.\n drops:\n - depletes: true\n item_id: copper_ore\n level: 1\n message: You manage to mine some {B2}copper ore{/}.\n quantity: 0\n table: \"\"\n weight: 90\n xp: 17\n - depletes: false\n item_id: \"\"\n level: 0\n message: You spot a glint of something valuable!\n quantity: 0\n table: gem_table\n weight: 10\n xp: 0\n exhausted_message: \"\"\n fail_message: You chip away but get nothing useful.\n gather_message: You swing your pickaxe at the rock...\n nest_chance: 0\n respawn_broadcast: A glint of copper catches your eye from some {name}.\n respawn_timer: 50\n skill: mining\n success:\n base: 0.55\n cap: 0.95\n per_level: 0.01\n tools:\n - pickaxe\nhidden: false\nid: copper_rock\ninroom_description: \"\"\nname: copper rock\nremoval_item: \"\"\n","new_content":"aliases: []\ncolor: B2\ndescription: \"\"\ngather:\n bait: \"\"\n deplete_timer: 0\n depleted_message: You don't see any ore in this rock.\n drops:\n - depletes: true\n item_id: copper_ore\n level: 1\n message: You manage to mine some {B2}copper ore{/}.\n quantity: 0\n table: \"\"\n weight: 90\n xp: 17\n - depletes: false\n item_id: \"\"\n level: 0\n message: You spot a glint of something valuable!\n quantity: 0\n table: gem_table\n weight: 10\n xp: 0\n exhausted_message: \"\"\n fail_message: You chip away but get nothing useful.\n gather_message: You swing your pickaxe at the rock...\n nest_chance: 0\n respawn_broadcast: A glint of copper catches your eye from some {name}.\n respawn_timer: 50\n skill: mining\n success:\n base: 0.5\n cap: 0.95\n per_level: 0.01\n tools:\n - pickaxe\nhidden: false\nid: copper_rock\ninroom_description: \"\"\nname: copper rock\nremoval_item: \"\"\n","is_delete":false,"is_create":false},{"time":"2026-06-30T17:57:25-04:00","description":"Update object copper_rock","file_path":"data/objects/copper_rock.yaml","old_content":"aliases: []\ncolor: B2\ndescription: \"\"\ngather:\n bait: \"\"\n deplete_timer: 0\n depleted_message: You don't see any ore in this rock.\n drops:\n - depletes: true\n item_id: copper_ore\n level: 1\n message: You manage to mine some {B2}copper ore{/}.\n quantity: 0\n table: \"\"\n weight: 90\n xp: 17\n - depletes: false\n item_id: \"\"\n level: 0\n message: You spot a glint of something valuable!\n quantity: 0\n table: gem_table\n weight: 10\n xp: 0\n exhausted_message: \"\"\n fail_message: You chip away but get nothing useful.\n gather_message: You swing your pickaxe at the rock...\n nest_chance: 0\n respawn_broadcast: A glint of copper catches your eye from some {name}.\n respawn_timer: 50\n skill: mining\n success:\n base: 0.5\n cap: 0.95\n per_level: 0.01\n tools:\n - pickaxe\nhidden: false\nid: copper_rock\ninroom_description: \"\"\nname: copper rock\nremoval_item: \"\"\n","new_content":"aliases: []\ncolor: B2\ndescription: \"\"\ngather:\n bait: \"\"\n deplete_timer: 0\n depleted_message: You don't see any ore in this rock.\n drops:\n - depletes: true\n item_id: copper_ore\n level: 1\n message: You manage to mine some {B2}copper ore{/}.\n quantity: 0\n table: \"\"\n weight: 90\n xp: 17\n - depletes: false\n item_id: \"\"\n level: 0\n message: You spot a glint of something valuable!\n quantity: 0\n table: gem_table\n weight: 10\n xp: 0\n exhausted_message: \"\"\n fail_message: You chip away but get nothing useful.\n gather_message: You swing your pickaxe at the rock...\n nest_chance: 0\n respawn_broadcast: A glint of copper catches your eye from some {name}.\n respawn_timer: 50\n skill: woodcutting\n success:\n base: 0.5\n cap: 0.95\n per_level: 0.01\n tools:\n - pickaxe\nhidden: false\nid: copper_rock\ninroom_description: \"\"\nname: copper rock\nremoval_item: \"\"\n","is_delete":false,"is_create":false},{"time":"2026-06-30T18:11:31-04:00","description":"Update object copper_rock","file_path":"data/objects/copper_rock.yaml","old_content":"aliases: []\ncolor: B2\ndescription: \"\"\ngather:\n bait: \"\"\n deplete_timer: 0\n depleted_message: You don't see any ore in this rock.\n drops:\n - depletes: true\n item_id: copper_ore\n level: 1\n message: You manage to mine some {B2}copper ore{/}.\n quantity: 0\n table: \"\"\n weight: 90\n xp: 17\n - depletes: false\n item_id: \"\"\n level: 0\n message: You spot a glint of something valuable!\n quantity: 0\n table: gem_table\n weight: 10\n xp: 0\n exhausted_message: \"\"\n fail_message: You chip away but get nothing useful.\n gather_message: You swing your pickaxe at the rock...\n nest_chance: 0\n respawn_broadcast: A glint of copper catches your eye from some {name}.\n respawn_timer: 50\n skill: woodcutting\n success:\n base: 0.5\n cap: 0.95\n per_level: 0.01\n tools:\n - pickaxe\nhidden: false\nid: copper_rock\ninroom_description: \"\"\nname: copper rock\nremoval_item: \"\"\n","new_content":"aliases: []\ncolor: B2\ndescription: \"\"\ngather:\n bait: \"\"\n deplete_timer: 0\n depleted_message: You don't see any ore in this rock.\n drops:\n - depletes: true\n item_id: copper_ore\n level: 1\n message: You manage to mine some {B2}copper ore{/}.\n quantity: 0\n table: \"\"\n weight: 90\n xp: 17\n - depletes: false\n item_id: \"\"\n level: 0\n message: You spot a glint of something valuable!\n quantity: 0\n table: gem_table\n weight: 10\n xp: 0\n exhausted_message: \"\"\n fail_message: You chip away but get nothing useful.\n gather_message: You swing your pickaxe at the rock...\n nest_chance: 0\n respawn_broadcast: A glint of copper catches your eye from some {name}.\n respawn_timer: 50\n skill: mining\n success:\n base: 0.5\n cap: 0.95\n per_level: 0.01\n tools:\n - pickaxe\nhidden: false\nid: copper_rock\ninroom_description: \"\"\nname: copper rock\nremoval_item: \"\"\n","is_delete":false,"is_create":false},{"time":"2026-06-30T18:11:34-04:00","description":"Create object copper_rock_copy","file_path":"data/objects/copper_rock_copy.yaml","old_content":"","new_content":"id: copper_rock_copy\n","is_delete":false,"is_create":true},{"time":"2026-06-30T18:11:34-04:00","description":"Update object copper_rock_copy","file_path":"data/objects/copper_rock_copy.yaml","old_content":"id: copper_rock_copy\n","new_content":"aliases: []\ncolor: B2\ndescription: \"\"\ngather:\n bait: \"\"\n deplete_timer: 0\n depleted_message: You don't see any ore in this rock.\n drops:\n - depletes: true\n item_id: copper_ore\n level: 1\n message: You manage to mine some {B2}copper ore{/}.\n quantity: 0\n table: \"\"\n weight: 90\n xp: 17\n - depletes: false\n item_id: \"\"\n level: 0\n message: You spot a glint of something valuable!\n quantity: 0\n table: gem_table\n weight: 10\n xp: 0\n exhausted_message: \"\"\n fail_message: You chip away but get nothing useful.\n gather_message: You swing your pickaxe at the rock...\n nest_chance: 0\n respawn_broadcast: A glint of copper catches your eye from some {name}.\n respawn_timer: 50\n skill: woodcutting\n success:\n base: 0.5\n cap: 0.95\n per_level: 0.01\n tools:\n - pickaxe\nhidden: false\nid: copper_rock_copy\ninroom_description: \"\"\nname: copper rock\nremoval_item: \"\"\n","is_delete":false,"is_create":false},{"time":"2026-06-30T18:11:39-04:00","description":"Delete object copper_rock_copy","file_path":"data/objects/copper_rock_copy.yaml","old_content":"aliases: []\ncolor: B2\ndescription: \"\"\ngather:\n bait: \"\"\n deplete_timer: 0\n depleted_message: You don't see any ore in this rock.\n drops:\n - depletes: true\n item_id: copper_ore\n level: 1\n message: You manage to mine some {B2}copper ore{/}.\n quantity: 0\n table: \"\"\n weight: 90\n xp: 17\n - depletes: false\n item_id: \"\"\n level: 0\n message: You spot a glint of something valuable!\n quantity: 0\n table: gem_table\n weight: 10\n xp: 0\n exhausted_message: \"\"\n fail_message: You chip away but get nothing useful.\n gather_message: You swing your pickaxe at the rock...\n nest_chance: 0\n respawn_broadcast: A glint of copper catches your eye from some {name}.\n respawn_timer: 50\n skill: woodcutting\n success:\n base: 0.5\n cap: 0.95\n per_level: 0.01\n tools:\n - pickaxe\nhidden: false\nid: copper_rock_copy\ninroom_description: \"\"\nname: copper rock\nremoval_item: \"\"\n","new_content":"","is_delete":true,"is_create":false}],"redo":null}
\ No newline at end of file +{"history":[{"time":"2026-06-30T14:29:37-04:00","description":"delete room 1014 (cleaned 0 exits)","file_path":"data/rooms/intro/1014.yaml","old_content":"id: 1014\nname: 'Room #1014'\ncolor: D5\ndescription: []\nexits:\n southwest:\n room: 1013\nobjects: []\nitem_spawns: []\nmobs: []\non_enter: []\nhazard: \"\"\nblock_transport: false\ntriggers: []\n","new_content":"","is_delete":true,"is_create":false},{"time":"2026-06-30T14:29:37-04:00","description":"delete room 1016 (cleaned 0 exits)","file_path":"data/rooms/intro/1016.yaml","old_content":"id: 1016\nname: New Room\ncolor: \"97\"\ndescription:\n - text: A featureless room.\nexits:\n down:\n room: 1017\n south:\n room: 1009\n southwest:\n room: 1005\nobjects: []\nitem_spawns: []\nmobs: []\non_enter: []\nhazard: \"\"\nblock_transport: false\ntriggers: []\n","new_content":"","is_delete":true,"is_create":false},{"time":"2026-06-30T14:29:38-04:00","description":"delete room 1015 (cleaned 0 exits)","file_path":"data/rooms/intro/1015.yaml","old_content":"id: 1015\nname: 'Room #1015'\ncolor: 0C\ndescription: []\nexits:\n northwest:\n room: 1018\nobjects: []\nitem_spawns: []\nmobs: []\non_enter: []\nhazard: \"\"\nblock_transport: false\ntriggers: []\n","new_content":"","is_delete":true,"is_create":false},{"time":"2026-06-30T14:29:39-04:00","description":"delete room 1017 (cleaned 0 exits)","file_path":"data/rooms/intro/1017.yaml","old_content":"id: 1017\nname: New Room\ncolor: \"\"\ndescription:\n - text: A featureless room.\nexits: {}\nobjects: []\nitem_spawns: []\nmobs: []\non_enter: []\nhazard: \"\"\nblock_transport: false\ntriggers: []\n","new_content":"","is_delete":true,"is_create":false},{"time":"2026-06-30T14:29:40-04:00","description":"delete room 1018 (cleaned 0 exits)","file_path":"data/rooms/intro/1018.yaml","old_content":"id: 1018\nname: 'Room #1018'\ncolor: D0\ndescription: []\nexits: {}\nobjects: []\nitem_spawns: []\nmobs: []\non_enter: []\nhazard: \"\"\nblock_transport: false\ntriggers: []\n","new_content":"","is_delete":true,"is_create":false},{"time":"2026-06-30T14:29:40-04:00","description":"delete room 1019 (cleaned 0 exits)","file_path":"data/rooms/intro/1019.yaml","old_content":"id: 1019\nname: 'Room #1019'\ncolor: \"\"\ndescription: []\nexits: {}\nobjects: []\nitem_spawns: []\nmobs: []\non_enter: []\nhazard: \"\"\nblock_transport: false\ntriggers: []\n","new_content":"","is_delete":true,"is_create":false},{"time":"2026-06-30T14:29:41-04:00","description":"delete room 1020 (cleaned 0 exits)","file_path":"data/rooms/intro/1020.yaml","old_content":"id: 1020\nname: 'Room #1020'\ncolor: \"\"\ndescription: []\nexits: {}\nobjects: []\nitem_spawns: []\nmobs: []\non_enter: []\nhazard: \"\"\nblock_transport: false\ntriggers: []\n","new_content":"","is_delete":true,"is_create":false},{"time":"2026-06-30T14:30:45-04:00","description":"delete room 1013 (cleaned 1 exits)","file_path":"data/rooms/intro/1013.yaml","old_content":"id: 1013\nname: 'Room #1013'\ncolor: \"72\"\ndescription: []\nexits:\n west:\n room: 1007\nobjects: []\nitem_spawns: []\nmobs: []\non_enter: []\nhazard: \"\"\nblock_transport: false\ntriggers: []\n","new_content":"","is_delete":true,"is_create":false},{"time":"2026-06-30T14:30:49-04:00","description":"delete room 1009 (cleaned 0 exits)","file_path":"data/rooms/intro/1009.yaml","old_content":"id: 1009\nname: New Room\ncolor: \"27\"\ndescription:\n - text: A featureless room.\nexits:\n northwest:\n room: 8\n southwest:\n room: 1006\n west:\n room: 1005\nobjects: []\nitem_spawns: []\nmobs:\n - id: man\n - id: man\non_enter: []\nhazard: \"\"\nblock_transport: false\ntriggers: []\n","new_content":"","is_delete":true,"is_create":false},{"time":"2026-06-30T14:30:51-04:00","description":"delete room 1007 (cleaned 1 exits)","file_path":"data/rooms/intro/1007.yaml","old_content":"id: 1007\nname: 'Room #1007'\ncolor: \"\"\ndescription: []\nexits:\n west:\n room: 2004\nobjects: []\nitem_spawns: []\nmobs: []\non_enter: []\nhazard: \"\"\nblock_transport: false\ntriggers: []\n","new_content":"","is_delete":true,"is_create":false},{"time":"2026-06-30T14:30:53-04:00","description":"delete room 1006 (cleaned 4 exits)","file_path":"data/rooms/intro/1006.yaml","old_content":"id: 1006\nname: New Room\ncolor: E2\ndescription:\n - text: A featureless room.\nexits:\n north:\n room: 1005\n northwest:\n room: 1008\n up:\n room: 1010\n west:\n room: 2003\nobjects: []\nitem_spawns: []\nmobs: []\non_enter: []\nhazard: \"\"\nblock_transport: false\ntriggers: []\n","new_content":"","is_delete":true,"is_create":false},{"time":"2026-06-30T14:30:59-04:00","description":"delete room 1010 (cleaned 1 exits)","file_path":"data/rooms/intro/1010.yaml","old_content":"id: 1010\nname: New Room\ncolor: \"\"\ndescription:\n - text: A featureless room.\nexits:\n north:\n room: 1011\nobjects: []\nitem_spawns: []\nmobs: []\non_enter: []\nhazard: \"\"\nblock_transport: false\ntriggers: []\n","new_content":"","is_delete":true,"is_create":false},{"time":"2026-06-30T14:31:00-04:00","description":"delete room 1011 (cleaned 0 exits)","file_path":"data/rooms/intro/1011.yaml","old_content":"id: 1011\nname: New Room\ncolor: \"\"\ndescription:\n - text: A featureless room.\nexits:\n east:\n room: 1012\nobjects: []\nitem_spawns: []\nmobs: []\non_enter: []\nhazard: \"\"\nblock_transport: false\ntriggers: []\n","new_content":"","is_delete":true,"is_create":false},{"time":"2026-06-30T14:31:01-04:00","description":"delete room 1012 (cleaned 0 exits)","file_path":"data/rooms/intro/1012.yaml","old_content":"id: 1012\nname: New Room\ncolor: \"\"\ndescription:\n - text: A featureless room.\nexits: {}\nobjects: []\nitem_spawns: []\nmobs: []\non_enter: []\nhazard: \"\"\nblock_transport: false\ntriggers: []\n","new_content":"","is_delete":true,"is_create":false},{"time":"2026-06-30T14:31:02-04:00","description":"delete room 1005 (cleaned 2 exits)","file_path":"data/rooms/intro/1005.yaml","old_content":"id: 1005\nname: New Room\ncolor: CC\ndescription:\n - text: A featureless room.\nexits:\n southwest:\n room: 2003\n west:\n room: 1008\nobjects: []\nitem_spawns: []\nmobs: []\non_enter: []\nhazard: \"\"\nblock_transport: false\ntriggers: []\n","new_content":"","is_delete":true,"is_create":false},{"time":"2026-06-30T14:31:03-04:00","description":"delete room 1008 (cleaned 1 exits)","file_path":"data/rooms/intro/1008.yaml","old_content":"id: 1008\nname: New Room\ncolor: A9\ndescription:\n - text: A featureless room.\nexits:\n north:\n room: 7\n south:\n room: 2003\nobjects: []\nitem_spawns: []\nmobs: []\non_enter: []\nhazard: \"\"\nblock_transport: false\ntriggers: []\n","new_content":"","is_delete":true,"is_create":false},{"time":"2026-06-30T14:32:29-04:00","description":"update room 2003 (add exit north to 1005)","file_path":"data/rooms/intro/2003.yaml","old_content":"id: 2003\nname: Test Room\ncolor: \"\"\ndescription:\n - text: It's a test room\nexits:\n south:\n room: 2004\n southwest:\n room: 2005\n west:\n room: 2002\nobjects: []\nitem_spawns: []\nmobs: []\non_enter: []\nhazard: \"\"\nblock_transport: false\ntriggers: []\n","new_content":"id: 2003\nname: Test Room\ncolor: \"\"\ndescription:\n - text: It's a test room\nexits:\n north:\n room: 1005\n south:\n room: 2004\n southwest:\n room: 2005\n west:\n room: 2002\nobjects: []\nitem_spawns: []\nmobs: []\non_enter: []\nhazard: \"\"\nblock_transport: false\ntriggers: []\n","is_delete":false,"is_create":false},{"time":"2026-06-30T14:32:29-04:00","description":"create room 1005","file_path":"data/rooms/intro/1005.yaml","old_content":"","new_content":"exits:\n south: 2003\nid: 1005\nname: 'Room #1005'\n","is_delete":false,"is_create":true},{"time":"2026-06-30T14:32:30-04:00","description":"update room 1005 (add exit east to 1006)","file_path":"data/rooms/intro/1005.yaml","old_content":"exits:\n south: 2003\nid: 1005\nname: 'Room #1005'\n","new_content":"id: 1005\nname: 'Room #1005'\ncolor: \"\"\ndescription: []\nexits:\n east:\n room: 1006\n south:\n room: 2003\nobjects: []\nitem_spawns: []\nmobs: []\non_enter: []\nhazard: \"\"\nblock_transport: false\ntriggers: []\n","is_delete":false,"is_create":false},{"time":"2026-06-30T14:32:30-04:00","description":"create room 1006","file_path":"data/rooms/intro/1006.yaml","old_content":"","new_content":"exits:\n west: 1005\nid: 1006\nname: 'Room #1006'\n","is_delete":false,"is_create":true},{"time":"2026-06-30T14:32:31-04:00","description":"update room 1006 (add exit south to 1007)","file_path":"data/rooms/intro/1006.yaml","old_content":"exits:\n west: 1005\nid: 1006\nname: 'Room #1006'\n","new_content":"id: 1006\nname: 'Room #1006'\ncolor: \"\"\ndescription: []\nexits:\n south:\n room: 1007\n west:\n room: 1005\nobjects: []\nitem_spawns: []\nmobs: []\non_enter: []\nhazard: \"\"\nblock_transport: false\ntriggers: []\n","is_delete":false,"is_create":false},{"time":"2026-06-30T14:32:31-04:00","description":"create room 1007","file_path":"data/rooms/intro/1007.yaml","old_content":"","new_content":"exits:\n north: 1006\nid: 1007\nname: 'Room #1007'\n","is_delete":false,"is_create":true},{"time":"2026-06-30T14:32:32-04:00","description":"update room 1007 (add exit east to 1008)","file_path":"data/rooms/intro/1007.yaml","old_content":"exits:\n north: 1006\nid: 1007\nname: 'Room #1007'\n","new_content":"id: 1007\nname: 'Room #1007'\ncolor: \"\"\ndescription: []\nexits:\n east:\n room: 1008\n north:\n room: 1006\nobjects: []\nitem_spawns: []\nmobs: []\non_enter: []\nhazard: \"\"\nblock_transport: false\ntriggers: []\n","is_delete":false,"is_create":false},{"time":"2026-06-30T14:32:32-04:00","description":"create room 1008","file_path":"data/rooms/intro/1008.yaml","old_content":"","new_content":"exits:\n west: 1007\nid: 1008\nname: 'Room #1008'\n","is_delete":false,"is_create":true},{"time":"2026-06-30T14:32:32-04:00","description":"update room 1008 (add exit north to 1009)","file_path":"data/rooms/intro/1008.yaml","old_content":"exits:\n west: 1007\nid: 1008\nname: 'Room #1008'\n","new_content":"id: 1008\nname: 'Room #1008'\ncolor: \"\"\ndescription: []\nexits:\n north:\n room: 1009\n west:\n room: 1007\nobjects: []\nitem_spawns: []\nmobs: []\non_enter: []\nhazard: \"\"\nblock_transport: false\ntriggers: []\n","is_delete":false,"is_create":false},{"time":"2026-06-30T14:32:32-04:00","description":"create room 1009","file_path":"data/rooms/intro/1009.yaml","old_content":"","new_content":"exits:\n south: 1008\nid: 1009\nname: 'Room #1009'\n","is_delete":false,"is_create":true},{"time":"2026-06-30T14:32:33-04:00","description":"update room 1009 (add exit north to 1010)","file_path":"data/rooms/intro/1009.yaml","old_content":"exits:\n south: 1008\nid: 1009\nname: 'Room #1009'\n","new_content":"id: 1009\nname: 'Room #1009'\ncolor: \"\"\ndescription: []\nexits:\n north:\n room: 1010\n south:\n room: 1008\nobjects: []\nitem_spawns: []\nmobs: []\non_enter: []\nhazard: \"\"\nblock_transport: false\ntriggers: []\n","is_delete":false,"is_create":false},{"time":"2026-06-30T14:32:33-04:00","description":"create room 1010","file_path":"data/rooms/intro/1010.yaml","old_content":"","new_content":"exits:\n south: 1009\nid: 1010\nname: 'Room #1010'\n","is_delete":false,"is_create":true},{"time":"2026-06-30T14:32:33-04:00","description":"update room 1010 (add exit east to 1011)","file_path":"data/rooms/intro/1010.yaml","old_content":"exits:\n south: 1009\nid: 1010\nname: 'Room #1010'\n","new_content":"id: 1010\nname: 'Room #1010'\ncolor: \"\"\ndescription: []\nexits:\n east:\n room: 1011\n south:\n room: 1009\nobjects: []\nitem_spawns: []\nmobs: []\non_enter: []\nhazard: \"\"\nblock_transport: false\ntriggers: []\n","is_delete":false,"is_create":false},{"time":"2026-06-30T14:32:33-04:00","description":"create room 1011","file_path":"data/rooms/intro/1011.yaml","old_content":"","new_content":"exits:\n west: 1010\nid: 1011\nname: 'Room #1011'\n","is_delete":false,"is_create":true},{"time":"2026-06-30T14:32:34-04:00","description":"update room 1011 (add exit south to 1012)","file_path":"data/rooms/intro/1011.yaml","old_content":"exits:\n west: 1010\nid: 1011\nname: 'Room #1011'\n","new_content":"id: 1011\nname: 'Room #1011'\ncolor: \"\"\ndescription: []\nexits:\n south:\n room: 1012\n west:\n room: 1010\nobjects: []\nitem_spawns: []\nmobs: []\non_enter: []\nhazard: \"\"\nblock_transport: false\ntriggers: []\n","is_delete":false,"is_create":false},{"time":"2026-06-30T14:32:34-04:00","description":"create room 1012","file_path":"data/rooms/intro/1012.yaml","old_content":"","new_content":"exits:\n north: 1011\nid: 1012\nname: 'Room #1012'\n","is_delete":false,"is_create":true},{"time":"2026-06-30T14:32:34-04:00","description":"update room 1012 (add exit south to 1013)","file_path":"data/rooms/intro/1012.yaml","old_content":"exits:\n north: 1011\nid: 1012\nname: 'Room #1012'\n","new_content":"id: 1012\nname: 'Room #1012'\ncolor: \"\"\ndescription: []\nexits:\n north:\n room: 1011\n south:\n room: 1013\nobjects: []\nitem_spawns: []\nmobs: []\non_enter: []\nhazard: \"\"\nblock_transport: false\ntriggers: []\n","is_delete":false,"is_create":false},{"time":"2026-06-30T14:32:34-04:00","description":"create room 1013","file_path":"data/rooms/intro/1013.yaml","old_content":"","new_content":"exits:\n north: 1012\nid: 1013\nname: 'Room #1013'\n","is_delete":false,"is_create":true},{"time":"2026-06-30T14:32:35-04:00","description":"delete room 1013 (cleaned 1 exits)","file_path":"data/rooms/intro/1013.yaml","old_content":"exits:\n north: 1012\nid: 1013\nname: 'Room #1013'\n","new_content":"","is_delete":true,"is_create":false},{"time":"2026-06-30T14:32:36-04:00","description":"delete room 1012 (cleaned 1 exits)","file_path":"data/rooms/intro/1012.yaml","old_content":"id: 1012\nname: 'Room #1012'\ncolor: \"\"\ndescription: []\nexits:\n north:\n room: 1011\nobjects: []\nitem_spawns: []\nmobs: []\non_enter: []\nhazard: \"\"\nblock_transport: false\ntriggers: []\n","new_content":"","is_delete":true,"is_create":false},{"time":"2026-06-30T14:32:37-04:00","description":"delete room 1011 (cleaned 1 exits)","file_path":"data/rooms/intro/1011.yaml","old_content":"id: 1011\nname: 'Room #1011'\ncolor: \"\"\ndescription: []\nexits:\n west:\n room: 1010\nobjects: []\nitem_spawns: []\nmobs: []\non_enter: []\nhazard: \"\"\nblock_transport: false\ntriggers: []\n","new_content":"","is_delete":true,"is_create":false},{"time":"2026-06-30T14:32:37-04:00","description":"delete room 1010 (cleaned 1 exits)","file_path":"data/rooms/intro/1010.yaml","old_content":"id: 1010\nname: 'Room #1010'\ncolor: \"\"\ndescription: []\nexits:\n south:\n room: 1009\nobjects: []\nitem_spawns: []\nmobs: []\non_enter: []\nhazard: \"\"\nblock_transport: false\ntriggers: []\n","new_content":"","is_delete":true,"is_create":false},{"time":"2026-06-30T14:32:38-04:00","description":"delete room 1009 (cleaned 1 exits)","file_path":"data/rooms/intro/1009.yaml","old_content":"id: 1009\nname: 'Room #1009'\ncolor: \"\"\ndescription: []\nexits:\n south:\n room: 1008\nobjects: []\nitem_spawns: []\nmobs: []\non_enter: []\nhazard: \"\"\nblock_transport: false\ntriggers: []\n","new_content":"","is_delete":true,"is_create":false},{"time":"2026-06-30T14:32:39-04:00","description":"delete room 1008 (cleaned 1 exits)","file_path":"data/rooms/intro/1008.yaml","old_content":"id: 1008\nname: 'Room #1008'\ncolor: \"\"\ndescription: []\nexits:\n west:\n room: 1007\nobjects: []\nitem_spawns: []\nmobs: []\non_enter: []\nhazard: \"\"\nblock_transport: false\ntriggers: []\n","new_content":"","is_delete":true,"is_create":false},{"time":"2026-06-30T14:32:40-04:00","description":"delete room 1007 (cleaned 1 exits)","file_path":"data/rooms/intro/1007.yaml","old_content":"id: 1007\nname: 'Room #1007'\ncolor: \"\"\ndescription: []\nexits:\n north:\n room: 1006\nobjects: []\nitem_spawns: []\nmobs: []\non_enter: []\nhazard: \"\"\nblock_transport: false\ntriggers: []\n","new_content":"","is_delete":true,"is_create":false},{"time":"2026-06-30T14:32:40-04:00","description":"delete room 1006 (cleaned 1 exits)","file_path":"data/rooms/intro/1006.yaml","old_content":"id: 1006\nname: 'Room #1006'\ncolor: \"\"\ndescription: []\nexits:\n west:\n room: 1005\nobjects: []\nitem_spawns: []\nmobs: []\non_enter: []\nhazard: \"\"\nblock_transport: false\ntriggers: []\n","new_content":"","is_delete":true,"is_create":false},{"time":"2026-06-30T14:32:41-04:00","description":"delete room 1005 (cleaned 1 exits)","file_path":"data/rooms/intro/1005.yaml","old_content":"id: 1005\nname: 'Room #1005'\ncolor: \"\"\ndescription: []\nexits:\n south:\n room: 2003\nobjects: []\nitem_spawns: []\nmobs: []\non_enter: []\nhazard: \"\"\nblock_transport: false\ntriggers: []\n","new_content":"","is_delete":true,"is_create":false},{"time":"2026-06-30T15:05:42-04:00","description":"update room 1001","file_path":"data/rooms/intro/1001.yaml","old_content":"id: 1001\nname: Inside Transport Shuttle\ncolor: \"\"\ndescription:\n - text: |-\n A dim, windowless shuttle interior with a few uncomfortable rows of steel seats facing forward. A large framed sign hangs next to the closed cockpit door. The piston-powered staircase is firmly closed at the rear of the craft.\n\n A dim, windowless shuttle interior with a few uncomfortable rows of steel seats facing forward. A large {11}framed sign{/} hangs next to the closed cockpit door. A piston-powered staircase leads down out the back of the small craft with a smiling attendant ready to help disembark.\nexits:\n down:\n room: 1002\n condition:\n flag: \"\"\n value: null\n not: false\n player_flag: 1001_touchdown\n has_item: \"\"\n min_credits: 0\n all_of: []\n any_of: []\n blocked_message: The piston-powered staircase is firmly closed.\n east:\n room: 2001\nobjects:\n - name: framed sign\n hidden: true\n description:\n - text: \"We hope you enjoy your trip on our shuttle! Your pilot is [TYLER].\\n\\nWhen you arrive at your final destination, please be aware of the following basic commands:\\n\\n{0B bold}Movement:{/} {0A}north{/}, {0A}south{/}, {0A}east{/}, {0A}west{/}, {0A}up{/}, {0A}down{/}\\n{0B bold}Look:{/} {0A}look{/}, {0A}look \u003citem/object/mob\u003e{/}, and {0A}map{/}\\n{0B bold}Items:{/} {0A}inv{/} to see your 28-slot inventory\\n {0A}get \u003citem\u003e{/}, {0A}drop \u003citem\u003e{/}, {0A}wear \u003citem\u003e{/}, {0A}remove \u003citem\u003e{/}\\n {0A}use \u003citem\u003e on \u003citem/object\u003e{/}\\n {0A}eq{/} for equiped gear\\n{0B bold}Comms:{/} {0A}talk \u003cmob\u003e{/} for NPC chat\\n {0A}say \u003cmsg\u003e{/} and {0A}global \u003cmsg\u003e{/} for human chat\\n{0B bold}Character:{/} {0A}score{/} and {0A}skills{/} for stats. \\n{0B bold}Combat{/} {0A}attack \u003cmob\u003e{/}\\n{0B bold}Skills{/} Many skills have shortcuts like {0A}mine{/}, {0A}fish{/}, or {0A}chop{/}\\n{0B bold}Options{/} {0A}options{/} for a list of account options\\n {0A}options \u003copt\u003e \u003cvalue\u003e{/} to change an option\\n\\nType {0C bold}what{/} for a list of possible common actions\\n\\nMake sure to check the {0A}help{/} pages, especially {0A}help newplayer{/}!\"\n on_look:\n set_flags: {}\n set_player_flags:\n 1001_look_sign: true\n give_item: \"\"\n take_item: \"\"\n teleport: 0\n heal: 0\n cost: 0\n shop: null\n assign_task: false\n skip_task: false\n extend_task: false\n reputation_cost: 0\n sawmill: false\n aps_node: false\n - name: door\n hidden: true\n description:\n - text: A sturdy, locked steel door that keeps passengers out of the cockpit. There is a tiny, thin window at eye level.\n - name: window\n hidden: true\n description:\n - text: A thick trim with rounded bolt heads frames the tiny window. It looks like it was cut into the door at some point, potentially as a simple replacement to computerized security systems. Inside the cockpit there's a pilot finishing up landing procedures on a large panel of analog instruments.\n - name: instrument panel\n aliases:\n - cockpit\n hidden: true\n description:\n - text: The cramped cockpit is surrounded by buttons, swiches, dials, and analog gauges. The parts are a mix of technologies from the last century. Part of the panel is obscured by a draped cloth as if to hide it from view. Odd.\n - name: pilot\n hidden: true\n description:\n - text: That's the guy who took you from the Passenger Barge Denali down here to Vesta. A middle-aged man in a neat white jumpsuit with a matching white sort of conductor's hat. He's following a written procedure checklist and seems to take his job seriously.\nitem_spawns: []\nmobs:\n - id: flight_attendant\non_enter:\n - message: '{0B bold}Welcome to The House of Icarus{/}'\n condition:\n flag: \"\"\n value: null\n not: true\n player_flag: 1001_welcome\n has_item: \"\"\n min_credits: 0\n all_of: []\n any_of: []\n delay: 5\n set_flags: {}\n set_player_flags: {}\n broadcast: \"\"\n broadcast_global: \"\"\n spawn_mob: null\n despawn_mob: \"\"\n give_item: \"\"\n take_item: \"\"\n teleport: 0\n heal: 0\n - message: '{0B}Type{/} {0A}look sign{/} {0B}or{/} {0A}talk attendant{/} {0B}to get started{/}'\n condition:\n flag: \"\"\n value: null\n not: true\n player_flag: 1001_welcome\n has_item: \"\"\n min_credits: 0\n all_of: []\n any_of: []\n delay: 7\n set_flags: {}\n set_player_flags:\n 1001_welcome: true\n broadcast: \"\"\n broadcast_global: \"\"\n spawn_mob: null\n despawn_mob: \"\"\n give_item: \"\"\n take_item: \"\"\n teleport: 0\n heal: 0\n - message: '{0B}Type{/} {0A}help newplayer{/} {0B}for the new player''s guide. That''s it. Explore and have fun.{/}'\n condition:\n flag: \"\"\n value: null\n not: true\n player_flag: 1001_welcome\n has_item: \"\"\n min_credits: 0\n all_of: []\n any_of: []\n delay: 7\n set_flags: {}\n set_player_flags: {}\n broadcast: \"\"\n broadcast_global: \"\"\n spawn_mob: null\n despawn_mob: \"\"\n give_item: \"\"\n take_item: \"\"\n teleport: 0\n heal: 0\nhazard: \"\"\nblock_transport: true\ntriggers:\n - id: \"\"\n on_player_flag: 1001_look_sign\n on_flag: \"\"\n value: null\n room: 0\n steps:\n - delay: 5\n message: The cabin shakes as the small craft touches down\n broadcast: \"\"\n broadcast_global: \"\"\n set_flags: {}\n set_player_flags: {}\n spawn_mob: null\n give_item: \"\"\n take_item: \"\"\n teleport: 0\n heal: 0\n despawn_mob: \"\"\n - delay: 5\n message: The pistons hiss as the rear staircase opens\n broadcast: \"\"\n broadcast_global: \"\"\n set_flags: {}\n set_player_flags: {}\n spawn_mob: null\n give_item: \"\"\n take_item: \"\"\n teleport: 0\n heal: 0\n despawn_mob: \"\"\n - delay: 0\n message: \"\"\n broadcast: \"\"\n broadcast_global: \"\"\n set_flags: {}\n set_player_flags:\n 1001_touchdown: true\n spawn_mob: null\n give_item: \"\"\n take_item: \"\"\n teleport: 0\n heal: 0\n despawn_mob: \"\"\n","new_content":"block_transport: true\ncolor: \"\"\ndescription:\n - text: |-\n A dim, windowless shuttle interior with a few uncomfortable rows of steel seats facing forward. A large framed sign hangs next to the closed cockpit door. The piston-powered staircase is firmly closed at the rear of the craft.\n\n A dim, windowless shuttle interior with a few uncomfortable rows of steel seats facing forward. A large {11}framed sign{/} hangs next to the closed cockpit door. A piston-powered staircase leads down out the back of the small craft with a smiling attendant ready to help disembark.\nexits:\n down:\n blocked_message: The piston-powered staircase is firmly closed.\n condition:\n all_of: []\n any_of: []\n flag: \"\"\n has_item: \"\"\n min_credits: 0\n not: false\n player_flag: 1001_touchdown\n value: null\n room: 1002\n east:\n room: 2001\nhazard: \"\"\nid: 1001\nitem_spawns: []\nmobs:\n - id: flight_attendant\nname: Inside Transport Shuttle\nobjects:\n - description:\n - text: \"We hope you enjoy your trip on our shuttle! Your pilot is [TYLER].\\n\\nWhen you arrive at your final destination, please be aware of the following basic commands:\\n\\n{0B bold}Movement:{/} {0A}north{/}, {0A}south{/}, {0A}east{/}, {0A}west{/}, {0A}up{/}, {0A}down{/}\\n{0B bold}Look:{/} {0A}look{/}, {0A}look \u003citem/object/mob\u003e{/}, and {0A}map{/}\\n{0B bold}Items:{/} {0A}inv{/} to see your 28-slot inventory\\n {0A}get \u003citem\u003e{/}, {0A}drop \u003citem\u003e{/}, {0A}wear \u003citem\u003e{/}, {0A}remove \u003citem\u003e{/}\\n {0A}use \u003citem\u003e on \u003citem/object\u003e{/}\\n {0A}eq{/} for equiped gear\\n{0B bold}Comms:{/} {0A}talk \u003cmob\u003e{/} for NPC chat\\n {0A}say \u003cmsg\u003e{/} and {0A}global \u003cmsg\u003e{/} for human chat\\n{0B bold}Character:{/} {0A}score{/} and {0A}skills{/} for stats. \\n{0B bold}Combat{/} {0A}attack \u003cmob\u003e{/}\\n{0B bold}Skills{/} Many skills have shortcuts like {0A}mine{/}, {0A}fish{/}, or {0A}chop{/}\\n{0B bold}Options{/} {0A}options{/} for a list of account options\\n {0A}options \u003copt\u003e \u003cvalue\u003e{/} to change an option\\n\\nType {0C bold}what{/} for a list of possible common actions\\n\\nMake sure to check the {0A}help{/} pages, especially {0A}help newplayer{/}!\"\n hidden: true\n name: framed sign\n on_look:\n aps_node: false\n assign_task: false\n cost: 0\n extend_task: false\n give_item: \"\"\n heal: 0\n reputation_cost: 0\n sawmill: false\n set_flags: {}\n set_player_flags:\n 1001_look_sign: true\n shop: null\n skip_task: false\n take_item: \"\"\n teleport: 0\n - description:\n - text: A sturdy, locked steel door that keeps passengers out of the cockpit. There is a tiny, thin window at eye level.\n hidden: true\n name: door\n - description:\n - text: A thick trim with rounded bolt heads frames the tiny window. It looks like it was cut into the door at some point, potentially as a simple replacement to computerized security systems. Inside the cockpit there's a pilot finishing up landing procedures on a large panel of analog instruments.\n hidden: true\n name: window\n - aliases:\n - cockpit\n description:\n - text: The cramped cockpit is surrounded by buttons, swiches, dials, and analog gauges. The parts are a mix of technologies from the last century. Part of the panel is obscured by a draped cloth as if to hide it from view. Odd.\n hidden: true\n name: instrument panel\n - aliases: []\n description:\n - text: That's the guy who took you from the Passenger Barge Denali down here to Vesta. A middle-aged man in a neat white jumpsuit with a matching white sort of conductor's hat. He's following a written procedure checklist and seems to take his job seriously.\n hidden: false\n name: pilot\non_enter:\n - broadcast: \"\"\n broadcast_global: \"\"\n condition:\n all_of: []\n any_of: []\n flag: \"\"\n has_item: \"\"\n min_credits: 0\n not: true\n player_flag: 1001_welcome\n value: null\n delay: 5\n despawn_mob: \"\"\n give_item: \"\"\n heal: 0\n message: '{0B bold}Welcome to The House of Icarus{/}'\n set_flags: {}\n set_player_flags: {}\n spawn_mob: null\n take_item: \"\"\n teleport: 0\n - broadcast: \"\"\n broadcast_global: \"\"\n condition:\n all_of: []\n any_of: []\n flag: \"\"\n has_item: \"\"\n min_credits: 0\n not: true\n player_flag: 1001_welcome\n value: null\n delay: 7\n despawn_mob: \"\"\n give_item: \"\"\n heal: 0\n message: '{0B}Type{/} {0A}look sign{/} {0B}or{/} {0A}talk attendant{/} {0B}to get started{/}'\n set_flags: {}\n set_player_flags:\n 1001_welcome: true\n spawn_mob: null\n take_item: \"\"\n teleport: 0\n - broadcast: \"\"\n broadcast_global: \"\"\n condition:\n all_of: []\n any_of: []\n flag: \"\"\n has_item: \"\"\n min_credits: 0\n not: true\n player_flag: 1001_welcome\n value: null\n delay: 7\n despawn_mob: \"\"\n give_item: \"\"\n heal: 0\n message: '{0B}Type{/} {0A}help newplayer{/} {0B}for the new player''s guide. That''s it. Explore and have fun.{/}'\n set_flags: {}\n set_player_flags: {}\n spawn_mob: null\n take_item: \"\"\n teleport: 0\ntriggers:\n - id: \"\"\n on_flag: \"\"\n on_player_flag: 1001_look_sign\n room: 0\n steps:\n - broadcast: \"\"\n broadcast_global: \"\"\n delay: 5\n despawn_mob: \"\"\n give_item: \"\"\n heal: 0\n message: The cabin shakes as the small craft touches down\n set_flags: {}\n set_player_flags: {}\n spawn_mob: null\n take_item: \"\"\n teleport: 0\n - broadcast: \"\"\n broadcast_global: \"\"\n delay: 5\n despawn_mob: \"\"\n give_item: \"\"\n heal: 0\n message: The pistons hiss as the rear staircase opens\n set_flags: {}\n set_player_flags: {}\n spawn_mob: null\n take_item: \"\"\n teleport: 0\n - broadcast: \"\"\n broadcast_global: \"\"\n delay: 0\n despawn_mob: \"\"\n give_item: \"\"\n heal: 0\n message: \"\"\n set_flags: {}\n set_player_flags:\n 1001_touchdown: true\n spawn_mob: null\n take_item: \"\"\n teleport: 0\n value: null\n","is_delete":false,"is_create":false},{"time":"2026-06-30T15:05:43-04:00","description":"update room 1001","file_path":"data/rooms/intro/1001.yaml","old_content":"block_transport: true\ncolor: \"\"\ndescription:\n - text: |-\n A dim, windowless shuttle interior with a few uncomfortable rows of steel seats facing forward. A large framed sign hangs next to the closed cockpit door. The piston-powered staircase is firmly closed at the rear of the craft.\n\n A dim, windowless shuttle interior with a few uncomfortable rows of steel seats facing forward. A large {11}framed sign{/} hangs next to the closed cockpit door. A piston-powered staircase leads down out the back of the small craft with a smiling attendant ready to help disembark.\nexits:\n down:\n blocked_message: The piston-powered staircase is firmly closed.\n condition:\n all_of: []\n any_of: []\n flag: \"\"\n has_item: \"\"\n min_credits: 0\n not: false\n player_flag: 1001_touchdown\n value: null\n room: 1002\n east:\n room: 2001\nhazard: \"\"\nid: 1001\nitem_spawns: []\nmobs:\n - id: flight_attendant\nname: Inside Transport Shuttle\nobjects:\n - description:\n - text: \"We hope you enjoy your trip on our shuttle! Your pilot is [TYLER].\\n\\nWhen you arrive at your final destination, please be aware of the following basic commands:\\n\\n{0B bold}Movement:{/} {0A}north{/}, {0A}south{/}, {0A}east{/}, {0A}west{/}, {0A}up{/}, {0A}down{/}\\n{0B bold}Look:{/} {0A}look{/}, {0A}look \u003citem/object/mob\u003e{/}, and {0A}map{/}\\n{0B bold}Items:{/} {0A}inv{/} to see your 28-slot inventory\\n {0A}get \u003citem\u003e{/}, {0A}drop \u003citem\u003e{/}, {0A}wear \u003citem\u003e{/}, {0A}remove \u003citem\u003e{/}\\n {0A}use \u003citem\u003e on \u003citem/object\u003e{/}\\n {0A}eq{/} for equiped gear\\n{0B bold}Comms:{/} {0A}talk \u003cmob\u003e{/} for NPC chat\\n {0A}say \u003cmsg\u003e{/} and {0A}global \u003cmsg\u003e{/} for human chat\\n{0B bold}Character:{/} {0A}score{/} and {0A}skills{/} for stats. \\n{0B bold}Combat{/} {0A}attack \u003cmob\u003e{/}\\n{0B bold}Skills{/} Many skills have shortcuts like {0A}mine{/}, {0A}fish{/}, or {0A}chop{/}\\n{0B bold}Options{/} {0A}options{/} for a list of account options\\n {0A}options \u003copt\u003e \u003cvalue\u003e{/} to change an option\\n\\nType {0C bold}what{/} for a list of possible common actions\\n\\nMake sure to check the {0A}help{/} pages, especially {0A}help newplayer{/}!\"\n hidden: true\n name: framed sign\n on_look:\n aps_node: false\n assign_task: false\n cost: 0\n extend_task: false\n give_item: \"\"\n heal: 0\n reputation_cost: 0\n sawmill: false\n set_flags: {}\n set_player_flags:\n 1001_look_sign: true\n shop: null\n skip_task: false\n take_item: \"\"\n teleport: 0\n - description:\n - text: A sturdy, locked steel door that keeps passengers out of the cockpit. There is a tiny, thin window at eye level.\n hidden: true\n name: door\n - description:\n - text: A thick trim with rounded bolt heads frames the tiny window. It looks like it was cut into the door at some point, potentially as a simple replacement to computerized security systems. Inside the cockpit there's a pilot finishing up landing procedures on a large panel of analog instruments.\n hidden: true\n name: window\n - aliases:\n - cockpit\n description:\n - text: The cramped cockpit is surrounded by buttons, swiches, dials, and analog gauges. The parts are a mix of technologies from the last century. Part of the panel is obscured by a draped cloth as if to hide it from view. Odd.\n hidden: true\n name: instrument panel\n - aliases: []\n description:\n - text: That's the guy who took you from the Passenger Barge Denali down here to Vesta. A middle-aged man in a neat white jumpsuit with a matching white sort of conductor's hat. He's following a written procedure checklist and seems to take his job seriously.\n hidden: false\n name: pilot\non_enter:\n - broadcast: \"\"\n broadcast_global: \"\"\n condition:\n all_of: []\n any_of: []\n flag: \"\"\n has_item: \"\"\n min_credits: 0\n not: true\n player_flag: 1001_welcome\n value: null\n delay: 5\n despawn_mob: \"\"\n give_item: \"\"\n heal: 0\n message: '{0B bold}Welcome to The House of Icarus{/}'\n set_flags: {}\n set_player_flags: {}\n spawn_mob: null\n take_item: \"\"\n teleport: 0\n - broadcast: \"\"\n broadcast_global: \"\"\n condition:\n all_of: []\n any_of: []\n flag: \"\"\n has_item: \"\"\n min_credits: 0\n not: true\n player_flag: 1001_welcome\n value: null\n delay: 7\n despawn_mob: \"\"\n give_item: \"\"\n heal: 0\n message: '{0B}Type{/} {0A}look sign{/} {0B}or{/} {0A}talk attendant{/} {0B}to get started{/}'\n set_flags: {}\n set_player_flags:\n 1001_welcome: true\n spawn_mob: null\n take_item: \"\"\n teleport: 0\n - broadcast: \"\"\n broadcast_global: \"\"\n condition:\n all_of: []\n any_of: []\n flag: \"\"\n has_item: \"\"\n min_credits: 0\n not: true\n player_flag: 1001_welcome\n value: null\n delay: 7\n despawn_mob: \"\"\n give_item: \"\"\n heal: 0\n message: '{0B}Type{/} {0A}help newplayer{/} {0B}for the new player''s guide. That''s it. Explore and have fun.{/}'\n set_flags: {}\n set_player_flags: {}\n spawn_mob: null\n take_item: \"\"\n teleport: 0\ntriggers:\n - id: \"\"\n on_flag: \"\"\n on_player_flag: 1001_look_sign\n room: 0\n steps:\n - broadcast: \"\"\n broadcast_global: \"\"\n delay: 5\n despawn_mob: \"\"\n give_item: \"\"\n heal: 0\n message: The cabin shakes as the small craft touches down\n set_flags: {}\n set_player_flags: {}\n spawn_mob: null\n take_item: \"\"\n teleport: 0\n - broadcast: \"\"\n broadcast_global: \"\"\n delay: 5\n despawn_mob: \"\"\n give_item: \"\"\n heal: 0\n message: The pistons hiss as the rear staircase opens\n set_flags: {}\n set_player_flags: {}\n spawn_mob: null\n take_item: \"\"\n teleport: 0\n - broadcast: \"\"\n broadcast_global: \"\"\n delay: 0\n despawn_mob: \"\"\n give_item: \"\"\n heal: 0\n message: \"\"\n set_flags: {}\n set_player_flags:\n 1001_touchdown: true\n spawn_mob: null\n take_item: \"\"\n teleport: 0\n value: null\n","new_content":"block_transport: true\ncolor: \"\"\ndescription:\n - text: |-\n A dim, windowless shuttle interior with a few uncomfortable rows of steel seats facing forward. A large framed sign hangs next to the closed cockpit door. The piston-powered staircase is firmly closed at the rear of the craft.\n\n A dim, windowless shuttle interior with a few uncomfortable rows of steel seats facing forward. A large {11}framed sign{/} hangs next to the closed cockpit door. A piston-powered staircase leads down out the back of the small craft with a smiling attendant ready to help disembark.\nexits:\n down:\n blocked_message: The piston-powered staircase is firmly closed.\n condition:\n all_of: []\n any_of: []\n flag: \"\"\n has_item: \"\"\n min_credits: 0\n not: false\n player_flag: 1001_touchdown\n value: null\n room: 1002\n east:\n room: 2001\nhazard: \"\"\nid: 1001\nitem_spawns: []\nmobs:\n - id: flight_attendant\nname: Inside Transport Shuttle\nobjects:\n - description:\n - text: \"We hope you enjoy your trip on our shuttle! Your pilot is [TYLER].\\n\\nWhen you arrive at your final destination, please be aware of the following basic commands:\\n\\n{0B bold}Movement:{/} {0A}north{/}, {0A}south{/}, {0A}east{/}, {0A}west{/}, {0A}up{/}, {0A}down{/}\\n{0B bold}Look:{/} {0A}look{/}, {0A}look \u003citem/object/mob\u003e{/}, and {0A}map{/}\\n{0B bold}Items:{/} {0A}inv{/} to see your 28-slot inventory\\n {0A}get \u003citem\u003e{/}, {0A}drop \u003citem\u003e{/}, {0A}wear \u003citem\u003e{/}, {0A}remove \u003citem\u003e{/}\\n {0A}use \u003citem\u003e on \u003citem/object\u003e{/}\\n {0A}eq{/} for equiped gear\\n{0B bold}Comms:{/} {0A}talk \u003cmob\u003e{/} for NPC chat\\n {0A}say \u003cmsg\u003e{/} and {0A}global \u003cmsg\u003e{/} for human chat\\n{0B bold}Character:{/} {0A}score{/} and {0A}skills{/} for stats. \\n{0B bold}Combat{/} {0A}attack \u003cmob\u003e{/}\\n{0B bold}Skills{/} Many skills have shortcuts like {0A}mine{/}, {0A}fish{/}, or {0A}chop{/}\\n{0B bold}Options{/} {0A}options{/} for a list of account options\\n {0A}options \u003copt\u003e \u003cvalue\u003e{/} to change an option\\n\\nType {0C bold}what{/} for a list of possible common actions\\n\\nMake sure to check the {0A}help{/} pages, especially {0A}help newplayer{/}!\"\n hidden: true\n name: framed sign\n on_look:\n aps_node: false\n assign_task: false\n cost: 0\n extend_task: false\n give_item: \"\"\n heal: 0\n reputation_cost: 0\n sawmill: false\n set_flags: {}\n set_player_flags:\n 1001_look_sign: true\n shop: null\n skip_task: false\n take_item: \"\"\n teleport: 0\n - description:\n - text: A sturdy, locked steel door that keeps passengers out of the cockpit. There is a tiny, thin window at eye level.\n hidden: true\n name: door\n - description:\n - text: A thick trim with rounded bolt heads frames the tiny window. It looks like it was cut into the door at some point, potentially as a simple replacement to computerized security systems. Inside the cockpit there's a pilot finishing up landing procedures on a large panel of analog instruments.\n hidden: true\n name: window\n - aliases:\n - cockpit\n description:\n - text: The cramped cockpit is surrounded by buttons, swiches, dials, and analog gauges. The parts are a mix of technologies from the last century. Part of the panel is obscured by a draped cloth as if to hide it from view. Odd.\n hidden: true\n name: instrument panel\n - aliases: []\n description:\n - text: That's the guy who took you from the Passenger Barge Denali down here to Vesta. A middle-aged man in a neat white jumpsuit with a matching white sort of conductor's hat. He's following a written procedure checklist and seems to take his job seriously.\n hidden: true\n name: pilot\non_enter:\n - broadcast: \"\"\n broadcast_global: \"\"\n condition:\n all_of: []\n any_of: []\n flag: \"\"\n has_item: \"\"\n min_credits: 0\n not: true\n player_flag: 1001_welcome\n value: null\n delay: 5\n despawn_mob: \"\"\n give_item: \"\"\n heal: 0\n message: '{0B bold}Welcome to The House of Icarus{/}'\n set_flags: {}\n set_player_flags: {}\n spawn_mob: null\n take_item: \"\"\n teleport: 0\n - broadcast: \"\"\n broadcast_global: \"\"\n condition:\n all_of: []\n any_of: []\n flag: \"\"\n has_item: \"\"\n min_credits: 0\n not: true\n player_flag: 1001_welcome\n value: null\n delay: 7\n despawn_mob: \"\"\n give_item: \"\"\n heal: 0\n message: '{0B}Type{/} {0A}look sign{/} {0B}or{/} {0A}talk attendant{/} {0B}to get started{/}'\n set_flags: {}\n set_player_flags:\n 1001_welcome: true\n spawn_mob: null\n take_item: \"\"\n teleport: 0\n - broadcast: \"\"\n broadcast_global: \"\"\n condition:\n all_of: []\n any_of: []\n flag: \"\"\n has_item: \"\"\n min_credits: 0\n not: true\n player_flag: 1001_welcome\n value: null\n delay: 7\n despawn_mob: \"\"\n give_item: \"\"\n heal: 0\n message: '{0B}Type{/} {0A}help newplayer{/} {0B}for the new player''s guide. That''s it. Explore and have fun.{/}'\n set_flags: {}\n set_player_flags: {}\n spawn_mob: null\n take_item: \"\"\n teleport: 0\ntriggers:\n - id: \"\"\n on_flag: \"\"\n on_player_flag: 1001_look_sign\n room: 0\n steps:\n - broadcast: \"\"\n broadcast_global: \"\"\n delay: 5\n despawn_mob: \"\"\n give_item: \"\"\n heal: 0\n message: The cabin shakes as the small craft touches down\n set_flags: {}\n set_player_flags: {}\n spawn_mob: null\n take_item: \"\"\n teleport: 0\n - broadcast: \"\"\n broadcast_global: \"\"\n delay: 5\n despawn_mob: \"\"\n give_item: \"\"\n heal: 0\n message: The pistons hiss as the rear staircase opens\n set_flags: {}\n set_player_flags: {}\n spawn_mob: null\n take_item: \"\"\n teleport: 0\n - broadcast: \"\"\n broadcast_global: \"\"\n delay: 0\n despawn_mob: \"\"\n give_item: \"\"\n heal: 0\n message: \"\"\n set_flags: {}\n set_player_flags:\n 1001_touchdown: true\n spawn_mob: null\n take_item: \"\"\n teleport: 0\n value: null\n","is_delete":false,"is_create":false},{"time":"2026-06-30T16:34:21-04:00","description":"update room 2001","file_path":"data/rooms/intro/2001.yaml","old_content":"block_transport: false\ncolor: \"\"\ndescription:\n - text: It's a test room\nexits:\n east:\n room: 2002\n south:\n room: 2006\n southeast:\n room: 2005\n west:\n room: 1001\nhazard: \"\"\nid: 2001\nitem_spawns: []\nmobs: []\nname: Test Room\nobjects: []\non_enter: []\ntriggers: []\n","new_content":"block_transport: false\ncolor: \"\"\ndescription:\n - text: It's a test room\nexits:\n east:\n room: 2002\n south:\n room: 2006\n southeast:\n room: 2005\n west:\n room: 1001\nhazard: \"\"\nid: 2001\nitem_spawns: []\nmobs: []\nname: Test Room\nobjects:\n - id: tree\non_enter: []\ntriggers: []\n","is_delete":false,"is_create":false},{"time":"2026-06-30T16:35:02-04:00","description":"update room 2001","file_path":"data/rooms/intro/2001.yaml","old_content":"block_transport: false\ncolor: \"\"\ndescription:\n - text: It's a test room\nexits:\n east:\n room: 2002\n south:\n room: 2006\n southeast:\n room: 2005\n west:\n room: 1001\nhazard: \"\"\nid: 2001\nitem_spawns: []\nmobs: []\nname: Test Room\nobjects:\n - id: tree\non_enter: []\ntriggers: []\n","new_content":"block_transport: false\ncolor: \"\"\ndescription:\n - text: It's a test room\nexits:\n east:\n room: 2002\n south:\n room: 2006\n southeast:\n room: 2005\n west:\n room: 1001\nhazard: \"\"\nid: 2001\nitem_spawns:\n - id: bronze_axe\n quantity: 1\n respawn_ticks: 0\nmobs: []\nname: Test Room\nobjects:\n - id: tree\non_enter: []\ntriggers: []\n","is_delete":false,"is_create":false},{"time":"2026-06-30T16:35:15-04:00","description":"update room 2001","file_path":"data/rooms/intro/2001.yaml","old_content":"block_transport: false\ncolor: \"\"\ndescription:\n - text: It's a test room\nexits:\n east:\n room: 2002\n south:\n room: 2006\n southeast:\n room: 2005\n west:\n room: 1001\nhazard: \"\"\nid: 2001\nitem_spawns:\n - id: bronze_axe\n quantity: 1\n respawn_ticks: 0\nmobs: []\nname: Test Room\nobjects:\n - id: tree\non_enter: []\ntriggers: []\n","new_content":"block_transport: false\ncolor: \"\"\ndescription:\n - text: It's a test room\nexits:\n east:\n room: 2002\n south:\n room: 2006\n southeast:\n room: 2005\n west:\n room: 1001\nhazard: \"\"\nid: 2001\nitem_spawns:\n - id: bronze_axe\n quantity: 1\n respawn_ticks: 1\nmobs: []\nname: Test Room\nobjects:\n - id: tree\non_enter: []\ntriggers: []\n","is_delete":false,"is_create":false},{"time":"2026-06-30T17:43:28-04:00","description":"Update object copper_rock","file_path":"data/objects/copper_rock.yaml","old_content":"color: \"B2\"\ngather:\n depleted_message: You don't see any ore in this rock.\n drops:\n - depletes: true\n item_id: copper_ore\n level: 1\n message: You manage to mine some {B2}copper ore{/}.\n weight: 90\n xp: 17\n - depletes: false\n message: You spot a glint of something valuable!\n table: gem_table\n weight: 10\n fail_message: You chip away but get nothing useful.\n gather_message: You swing your pickaxe at the rock...\n respawn_broadcast: A glint of copper catches your eye from some {name}.\n respawn_timer: 50\n skill: mining\n success:\n base: 0.5\n cap: 0.95\n per_level: 0.01\n tools:\n - pickaxe\nname: copper rock\n","new_content":"aliases: []\ncolor: B2\ndescription: \"\"\ngather:\n bait: \"\"\n deplete_timer: 0\n depleted_message: You don't see any ore in this rock.\n drops:\n - depletes: true\n item_id: copper_ore\n level: 1\n message: You manage to mine some {B2}copper ore{/}.\n quantity: 0\n table: \"\"\n weight: 90\n xp: 17\n - depletes: false\n item_id: \"\"\n level: 0\n message: You spot a glint of something valuable!\n quantity: 0\n table: gem_table\n weight: 10\n xp: 0\n exhausted_message: \"\"\n fail_message: You chip away but get nothing useful.\n gather_message: You swing your pickaxe at the rock...\n nest_chance: 0\n respawn_broadcast: A glint of copper catches your eye from some {name}.\n respawn_timer: 50\n skill: mining\n success:\n base: 0.5\n cap: 0.95\n per_level: 0.01\n tools:\n - pickaxe\nhidden: false\nid: copper_rock\ninroom_description: \"\"\nname: copper rock\nremoval_item: \"\"\n","is_delete":false,"is_create":false},{"time":"2026-06-30T23:48:18-04:00","description":"update room 2001","file_path":"data/rooms/intro/2001.yaml","old_content":"block_transport: false\ncolor: \"\"\ndescription:\n - text: It's a test room\nexits:\n east:\n room: 2002\n south:\n room: 2006\n southeast:\n room: 2005\n west:\n room: 1001\nhazard: \"\"\nid: 2001\nitem_spawns:\n - id: bronze_axe\n quantity: 1\n respawn_ticks: 1\nmobs: []\nname: Test Room\nobjects:\n - id: tree\non_enter: []\ntriggers: []\n","new_content":"block_transport: false\ncolor: \"\"\ndescription:\n - text: It's a test room\nexits:\n east:\n room: 2002\n south:\n room: 2006\n southeast:\n room: 2005\n west:\n room: 1001\nhazard: \"\"\nid: 2001\nitem_spawns:\n - id: bronze_axe\n quantity: 1\n respawn_ticks: 1\n - id: pot_of_flour\n quantity: 1\n respawn_ticks: 0\nmobs: []\nname: Test Room\nobjects:\n - id: tree\non_enter: []\ntriggers: []\n","is_delete":false,"is_create":false},{"time":"2026-06-30T23:48:23-04:00","description":"update room 2001","file_path":"data/rooms/intro/2001.yaml","old_content":"block_transport: false\ncolor: \"\"\ndescription:\n - text: It's a test room\nexits:\n east:\n room: 2002\n south:\n room: 2006\n southeast:\n room: 2005\n west:\n room: 1001\nhazard: \"\"\nid: 2001\nitem_spawns:\n - id: bronze_axe\n quantity: 1\n respawn_ticks: 1\n - id: pot_of_flour\n quantity: 1\n respawn_ticks: 0\nmobs: []\nname: Test Room\nobjects:\n - id: tree\non_enter: []\ntriggers: []\n","new_content":"block_transport: false\ncolor: \"\"\ndescription:\n - text: It's a test room\nexits:\n east:\n room: 2002\n south:\n room: 2006\n southeast:\n room: 2005\n west:\n room: 1001\nhazard: \"\"\nid: 2001\nitem_spawns:\n - id: bronze_axe\n quantity: 1\n respawn_ticks: 1\n - id: pot_of_flour\n quantity: 1\n respawn_ticks: 0\n - id: bucket_of_water\n quantity: 1\n respawn_ticks: 0\nmobs: []\nname: Test Room\nobjects:\n - id: tree\non_enter: []\ntriggers: []\n","is_delete":false,"is_create":false},{"time":"2026-06-30T23:53:08-04:00","description":"Update item bread_dough","file_path":"data/items/consumables/bread_dough.yaml","old_content":"color: \"DE\"\ncraft:\n type: combine\n consume:\n - byproducts:\n - empty_pot\n items:\n - pot_of_flour\n quantity: 1\n - byproducts:\n - empty_bucket\n - empty_jug\n items:\n - bucket_of_water\n - jug_of_water\n quantity: 1\n wait: 2\ndescription: A ball of uncooked bread dough. It needs to be baked.\nname: bread dough\nstackable: false\nvalue: 3\n","new_content":"color: DE\ncraft:\n - consume:\n - byproducts:\n - empty_pot\n items:\n - pot_of_flour\n quantity: 1\n - byproducts:\n - empty_bucket\n - empty_jug\n items:\n - bucket_of_water\n - jug_of_water\n quantity: 1\n end_message: testend\n fail: \"\"\n level: 0\n message: testmsg\n output_qty: 0\n start_message: teststart\n station: []\n subtype: \"\"\n tool: \"\"\n type: combine\n wait: 2\n xp: 0\ndescription: A ball of uncooked bread dough. It needs to be baked.\nid: bread_dough\nmax_quality: 0\nname: bread dough\nquality: 0\nstackable: false\nvalue: 3\n","is_delete":false,"is_create":false},{"time":"2026-07-01T00:23:04-04:00","description":"Update item bread_dough","file_path":"data/items/consumables/bread_dough.yaml","old_content":"color: DE\ncraft:\n - consume:\n - byproducts:\n - empty_pot\n items:\n - pot_of_flour\n quantity: 1\n - byproducts:\n - empty_bucket\n - empty_jug\n items:\n - bucket_of_water\n - jug_of_water\n quantity: 1\n end_message: testend\n fail: \"\"\n level: 0\n message: testmsg\n output_qty: 0\n start_message: teststart\n station: []\n subtype: \"\"\n tool: \"\"\n type: combine\n wait: 2\n xp: 0\ndescription: A ball of uncooked bread dough. It needs to be baked.\nid: bread_dough\nmax_quality: 0\nname: bread dough\nquality: 0\nstackable: false\nvalue: 3\n","new_content":"color: DE\ncraft:\n - consume:\n - byproducts:\n - empty_pot\n items:\n - pot_of_flour\n quantity: 1\n - byproducts:\n - empty_bucket\n - empty_jug\n items:\n - bucket_of_water\n - jug_of_water\n quantity: 1\n end_message: testend\n fail: \"\"\n level: 0\n message: testmsg\n output_qty: 0\n start_message: teststart\n station: []\n subtype: \"\"\n tool: \"\"\n type: combine\n wait: 2\n xp: 0\ndescription: A ball of uncooked bread dough. It needs to be baked.\nid: bread_dough\nmax_quality: 0\nname: bread dough\nquality: 0\nstackable: false\nvalue: 3\n","is_delete":false,"is_create":false},{"time":"2026-07-01T01:22:55-04:00","description":"update room 1001","file_path":"data/rooms/intro/1001.yaml","old_content":"block_transport: true\ncolor: \"\"\ndescription:\n - text: |-\n A dim, windowless shuttle interior with a few uncomfortable rows of steel seats facing forward. A large framed sign hangs next to the closed cockpit door. The piston-powered staircase is firmly closed at the rear of the craft.\n\n A dim, windowless shuttle interior with a few uncomfortable rows of steel seats facing forward. A large {11}framed sign{/} hangs next to the closed cockpit door. A piston-powered staircase leads down out the back of the small craft with a smiling attendant ready to help disembark.\nexits:\n down:\n blocked_message: The piston-powered staircase is firmly closed.\n condition:\n all_of: []\n any_of: []\n flag: \"\"\n has_item: \"\"\n min_credits: 0\n not: false\n player_flag: 1001_touchdown\n value: null\n room: 1002\n east:\n room: 2001\nhazard: \"\"\nid: 1001\nitem_spawns: []\nmobs:\n - id: flight_attendant\nname: Inside Transport Shuttle\nobjects:\n - description:\n - text: \"We hope you enjoy your trip on our shuttle! Your pilot is [TYLER].\\n\\nWhen you arrive at your final destination, please be aware of the following basic commands:\\n\\n{0B bold}Movement:{/} {0A}north{/}, {0A}south{/}, {0A}east{/}, {0A}west{/}, {0A}up{/}, {0A}down{/}\\n{0B bold}Look:{/} {0A}look{/}, {0A}look \u003citem/object/mob\u003e{/}, and {0A}map{/}\\n{0B bold}Items:{/} {0A}inv{/} to see your 28-slot inventory\\n {0A}get \u003citem\u003e{/}, {0A}drop \u003citem\u003e{/}, {0A}wear \u003citem\u003e{/}, {0A}remove \u003citem\u003e{/}\\n {0A}use \u003citem\u003e on \u003citem/object\u003e{/}\\n {0A}eq{/} for equiped gear\\n{0B bold}Comms:{/} {0A}talk \u003cmob\u003e{/} for NPC chat\\n {0A}say \u003cmsg\u003e{/} and {0A}global \u003cmsg\u003e{/} for human chat\\n{0B bold}Character:{/} {0A}score{/} and {0A}skills{/} for stats. \\n{0B bold}Combat{/} {0A}attack \u003cmob\u003e{/}\\n{0B bold}Skills{/} Many skills have shortcuts like {0A}mine{/}, {0A}fish{/}, or {0A}chop{/}\\n{0B bold}Options{/} {0A}options{/} for a list of account options\\n {0A}options \u003copt\u003e \u003cvalue\u003e{/} to change an option\\n\\nType {0C bold}what{/} for a list of possible common actions\\n\\nMake sure to check the {0A}help{/} pages, especially {0A}help newplayer{/}!\"\n hidden: true\n name: framed sign\n on_look:\n aps_node: false\n assign_task: false\n cost: 0\n extend_task: false\n give_item: \"\"\n heal: 0\n reputation_cost: 0\n sawmill: false\n set_flags: {}\n set_player_flags:\n 1001_look_sign: true\n shop: null\n skip_task: false\n take_item: \"\"\n teleport: 0\n - description:\n - text: A sturdy, locked steel door that keeps passengers out of the cockpit. There is a tiny, thin window at eye level.\n hidden: true\n name: door\n - description:\n - text: A thick trim with rounded bolt heads frames the tiny window. It looks like it was cut into the door at some point, potentially as a simple replacement to computerized security systems. Inside the cockpit there's a pilot finishing up landing procedures on a large panel of analog instruments.\n hidden: true\n name: window\n - aliases:\n - cockpit\n description:\n - text: The cramped cockpit is surrounded by buttons, swiches, dials, and analog gauges. The parts are a mix of technologies from the last century. Part of the panel is obscured by a draped cloth as if to hide it from view. Odd.\n hidden: true\n name: instrument panel\n - aliases: []\n description:\n - text: That's the guy who took you from the Passenger Barge Denali down here to Vesta. A middle-aged man in a neat white jumpsuit with a matching white sort of conductor's hat. He's following a written procedure checklist and seems to take his job seriously.\n hidden: true\n name: pilot\non_enter:\n - broadcast: \"\"\n broadcast_global: \"\"\n condition:\n all_of: []\n any_of: []\n flag: \"\"\n has_item: \"\"\n min_credits: 0\n not: true\n player_flag: 1001_welcome\n value: null\n delay: 5\n despawn_mob: \"\"\n give_item: \"\"\n heal: 0\n message: '{0B bold}Welcome to The House of Icarus{/}'\n set_flags: {}\n set_player_flags: {}\n spawn_mob: null\n take_item: \"\"\n teleport: 0\n - broadcast: \"\"\n broadcast_global: \"\"\n condition:\n all_of: []\n any_of: []\n flag: \"\"\n has_item: \"\"\n min_credits: 0\n not: true\n player_flag: 1001_welcome\n value: null\n delay: 7\n despawn_mob: \"\"\n give_item: \"\"\n heal: 0\n message: '{0B}Type{/} {0A}look sign{/} {0B}or{/} {0A}talk attendant{/} {0B}to get started{/}'\n set_flags: {}\n set_player_flags:\n 1001_welcome: true\n spawn_mob: null\n take_item: \"\"\n teleport: 0\n - broadcast: \"\"\n broadcast_global: \"\"\n condition:\n all_of: []\n any_of: []\n flag: \"\"\n has_item: \"\"\n min_credits: 0\n not: true\n player_flag: 1001_welcome\n value: null\n delay: 7\n despawn_mob: \"\"\n give_item: \"\"\n heal: 0\n message: '{0B}Type{/} {0A}help newplayer{/} {0B}for the new player''s guide. That''s it. Explore and have fun.{/}'\n set_flags: {}\n set_player_flags: {}\n spawn_mob: null\n take_item: \"\"\n teleport: 0\ntriggers:\n - id: \"\"\n on_flag: \"\"\n on_player_flag: 1001_look_sign\n room: 0\n steps:\n - broadcast: \"\"\n broadcast_global: \"\"\n delay: 5\n despawn_mob: \"\"\n give_item: \"\"\n heal: 0\n message: The cabin shakes as the small craft touches down\n set_flags: {}\n set_player_flags: {}\n spawn_mob: null\n take_item: \"\"\n teleport: 0\n - broadcast: \"\"\n broadcast_global: \"\"\n delay: 5\n despawn_mob: \"\"\n give_item: \"\"\n heal: 0\n message: The pistons hiss as the rear staircase opens\n set_flags: {}\n set_player_flags: {}\n spawn_mob: null\n take_item: \"\"\n teleport: 0\n - broadcast: \"\"\n broadcast_global: \"\"\n delay: 0\n despawn_mob: \"\"\n give_item: \"\"\n heal: 0\n message: \"\"\n set_flags: {}\n set_player_flags:\n 1001_touchdown: true\n spawn_mob: null\n take_item: \"\"\n teleport: 0\n value: null\n","new_content":"block_transport: true\ncolor: \"\"\ndescription:\n - text: |-\n A dim, windowless shuttle interior with a few uncomfortable rows of steel seats facing forward. A large framed sign hangs next to the closed cockpit door. The piston-powered staircase is firmly closed at the rear of the craft.\n\n A dim, windowless shuttle interior with a few uncomfortable rows of steel seats facing forward. A large {11}framed sign{/} hangs next to the closed cockpit door. A piston-powered staircase leads down out the back of the small craft with a smiling attendant ready to help disembark.\nexits:\n down:\n blocked_message: The piston-powered staircase is firmly closed.\n condition:\n all_of: []\n any_of: []\n flag: \"\"\n has_item: \"\"\n min_credits: 0\n not: false\n player_flag: 1001_touchdown\n value: null\n room: 1002\n east:\n room: 2001\nhazard: \"\"\nid: 1001\nitem_spawns: []\nmobs:\n - id: flight_attendant\nname: Inside Transport Shuttle\nobjects:\n - description:\n - text: \"We hope you enjoy your trip on our shuttle! Your pilot is [TYLER].\\n\\nWhen you arrive at your final destination, please be aware of the following basic commands:\\n\\n{0B bold}Movement:{/} {0A}north{/}, {0A}south{/}, {0A}east{/}, {0A}west{/}, {0A}up{/}, {0A}down{/}\\n{0B bold}Look:{/} {0A}look{/}, {0A}look \u003citem/object/mob\u003e{/}, and {0A}map{/}\\n{0B bold}Items:{/} {0A}inv{/} to see your 28-slot inventory\\n {0A}get \u003citem\u003e{/}, {0A}drop \u003citem\u003e{/}, {0A}wear \u003citem\u003e{/}, {0A}remove \u003citem\u003e{/}\\n {0A}use \u003citem\u003e on \u003citem/object\u003e{/}\\n {0A}eq{/} for equiped gear\\n{0B bold}Comms:{/} {0A}talk \u003cmob\u003e{/} for NPC chat\\n {0A}say \u003cmsg\u003e{/} and {0A}global \u003cmsg\u003e{/} for human chat\\n{0B bold}Character:{/} {0A}score{/} and {0A}skills{/} for stats. \\n{0B bold}Combat{/} {0A}attack \u003cmob\u003e{/}\\n{0B bold}Skills{/} Many skills have shortcuts like {0A}mine{/}, {0A}fish{/}, or {0A}chop{/}\\n{0B bold}Options{/} {0A}options{/} for a list of account options\\n {0A}options \u003copt\u003e \u003cvalue\u003e{/} to change an option\\n\\nType {0C bold}what{/} for a list of possible common actions\\n\\nMake sure to check the {0A}help{/} pages, especially {0A}help newplayer{/}!\"\n hidden: true\n name: framed sign\n on_look:\n aps_node: false\n assign_task: false\n cost: 0\n extend_task: false\n give_item: \"\"\n heal: 0\n reputation_cost: 0\n sawmill: false\n set_flags: {}\n set_player_flags:\n 1001_look_sign: true\n shop: null\n skip_task: false\n take_item: \"\"\n teleport: 0\n - description:\n - text: A sturdy, locked steel door that keeps passengers out of the cockpit. There is a tiny, thin window at eye level.\n hidden: true\n name: door\n - description:\n - text: A thick trim with rounded bolt heads frames the tiny window. It looks like it was cut into the door at some point, potentially as a simple replacement to computerized security systems. Inside the cockpit there's a pilot finishing up landing procedures on a large panel of analog instruments.\n hidden: true\n name: window\n - aliases:\n - cockpit\n description:\n - text: The cramped cockpit is surrounded by buttons, swiches, dials, and analog gauges. The parts are a mix of technologies from the last century. Part of the panel is obscured by a draped cloth as if to hide it from view. Odd.\n hidden: true\n name: instrument panel\n - aliases: []\n description:\n - text: That's the guy who took you from the Passenger Barge Denali down here to Vesta. A middle-aged man in a neat white jumpsuit with a matching white sort of conductor's hat. He's following a written procedure checklist and seems to take his job seriously.\n hidden: true\n name: pilot\non_enter:\n - broadcast: \"\"\n broadcast_global: \"\"\n condition:\n all_of: []\n any_of: []\n flag: \"\"\n has_item: \"\"\n min_credits: 0\n not: true\n player_flag: 1001_welcome\n value: null\n delay: 5\n despawn_mob: \"\"\n give_item: \"\"\n heal: 0\n message: '{0B bold}Welcome to The House of Icarus{/}'\n set_flags: {}\n set_player_flags: {}\n spawn_mob: null\n take_item: \"\"\n teleport: 0\n - broadcast: \"\"\n broadcast_global: \"\"\n condition:\n all_of: []\n any_of: []\n flag: \"\"\n has_item: \"\"\n min_credits: 0\n not: true\n player_flag: 1001_welcome\n value: null\n delay: 7\n despawn_mob: \"\"\n give_item: \"\"\n heal: 0\n message: '{0B}Type{/} {0A}look sign{/} {0B}or{/} {0A}talk attendant{/} {0B}to get started{/}'\n set_flags: {}\n set_player_flags:\n 1001_welcome: true\n spawn_mob: null\n take_item: \"\"\n teleport: 0\n - broadcast: \"\"\n broadcast_global: \"\"\n condition:\n all_of: []\n any_of: []\n flag: \"\"\n has_item: \"\"\n min_credits: 0\n not: true\n player_flag: 1001_welcome\n value: null\n delay: 7\n despawn_mob: \"\"\n give_item: \"\"\n heal: 0\n message: '{0B}Type{/} {0A}help newplayer{/} {0B}for the new player''s guide. That''s it. Explore and have fun.{/}'\n set_flags: {}\n set_player_flags: {}\n spawn_mob: null\n take_item: \"\"\n teleport: 0\ntriggers:\n - id: \"\"\n on_flag: \"\"\n on_player_flag: 1001_look_sign\n room: 0\n steps:\n - broadcast: \"\"\n broadcast_global: \"\"\n delay: 5\n despawn_mob: \"\"\n give_item: \"\"\n heal: 0\n message: The cabin shakes as the small craft touches down\n set_flags: {}\n set_player_flags: {}\n spawn_mob: null\n take_item: \"\"\n teleport: 0\n - broadcast: \"\"\n broadcast_global: \"\"\n delay: 5\n despawn_mob: \"\"\n give_item: \"\"\n heal: 0\n message: The pistons hiss as the rear staircase opens\n set_flags: {}\n set_player_flags: {}\n spawn_mob: null\n take_item: \"\"\n teleport: 0\n - broadcast: \"\"\n broadcast_global: \"\"\n delay: 0\n despawn_mob: \"\"\n give_item: \"\"\n heal: 0\n message: \"\"\n set_flags: {}\n set_player_flags:\n 1001_touchdown: true\n spawn_mob: null\n take_item: \"\"\n teleport: 0\n value: null\n","is_delete":false,"is_create":false}],"redo":null}
\ No newline at end of file diff --git a/data/drops/christmas_cracker_hat.yaml b/data/drops/christmas_cracker_hat.yaml index e9f7a77..23f7231 100644 --- a/data/drops/christmas_cracker_hat.yaml +++ b/data/drops/christmas_cracker_hat.yaml @@ -11,3 +11,11 @@ drops: weight: 1 - item_id: party_hat_white weight: 1 + - item_id: ashes + weight: 1 + - item_id: bread + weight: 1 + - item_id: bronze_pickaxe + weight: 1 + - item_id: "" + weight: 3 diff --git a/data/drops/christmas_cracker_misc.yaml b/data/drops/christmas_cracker_misc.yaml deleted file mode 100644 index 94debfd..0000000 --- a/data/drops/christmas_cracker_misc.yaml +++ /dev/null @@ -1,9 +0,0 @@ -drops: - - item_id: ashes - weight: 1 - - item_id: bread - weight: 1 - - item_id: bronze_pickaxe - weight: 1 - - item_id: "" - weight: 3 diff --git a/data/items/ammo/adamant_arrow.yaml b/data/items/ammo/adamant_arrow.yaml index a7cb647..3b1a750 100644 --- a/data/items/ammo/adamant_arrow.yaml +++ b/data/items/ammo/adamant_arrow.yaml @@ -1,23 +1,24 @@ color: "78" craft: - consume: - - items: - - headless_arrow - quantity: 15 - - items: - - adamant_arrowtips - quantity: 15 - level: 60 - output_qty: 15 - skill: fletching - type: fletching - wait: 2 - xp: 10 + ingredients: + - items: + - headless_arrow + quantity: 15 + - items: + - adamant_arrowtips + quantity: 15 + level: 60 + output_qty: 15 + type: fletching + wait: 2 + xp: 10 description: An adamant-tipped arrow. -equip_slot: ammo +equipment: + other: + ranged: 31 + slot: ammo + type: ammo name: adamant arrow -stackable: true recoverable: true -stats: - ranged_strength: 31 +stackable: true value: 20 diff --git a/data/items/ammo/adamant_arrowtips.yaml b/data/items/ammo/adamant_arrowtips.yaml index 6a8bb76..8e83ec8 100644 --- a/data/items/ammo/adamant_arrowtips.yaml +++ b/data/items/ammo/adamant_arrowtips.yaml @@ -1,12 +1,11 @@ color: "78" craft: - consume: + ingredients: - items: - adamantite_bar quantity: 1 level: 75 output_qty: 15 - skill: smithing station: - anvil type: smithing diff --git a/data/items/ammo/adamant_bolts.yaml b/data/items/ammo/adamant_bolts.yaml index e61acd6..2a416ec 100644 --- a/data/items/ammo/adamant_bolts.yaml +++ b/data/items/ammo/adamant_bolts.yaml @@ -1,22 +1,23 @@ color: "78" craft: - consume: - - items: - - adamant_bolts_unf - quantity: 10 - - items: - - feather - quantity: 10 - level: 61 - output_qty: 10 - skill: fletching - type: fletching - wait: 0 - xp: 70 + ingredients: + - items: + - adamant_bolts_unf + quantity: 10 + - items: + - feather + quantity: 10 + level: 61 + output_qty: 10 + type: fletching + wait: 0 + xp: 70 description: Adamant crossbow bolts. -equip_slot: ammo +equipment: + other: + ranged: 43 + slot: ammo + type: ammo name: adamant bolts stackable: true -stats: - ranged_strength: 43 value: 24 diff --git a/data/items/ammo/adamant_bolts_unf.yaml b/data/items/ammo/adamant_bolts_unf.yaml index 96d2fec..857dc34 100644 --- a/data/items/ammo/adamant_bolts_unf.yaml +++ b/data/items/ammo/adamant_bolts_unf.yaml @@ -1,12 +1,11 @@ color: "78" craft: - consume: + ingredients: - items: - adamantite_bar quantity: 1 level: 76 output_qty: 10 - skill: smithing station: - anvil type: smithing diff --git a/data/items/ammo/arrow_shaft.yaml b/data/items/ammo/arrow_shaft.yaml index b4500a9..ce44c90 100644 --- a/data/items/ammo/arrow_shaft.yaml +++ b/data/items/ammo/arrow_shaft.yaml @@ -1,67 +1,61 @@ color: "89" craft: - - consume: + - ingredients: - items: - logs quantity: 1 level: 1 output_qty: 15 - skill: fletching tool: knife type: fletching wait: 5 xp: 5 - - consume: + - ingredients: - items: - oak_logs quantity: 1 level: 15 output_qty: 20 - skill: fletching tool: knife type: fletching wait: 5 xp: 10 - - consume: + - ingredients: - items: - willow_logs quantity: 1 level: 30 output_qty: 25 - skill: fletching tool: knife type: fletching wait: 5 xp: 15 - - consume: + - ingredients: - items: - maple_logs quantity: 1 level: 45 output_qty: 30 - skill: fletching tool: knife type: fletching wait: 5 xp: 20 - - consume: + - ingredients: - items: - yew_logs quantity: 1 level: 60 output_qty: 35 - skill: fletching tool: knife type: fletching wait: 5 xp: 25 - - consume: + - ingredients: - items: - magic_logs quantity: 1 level: 75 output_qty: 40 - skill: fletching tool: knife type: fletching wait: 5 diff --git a/data/items/ammo/bronze_arrow.yaml b/data/items/ammo/bronze_arrow.yaml index 85fac40..dfdac57 100644 --- a/data/items/ammo/bronze_arrow.yaml +++ b/data/items/ammo/bronze_arrow.yaml @@ -1,23 +1,24 @@ -color: "B2" +color: B2 craft: - consume: - - items: - - headless_arrow - quantity: 15 - - items: - - bronze_arrowtips - quantity: 15 - level: 1 - output_qty: 15 - skill: fletching - type: fletching - wait: 2 - xp: 1 + ingredients: + - items: + - headless_arrow + quantity: 15 + - items: + - bronze_arrowtips + quantity: 15 + level: 1 + output_qty: 15 + type: fletching + wait: 2 + xp: 1 description: A bronze-tipped arrow. -equip_slot: ammo +equipment: + other: + ranged: 7 + slot: ammo + type: ammo name: bronze arrow -stackable: true recoverable: true -stats: - ranged_strength: 7 +stackable: true value: 1 diff --git a/data/items/ammo/bronze_arrowtips.yaml b/data/items/ammo/bronze_arrowtips.yaml index 3935852..d8dd71e 100644 --- a/data/items/ammo/bronze_arrowtips.yaml +++ b/data/items/ammo/bronze_arrowtips.yaml @@ -1,12 +1,11 @@ color: "B2" craft: - consume: + ingredients: - items: - bronze_bar quantity: 1 level: 5 output_qty: 15 - skill: smithing station: - anvil type: smithing diff --git a/data/items/ammo/bronze_bolts.yaml b/data/items/ammo/bronze_bolts.yaml index bd45e8b..3aeb21b 100644 --- a/data/items/ammo/bronze_bolts.yaml +++ b/data/items/ammo/bronze_bolts.yaml @@ -1,22 +1,23 @@ -color: "B2" +color: B2 craft: - consume: - - items: - - bronze_bolts_unf - quantity: 10 - - items: - - feather - quantity: 10 - level: 9 - output_qty: 10 - skill: fletching - type: fletching - wait: 0 - xp: 5 + ingredients: + - items: + - bronze_bolts_unf + quantity: 10 + - items: + - feather + quantity: 10 + level: 9 + output_qty: 10 + type: fletching + wait: 0 + xp: 5 description: Bronze crossbow bolts. -equip_slot: ammo +equipment: + other: + ranged: 10 + slot: ammo + type: ammo name: bronze bolts stackable: true -stats: - ranged_strength: 10 value: 1 diff --git a/data/items/ammo/bronze_bolts_unf.yaml b/data/items/ammo/bronze_bolts_unf.yaml index 83ed723..ff0a8be 100644 --- a/data/items/ammo/bronze_bolts_unf.yaml +++ b/data/items/ammo/bronze_bolts_unf.yaml @@ -1,12 +1,11 @@ color: "B2" craft: - consume: + ingredients: - items: - bronze_bar quantity: 1 level: 6 output_qty: 10 - skill: smithing station: - anvil type: smithing diff --git a/data/items/ammo/diamond_bolt_tips.yaml b/data/items/ammo/diamond_bolt_tips.yaml index 4ad1809..96bc0eb 100644 --- a/data/items/ammo/diamond_bolt_tips.yaml +++ b/data/items/ammo/diamond_bolt_tips.yaml @@ -1,12 +1,11 @@ color: "FF" craft: - consume: + ingredients: - items: - uncut_diamond quantity: 1 level: 65 output_qty: 12 - skill: fletching tool: chisel type: fletching wait: 5 diff --git a/data/items/ammo/diamond_bolts.yaml b/data/items/ammo/diamond_bolts.yaml index ea3e0af..1cbc3f6 100644 --- a/data/items/ammo/diamond_bolts.yaml +++ b/data/items/ammo/diamond_bolts.yaml @@ -1,22 +1,23 @@ -color: "FF" +color: FF craft: - consume: - - items: - - adamant_bolts - quantity: 10 - - items: - - diamond_bolt_tips - quantity: 10 - level: 65 - output_qty: 10 - skill: fletching - type: fletching - wait: 2 - xp: 7 + ingredients: + - items: + - adamant_bolts + quantity: 10 + - items: + - diamond_bolt_tips + quantity: 10 + level: 65 + output_qty: 10 + type: fletching + wait: 2 + xp: 7 description: Bolts tipped with diamond. Can be enchanted via science. -equip_slot: ammo +equipment: + attack: + ranged: 9 + slot: ammo + type: ammo name: diamond bolts stackable: true -stats: - ranged_attack: 9 value: 130 diff --git a/data/items/ammo/diamond_bolts_e.yaml b/data/items/ammo/diamond_bolts_e.yaml index 1243882..86209f2 100644 --- a/data/items/ammo/diamond_bolts_e.yaml +++ b/data/items/ammo/diamond_bolts_e.yaml @@ -1,8 +1,10 @@ +color: FF bold +description: Enchanted diamond-tipped bolts. Have a chance to ignore the target's defense. +equipment: + attack: + ranged: 10 + slot: ammo + type: ammo name: diamond bolts e -color: "FF bold" -description: "Enchanted diamond-tipped bolts. Have a chance to ignore the target's defense." -value: 180 stackable: true -equip_slot: ammo -stats: - ranged_attack: 10 +value: 180 diff --git a/data/items/ammo/emerald_bolt_tips.yaml b/data/items/ammo/emerald_bolt_tips.yaml index 9d94694..871ac1d 100644 --- a/data/items/ammo/emerald_bolt_tips.yaml +++ b/data/items/ammo/emerald_bolt_tips.yaml @@ -1,12 +1,11 @@ color: "53" craft: - consume: + ingredients: - items: - uncut_emerald quantity: 1 level: 66 output_qty: 12 - skill: fletching tool: chisel type: fletching wait: 5 diff --git a/data/items/ammo/emerald_bolts.yaml b/data/items/ammo/emerald_bolts.yaml index 15fde56..8cafc32 100644 --- a/data/items/ammo/emerald_bolts.yaml +++ b/data/items/ammo/emerald_bolts.yaml @@ -1,22 +1,23 @@ color: "22" craft: - consume: - - items: - - mithril_bolts - quantity: 10 - - items: - - emerald_bolt_tips - quantity: 10 - level: 66 - output_qty: 10 - skill: fletching - type: fletching - wait: 2 - xp: 5 + ingredients: + - items: + - mithril_bolts + quantity: 10 + - items: + - emerald_bolt_tips + quantity: 10 + level: 66 + output_qty: 10 + type: fletching + wait: 2 + xp: 5 description: Bolts tipped with emerald. Can be enchanted via science. -equip_slot: ammo +equipment: + attack: + ranged: 5 + slot: ammo + type: ammo name: emerald bolts stackable: true -stats: - ranged_attack: 5 value: 40 diff --git a/data/items/ammo/emerald_bolts_e.yaml b/data/items/ammo/emerald_bolts_e.yaml index 390730f..59f3883 100644 --- a/data/items/ammo/emerald_bolts_e.yaml +++ b/data/items/ammo/emerald_bolts_e.yaml @@ -1,8 +1,10 @@ +color: 22 bold +description: Enchanted emerald-tipped bolts. Have a chance to poison the target. +equipment: + attack: + ranged: 6 + slot: ammo + type: ammo name: emerald bolts e -color: "22 bold" -description: "Enchanted emerald-tipped bolts. Have a chance to poison the target." -value: 55 stackable: true -equip_slot: ammo -stats: - ranged_attack: 6 +value: 55 diff --git a/data/items/ammo/headless_arrow.yaml b/data/items/ammo/headless_arrow.yaml index d27cc1e..61ad40f 100644 --- a/data/items/ammo/headless_arrow.yaml +++ b/data/items/ammo/headless_arrow.yaml @@ -1,6 +1,6 @@ color: "89" craft: - consume: + ingredients: - items: - arrow_shaft quantity: 15 @@ -10,7 +10,6 @@ craft: level: 1 message: "You attach feathers to the %i1." output_qty: 15 - skill: fletching type: fletching wait: 2 xp: 1 diff --git a/data/items/ammo/iron_arrow.yaml b/data/items/ammo/iron_arrow.yaml index 9a17ff8..f0036d8 100644 --- a/data/items/ammo/iron_arrow.yaml +++ b/data/items/ammo/iron_arrow.yaml @@ -1,23 +1,24 @@ -color: "FA" +color: FA craft: - consume: - - items: - - headless_arrow - quantity: 15 - - items: - - iron_arrowtips - quantity: 15 - level: 15 - output_qty: 15 - skill: fletching - type: fletching - wait: 2 - xp: 2 + ingredients: + - items: + - headless_arrow + quantity: 15 + - items: + - iron_arrowtips + quantity: 15 + level: 15 + output_qty: 15 + type: fletching + wait: 2 + xp: 2 description: An iron-tipped arrow. -equip_slot: ammo +equipment: + other: + ranged: 10 + slot: ammo + type: ammo name: iron arrow -stackable: true recoverable: true -stats: - ranged_strength: 10 +stackable: true value: 2 diff --git a/data/items/ammo/iron_arrowtips.yaml b/data/items/ammo/iron_arrowtips.yaml index aa4cc33..8aec7d9 100644 --- a/data/items/ammo/iron_arrowtips.yaml +++ b/data/items/ammo/iron_arrowtips.yaml @@ -1,12 +1,11 @@ color: "FA" craft: - consume: + ingredients: - items: - iron_bar quantity: 1 level: 25 output_qty: 15 - skill: smithing station: - anvil type: smithing diff --git a/data/items/ammo/iron_bolts.yaml b/data/items/ammo/iron_bolts.yaml index f8ac883..30e5b28 100644 --- a/data/items/ammo/iron_bolts.yaml +++ b/data/items/ammo/iron_bolts.yaml @@ -1,22 +1,23 @@ -color: "FA" +color: FA craft: - consume: - - items: - - iron_bolts_unf - quantity: 10 - - items: - - feather - quantity: 10 - level: 39 - output_qty: 10 - skill: fletching - type: fletching - wait: 0 - xp: 15 + ingredients: + - items: + - iron_bolts_unf + quantity: 10 + - items: + - feather + quantity: 10 + level: 39 + output_qty: 10 + type: fletching + wait: 0 + xp: 15 description: Iron crossbow bolts. -equip_slot: ammo +equipment: + other: + ranged: 17 + slot: ammo + type: ammo name: iron bolts stackable: true -stats: - ranged_strength: 17 value: 3 diff --git a/data/items/ammo/iron_bolts_unf.yaml b/data/items/ammo/iron_bolts_unf.yaml index 32950fa..181a5e2 100644 --- a/data/items/ammo/iron_bolts_unf.yaml +++ b/data/items/ammo/iron_bolts_unf.yaml @@ -1,12 +1,11 @@ color: "FA" craft: - consume: + ingredients: - items: - iron_bar quantity: 1 level: 26 output_qty: 10 - skill: smithing station: - anvil type: smithing diff --git a/data/items/ammo/mithril_arrow.yaml b/data/items/ammo/mithril_arrow.yaml index 281f24a..853b38d 100644 --- a/data/items/ammo/mithril_arrow.yaml +++ b/data/items/ammo/mithril_arrow.yaml @@ -1,23 +1,24 @@ -color: "4B" +color: 4B craft: - consume: - - items: - - headless_arrow - quantity: 15 - - items: - - mithril_arrowtips - quantity: 15 - level: 45 - output_qty: 15 - skill: fletching - type: fletching - wait: 2 - xp: 7 + ingredients: + - items: + - headless_arrow + quantity: 15 + - items: + - mithril_arrowtips + quantity: 15 + level: 45 + output_qty: 15 + type: fletching + wait: 2 + xp: 7 description: A mithril-tipped arrow. -equip_slot: ammo +equipment: + other: + ranged: 22 + slot: ammo + type: ammo name: mithril arrow -stackable: true recoverable: true -stats: - ranged_strength: 22 +stackable: true value: 10 diff --git a/data/items/ammo/mithril_arrowtips.yaml b/data/items/ammo/mithril_arrowtips.yaml index d6acbf8..8f213ec 100644 --- a/data/items/ammo/mithril_arrowtips.yaml +++ b/data/items/ammo/mithril_arrowtips.yaml @@ -1,12 +1,11 @@ color: "4B" craft: - consume: + ingredients: - items: - mithril_bar quantity: 1 level: 55 output_qty: 15 - skill: smithing station: - anvil type: smithing diff --git a/data/items/ammo/mithril_bolts.yaml b/data/items/ammo/mithril_bolts.yaml index fb3f10c..5f64ba1 100644 --- a/data/items/ammo/mithril_bolts.yaml +++ b/data/items/ammo/mithril_bolts.yaml @@ -1,22 +1,23 @@ -color: "4B" +color: 4B craft: - consume: - - items: - - mithril_bolts_unf - quantity: 10 - - items: - - feather - quantity: 10 - level: 54 - output_qty: 10 - skill: fletching - type: fletching - wait: 0 - xp: 50 + ingredients: + - items: + - mithril_bolts_unf + quantity: 10 + - items: + - feather + quantity: 10 + level: 54 + output_qty: 10 + type: fletching + wait: 0 + xp: 50 description: Mithril crossbow bolts. -equip_slot: ammo +equipment: + other: + ranged: 32 + slot: ammo + type: ammo name: mithril bolts stackable: true -stats: - ranged_strength: 32 value: 12 diff --git a/data/items/ammo/mithril_bolts_unf.yaml b/data/items/ammo/mithril_bolts_unf.yaml index ea3879a..0ff8efe 100644 --- a/data/items/ammo/mithril_bolts_unf.yaml +++ b/data/items/ammo/mithril_bolts_unf.yaml @@ -1,12 +1,11 @@ color: "4B" craft: - consume: + ingredients: - items: - mithril_bar quantity: 1 level: 56 output_qty: 10 - skill: smithing station: - anvil type: smithing diff --git a/data/items/ammo/ruby_bolt_tips.yaml b/data/items/ammo/ruby_bolt_tips.yaml index e8a1e0b..a900f90 100644 --- a/data/items/ammo/ruby_bolt_tips.yaml +++ b/data/items/ammo/ruby_bolt_tips.yaml @@ -1,12 +1,11 @@ color: "C4" craft: - consume: + ingredients: - items: - uncut_ruby quantity: 1 level: 73 output_qty: 12 - skill: fletching tool: chisel type: fletching wait: 5 diff --git a/data/items/ammo/ruby_bolts.yaml b/data/items/ammo/ruby_bolts.yaml index a30b5bb..354d595 100644 --- a/data/items/ammo/ruby_bolts.yaml +++ b/data/items/ammo/ruby_bolts.yaml @@ -1,22 +1,23 @@ -color: "C4" +color: C4 craft: - consume: - - items: - - adamant_bolts - quantity: 10 - - items: - - ruby_bolt_tips - quantity: 10 - level: 73 - output_qty: 10 - skill: fletching - type: fletching - wait: 2 - xp: 6 + ingredients: + - items: + - adamant_bolts + quantity: 10 + - items: + - ruby_bolt_tips + quantity: 10 + level: 73 + output_qty: 10 + type: fletching + wait: 2 + xp: 6 description: Bolts tipped with ruby. Can be enchanted via science. -equip_slot: ammo +equipment: + attack: + ranged: 7 + slot: ammo + type: ammo name: ruby bolts stackable: true -stats: - ranged_attack: 7 value: 75 diff --git a/data/items/ammo/ruby_bolts_e.yaml b/data/items/ammo/ruby_bolts_e.yaml index 0aaa79e..618cf62 100644 --- a/data/items/ammo/ruby_bolts_e.yaml +++ b/data/items/ammo/ruby_bolts_e.yaml @@ -1,8 +1,10 @@ +color: C4 bold +description: Enchanted ruby-tipped bolts. Have a chance to deal extra damage based on the target's remaining HP. +equipment: + attack: + ranged: 8 + slot: ammo + type: ammo name: ruby bolts e -color: "C4 bold" -description: "Enchanted ruby-tipped bolts. Have a chance to deal extra damage based on the target's remaining HP." -value: 100 stackable: true -equip_slot: ammo -stats: - ranged_attack: 8 +value: 100 diff --git a/data/items/ammo/rune_arrow.yaml b/data/items/ammo/rune_arrow.yaml index f6cee8e..e997871 100644 --- a/data/items/ammo/rune_arrow.yaml +++ b/data/items/ammo/rune_arrow.yaml @@ -1,23 +1,24 @@ color: "57" craft: - consume: - - items: - - headless_arrow - quantity: 15 - - items: - - rune_arrowtips - quantity: 15 - level: 75 - output_qty: 15 - skill: fletching - type: fletching - wait: 2 - xp: 12 + ingredients: + - items: + - headless_arrow + quantity: 15 + - items: + - rune_arrowtips + quantity: 15 + level: 75 + output_qty: 15 + type: fletching + wait: 2 + xp: 12 description: A rune-tipped arrow. -equip_slot: ammo +equipment: + other: + ranged: 49 + slot: ammo + type: ammo name: rune arrow -stackable: true recoverable: true -stats: - ranged_strength: 49 +stackable: true value: 40 diff --git a/data/items/ammo/rune_arrowtips.yaml b/data/items/ammo/rune_arrowtips.yaml index d729996..354cf0e 100644 --- a/data/items/ammo/rune_arrowtips.yaml +++ b/data/items/ammo/rune_arrowtips.yaml @@ -1,12 +1,11 @@ color: "57" craft: - consume: + ingredients: - items: - runite_bar quantity: 1 level: 90 output_qty: 15 - skill: smithing station: - anvil type: smithing diff --git a/data/items/ammo/rune_bolts.yaml b/data/items/ammo/rune_bolts.yaml index 738cd4c..534dc94 100644 --- a/data/items/ammo/rune_bolts.yaml +++ b/data/items/ammo/rune_bolts.yaml @@ -1,22 +1,23 @@ color: "57" craft: - consume: - - items: - - rune_bolts_unf - quantity: 10 - - items: - - feather - quantity: 10 - level: 69 - output_qty: 10 - skill: fletching - type: fletching - wait: 0 - xp: 100 + ingredients: + - items: + - rune_bolts_unf + quantity: 10 + - items: + - feather + quantity: 10 + level: 69 + output_qty: 10 + type: fletching + wait: 0 + xp: 100 description: Rune crossbow bolts. -equip_slot: ammo +equipment: + other: + ranged: 55 + slot: ammo + type: ammo name: rune bolts stackable: true -stats: - ranged_strength: 55 value: 48 diff --git a/data/items/ammo/rune_bolts_unf.yaml b/data/items/ammo/rune_bolts_unf.yaml index 0b824f6..a529c37 100644 --- a/data/items/ammo/rune_bolts_unf.yaml +++ b/data/items/ammo/rune_bolts_unf.yaml @@ -1,12 +1,11 @@ color: "57" craft: - consume: + ingredients: - items: - runite_bar quantity: 1 level: 91 output_qty: 10 - skill: smithing station: - anvil type: smithing diff --git a/data/items/ammo/sapphire_bolt_tips.yaml b/data/items/ammo/sapphire_bolt_tips.yaml index 92e04f0..bffee83 100644 --- a/data/items/ammo/sapphire_bolt_tips.yaml +++ b/data/items/ammo/sapphire_bolt_tips.yaml @@ -1,12 +1,11 @@ color: "45" craft: - consume: + ingredients: - items: - uncut_sapphire quantity: 1 level: 63 output_qty: 12 - skill: fletching tool: chisel type: fletching wait: 5 diff --git a/data/items/ammo/sapphire_bolts.yaml b/data/items/ammo/sapphire_bolts.yaml index ec7ae3d..253de08 100644 --- a/data/items/ammo/sapphire_bolts.yaml +++ b/data/items/ammo/sapphire_bolts.yaml @@ -1,22 +1,23 @@ color: "27" craft: - consume: - - items: - - mithril_bolts - quantity: 10 - - items: - - sapphire_bolt_tips - quantity: 10 - level: 63 - output_qty: 10 - skill: fletching - type: fletching - wait: 2 - xp: 4 + ingredients: + - items: + - mithril_bolts + quantity: 10 + - items: + - sapphire_bolt_tips + quantity: 10 + level: 63 + output_qty: 10 + type: fletching + wait: 2 + xp: 4 description: Bolts tipped with sapphire. Can be enchanted via science. -equip_slot: ammo +equipment: + attack: + ranged: 3 + slot: ammo + type: ammo name: sapphire bolts stackable: true -stats: - ranged_attack: 3 value: 20 diff --git a/data/items/ammo/sapphire_bolts_e.yaml b/data/items/ammo/sapphire_bolts_e.yaml index af05b9c..07694ea 100644 --- a/data/items/ammo/sapphire_bolts_e.yaml +++ b/data/items/ammo/sapphire_bolts_e.yaml @@ -1,8 +1,10 @@ +color: 27 bold +description: Enchanted sapphire-tipped bolts. Have a chance to drain the target's Science level. +equipment: + attack: + ranged: 4 + slot: ammo + type: ammo name: sapphire bolts e -color: "27 bold" -description: "Enchanted sapphire-tipped bolts. Have a chance to drain the target's Science level." -value: 30 stackable: true -equip_slot: ammo -stats: - ranged_attack: 4 +value: 30 diff --git a/data/items/ammo/steel_arrow.yaml b/data/items/ammo/steel_arrow.yaml index 8d8f18c..4f0fe7d 100644 --- a/data/items/ammo/steel_arrow.yaml +++ b/data/items/ammo/steel_arrow.yaml @@ -1,23 +1,24 @@ -color: "FD" +color: FD craft: - consume: - - items: - - headless_arrow - quantity: 15 - - items: - - steel_arrowtips - quantity: 15 - level: 30 - output_qty: 15 - skill: fletching - type: fletching - wait: 2 - xp: 5 + ingredients: + - items: + - headless_arrow + quantity: 15 + - items: + - steel_arrowtips + quantity: 15 + level: 30 + output_qty: 15 + type: fletching + wait: 2 + xp: 5 description: A steel-tipped arrow. -equip_slot: ammo +equipment: + other: + ranged: 16 + slot: ammo + type: ammo name: steel arrow -stackable: true recoverable: true -stats: - ranged_strength: 16 +stackable: true value: 5 diff --git a/data/items/ammo/steel_arrowtips.yaml b/data/items/ammo/steel_arrowtips.yaml index 519ce09..b455f31 100644 --- a/data/items/ammo/steel_arrowtips.yaml +++ b/data/items/ammo/steel_arrowtips.yaml @@ -1,12 +1,11 @@ color: "FD" craft: - consume: + ingredients: - items: - steel_bar quantity: 1 level: 35 output_qty: 15 - skill: smithing station: - anvil type: smithing diff --git a/data/items/ammo/steel_bolts.yaml b/data/items/ammo/steel_bolts.yaml index 4dfa7d4..f91b024 100644 --- a/data/items/ammo/steel_bolts.yaml +++ b/data/items/ammo/steel_bolts.yaml @@ -1,22 +1,23 @@ -color: "FD" +color: FD craft: - consume: - - items: - - steel_bolts_unf - quantity: 10 - - items: - - feather - quantity: 10 - level: 46 - output_qty: 10 - skill: fletching - type: fletching - wait: 0 - xp: 35 + ingredients: + - items: + - steel_bolts_unf + quantity: 10 + - items: + - feather + quantity: 10 + level: 46 + output_qty: 10 + type: fletching + wait: 0 + xp: 35 description: Steel crossbow bolts. -equip_slot: ammo +equipment: + other: + ranged: 25 + slot: ammo + type: ammo name: steel bolts stackable: true -stats: - ranged_strength: 25 value: 6 diff --git a/data/items/ammo/steel_bolts_unf.yaml b/data/items/ammo/steel_bolts_unf.yaml index dd69c37..4532220 100644 --- a/data/items/ammo/steel_bolts_unf.yaml +++ b/data/items/ammo/steel_bolts_unf.yaml @@ -1,12 +1,11 @@ color: "FD" craft: - consume: + ingredients: - items: - steel_bar quantity: 1 level: 36 output_qty: 10 - skill: smithing station: - anvil type: smithing diff --git a/data/items/consumables/amp_potion.yaml b/data/items/consumables/amp_potion.yaml index 8afe6a8..22f9dd7 100644 --- a/data/items/consumables/amp_potion.yaml +++ b/data/items/consumables/amp_potion.yaml @@ -1,6 +1,6 @@ color: "DC" craft: - consume: + ingredients: - items: - tarromin_potion_unf quantity: 1 @@ -8,7 +8,6 @@ craft: - limpwurt_root quantity: 1 level: 12 - skill: pharmacy type: pharmacy wait: 4 xp: 50 diff --git a/data/items/consumables/anchovies.yaml b/data/items/consumables/anchovies.yaml index 51a2e99..1d1dfdd 100644 --- a/data/items/consumables/anchovies.yaml +++ b/data/items/consumables/anchovies.yaml @@ -1,13 +1,12 @@ color: "D1" craft: - consume: + ingredients: - items: - raw_anchovies quantity: 1 fail: burnt_fish fail_message: You accidentally burn the anchovies. level: 1 - skill: cooking station: - fire - cooking_range diff --git a/data/items/consumables/avantoe_potion_unf.yaml b/data/items/consumables/avantoe_potion_unf.yaml index 49c8122..8cee682 100644 --- a/data/items/consumables/avantoe_potion_unf.yaml +++ b/data/items/consumables/avantoe_potion_unf.yaml @@ -1,7 +1,7 @@ color: "30" craft: type: pharmacy - consume: + ingredients: - items: - avantoe quantity: 1 diff --git a/data/items/consumables/bio_serum.yaml b/data/items/consumables/bio_serum.yaml index ba7a7f5..68147b1 100644 --- a/data/items/consumables/bio_serum.yaml +++ b/data/items/consumables/bio_serum.yaml @@ -1,6 +1,6 @@ color: "30" craft: - consume: + ingredients: - items: - marrentill_potion_unf quantity: 1 @@ -8,7 +8,6 @@ craft: - antitoxin_powder quantity: 1 level: 5 - skill: pharmacy type: pharmacy wait: 4 xp: 38 diff --git a/data/items/consumables/bread.yaml b/data/items/consumables/bread.yaml index bde89dd..1f8a996 100644 --- a/data/items/consumables/bread.yaml +++ b/data/items/consumables/bread.yaml @@ -1,6 +1,6 @@ color: "DE" craft: - consume: + ingredients: - items: - bread_dough quantity: 1 @@ -8,7 +8,6 @@ craft: fail_message: You burn the bread to a crisp. level: 1 message: "You bake the dough into a %n." - skill: cooking station: - cooking_range type: cooking diff --git a/data/items/consumables/bread_dough.yaml b/data/items/consumables/bread_dough.yaml index 2df433f..48fa986 100644 --- a/data/items/consumables/bread_dough.yaml +++ b/data/items/consumables/bread_dough.yaml @@ -1,21 +1,34 @@ -color: "DE" +color: DE craft: + - ingredients: + - byproducts: + - empty_pot + items: + - pot_of_flour + quantity: 1 + - byproducts: + - empty_bucket + - empty_jug + items: + - bucket_of_water + - jug_of_water + quantity: 1 + end_message: testend + fail: "" + level: 0 + message: testmsg + output_qty: 0 + start_message: teststart + station: [] + subtype: "" + tool: "" type: combine - consume: - - byproducts: - - empty_pot - items: - - pot_of_flour - quantity: 1 - - byproducts: - - empty_bucket - - empty_jug - items: - - bucket_of_water - - jug_of_water - quantity: 1 wait: 2 + xp: 0 description: A ball of uncooked bread dough. It needs to be baked. +id: bread_dough +max_quality: 0 name: bread dough +quality: 0 stackable: false value: 3 diff --git a/data/items/consumables/cadantine_potion_unf.yaml b/data/items/consumables/cadantine_potion_unf.yaml index 5198f36..d222ed4 100644 --- a/data/items/consumables/cadantine_potion_unf.yaml +++ b/data/items/consumables/cadantine_potion_unf.yaml @@ -1,7 +1,7 @@ color: "30" craft: type: pharmacy - consume: + ingredients: - items: - cadantine quantity: 1 diff --git a/data/items/consumables/dwarf_weed_potion_unf.yaml b/data/items/consumables/dwarf_weed_potion_unf.yaml index c5b814c..084a434 100644 --- a/data/items/consumables/dwarf_weed_potion_unf.yaml +++ b/data/items/consumables/dwarf_weed_potion_unf.yaml @@ -1,7 +1,7 @@ color: "30" craft: type: pharmacy - consume: + ingredients: - items: - dwarf_weed quantity: 1 diff --git a/data/items/consumables/full_restore.yaml b/data/items/consumables/full_restore.yaml index b817bc5..178914e 100644 --- a/data/items/consumables/full_restore.yaml +++ b/data/items/consumables/full_restore.yaml @@ -1,6 +1,6 @@ color: "D0" craft: - consume: + ingredients: - items: - snapdragon_potion_unf quantity: 1 @@ -8,7 +8,6 @@ craft: - arachnid_enzyme quantity: 1 level: 63 - skill: pharmacy type: pharmacy wait: 4 xp: 143 diff --git a/data/items/consumables/guam_potion_unf.yaml b/data/items/consumables/guam_potion_unf.yaml index 298c578..dc963ed 100644 --- a/data/items/consumables/guam_potion_unf.yaml +++ b/data/items/consumables/guam_potion_unf.yaml @@ -1,7 +1,7 @@ color: "30" craft: type: pharmacy - consume: + ingredients: - items: - guam quantity: 1 diff --git a/data/items/consumables/harralander_potion_unf.yaml b/data/items/consumables/harralander_potion_unf.yaml index 29999ac..cf4873f 100644 --- a/data/items/consumables/harralander_potion_unf.yaml +++ b/data/items/consumables/harralander_potion_unf.yaml @@ -1,7 +1,7 @@ color: "30" craft: type: pharmacy - consume: + ingredients: - items: - harralander quantity: 1 diff --git a/data/items/consumables/herring.yaml b/data/items/consumables/herring.yaml index 4ff4e19..165802b 100644 --- a/data/items/consumables/herring.yaml +++ b/data/items/consumables/herring.yaml @@ -1,13 +1,12 @@ color: "D1" craft: - consume: + ingredients: - items: - raw_herring quantity: 1 fail: burnt_fish fail_message: You accidentally burn the herring. level: 5 - skill: cooking station: - fire - cooking_range diff --git a/data/items/consumables/irit_potion_unf.yaml b/data/items/consumables/irit_potion_unf.yaml index 1c24007..b358c07 100644 --- a/data/items/consumables/irit_potion_unf.yaml +++ b/data/items/consumables/irit_potion_unf.yaml @@ -1,7 +1,7 @@ color: "30" craft: type: pharmacy - consume: + ingredients: - items: - irit quantity: 1 diff --git a/data/items/consumables/kwuarm_potion_unf.yaml b/data/items/consumables/kwuarm_potion_unf.yaml index 9a54ac3..801d301 100644 --- a/data/items/consumables/kwuarm_potion_unf.yaml +++ b/data/items/consumables/kwuarm_potion_unf.yaml @@ -1,7 +1,7 @@ color: "30" craft: type: pharmacy - consume: + ingredients: - items: - kwuarm quantity: 1 diff --git a/data/items/consumables/lantadyme_potion_unf.yaml b/data/items/consumables/lantadyme_potion_unf.yaml index d084ac1..069cf22 100644 --- a/data/items/consumables/lantadyme_potion_unf.yaml +++ b/data/items/consumables/lantadyme_potion_unf.yaml @@ -1,7 +1,7 @@ color: "30" craft: type: pharmacy - consume: + ingredients: - items: - lantadyme quantity: 1 diff --git a/data/items/consumables/marrentill_potion_unf.yaml b/data/items/consumables/marrentill_potion_unf.yaml index 3a6d6d0..f39094e 100644 --- a/data/items/consumables/marrentill_potion_unf.yaml +++ b/data/items/consumables/marrentill_potion_unf.yaml @@ -1,7 +1,7 @@ color: "30" craft: type: pharmacy - consume: + ingredients: - items: - marrentill quantity: 1 diff --git a/data/items/consumables/nano_restore.yaml b/data/items/consumables/nano_restore.yaml index 3afbe16..ddb355a 100644 --- a/data/items/consumables/nano_restore.yaml +++ b/data/items/consumables/nano_restore.yaml @@ -1,6 +1,6 @@ color: "D0" craft: - consume: + ingredients: - items: - harralander_potion_unf quantity: 1 @@ -8,7 +8,6 @@ craft: - arachnid_enzyme quantity: 1 level: 22 - skill: pharmacy type: pharmacy wait: 4 xp: 63 diff --git a/data/items/consumables/pastry_dough.yaml b/data/items/consumables/pastry_dough.yaml index a72c6c3..8c106e0 100644 --- a/data/items/consumables/pastry_dough.yaml +++ b/data/items/consumables/pastry_dough.yaml @@ -1,7 +1,7 @@ color: "DE" craft: type: combine - consume: + ingredients: - items: - pot_of_flour quantity: 1 diff --git a/data/items/consumables/pie_dish.yaml b/data/items/consumables/pie_dish.yaml index b95a291..89d82e4 100644 --- a/data/items/consumables/pie_dish.yaml +++ b/data/items/consumables/pie_dish.yaml @@ -1,13 +1,12 @@ color: "82" craft: - consume: + ingredients: - items: - unfired_pie_dish quantity: 1 fail_message: The pie dish cracks in the oven and is ruined. level: 7 message: "You fire the %i1 in the oven." - skill: crafting station: - pottery_oven success: diff --git a/data/items/consumables/pizza_dough.yaml b/data/items/consumables/pizza_dough.yaml index 5223d9b..c8e29dc 100644 --- a/data/items/consumables/pizza_dough.yaml +++ b/data/items/consumables/pizza_dough.yaml @@ -1,7 +1,7 @@ color: "DE" craft: type: combine - consume: + ingredients: - items: - pot_of_flour quantity: 1 diff --git a/data/items/consumables/ranarr_potion_unf.yaml b/data/items/consumables/ranarr_potion_unf.yaml index 08a2857..3adfbf7 100644 --- a/data/items/consumables/ranarr_potion_unf.yaml +++ b/data/items/consumables/ranarr_potion_unf.yaml @@ -1,7 +1,7 @@ color: "30" craft: type: pharmacy - consume: + ingredients: - items: - ranarr quantity: 1 diff --git a/data/items/consumables/restoration_compound.yaml b/data/items/consumables/restoration_compound.yaml index b9c36cd..79eac7a 100644 --- a/data/items/consumables/restoration_compound.yaml +++ b/data/items/consumables/restoration_compound.yaml @@ -1,6 +1,6 @@ color: "33" craft: - consume: + ingredients: - items: - toadflax_potion_unf quantity: 1 @@ -8,7 +8,6 @@ craft: - crushed_nest quantity: 1 level: 81 - skill: pharmacy type: pharmacy wait: 4 xp: 180 diff --git a/data/items/consumables/salmon.yaml b/data/items/consumables/salmon.yaml index dc9a956..b29f935 100644 --- a/data/items/consumables/salmon.yaml +++ b/data/items/consumables/salmon.yaml @@ -1,13 +1,12 @@ color: "D1" craft: - consume: + ingredients: - items: - raw_salmon quantity: 1 fail: burnt_fish fail_message: You accidentally burn the salmon. level: 25 - skill: cooking station: - fire - cooking_range diff --git a/data/items/consumables/sardine.yaml b/data/items/consumables/sardine.yaml index ac33a49..0c4f53e 100644 --- a/data/items/consumables/sardine.yaml +++ b/data/items/consumables/sardine.yaml @@ -1,13 +1,12 @@ color: "D1" craft: - consume: + ingredients: - items: - raw_sardine quantity: 1 fail: burnt_fish fail_message: You accidentally burn the sardine. level: 1 - skill: cooking station: - fire - cooking_range diff --git a/data/items/consumables/science_serum.yaml b/data/items/consumables/science_serum.yaml index 39ab495..4915ea8 100644 --- a/data/items/consumables/science_serum.yaml +++ b/data/items/consumables/science_serum.yaml @@ -1,6 +1,6 @@ color: "8D" craft: - consume: + ingredients: - items: - lantadyme_potion_unf quantity: 1 @@ -8,7 +8,6 @@ craft: - potato_cactus quantity: 1 level: 76 - skill: pharmacy type: pharmacy wait: 4 xp: 173 diff --git a/data/items/consumables/shield_potion.yaml b/data/items/consumables/shield_potion.yaml index 92f4980..88d1967 100644 --- a/data/items/consumables/shield_potion.yaml +++ b/data/items/consumables/shield_potion.yaml @@ -1,6 +1,6 @@ color: "15" craft: - consume: + ingredients: - items: - ranarr_potion_unf quantity: 1 @@ -8,7 +8,6 @@ craft: - white_berries quantity: 1 level: 30 - skill: pharmacy type: pharmacy wait: 4 xp: 75 diff --git a/data/items/consumables/shrimps.yaml b/data/items/consumables/shrimps.yaml index 536c3f5..be11251 100644 --- a/data/items/consumables/shrimps.yaml +++ b/data/items/consumables/shrimps.yaml @@ -1,13 +1,12 @@ color: "D1" craft: - consume: + ingredients: - items: - raw_shrimps quantity: 1 fail: burnt_fish fail_message: You accidentally burn the shrimps. level: 1 - skill: cooking station: - fire - cooking_range diff --git a/data/items/consumables/snapdragon_potion_unf.yaml b/data/items/consumables/snapdragon_potion_unf.yaml index 5bc76b3..d3e8a9e 100644 --- a/data/items/consumables/snapdragon_potion_unf.yaml +++ b/data/items/consumables/snapdragon_potion_unf.yaml @@ -1,7 +1,7 @@ color: "30" craft: type: pharmacy - consume: + ingredients: - items: - snapdragon quantity: 1 diff --git a/data/items/consumables/stim_potion.yaml b/data/items/consumables/stim_potion.yaml index a19d611..c61e4fb 100644 --- a/data/items/consumables/stim_potion.yaml +++ b/data/items/consumables/stim_potion.yaml @@ -1,6 +1,6 @@ color: "C4" craft: - consume: + ingredients: - items: - guam_potion_unf quantity: 1 @@ -8,7 +8,6 @@ craft: - eye_of_newt quantity: 1 level: 1 - skill: pharmacy type: pharmacy wait: 4 xp: 25 diff --git a/data/items/consumables/super_amp.yaml b/data/items/consumables/super_amp.yaml index 7f851c6..f8fd85c 100644 --- a/data/items/consumables/super_amp.yaml +++ b/data/items/consumables/super_amp.yaml @@ -1,6 +1,6 @@ color: "DC" craft: - consume: + ingredients: - items: - kwuarm_potion_unf quantity: 1 @@ -8,7 +8,6 @@ craft: - limpwurt_root quantity: 1 level: 55 - skill: pharmacy type: pharmacy wait: 4 xp: 125 diff --git a/data/items/consumables/super_bio_serum.yaml b/data/items/consumables/super_bio_serum.yaml index 08154d2..d4003a4 100644 --- a/data/items/consumables/super_bio_serum.yaml +++ b/data/items/consumables/super_bio_serum.yaml @@ -1,6 +1,6 @@ color: "30" craft: - consume: + ingredients: - items: - irit_potion_unf quantity: 1 @@ -8,7 +8,6 @@ craft: - antitoxin_powder quantity: 1 level: 48 - skill: pharmacy type: pharmacy wait: 4 xp: 106 diff --git a/data/items/consumables/super_shield.yaml b/data/items/consumables/super_shield.yaml index 570af87..90389d6 100644 --- a/data/items/consumables/super_shield.yaml +++ b/data/items/consumables/super_shield.yaml @@ -1,6 +1,6 @@ color: "15" craft: - consume: + ingredients: - items: - cadantine_potion_unf quantity: 1 @@ -8,7 +8,6 @@ craft: - white_berries quantity: 1 level: 66 - skill: pharmacy type: pharmacy wait: 4 xp: 150 diff --git a/data/items/consumables/super_stim.yaml b/data/items/consumables/super_stim.yaml index 2b35d62..27662a5 100644 --- a/data/items/consumables/super_stim.yaml +++ b/data/items/consumables/super_stim.yaml @@ -1,6 +1,6 @@ color: "C4" craft: - consume: + ingredients: - items: - irit_potion_unf quantity: 1 @@ -8,7 +8,6 @@ craft: - eye_of_newt quantity: 1 level: 45 - skill: pharmacy type: pharmacy wait: 4 xp: 100 diff --git a/data/items/consumables/super_stim_cell.yaml b/data/items/consumables/super_stim_cell.yaml index 45dca94..37c4af2 100644 --- a/data/items/consumables/super_stim_cell.yaml +++ b/data/items/consumables/super_stim_cell.yaml @@ -1,6 +1,6 @@ color: "E2" craft: - consume: + ingredients: - items: - avantoe_potion_unf quantity: 1 @@ -8,7 +8,6 @@ craft: - blight_spore quantity: 1 level: 52 - skill: pharmacy type: pharmacy wait: 4 xp: 118 diff --git a/data/items/consumables/targeting_serum.yaml b/data/items/consumables/targeting_serum.yaml index e8b8864..74b3e73 100644 --- a/data/items/consumables/targeting_serum.yaml +++ b/data/items/consumables/targeting_serum.yaml @@ -1,6 +1,6 @@ color: "CA" craft: - consume: + ingredients: - items: - dwarf_weed_potion_unf quantity: 1 @@ -8,7 +8,6 @@ craft: - catalyst_wine quantity: 1 level: 72 - skill: pharmacy type: pharmacy wait: 4 xp: 163 diff --git a/data/items/consumables/tarromin_potion_unf.yaml b/data/items/consumables/tarromin_potion_unf.yaml index 1db2c0a..c8798f6 100644 --- a/data/items/consumables/tarromin_potion_unf.yaml +++ b/data/items/consumables/tarromin_potion_unf.yaml @@ -1,7 +1,7 @@ color: "30" craft: type: pharmacy - consume: + ingredients: - items: - tarromin quantity: 1 diff --git a/data/items/consumables/tech_serum.yaml b/data/items/consumables/tech_serum.yaml index 79224ad..01ad080 100644 --- a/data/items/consumables/tech_serum.yaml +++ b/data/items/consumables/tech_serum.yaml @@ -1,6 +1,6 @@ color: "4B" craft: - consume: + ingredients: - items: - ranarr_potion_unf quantity: 1 @@ -8,7 +8,6 @@ craft: - snape_grass quantity: 1 level: 38 - skill: pharmacy type: pharmacy wait: 4 xp: 88 diff --git a/data/items/consumables/toadflax_potion_unf.yaml b/data/items/consumables/toadflax_potion_unf.yaml index ff9bf79..aa56ef7 100644 --- a/data/items/consumables/toadflax_potion_unf.yaml +++ b/data/items/consumables/toadflax_potion_unf.yaml @@ -1,7 +1,7 @@ color: "30" craft: type: pharmacy - consume: + ingredients: - items: - toadflax quantity: 1 diff --git a/data/items/consumables/torstol_potion_unf.yaml b/data/items/consumables/torstol_potion_unf.yaml index 1008463..89e8f8c 100644 --- a/data/items/consumables/torstol_potion_unf.yaml +++ b/data/items/consumables/torstol_potion_unf.yaml @@ -1,7 +1,7 @@ color: "30" craft: type: pharmacy - consume: + ingredients: - items: - torstol quantity: 1 diff --git a/data/items/consumables/trout.yaml b/data/items/consumables/trout.yaml index 4c5a2e1..91933d6 100644 --- a/data/items/consumables/trout.yaml +++ b/data/items/consumables/trout.yaml @@ -1,13 +1,12 @@ color: "D1" craft: - consume: + ingredients: - items: - raw_trout quantity: 1 fail: burnt_fish fail_message: You accidentally burn the trout. level: 15 - skill: cooking station: - fire - cooking_range diff --git a/data/items/decks/advanced_bio_deck.yaml b/data/items/decks/advanced_bio_deck.yaml index 6eb1559..dffbbe0 100644 --- a/data/items/decks/advanced_bio_deck.yaml +++ b/data/items/decks/advanced_bio_deck.yaml @@ -1,10 +1,11 @@ +color: C4 bold +description: A high-powered bio deck with enhanced circuitry. Provides unlimited biojunk and removes the scrap requirement. +equipment: + attack: + science: 20 + junk: biojunk + slot: main_hand + speed: 5 + type: tech_weapon name: advanced bio deck -color: "C4 bold" -description: "A high-powered bio deck with enhanced circuitry. Provides unlimited biojunk and removes the scrap requirement." value: 15000 -equip_slot: main_hand -weapon_type: science -speed: 5 -stats: - science_attack: 20 -provides_junk: biojunk diff --git a/data/items/decks/advanced_eco_deck.yaml b/data/items/decks/advanced_eco_deck.yaml index 9c4d58a..419e157 100644 --- a/data/items/decks/advanced_eco_deck.yaml +++ b/data/items/decks/advanced_eco_deck.yaml @@ -1,10 +1,11 @@ +color: 22 bold +description: A high-powered eco deck with enhanced circuitry. Provides unlimited ecojunk and removes the scrap requirement. +equipment: + attack: + science: 20 + junk: ecojunk + slot: main_hand + speed: 5 + type: tech_weapon name: advanced eco deck -color: "22 bold" -description: "A high-powered eco deck with enhanced circuitry. Provides unlimited ecojunk and removes the scrap requirement." value: 15000 -equip_slot: main_hand -weapon_type: science -speed: 5 -stats: - science_attack: 20 -provides_junk: ecojunk diff --git a/data/items/decks/advanced_hydro_deck.yaml b/data/items/decks/advanced_hydro_deck.yaml index bf165b8..e1c7181 100644 --- a/data/items/decks/advanced_hydro_deck.yaml +++ b/data/items/decks/advanced_hydro_deck.yaml @@ -1,10 +1,11 @@ +color: 27 bold +description: A high-powered hydro deck with enhanced circuitry. Provides unlimited hydrojunk and removes the scrap requirement. +equipment: + attack: + science: 20 + junk: hydrojunk + slot: main_hand + speed: 5 + type: tech_weapon name: advanced hydro deck -color: "27 bold" -description: "A high-powered hydro deck with enhanced circuitry. Provides unlimited hydrojunk and removes the scrap requirement." value: 15000 -equip_slot: main_hand -weapon_type: science -speed: 5 -stats: - science_attack: 20 -provides_junk: hydrojunk diff --git a/data/items/decks/advanced_solar_deck.yaml b/data/items/decks/advanced_solar_deck.yaml index 98d4e76..25ce3d5 100644 --- a/data/items/decks/advanced_solar_deck.yaml +++ b/data/items/decks/advanced_solar_deck.yaml @@ -1,10 +1,11 @@ +color: DC bold +description: A high-powered solar deck with enhanced circuitry. Provides unlimited solarjunk and removes the scrap requirement. +equipment: + attack: + science: 20 + junk: solarjunk + slot: main_hand + speed: 5 + type: tech_weapon name: advanced solar deck -color: "DC bold" -description: "A high-powered solar deck with enhanced circuitry. Provides unlimited solarjunk and removes the scrap requirement." value: 15000 -equip_slot: main_hand -weapon_type: science -speed: 5 -stats: - science_attack: 20 -provides_junk: solarjunk diff --git a/data/items/decks/basic_deck.yaml b/data/items/decks/basic_deck.yaml index da478b0..52bcea7 100644 --- a/data/items/decks/basic_deck.yaml +++ b/data/items/decks/basic_deck.yaml @@ -1,9 +1,10 @@ +color: F5 +description: A simple programmable deck. Removes the scrap requirement for triggering mods, but provides no elemental junk. +equipment: + attack: + science: 5 + slot: main_hand + speed: 5 + type: tech_weapon name: basic deck -color: "F5" -description: "A simple programmable deck. Removes the scrap requirement for triggering mods, but provides no elemental junk." value: 500 -equip_slot: main_hand -weapon_type: science -speed: 5 -stats: - science_attack: 5 diff --git a/data/items/decks/bio_deck.yaml b/data/items/decks/bio_deck.yaml index 7211ddc..373202c 100644 --- a/data/items/decks/bio_deck.yaml +++ b/data/items/decks/bio_deck.yaml @@ -1,10 +1,11 @@ +color: C4 +description: A programmable deck infused with bio-synthetic membranes. Provides unlimited biojunk and removes the scrap requirement. +equipment: + attack: + science: 10 + junk: biojunk + slot: main_hand + speed: 5 + type: tech_weapon name: bio deck -color: "C4" -description: "A programmable deck infused with bio-synthetic membranes. Provides unlimited biojunk and removes the scrap requirement." value: 1500 -equip_slot: main_hand -weapon_type: science -speed: 5 -stats: - science_attack: 10 -provides_junk: biojunk diff --git a/data/items/decks/eco_deck.yaml b/data/items/decks/eco_deck.yaml index b922eea..9d679de 100644 --- a/data/items/decks/eco_deck.yaml +++ b/data/items/decks/eco_deck.yaml @@ -1,10 +1,11 @@ -name: eco deck color: "22" -description: "A programmable deck threaded with eco-organic circuits. Provides unlimited ecojunk and removes the scrap requirement." +description: A programmable deck threaded with eco-organic circuits. Provides unlimited ecojunk and removes the scrap requirement. +equipment: + attack: + science: 10 + junk: ecojunk + slot: main_hand + speed: 5 + type: tech_weapon +name: eco deck value: 1500 -equip_slot: main_hand -weapon_type: science -speed: 5 -stats: - science_attack: 10 -provides_junk: ecojunk diff --git a/data/items/decks/hydro_deck.yaml b/data/items/decks/hydro_deck.yaml index 51e23e3..e49cedd 100644 --- a/data/items/decks/hydro_deck.yaml +++ b/data/items/decks/hydro_deck.yaml @@ -1,10 +1,11 @@ -name: hydro deck color: "27" -description: "A programmable deck infused with hydro circuitry. Provides unlimited hydrojunk and removes the scrap requirement." +description: A programmable deck infused with hydro circuitry. Provides unlimited hydrojunk and removes the scrap requirement. +equipment: + attack: + science: 10 + junk: hydrojunk + slot: main_hand + speed: 5 + type: tech_weapon +name: hydro deck value: 1500 -equip_slot: main_hand -weapon_type: science -speed: 5 -stats: - science_attack: 10 -provides_junk: hydrojunk diff --git a/data/items/decks/solar_deck.yaml b/data/items/decks/solar_deck.yaml index c597ac6..e7816a1 100644 --- a/data/items/decks/solar_deck.yaml +++ b/data/items/decks/solar_deck.yaml @@ -1,10 +1,11 @@ +color: DC +description: A programmable deck pulsing with solar energy. Provides unlimited solarjunk and removes the scrap requirement. +equipment: + attack: + science: 10 + junk: solarjunk + slot: main_hand + speed: 5 + type: tech_weapon name: solar deck -color: "DC" -description: "A programmable deck pulsing with solar energy. Provides unlimited solarjunk and removes the scrap requirement." value: 1500 -equip_slot: main_hand -weapon_type: science -speed: 5 -stats: - science_attack: 10 -provides_junk: solarjunk diff --git a/data/items/equipment/abyssal_bracelet.yaml b/data/items/equipment/abyssal_bracelet.yaml index df10e72..f20c1c4 100644 --- a/data/items/equipment/abyssal_bracelet.yaml +++ b/data/items/equipment/abyssal_bracelet.yaml @@ -1,5 +1,7 @@ +color: FF +description: An enchanted diamond bracelet that increases scavenging output. +equipment: + slot: hands + type: armor name: abyssal bracelet -color: "FF" -description: "An enchanted diamond bracelet that increases scavenging output." value: 6000 -equip_slot: hands diff --git a/data/items/equipment/adamant_dagger.yaml b/data/items/equipment/adamant_dagger.yaml index 3f8263c..7a4a832 100644 --- a/data/items/equipment/adamant_dagger.yaml +++ b/data/items/equipment/adamant_dagger.yaml @@ -1,28 +1,29 @@ -attack_type: stab color: "78" craft: - consume: - - items: - - adamantite_bar - quantity: 1 - level: 70 - skill: smithing - station: - - anvil - type: smithing - wait: 4 - xp: 62 + ingredients: + - items: + - adamantite_bar + quantity: 1 + level: 70 + station: + - anvil + type: smithing + wait: 4 + xp: 62 description: A small adamant dagger. -equip_slot: main_hand +equipment: + attack: + crush: -1 + slash: 14 + stab: 23 + attack_type: stab + other: + strength: 19 + slot: main_hand + speed: 3 + type: melee_weapon name: adamant dagger requirements: - accuracy: 30 -speed: 3 + accuracy: 30 stackable: false -stats: - crush_attack: -1 - slash_attack: 14 - stab_attack: 23 - strength_bonus: 19 value: 400 -weapon_type: melee diff --git a/data/items/equipment/adamant_full_helm.yaml b/data/items/equipment/adamant_full_helm.yaml index 9a8e2a2..5d4bd24 100644 --- a/data/items/equipment/adamant_full_helm.yaml +++ b/data/items/equipment/adamant_full_helm.yaml @@ -1,26 +1,27 @@ color: "78" craft: - consume: - - items: - - adamantite_bar - quantity: 2 - level: 77 - skill: smithing - station: - - anvil - type: smithing - wait: 4 - xp: 125 + ingredients: + - items: + - adamantite_bar + quantity: 2 + level: 77 + station: + - anvil + type: smithing + wait: 4 + xp: 125 description: An adamant full helmet. -equip_slot: head +equipment: + defense: + crush: 16 + ranged: 22 + science: -8 + slash: 24 + stab: 22 + slot: head + type: armor name: adamant full helm requirements: - defense: 30 + defense: 30 stackable: false -stats: - crush_defense: 16 - ranged_defense: 22 - science_defense: -8 - slash_defense: 24 - stab_defense: 22 value: 1000 diff --git a/data/items/equipment/adamant_med_helm.yaml b/data/items/equipment/adamant_med_helm.yaml index baa3cf3..3b06767 100644 --- a/data/items/equipment/adamant_med_helm.yaml +++ b/data/items/equipment/adamant_med_helm.yaml @@ -1,26 +1,27 @@ color: "78" craft: - consume: - - items: - - adamantite_bar - quantity: 1 - level: 73 - skill: smithing - station: - - anvil - type: smithing - wait: 4 - xp: 62 + ingredients: + - items: + - adamantite_bar + quantity: 1 + level: 73 + station: + - anvil + type: smithing + wait: 4 + xp: 62 description: An adamant medium helmet. -equip_slot: head +equipment: + defense: + crush: 10 + ranged: 14 + science: -3 + slash: 16 + stab: 14 + slot: head + type: armor name: adamant med helm requirements: - defense: 30 + defense: 30 stackable: false -stats: - crush_defense: 10 - ranged_defense: 14 - science_defense: -3 - slash_defense: 16 - stab_defense: 14 value: 400 diff --git a/data/items/equipment/adamant_platebody.yaml b/data/items/equipment/adamant_platebody.yaml index a80f375..144bf78 100644 --- a/data/items/equipment/adamant_platebody.yaml +++ b/data/items/equipment/adamant_platebody.yaml @@ -1,26 +1,27 @@ color: "78" craft: - consume: - - items: - - adamantite_bar - quantity: 5 - level: 88 - skill: smithing - station: - - anvil - type: smithing - wait: 4 - xp: 312 + ingredients: + - items: + - adamantite_bar + quantity: 5 + level: 88 + station: + - anvil + type: smithing + wait: 4 + xp: 312 description: An adamant platebody. -equip_slot: torso +equipment: + defense: + crush: 40 + ranged: 49 + science: -25 + slash: 55 + stab: 49 + slot: torso + type: armor name: adamant platebody requirements: - defense: 30 + defense: 30 stackable: false -stats: - crush_defense: 40 - ranged_defense: 49 - science_defense: -25 - slash_defense: 55 - stab_defense: 49 value: 5000 diff --git a/data/items/equipment/adamant_sword.yaml b/data/items/equipment/adamant_sword.yaml index 0033f76..052d501 100644 --- a/data/items/equipment/adamant_sword.yaml +++ b/data/items/equipment/adamant_sword.yaml @@ -1,28 +1,29 @@ -attack_type: slash color: "78" craft: - consume: - - items: - - adamantite_bar - quantity: 1 - level: 74 - skill: smithing - station: - - anvil - type: smithing - wait: 4 - xp: 62 + ingredients: + - items: + - adamantite_bar + quantity: 1 + level: 74 + station: + - anvil + type: smithing + wait: 4 + xp: 62 description: An adamant sword. -equip_slot: main_hand +equipment: + attack: + crush: -2 + slash: 40 + stab: 20 + attack_type: slash + other: + strength: 27 + slot: main_hand + speed: 4 + type: melee_weapon name: adamant sword requirements: - accuracy: 30 -speed: 4 + accuracy: 30 stackable: false -stats: - crush_attack: -2 - slash_attack: 40 - stab_attack: 20 - strength_bonus: 27 value: 700 -weapon_type: melee diff --git a/data/items/equipment/binding_necklace.yaml b/data/items/equipment/binding_necklace.yaml index 6518ce7..879271e 100644 --- a/data/items/equipment/binding_necklace.yaml +++ b/data/items/equipment/binding_necklace.yaml @@ -1,5 +1,7 @@ -name: binding necklace color: "22" -description: "An enchanted emerald necklace. Provides a 100 percent success rate when identifying junk at altars." +description: An enchanted emerald necklace. Provides a 100 percent success rate when identifying junk at altars. +equipment: + slot: neck + type: armor +name: binding necklace value: 1200 -equip_slot: neck diff --git a/data/items/equipment/black_axe.yaml b/data/items/equipment/black_axe.yaml index ffff723..e0bbad2 100644 --- a/data/items/equipment/black_axe.yaml +++ b/data/items/equipment/black_axe.yaml @@ -1,18 +1,21 @@ +color: F0 +description: A black axe, good for woodcutting. +equipment: + attack: + crush: 14 + slash: 18 + stab: -2 + attack_type: slash + other: + strength: 14 + slot: main_hand + speed: 5 + type: melee_weapon name: black axe -color: "F0" -description: "A black axe, good for woodcutting." -value: 150 -stackable: false -equip_slot: main_hand -weapon_type: melee -attack_type: slash -stats: - stab_attack: -2 - slash_attack: 18 - crush_attack: 14 - strength_bonus: 14 -speed: 5 -tool_type: axe -tool_speed: 2.5 requirements: - accuracy: 10 + accuracy: 10 +stackable: false +tool: + speed: 2.5 + type: axe +value: 150 diff --git a/data/items/equipment/bracelet_of_clay.yaml b/data/items/equipment/bracelet_of_clay.yaml index ed9f92f..297538c 100644 --- a/data/items/equipment/bracelet_of_clay.yaml +++ b/data/items/equipment/bracelet_of_clay.yaml @@ -1,5 +1,7 @@ -name: bracelet of clay color: "27" -description: "An enchanted sapphire bracelet. Softens clay for easier crafting." +description: An enchanted sapphire bracelet. Softens clay for easier crafting. +equipment: + slot: hands + type: armor +name: bracelet of clay value: 500 -equip_slot: hands diff --git a/data/items/equipment/bracelet_of_slaughter.yaml b/data/items/equipment/bracelet_of_slaughter.yaml index 785a379..4ce08c9 100644 --- a/data/items/equipment/bracelet_of_slaughter.yaml +++ b/data/items/equipment/bracelet_of_slaughter.yaml @@ -1,5 +1,7 @@ -name: bracelet of slaughter color: "22" -description: "An enchanted emerald bracelet that provides bonus XP on kills." +description: An enchanted emerald bracelet that provides bonus XP on kills. +equipment: + slot: hands + type: armor +name: bracelet of slaughter value: 1200 -equip_slot: hands diff --git a/data/items/equipment/bronze_dagger.yaml b/data/items/equipment/bronze_dagger.yaml index d74276e..a1fa416 100644 --- a/data/items/equipment/bronze_dagger.yaml +++ b/data/items/equipment/bronze_dagger.yaml @@ -1,26 +1,27 @@ -attack_type: stab -color: "B2" +color: B2 craft: - consume: - - items: - - bronze_bar - quantity: 1 - level: 1 - skill: smithing - station: - - anvil - type: smithing - wait: 4 - xp: 12 + ingredients: + - items: + - bronze_bar + quantity: 1 + level: 1 + station: + - anvil + type: smithing + wait: 4 + xp: 12 description: A small bronze dagger. -equip_slot: main_hand +equipment: + attack: + crush: -1 + slash: 3 + stab: 5 + attack_type: stab + other: + strength: 4 + slot: main_hand + speed: 3 + type: melee_weapon name: bronze dagger -speed: 3 stackable: false -stats: - crush_attack: -1 - slash_attack: 3 - stab_attack: 5 - strength_bonus: 4 value: 8 -weapon_type: melee diff --git a/data/items/equipment/bronze_full_helm.yaml b/data/items/equipment/bronze_full_helm.yaml index 07db7f4..1d61b36 100644 --- a/data/items/equipment/bronze_full_helm.yaml +++ b/data/items/equipment/bronze_full_helm.yaml @@ -1,24 +1,25 @@ -color: "B2" +color: B2 craft: - consume: - - items: - - bronze_bar - quantity: 2 - level: 7 - skill: smithing - station: - - anvil - type: smithing - wait: 4 - xp: 25 + ingredients: + - items: + - bronze_bar + quantity: 2 + level: 7 + station: + - anvil + type: smithing + wait: 4 + xp: 25 description: A bronze full helmet. -equip_slot: head +equipment: + defense: + crush: 4 + ranged: 5 + science: -3 + slash: 6 + stab: 5 + slot: head + type: armor name: bronze full helm stackable: false -stats: - crush_defense: 4 - ranged_defense: 5 - science_defense: -3 - slash_defense: 6 - stab_defense: 5 value: 20 diff --git a/data/items/equipment/bronze_med_helm.yaml b/data/items/equipment/bronze_med_helm.yaml index d6a31ad..4832b3d 100644 --- a/data/items/equipment/bronze_med_helm.yaml +++ b/data/items/equipment/bronze_med_helm.yaml @@ -1,24 +1,25 @@ -color: "B2" +color: B2 craft: - consume: - - items: - - bronze_bar - quantity: 1 - level: 3 - skill: smithing - station: - - anvil - type: smithing - wait: 4 - xp: 12 + ingredients: + - items: + - bronze_bar + quantity: 1 + level: 3 + station: + - anvil + type: smithing + wait: 4 + xp: 12 description: A bronze medium helmet. -equip_slot: head +equipment: + defense: + crush: 2 + ranged: 3 + science: -1 + slash: 4 + stab: 3 + slot: head + type: armor name: bronze med helm stackable: false -stats: - crush_defense: 2 - ranged_defense: 3 - science_defense: -1 - slash_defense: 4 - stab_defense: 3 value: 8 diff --git a/data/items/equipment/bronze_platebody.yaml b/data/items/equipment/bronze_platebody.yaml index d6954a2..a642f14 100644 --- a/data/items/equipment/bronze_platebody.yaml +++ b/data/items/equipment/bronze_platebody.yaml @@ -1,24 +1,25 @@ -color: "B2" +color: B2 craft: - consume: - - items: - - bronze_bar - quantity: 5 - level: 18 - skill: smithing - station: - - anvil - type: smithing - wait: 4 - xp: 62 + ingredients: + - items: + - bronze_bar + quantity: 5 + level: 18 + station: + - anvil + type: smithing + wait: 4 + xp: 62 description: A bronze platebody. -equip_slot: torso +equipment: + defense: + crush: 10 + ranged: 12 + science: -10 + slash: 15 + stab: 12 + slot: torso + type: armor name: bronze platebody stackable: false -stats: - crush_defense: 10 - ranged_defense: 12 - science_defense: -10 - slash_defense: 15 - stab_defense: 12 value: 60 diff --git a/data/items/equipment/bronze_sword.yaml b/data/items/equipment/bronze_sword.yaml index 7a93c4c..56160f4 100644 --- a/data/items/equipment/bronze_sword.yaml +++ b/data/items/equipment/bronze_sword.yaml @@ -1,26 +1,27 @@ -attack_type: slash -color: "B2" +color: B2 craft: - consume: - - items: - - bronze_bar - quantity: 1 - level: 4 - skill: smithing - station: - - anvil - type: smithing - wait: 4 - xp: 12 + ingredients: + - items: + - bronze_bar + quantity: 1 + level: 4 + station: + - anvil + type: smithing + wait: 4 + xp: 12 description: A basic bronze sword. -equip_slot: main_hand +equipment: + attack: + crush: -2 + slash: 10 + stab: 4 + attack_type: slash + other: + strength: 7 + slot: main_hand + speed: 4 + type: melee_weapon name: bronze sword -speed: 4 stackable: false -stats: - crush_attack: -2 - slash_attack: 10 - stab_attack: 4 - strength_bonus: 7 value: 12 -weapon_type: melee diff --git a/data/items/equipment/capacitor_gloves.yaml b/data/items/equipment/capacitor_gloves.yaml index 85cccc0..4b30983 100644 --- a/data/items/equipment/capacitor_gloves.yaml +++ b/data/items/equipment/capacitor_gloves.yaml @@ -1,10 +1,13 @@ +color: FA +description: Gloves woven with superconducting filaments. +equipment: + defense: + crush: 2 + slash: 2 + stab: 2 + other: + technology: 2 + slot: hands + type: armor name: Capacitor Gloves -description: "Gloves woven with superconducting filaments." -color: "FA" value: 300 -equip_slot: hands -stats: - stab_defense: 2 - slash_defense: 2 - crush_defense: 2 - technology_bonus: 2 diff --git a/data/items/equipment/cape_of_agility.yaml b/data/items/equipment/cape_of_agility.yaml index 62b8635..a64be10 100644 --- a/data/items/equipment/cape_of_agility.yaml +++ b/data/items/equipment/cape_of_agility.yaml @@ -1,5 +1,7 @@ +color: g:DF,E7,DF +description: A lightweight cape that allows the wearer to move with extraordinary speed. +equipment: + slot: back + type: armor name: cape of agility -color: "g:DF,E7,DF" -description: "A lightweight cape that allows the wearer to move with extraordinary speed." value: 500 -equip_slot: back diff --git a/data/items/equipment/coif.yaml b/data/items/equipment/coif.yaml index ea02d92..7aeab1b 100644 --- a/data/items/equipment/coif.yaml +++ b/data/items/equipment/coif.yaml @@ -1,29 +1,31 @@ -color: "5E" +color: 5E craft: - consume: - - items: - - hard_leather - quantity: 1 - - items: - - thread - quantity: 1 - level: 38 - skill: crafting - tool: needle - type: crafting - wait: 4 - xp: 37 + ingredients: + - items: + - hard_leather + quantity: 1 + - items: + - thread + quantity: 1 + level: 38 + tool: needle + type: crafting + wait: 4 + xp: 37 description: A hard leather coif. -equip_slot: head +equipment: + attack: + ranged: 2 + defense: + crush: 2 + ranged: 6 + science: 4 + slash: 4 + stab: 2 + slot: head + type: armor name: coif requirements: - defense: 20 - ranged: 20 -stats: - crush_defense: 2 - ranged_attack: 2 - ranged_defense: 6 - science_defense: 4 - slash_defense: 4 - stab_defense: 2 + defense: 20 + ranged: 20 value: 45 diff --git a/data/items/equipment/diamond_amulet_u.yaml b/data/items/equipment/diamond_amulet_u.yaml index 2959aac..e8be864 100644 --- a/data/items/equipment/diamond_amulet_u.yaml +++ b/data/items/equipment/diamond_amulet_u.yaml @@ -1,6 +1,6 @@ color: "FF" craft: - consume: + ingredients: - items: - gold_bar quantity: 1 @@ -13,7 +13,6 @@ craft: - amulet_mould quantity: 1 level: 70 - skill: crafting station: - furnace type: crafting diff --git a/data/items/equipment/diamond_bracelet.yaml b/data/items/equipment/diamond_bracelet.yaml index 13acc98..090f4f5 100644 --- a/data/items/equipment/diamond_bracelet.yaml +++ b/data/items/equipment/diamond_bracelet.yaml @@ -1,25 +1,26 @@ -color: "FF" +color: FF craft: - consume: - - items: - - gold_bar - quantity: 1 - - items: - - diamond - quantity: 1 - - byproducts: - - bracelet_mould - items: - - bracelet_mould - quantity: 1 - level: 58 - skill: crafting - station: - - furnace - type: crafting - wait: 4 - xp: 95 + ingredients: + - items: + - gold_bar + quantity: 1 + - items: + - diamond + quantity: 1 + - byproducts: + - bracelet_mould + items: + - bracelet_mould + quantity: 1 + level: 58 + station: + - furnace + type: crafting + wait: 4 + xp: 95 description: A bracelet set with a diamond. Can be enchanted. -equip_slot: hands +equipment: + slot: hands + type: armor name: diamond bracelet value: 1500 diff --git a/data/items/equipment/diamond_necklace.yaml b/data/items/equipment/diamond_necklace.yaml index 19d485a..1c3510d 100644 --- a/data/items/equipment/diamond_necklace.yaml +++ b/data/items/equipment/diamond_necklace.yaml @@ -1,25 +1,26 @@ -color: "FF" +color: FF craft: - consume: - - items: - - gold_bar - quantity: 1 - - items: - - diamond - quantity: 1 - - byproducts: - - necklace_mould - items: - - necklace_mould - quantity: 1 - level: 56 - skill: crafting - station: - - furnace - type: crafting - wait: 4 - xp: 90 + ingredients: + - items: + - gold_bar + quantity: 1 + - items: + - diamond + quantity: 1 + - byproducts: + - necklace_mould + items: + - necklace_mould + quantity: 1 + level: 56 + station: + - furnace + type: crafting + wait: 4 + xp: 90 description: A necklace set with a diamond. Can be enchanted. -equip_slot: neck +equipment: + slot: neck + type: armor name: diamond necklace value: 1600 diff --git a/data/items/equipment/diamond_ring.yaml b/data/items/equipment/diamond_ring.yaml index f8fc583..a8f8017 100644 --- a/data/items/equipment/diamond_ring.yaml +++ b/data/items/equipment/diamond_ring.yaml @@ -1,25 +1,26 @@ -color: "FF" +color: FF craft: - consume: - - items: - - gold_bar - quantity: 1 - - items: - - diamond - quantity: 1 - - byproducts: - - ring_mould - items: - - ring_mould - quantity: 1 - level: 43 - skill: crafting - station: - - furnace - type: crafting - wait: 4 - xp: 85 + ingredients: + - items: + - gold_bar + quantity: 1 + - items: + - diamond + quantity: 1 + - byproducts: + - ring_mould + items: + - ring_mould + quantity: 1 + level: 43 + station: + - furnace + type: crafting + wait: 4 + xp: 85 description: A ring set with a diamond. Can be enchanted. -equip_slot: ring +equipment: + slot: ring + type: armor name: diamond ring value: 1500 diff --git a/data/items/equipment/digsite_pendant.yaml b/data/items/equipment/digsite_pendant.yaml index b8a2985..49942f1 100644 --- a/data/items/equipment/digsite_pendant.yaml +++ b/data/items/equipment/digsite_pendant.yaml @@ -1,5 +1,7 @@ +color: C4 +description: An enchanted ruby necklace that can teleport you to dig sites. +equipment: + slot: neck + type: armor name: digsite pendant -color: "C4" -description: "An enchanted ruby necklace that can teleport you to dig sites." value: 2500 -equip_slot: neck diff --git a/data/items/equipment/dragon_axe.yaml b/data/items/equipment/dragon_axe.yaml index 127b343..81f7c48 100644 --- a/data/items/equipment/dragon_axe.yaml +++ b/data/items/equipment/dragon_axe.yaml @@ -1,18 +1,21 @@ +color: C4 +description: A powerful dragon axe. +equipment: + attack: + crush: 32 + slash: 43 + stab: -2 + attack_type: slash + other: + strength: 36 + slot: main_hand + speed: 5 + type: melee_weapon name: dragon axe -color: "C4" -description: "A powerful dragon axe." -value: 50000 -stackable: false -equip_slot: main_hand -weapon_type: melee -attack_type: slash -stats: - stab_attack: -2 - slash_attack: 43 - crush_attack: 32 - strength_bonus: 36 -speed: 5 -tool_type: axe -tool_speed: 1 requirements: accuracy: 60 +stackable: false +tool: + speed: 1 + type: axe +value: 50000 diff --git a/data/items/equipment/emerald_amulet_u.yaml b/data/items/equipment/emerald_amulet_u.yaml index 27421f2..0e0ac26 100644 --- a/data/items/equipment/emerald_amulet_u.yaml +++ b/data/items/equipment/emerald_amulet_u.yaml @@ -1,6 +1,6 @@ color: "53" craft: - consume: + ingredients: - items: - gold_bar quantity: 1 @@ -13,7 +13,6 @@ craft: - amulet_mould quantity: 1 level: 31 - skill: crafting station: - furnace type: crafting diff --git a/data/items/equipment/emerald_bracelet.yaml b/data/items/equipment/emerald_bracelet.yaml index 55ad471..990a7eb 100644 --- a/data/items/equipment/emerald_bracelet.yaml +++ b/data/items/equipment/emerald_bracelet.yaml @@ -1,25 +1,26 @@ color: "22" craft: - consume: - - items: - - gold_bar - quantity: 1 - - items: - - emerald - quantity: 1 - - byproducts: - - bracelet_mould - items: - - bracelet_mould - quantity: 1 - level: 30 - skill: crafting - station: - - furnace - type: crafting - wait: 4 - xp: 65 + ingredients: + - items: + - gold_bar + quantity: 1 + - items: + - emerald + quantity: 1 + - byproducts: + - bracelet_mould + items: + - bracelet_mould + quantity: 1 + level: 30 + station: + - furnace + type: crafting + wait: 4 + xp: 65 description: A bracelet set with an emerald. Can be enchanted. -equip_slot: hands +equipment: + slot: hands + type: armor name: emerald bracelet value: 400 diff --git a/data/items/equipment/emerald_necklace.yaml b/data/items/equipment/emerald_necklace.yaml index a0a8b95..99f1af2 100644 --- a/data/items/equipment/emerald_necklace.yaml +++ b/data/items/equipment/emerald_necklace.yaml @@ -1,25 +1,26 @@ color: "22" craft: - consume: - - items: - - gold_bar - quantity: 1 - - items: - - emerald - quantity: 1 - - byproducts: - - necklace_mould - items: - - necklace_mould - quantity: 1 - level: 29 - skill: crafting - station: - - furnace - type: crafting - wait: 4 - xp: 60 + ingredients: + - items: + - gold_bar + quantity: 1 + - items: + - emerald + quantity: 1 + - byproducts: + - necklace_mould + items: + - necklace_mould + quantity: 1 + level: 29 + station: + - furnace + type: crafting + wait: 4 + xp: 60 description: A necklace set with an emerald. Can be enchanted. -equip_slot: neck +equipment: + slot: neck + type: armor name: emerald necklace value: 450 diff --git a/data/items/equipment/emerald_ring.yaml b/data/items/equipment/emerald_ring.yaml index c51f9ea..401ac71 100644 --- a/data/items/equipment/emerald_ring.yaml +++ b/data/items/equipment/emerald_ring.yaml @@ -1,25 +1,26 @@ color: "22" craft: - consume: - - items: - - gold_bar - quantity: 1 - - items: - - emerald - quantity: 1 - - byproducts: - - ring_mould - items: - - ring_mould - quantity: 1 - level: 27 - skill: crafting - station: - - furnace - type: crafting - wait: 4 - xp: 55 + ingredients: + - items: + - gold_bar + quantity: 1 + - items: + - emerald + quantity: 1 + - byproducts: + - ring_mould + items: + - ring_mould + quantity: 1 + level: 27 + station: + - furnace + type: crafting + wait: 4 + xp: 55 description: A ring set with an emerald. Can be enchanted. -equip_slot: ring +equipment: + slot: ring + type: armor name: emerald ring value: 400 diff --git a/data/items/equipment/gold_amulet_u.yaml b/data/items/equipment/gold_amulet_u.yaml index 705042d..bc8041c 100644 --- a/data/items/equipment/gold_amulet_u.yaml +++ b/data/items/equipment/gold_amulet_u.yaml @@ -1,6 +1,6 @@ color: "DC" craft: - consume: + ingredients: - items: - gold_bar quantity: 1 @@ -10,7 +10,6 @@ craft: - amulet_mould quantity: 1 level: 8 - skill: crafting station: - furnace type: crafting diff --git a/data/items/equipment/gold_bracelet.yaml b/data/items/equipment/gold_bracelet.yaml index 874441a..56882c2 100644 --- a/data/items/equipment/gold_bracelet.yaml +++ b/data/items/equipment/gold_bracelet.yaml @@ -1,22 +1,23 @@ -color: "DC" +color: DC craft: - consume: - - items: - - gold_bar - quantity: 1 - - byproducts: - - bracelet_mould - items: - - bracelet_mould - quantity: 1 - level: 7 - skill: crafting - station: - - furnace - type: crafting - wait: 4 - xp: 25 + ingredients: + - items: + - gold_bar + quantity: 1 + - byproducts: + - bracelet_mould + items: + - bracelet_mould + quantity: 1 + level: 7 + station: + - furnace + type: crafting + wait: 4 + xp: 25 description: A gold bracelet. -equip_slot: hands +equipment: + slot: hands + type: armor name: gold bracelet value: 65 diff --git a/data/items/equipment/gold_necklace.yaml b/data/items/equipment/gold_necklace.yaml index 2366bd8..dc8d439 100644 --- a/data/items/equipment/gold_necklace.yaml +++ b/data/items/equipment/gold_necklace.yaml @@ -1,22 +1,23 @@ -color: "DC" +color: DC craft: - consume: - - items: - - gold_bar - quantity: 1 - - byproducts: - - necklace_mould - items: - - necklace_mould - quantity: 1 - level: 6 - skill: crafting - station: - - furnace - type: crafting - wait: 4 - xp: 20 + ingredients: + - items: + - gold_bar + quantity: 1 + - byproducts: + - necklace_mould + items: + - necklace_mould + quantity: 1 + level: 6 + station: + - furnace + type: crafting + wait: 4 + xp: 20 description: A gold necklace. -equip_slot: neck +equipment: + slot: neck + type: armor name: gold necklace value: 60 diff --git a/data/items/equipment/gold_ring.yaml b/data/items/equipment/gold_ring.yaml index 8b6dc9d..f9106ce 100644 --- a/data/items/equipment/gold_ring.yaml +++ b/data/items/equipment/gold_ring.yaml @@ -1,22 +1,23 @@ -color: "DC" +color: DC craft: - consume: - - items: - - gold_bar - quantity: 1 - - byproducts: - - ring_mould - items: - - ring_mould - quantity: 1 - level: 5 - skill: crafting - station: - - furnace - type: crafting - wait: 4 - xp: 15 + ingredients: + - items: + - gold_bar + quantity: 1 + - byproducts: + - ring_mould + items: + - ring_mould + quantity: 1 + level: 5 + station: + - furnace + type: crafting + wait: 4 + xp: 15 description: A simple gold ring. -equip_slot: ring +equipment: + slot: ring + type: armor name: gold ring value: 50 diff --git a/data/items/equipment/graceful_boots.yaml b/data/items/equipment/graceful_boots.yaml index 52c0e9a..c300bc6 100644 --- a/data/items/equipment/graceful_boots.yaml +++ b/data/items/equipment/graceful_boots.yaml @@ -1,5 +1,7 @@ +color: E6 +description: Lightweight boots. Part of the graceful set. +equipment: + slot: feet + type: armor name: graceful boots -color: "E6" -description: "Lightweight boots. Part of the graceful set." value: 80 -equip_slot: feet diff --git a/data/items/equipment/graceful_cape.yaml b/data/items/equipment/graceful_cape.yaml index 88ebd9d..433be48 100644 --- a/data/items/equipment/graceful_cape.yaml +++ b/data/items/equipment/graceful_cape.yaml @@ -1,5 +1,7 @@ +color: E6 +description: A lightweight cape. Part of the graceful set. +equipment: + slot: back + type: armor name: graceful cape -color: "E6" -description: "A lightweight cape. Part of the graceful set." value: 100 -equip_slot: back diff --git a/data/items/equipment/graceful_gloves.yaml b/data/items/equipment/graceful_gloves.yaml index c55d41b..265b321 100644 --- a/data/items/equipment/graceful_gloves.yaml +++ b/data/items/equipment/graceful_gloves.yaml @@ -1,5 +1,7 @@ +color: E6 +description: Lightweight gloves. Part of the graceful set. +equipment: + slot: hands + type: armor name: graceful gloves -color: "E6" -description: "Lightweight gloves. Part of the graceful set." value: 80 -equip_slot: hands diff --git a/data/items/equipment/graceful_hat.yaml b/data/items/equipment/graceful_hat.yaml index 3c7a211..a0a524a 100644 --- a/data/items/equipment/graceful_hat.yaml +++ b/data/items/equipment/graceful_hat.yaml @@ -1,5 +1,7 @@ +color: E6 +description: A lightweight hat. Part of the graceful set. +equipment: + slot: head + type: armor name: graceful hat -color: "E6" -description: "A lightweight hat. Part of the graceful set." value: 100 -equip_slot: head diff --git a/data/items/equipment/graceful_legs.yaml b/data/items/equipment/graceful_legs.yaml index 5b7eb44..5142692 100644 --- a/data/items/equipment/graceful_legs.yaml +++ b/data/items/equipment/graceful_legs.yaml @@ -1,5 +1,7 @@ +color: E6 +description: Lightweight leg armour. Part of the graceful set. +equipment: + slot: legs + type: armor name: graceful legs -color: "E6" -description: "Lightweight leg armour. Part of the graceful set." value: 150 -equip_slot: legs diff --git a/data/items/equipment/graceful_torso.yaml b/data/items/equipment/graceful_torso.yaml index 656918a..502573e 100644 --- a/data/items/equipment/graceful_torso.yaml +++ b/data/items/equipment/graceful_torso.yaml @@ -1,5 +1,7 @@ +color: E6 +description: A lightweight top. Part of the graceful set. +equipment: + slot: torso + type: armor name: graceful torso -color: "E6" -description: "A lightweight top. Part of the graceful set." value: 150 -equip_slot: torso diff --git a/data/items/equipment/hard_leather_body.yaml b/data/items/equipment/hard_leather_body.yaml index 8951f1d..f621852 100644 --- a/data/items/equipment/hard_leather_body.yaml +++ b/data/items/equipment/hard_leather_body.yaml @@ -1,27 +1,28 @@ -color: "5E" +color: 5E craft: - consume: - - items: - - hard_leather - quantity: 1 - - items: - - thread - quantity: 1 - level: 28 - skill: crafting - tool: needle - type: crafting - wait: 4 - xp: 35 + ingredients: + - items: + - hard_leather + quantity: 1 + - items: + - thread + quantity: 1 + level: 28 + tool: needle + type: crafting + wait: 4 + xp: 35 description: A hardened leather body armour. -equip_slot: torso +equipment: + defense: + crush: 8 + ranged: 14 + science: 6 + slash: 12 + stab: 8 + slot: torso + type: armor name: hard leather body requirements: - defense: 10 -stats: - crush_defense: 8 - ranged_defense: 14 - science_defense: 6 - slash_defense: 12 - stab_defense: 8 + defense: 10 value: 60 diff --git a/data/items/equipment/hard_leather_shield.yaml b/data/items/equipment/hard_leather_shield.yaml index 7ea33cb..5d4a0d8 100644 --- a/data/items/equipment/hard_leather_shield.yaml +++ b/data/items/equipment/hard_leather_shield.yaml @@ -1,27 +1,28 @@ -color: "5E" +color: 5E craft: - consume: - - items: - - hard_leather - quantity: 1 - - items: - - thread - quantity: 1 - level: 41 - skill: crafting - tool: needle - type: crafting - wait: 4 - xp: 40 + ingredients: + - items: + - hard_leather + quantity: 1 + - items: + - thread + quantity: 1 + level: 41 + tool: needle + type: crafting + wait: 4 + xp: 40 description: A shield made of hardened leather. -equip_slot: off_hand +equipment: + defense: + crush: 5 + ranged: 8 + science: 4 + slash: 7 + stab: 5 + slot: off_hand + type: armor name: hard leather shield requirements: - defense: 10 -stats: - crush_defense: 5 - ranged_defense: 8 - science_defense: 4 - slash_defense: 7 - stab_defense: 5 + defense: 10 value: 55 diff --git a/data/items/equipment/inoculation_bracelet.yaml b/data/items/equipment/inoculation_bracelet.yaml index ce55652..2029a71 100644 --- a/data/items/equipment/inoculation_bracelet.yaml +++ b/data/items/equipment/inoculation_bracelet.yaml @@ -1,5 +1,7 @@ +color: C4 +description: An enchanted ruby bracelet that provides resistance to poison. +equipment: + slot: hands + type: armor name: inoculation bracelet -color: "C4" -description: "An enchanted ruby bracelet that provides resistance to poison." value: 2500 -equip_slot: hands diff --git a/data/items/equipment/insulated_gloves.yaml b/data/items/equipment/insulated_gloves.yaml index 3c50755..08740ce 100644 --- a/data/items/equipment/insulated_gloves.yaml +++ b/data/items/equipment/insulated_gloves.yaml @@ -1,8 +1,8 @@ +color: D6 +description: Heavy rubber gloves that protect against electrical attacks. Essential when fighting drones. +equipment: + slot: hands + type: armor name: insulated gloves -color: "D6" -description: "Heavy rubber gloves that protect against electrical attacks. Essential when fighting drones." -value: 50 stackable: false -equip_slot: hands -stats: - defense_bonus: 1 +value: 50 diff --git a/data/items/equipment/iron_dagger.yaml b/data/items/equipment/iron_dagger.yaml index 80c0382..024e4e1 100644 --- a/data/items/equipment/iron_dagger.yaml +++ b/data/items/equipment/iron_dagger.yaml @@ -1,26 +1,27 @@ -attack_type: stab -color: "FA" +color: FA craft: - consume: - - items: - - iron_bar - quantity: 1 - level: 20 - skill: smithing - station: - - anvil - type: smithing - wait: 4 - xp: 25 + ingredients: + - items: + - iron_bar + quantity: 1 + level: 20 + station: + - anvil + type: smithing + wait: 4 + xp: 25 description: A small iron dagger. -equip_slot: main_hand +equipment: + attack: + crush: -1 + slash: 5 + stab: 8 + attack_type: stab + other: + strength: 7 + slot: main_hand + speed: 3 + type: melee_weapon name: iron dagger -speed: 3 stackable: false -stats: - crush_attack: -1 - slash_attack: 5 - stab_attack: 8 - strength_bonus: 7 value: 20 -weapon_type: melee diff --git a/data/items/equipment/iron_full_helm.yaml b/data/items/equipment/iron_full_helm.yaml index 5e9e500..d828b95 100644 --- a/data/items/equipment/iron_full_helm.yaml +++ b/data/items/equipment/iron_full_helm.yaml @@ -1,24 +1,25 @@ -color: "FA" +color: FA craft: - consume: - - items: - - iron_bar - quantity: 2 - level: 27 - skill: smithing - station: - - anvil - type: smithing - wait: 4 - xp: 50 + ingredients: + - items: + - iron_bar + quantity: 2 + level: 27 + station: + - anvil + type: smithing + wait: 4 + xp: 50 description: An iron full helmet. -equip_slot: head +equipment: + defense: + crush: 6 + ranged: 8 + science: -3 + slash: 9 + stab: 8 + slot: head + type: armor name: iron full helm stackable: false -stats: - crush_defense: 6 - ranged_defense: 8 - science_defense: -3 - slash_defense: 9 - stab_defense: 8 value: 50 diff --git a/data/items/equipment/iron_med_helm.yaml b/data/items/equipment/iron_med_helm.yaml index 6fea4b8..250327d 100644 --- a/data/items/equipment/iron_med_helm.yaml +++ b/data/items/equipment/iron_med_helm.yaml @@ -1,24 +1,25 @@ -color: "FA" +color: FA craft: - consume: - - items: - - iron_bar - quantity: 1 - level: 22 - skill: smithing - station: - - anvil - type: smithing - wait: 4 - xp: 25 + ingredients: + - items: + - iron_bar + quantity: 1 + level: 22 + station: + - anvil + type: smithing + wait: 4 + xp: 25 description: An iron medium helmet. -equip_slot: head +equipment: + defense: + crush: 3 + ranged: 5 + science: -1 + slash: 6 + stab: 5 + slot: head + type: armor name: iron med helm stackable: false -stats: - crush_defense: 3 - ranged_defense: 5 - science_defense: -1 - slash_defense: 6 - stab_defense: 5 value: 20 diff --git a/data/items/equipment/iron_platebody.yaml b/data/items/equipment/iron_platebody.yaml index e7bfa17..73c40f1 100644 --- a/data/items/equipment/iron_platebody.yaml +++ b/data/items/equipment/iron_platebody.yaml @@ -1,24 +1,25 @@ -color: "FA" +color: FA craft: - consume: - - items: - - iron_bar - quantity: 5 - level: 33 - skill: smithing - station: - - anvil - type: smithing - wait: 4 - xp: 125 + ingredients: + - items: + - iron_bar + quantity: 5 + level: 33 + station: + - anvil + type: smithing + wait: 4 + xp: 125 description: An iron platebody. -equip_slot: torso +equipment: + defense: + crush: 14 + ranged: 18 + science: -10 + slash: 22 + stab: 18 + slot: torso + type: armor name: iron platebody stackable: false -stats: - crush_defense: 14 - ranged_defense: 18 - science_defense: -10 - slash_defense: 22 - stab_defense: 18 value: 150 diff --git a/data/items/equipment/iron_sword.yaml b/data/items/equipment/iron_sword.yaml index cdc6017..392fe53 100644 --- a/data/items/equipment/iron_sword.yaml +++ b/data/items/equipment/iron_sword.yaml @@ -1,26 +1,27 @@ -attack_type: slash -color: "FA" +color: FA craft: - consume: - - items: - - iron_bar - quantity: 1 - level: 24 - skill: smithing - station: - - anvil - type: smithing - wait: 4 - xp: 25 + ingredients: + - items: + - iron_bar + quantity: 1 + level: 24 + station: + - anvil + type: smithing + wait: 4 + xp: 25 description: An iron sword. -equip_slot: main_hand +equipment: + attack: + crush: -2 + slash: 15 + stab: 7 + attack_type: slash + other: + strength: 10 + slot: main_hand + speed: 4 + type: melee_weapon name: iron sword -speed: 4 stackable: false -stats: - crush_attack: -2 - slash_attack: 15 - stab_attack: 7 - strength_bonus: 10 value: 30 -weapon_type: melee diff --git a/data/items/equipment/leather_body.yaml b/data/items/equipment/leather_body.yaml index e201f10..6611ce2 100644 --- a/data/items/equipment/leather_body.yaml +++ b/data/items/equipment/leather_body.yaml @@ -1,25 +1,26 @@ color: "82" craft: - consume: - - items: - - leather - quantity: 1 - - items: - - thread - quantity: 1 - level: 14 - skill: crafting - tool: needle - type: crafting - wait: 4 - xp: 25 + ingredients: + - items: + - leather + quantity: 1 + - items: + - thread + quantity: 1 + level: 14 + tool: needle + type: crafting + wait: 4 + xp: 25 description: A leather body armour. -equip_slot: torso +equipment: + defense: + crush: 5 + ranged: 10 + science: 4 + slash: 7 + stab: 4 + slot: torso + type: armor name: leather body -stats: - crush_defense: 5 - ranged_defense: 10 - science_defense: 4 - slash_defense: 7 - stab_defense: 4 value: 25 diff --git a/data/items/equipment/leather_boots.yaml b/data/items/equipment/leather_boots.yaml index a917637..2d8d280 100644 --- a/data/items/equipment/leather_boots.yaml +++ b/data/items/equipment/leather_boots.yaml @@ -1,25 +1,26 @@ color: "82" craft: - consume: - - items: - - leather - quantity: 1 - - items: - - thread - quantity: 1 - level: 7 - skill: crafting - tool: needle - type: crafting - wait: 4 - xp: 16 + ingredients: + - items: + - leather + quantity: 1 + - items: + - thread + quantity: 1 + level: 7 + tool: needle + type: crafting + wait: 4 + xp: 16 description: A pair of leather boots. -equip_slot: feet +equipment: + defense: + crush: 1 + ranged: 2 + science: 1 + slash: 1 + stab: 1 + slot: feet + type: armor name: leather boots -stats: - crush_defense: 1 - ranged_defense: 2 - science_defense: 1 - slash_defense: 1 - stab_defense: 1 value: 12 diff --git a/data/items/equipment/leather_chaps.yaml b/data/items/equipment/leather_chaps.yaml index 8917732..8246c8a 100644 --- a/data/items/equipment/leather_chaps.yaml +++ b/data/items/equipment/leather_chaps.yaml @@ -1,25 +1,26 @@ color: "82" craft: - consume: - - items: - - leather - quantity: 1 - - items: - - thread - quantity: 1 - level: 18 - skill: crafting - tool: needle - type: crafting - wait: 4 - xp: 27 + ingredients: + - items: + - leather + quantity: 1 + - items: + - thread + quantity: 1 + level: 18 + tool: needle + type: crafting + wait: 4 + xp: 27 description: A pair of leather chaps. -equip_slot: legs +equipment: + defense: + crush: 3 + ranged: 6 + science: 3 + slash: 4 + stab: 2 + slot: legs + type: armor name: leather chaps -stats: - crush_defense: 3 - ranged_defense: 6 - science_defense: 3 - slash_defense: 4 - stab_defense: 2 value: 20 diff --git a/data/items/equipment/leather_cowl.yaml b/data/items/equipment/leather_cowl.yaml index b48ba23..c918ef0 100644 --- a/data/items/equipment/leather_cowl.yaml +++ b/data/items/equipment/leather_cowl.yaml @@ -1,25 +1,26 @@ color: "82" craft: - consume: - - items: - - leather - quantity: 1 - - items: - - thread - quantity: 1 - level: 9 - skill: crafting - tool: needle - type: crafting - wait: 4 - xp: 19 + ingredients: + - items: + - leather + quantity: 1 + - items: + - thread + quantity: 1 + level: 9 + tool: needle + type: crafting + wait: 4 + xp: 19 description: A leather cowl. -equip_slot: head +equipment: + defense: + crush: 1 + ranged: 4 + science: 2 + slash: 2 + stab: 1 + slot: head + type: armor name: leather cowl -stats: - crush_defense: 1 - ranged_defense: 4 - science_defense: 2 - slash_defense: 2 - stab_defense: 1 value: 15 diff --git a/data/items/equipment/leather_gloves.yaml b/data/items/equipment/leather_gloves.yaml index 04efee9..65a0168 100644 --- a/data/items/equipment/leather_gloves.yaml +++ b/data/items/equipment/leather_gloves.yaml @@ -1,25 +1,26 @@ color: "82" craft: - consume: - - items: - - leather - quantity: 1 - - items: - - thread - quantity: 1 - level: 1 - skill: crafting - tool: needle - type: crafting - wait: 4 - xp: 14 + ingredients: + - items: + - leather + quantity: 1 + - items: + - thread + quantity: 1 + level: 1 + tool: needle + type: crafting + wait: 4 + xp: 14 description: A pair of leather gloves. -equip_slot: hands +equipment: + defense: + crush: 1 + ranged: 2 + science: 1 + slash: 1 + stab: 1 + slot: hands + type: armor name: leather gloves -stats: - crush_defense: 1 - ranged_defense: 2 - science_defense: 1 - slash_defense: 1 - stab_defense: 1 value: 10 diff --git a/data/items/equipment/leather_vambraces.yaml b/data/items/equipment/leather_vambraces.yaml index 7b8022d..26b0dea 100644 --- a/data/items/equipment/leather_vambraces.yaml +++ b/data/items/equipment/leather_vambraces.yaml @@ -1,26 +1,28 @@ color: "82" craft: - consume: - - items: - - leather - quantity: 1 - - items: - - thread - quantity: 1 - level: 11 - skill: crafting - tool: needle - type: crafting - wait: 4 - xp: 22 + ingredients: + - items: + - leather + quantity: 1 + - items: + - thread + quantity: 1 + level: 11 + tool: needle + type: crafting + wait: 4 + xp: 22 description: A pair of leather vambraces. -equip_slot: hands +equipment: + attack: + ranged: 4 + defense: + crush: 2 + ranged: 4 + science: 2 + slash: 2 + stab: 2 + slot: hands + type: armor name: leather vambraces -stats: - crush_defense: 2 - ranged_attack: 4 - ranged_defense: 4 - science_defense: 2 - slash_defense: 2 - stab_defense: 2 value: 18 diff --git a/data/items/equipment/longbow.yaml b/data/items/equipment/longbow.yaml index 8c2aac5..5529c1c 100644 --- a/data/items/equipment/longbow.yaml +++ b/data/items/equipment/longbow.yaml @@ -1,23 +1,23 @@ -attack_type: ranged color: "89" craft: - consume: - - items: - - longbow_u - quantity: 1 - - items: - - bowstring - quantity: 1 - level: 10 - skill: fletching - type: fletching - wait: 2 - xp: 10 + ingredients: + - items: + - longbow_u + quantity: 1 + - items: + - bowstring + quantity: 1 + level: 10 + type: fletching + wait: 2 + xp: 10 description: A longbow. -equip_slot: main_hand +equipment: + attack: + ranged: 8 + attack_type: ranged + slot: main_hand + speed: 6 + type: ranged_weapon name: longbow -speed: 6 -stats: - ranged_attack: 8 value: 20 -weapon_type: ranged diff --git a/data/items/equipment/longbow_u.yaml b/data/items/equipment/longbow_u.yaml index b6f2c44..9597919 100644 --- a/data/items/equipment/longbow_u.yaml +++ b/data/items/equipment/longbow_u.yaml @@ -1,11 +1,10 @@ color: "89" craft: - consume: + ingredients: - items: - logs quantity: 1 level: 10 - skill: fletching tool: knife type: fletching wait: 3 diff --git a/data/items/equipment/magic_longbow.yaml b/data/items/equipment/magic_longbow.yaml index becbf99..fd39e94 100644 --- a/data/items/equipment/magic_longbow.yaml +++ b/data/items/equipment/magic_longbow.yaml @@ -1,25 +1,25 @@ -attack_type: ranged -color: "3F" +color: 3F craft: - consume: - - items: - - magic_longbow_u - quantity: 1 - - items: - - bowstring - quantity: 1 - level: 85 - skill: fletching - type: fletching - wait: 2 - xp: 91 + ingredients: + - items: + - magic_longbow_u + quantity: 1 + - items: + - bowstring + quantity: 1 + level: 85 + type: fletching + wait: 2 + xp: 91 description: A magic longbow. -equip_slot: main_hand +equipment: + attack: + ranged: 69 + attack_type: ranged + slot: main_hand + speed: 6 + type: ranged_weapon name: magic longbow requirements: - ranged: 50 -speed: 6 -stats: - ranged_attack: 69 + ranged: 50 value: 6000 -weapon_type: ranged diff --git a/data/items/equipment/magic_longbow_u.yaml b/data/items/equipment/magic_longbow_u.yaml index ac81260..fae49b7 100644 --- a/data/items/equipment/magic_longbow_u.yaml +++ b/data/items/equipment/magic_longbow_u.yaml @@ -1,11 +1,10 @@ color: "3F" craft: - consume: + ingredients: - items: - magic_logs quantity: 1 level: 85 - skill: fletching tool: knife type: fletching wait: 3 diff --git a/data/items/equipment/magic_shortbow.yaml b/data/items/equipment/magic_shortbow.yaml index 210dffe..424a504 100644 --- a/data/items/equipment/magic_shortbow.yaml +++ b/data/items/equipment/magic_shortbow.yaml @@ -1,25 +1,25 @@ -attack_type: ranged -color: "3F" +color: 3F craft: - consume: - - items: - - magic_shortbow_u - quantity: 1 - - items: - - bowstring - quantity: 1 - level: 80 - skill: fletching - type: fletching - wait: 2 - xp: 83 + ingredients: + - items: + - magic_shortbow_u + quantity: 1 + - items: + - bowstring + quantity: 1 + level: 80 + type: fletching + wait: 2 + xp: 83 description: A magic shortbow. -equip_slot: main_hand +equipment: + attack: + ranged: 69 + attack_type: ranged + slot: main_hand + speed: 4 + type: ranged_weapon name: magic shortbow requirements: - ranged: 50 -speed: 4 -stats: - ranged_attack: 69 + ranged: 50 value: 4000 -weapon_type: ranged diff --git a/data/items/equipment/magic_shortbow_u.yaml b/data/items/equipment/magic_shortbow_u.yaml index aa9e455..4ba09d6 100644 --- a/data/items/equipment/magic_shortbow_u.yaml +++ b/data/items/equipment/magic_shortbow_u.yaml @@ -1,11 +1,10 @@ color: "3F" craft: - consume: + ingredients: - items: - magic_logs quantity: 1 level: 80 - skill: fletching tool: knife type: fletching wait: 3 diff --git a/data/items/equipment/maple_longbow.yaml b/data/items/equipment/maple_longbow.yaml index 66ee5a0..994a60e 100644 --- a/data/items/equipment/maple_longbow.yaml +++ b/data/items/equipment/maple_longbow.yaml @@ -1,25 +1,25 @@ -attack_type: ranged -color: "AC" +color: AC craft: - consume: - - items: - - maple_longbow_u - quantity: 1 - - items: - - bowstring - quantity: 1 - level: 55 - skill: fletching - type: fletching - wait: 2 - xp: 58 + ingredients: + - items: + - maple_longbow_u + quantity: 1 + - items: + - bowstring + quantity: 1 + level: 55 + type: fletching + wait: 2 + xp: 58 description: A maple longbow. -equip_slot: main_hand +equipment: + attack: + ranged: 29 + attack_type: ranged + slot: main_hand + speed: 6 + type: ranged_weapon name: maple longbow requirements: - ranged: 30 -speed: 6 -stats: - ranged_attack: 29 + ranged: 30 value: 1280 -weapon_type: ranged diff --git a/data/items/equipment/maple_longbow_u.yaml b/data/items/equipment/maple_longbow_u.yaml index b26bae6..85d558a 100644 --- a/data/items/equipment/maple_longbow_u.yaml +++ b/data/items/equipment/maple_longbow_u.yaml @@ -1,11 +1,10 @@ color: "AC" craft: - consume: + ingredients: - items: - maple_logs quantity: 1 level: 55 - skill: fletching tool: knife type: fletching wait: 3 diff --git a/data/items/equipment/maple_shortbow.yaml b/data/items/equipment/maple_shortbow.yaml index 385cbd0..cd3a02c 100644 --- a/data/items/equipment/maple_shortbow.yaml +++ b/data/items/equipment/maple_shortbow.yaml @@ -1,25 +1,25 @@ -attack_type: ranged -color: "AC" +color: AC craft: - consume: - - items: - - maple_shortbow_u - quantity: 1 - - items: - - bowstring - quantity: 1 - level: 50 - skill: fletching - type: fletching - wait: 2 - xp: 50 + ingredients: + - items: + - maple_shortbow_u + quantity: 1 + - items: + - bowstring + quantity: 1 + level: 50 + type: fletching + wait: 2 + xp: 50 description: A maple shortbow. -equip_slot: main_hand +equipment: + attack: + ranged: 29 + attack_type: ranged + slot: main_hand + speed: 4 + type: ranged_weapon name: maple shortbow requirements: - ranged: 30 -speed: 4 -stats: - ranged_attack: 29 + ranged: 30 value: 640 -weapon_type: ranged diff --git a/data/items/equipment/maple_shortbow_u.yaml b/data/items/equipment/maple_shortbow_u.yaml index 5c58cbf..93e7d6c 100644 --- a/data/items/equipment/maple_shortbow_u.yaml +++ b/data/items/equipment/maple_shortbow_u.yaml @@ -1,11 +1,10 @@ color: "AC" craft: - consume: + ingredients: - items: - maple_logs quantity: 1 level: 50 - skill: fletching tool: knife type: fletching wait: 3 diff --git a/data/items/equipment/mithril_dagger.yaml b/data/items/equipment/mithril_dagger.yaml index 3b258cf..0f717e7 100644 --- a/data/items/equipment/mithril_dagger.yaml +++ b/data/items/equipment/mithril_dagger.yaml @@ -1,28 +1,29 @@ -attack_type: stab -color: "4B" +color: 4B craft: - consume: - - items: - - mithril_bar - quantity: 1 - level: 50 - skill: smithing - station: - - anvil - type: smithing - wait: 4 - xp: 50 + ingredients: + - items: + - mithril_bar + quantity: 1 + level: 50 + station: + - anvil + type: smithing + wait: 4 + xp: 50 description: A small mithril dagger. -equip_slot: main_hand +equipment: + attack: + crush: -1 + slash: 10 + stab: 17 + attack_type: stab + other: + strength: 14 + slot: main_hand + speed: 3 + type: melee_weapon name: mithril dagger requirements: - accuracy: 20 -speed: 3 + accuracy: 20 stackable: false -stats: - crush_attack: -1 - slash_attack: 10 - stab_attack: 17 - strength_bonus: 14 value: 150 -weapon_type: melee diff --git a/data/items/equipment/mithril_full_helm.yaml b/data/items/equipment/mithril_full_helm.yaml index 9b0787b..6d40856 100644 --- a/data/items/equipment/mithril_full_helm.yaml +++ b/data/items/equipment/mithril_full_helm.yaml @@ -1,26 +1,27 @@ -color: "4B" +color: 4B craft: - consume: - - items: - - mithril_bar - quantity: 2 - level: 57 - skill: smithing - station: - - anvil - type: smithing - wait: 4 - xp: 100 + ingredients: + - items: + - mithril_bar + quantity: 2 + level: 57 + station: + - anvil + type: smithing + wait: 4 + xp: 100 description: A mithril full helmet. -equip_slot: head +equipment: + defense: + crush: 12 + ranged: 16 + science: -6 + slash: 18 + stab: 16 + slot: head + type: armor name: mithril full helm requirements: - defense: 20 + defense: 20 stackable: false -stats: - crush_defense: 12 - ranged_defense: 16 - science_defense: -6 - slash_defense: 18 - stab_defense: 16 value: 400 diff --git a/data/items/equipment/mithril_med_helm.yaml b/data/items/equipment/mithril_med_helm.yaml index 0c5c936..8bf7ac1 100644 --- a/data/items/equipment/mithril_med_helm.yaml +++ b/data/items/equipment/mithril_med_helm.yaml @@ -1,26 +1,27 @@ -color: "4B" +color: 4B craft: - consume: - - items: - - mithril_bar - quantity: 1 - level: 53 - skill: smithing - station: - - anvil - type: smithing - wait: 4 - xp: 50 + ingredients: + - items: + - mithril_bar + quantity: 1 + level: 53 + station: + - anvil + type: smithing + wait: 4 + xp: 50 description: A mithril medium helmet. -equip_slot: head +equipment: + defense: + crush: 7 + ranged: 10 + science: -3 + slash: 12 + stab: 10 + slot: head + type: armor name: mithril med helm requirements: - defense: 20 + defense: 20 stackable: false -stats: - crush_defense: 7 - ranged_defense: 10 - science_defense: -3 - slash_defense: 12 - stab_defense: 10 value: 150 diff --git a/data/items/equipment/mithril_platebody.yaml b/data/items/equipment/mithril_platebody.yaml index 4683a50..04ca44e 100644 --- a/data/items/equipment/mithril_platebody.yaml +++ b/data/items/equipment/mithril_platebody.yaml @@ -1,26 +1,27 @@ -color: "4B" +color: 4B craft: - consume: - - items: - - mithril_bar - quantity: 5 - level: 68 - skill: smithing - station: - - anvil - type: smithing - wait: 4 - xp: 250 + ingredients: + - items: + - mithril_bar + quantity: 5 + level: 68 + station: + - anvil + type: smithing + wait: 4 + xp: 250 description: A mithril platebody. -equip_slot: torso +equipment: + defense: + crush: 30 + ranged: 36 + science: -20 + slash: 42 + stab: 36 + slot: torso + type: armor name: mithril platebody requirements: - defense: 20 + defense: 20 stackable: false -stats: - crush_defense: 30 - ranged_defense: 36 - science_defense: -20 - slash_defense: 42 - stab_defense: 36 value: 1500 diff --git a/data/items/equipment/mithril_sword.yaml b/data/items/equipment/mithril_sword.yaml index aee233a..fa87e56 100644 --- a/data/items/equipment/mithril_sword.yaml +++ b/data/items/equipment/mithril_sword.yaml @@ -1,28 +1,29 @@ -attack_type: slash -color: "4B" +color: 4B craft: - consume: - - items: - - mithril_bar - quantity: 1 - level: 54 - skill: smithing - station: - - anvil - type: smithing - wait: 4 - xp: 50 + ingredients: + - items: + - mithril_bar + quantity: 1 + level: 54 + station: + - anvil + type: smithing + wait: 4 + xp: 50 description: A mithril sword. -equip_slot: main_hand +equipment: + attack: + crush: -2 + slash: 30 + stab: 14 + attack_type: slash + other: + strength: 20 + slot: main_hand + speed: 4 + type: melee_weapon name: mithril sword requirements: - accuracy: 20 -speed: 4 + accuracy: 20 stackable: false -stats: - crush_attack: -2 - slash_attack: 30 - stab_attack: 14 - strength_bonus: 20 value: 250 -weapon_type: melee diff --git a/data/items/equipment/necklace_of_passage.yaml b/data/items/equipment/necklace_of_passage.yaml index 6fefd6b..b6ebe71 100644 --- a/data/items/equipment/necklace_of_passage.yaml +++ b/data/items/equipment/necklace_of_passage.yaml @@ -1,5 +1,7 @@ -name: necklace of passage color: "27" -description: "An enchanted sapphire necklace that can teleport the wearer to various locations." +description: An enchanted sapphire necklace that can teleport the wearer to various locations. +equipment: + slot: neck + type: armor +name: necklace of passage value: 750 -equip_slot: neck diff --git a/data/items/equipment/neural_headband.yaml b/data/items/equipment/neural_headband.yaml index aede26e..14a1a34 100644 --- a/data/items/equipment/neural_headband.yaml +++ b/data/items/equipment/neural_headband.yaml @@ -1,10 +1,13 @@ -name: Neural Headband -description: "A thin band of circuitry that amplifies neural signals, reducing battery drain." color: "27" +description: A thin band of circuitry that amplifies neural signals, reducing battery drain. +equipment: + defense: + crush: 1 + slash: 1 + stab: 1 + other: + technology: 4 + slot: head + type: armor +name: Neural Headband value: 500 -equip_slot: head -stats: - stab_defense: 1 - slash_defense: 1 - crush_defense: 1 - technology_bonus: 4 diff --git a/data/items/equipment/oak_longbow.yaml b/data/items/equipment/oak_longbow.yaml index bf2c259..45ef2fc 100644 --- a/data/items/equipment/oak_longbow.yaml +++ b/data/items/equipment/oak_longbow.yaml @@ -1,25 +1,25 @@ -attack_type: ranged color: "88" craft: - consume: - - items: - - oak_longbow_u - quantity: 1 - - items: - - bowstring - quantity: 1 - level: 25 - skill: fletching - type: fletching - wait: 2 - xp: 25 + ingredients: + - items: + - oak_longbow_u + quantity: 1 + - items: + - bowstring + quantity: 1 + level: 25 + type: fletching + wait: 2 + xp: 25 description: An oak longbow. -equip_slot: main_hand +equipment: + attack: + ranged: 14 + attack_type: ranged + slot: main_hand + speed: 6 + type: ranged_weapon name: oak longbow requirements: - ranged: 5 -speed: 6 -stats: - ranged_attack: 14 + ranged: 5 value: 80 -weapon_type: ranged diff --git a/data/items/equipment/oak_longbow_u.yaml b/data/items/equipment/oak_longbow_u.yaml index 89e7aa7..9d3cf68 100644 --- a/data/items/equipment/oak_longbow_u.yaml +++ b/data/items/equipment/oak_longbow_u.yaml @@ -1,11 +1,10 @@ color: "88" craft: - consume: + ingredients: - items: - oak_logs quantity: 1 level: 25 - skill: fletching tool: knife type: fletching wait: 3 diff --git a/data/items/equipment/oak_shortbow.yaml b/data/items/equipment/oak_shortbow.yaml index 879dead..767bb43 100644 --- a/data/items/equipment/oak_shortbow.yaml +++ b/data/items/equipment/oak_shortbow.yaml @@ -1,25 +1,25 @@ -attack_type: ranged color: "88" craft: - consume: - - items: - - oak_shortbow_u - quantity: 1 - - items: - - bowstring - quantity: 1 - level: 20 - skill: fletching - type: fletching - wait: 2 - xp: 16 + ingredients: + - items: + - oak_shortbow_u + quantity: 1 + - items: + - bowstring + quantity: 1 + level: 20 + type: fletching + wait: 2 + xp: 16 description: An oak shortbow. -equip_slot: main_hand +equipment: + attack: + ranged: 14 + attack_type: ranged + slot: main_hand + speed: 4 + type: ranged_weapon name: oak shortbow requirements: - ranged: 5 -speed: 4 -stats: - ranged_attack: 14 + ranged: 5 value: 40 -weapon_type: ranged diff --git a/data/items/equipment/oak_shortbow_u.yaml b/data/items/equipment/oak_shortbow_u.yaml index 553b9bd..0b567c2 100644 --- a/data/items/equipment/oak_shortbow_u.yaml +++ b/data/items/equipment/oak_shortbow_u.yaml @@ -1,11 +1,10 @@ color: "88" craft: - consume: + ingredients: - items: - oak_logs quantity: 1 level: 20 - skill: fletching tool: knife type: fletching wait: 3 diff --git a/data/items/equipment/party_hat_blue.yaml b/data/items/equipment/party_hat_blue.yaml index 87fe732..0d2f33e 100644 --- a/data/items/equipment/party_hat_blue.yaml +++ b/data/items/equipment/party_hat_blue.yaml @@ -1,6 +1,8 @@ -name: blue party hat color: "45" -description: "A festive blue party hat." -value: 2 -equip_slot: head +description: A festive blue party hat. +equipment: + slot: head + type: armor +name: blue party hat stackable: false +value: 2 diff --git a/data/items/equipment/party_hat_green.yaml b/data/items/equipment/party_hat_green.yaml index 39efc53..e8b6349 100644 --- a/data/items/equipment/party_hat_green.yaml +++ b/data/items/equipment/party_hat_green.yaml @@ -1,6 +1,8 @@ -name: green party hat color: "53" -description: "A festive green party hat." -value: 2 -equip_slot: head +description: A festive green party hat. +equipment: + slot: head + type: armor +name: green party hat stackable: false +value: 2 diff --git a/data/items/equipment/party_hat_pink.yaml b/data/items/equipment/party_hat_pink.yaml index 37473d5..da52fb7 100644 --- a/data/items/equipment/party_hat_pink.yaml +++ b/data/items/equipment/party_hat_pink.yaml @@ -1,6 +1,8 @@ +color: D5 +description: A festive pink party hat. +equipment: + slot: head + type: armor name: pink party hat -color: "D5" -description: "A festive pink party hat." -value: 2 -equip_slot: head stackable: false +value: 2 diff --git a/data/items/equipment/party_hat_red.yaml b/data/items/equipment/party_hat_red.yaml index a26b690..322c008 100644 --- a/data/items/equipment/party_hat_red.yaml +++ b/data/items/equipment/party_hat_red.yaml @@ -1,6 +1,8 @@ +color: C4 +description: A festive red party hat. +equipment: + slot: head + type: armor name: red party hat -color: "C4" -description: "A festive red party hat." -value: 2 -equip_slot: head stackable: false +value: 2 diff --git a/data/items/equipment/party_hat_white.yaml b/data/items/equipment/party_hat_white.yaml index f1e748c..138a1ab 100644 --- a/data/items/equipment/party_hat_white.yaml +++ b/data/items/equipment/party_hat_white.yaml @@ -1,6 +1,8 @@ +color: FF +description: A festive white party hat. +equipment: + slot: head + type: armor name: white party hat -color: "FF" -description: "A festive white party hat." -value: 2 -equip_slot: head stackable: false +value: 2 diff --git a/data/items/equipment/party_hat_yellow.yaml b/data/items/equipment/party_hat_yellow.yaml index eda601b..3ec9303 100644 --- a/data/items/equipment/party_hat_yellow.yaml +++ b/data/items/equipment/party_hat_yellow.yaml @@ -1,6 +1,8 @@ +color: E2 +description: A festive yellow party hat. +equipment: + slot: head + type: armor name: yellow party hat -color: "E2" -description: "A festive yellow party hat." -value: 2 -equip_slot: head stackable: false +value: 2 diff --git a/data/items/equipment/phoenix_necklace.yaml b/data/items/equipment/phoenix_necklace.yaml index 8db7ed8..c163b1f 100644 --- a/data/items/equipment/phoenix_necklace.yaml +++ b/data/items/equipment/phoenix_necklace.yaml @@ -1,5 +1,7 @@ +color: FF +description: An enchanted diamond necklace that restores HP when you drop below 20 percent health. +equipment: + slot: neck + type: armor name: phoenix necklace -color: "FF" -description: "An enchanted diamond necklace that restores HP when you drop below 20 percent health." value: 5500 -equip_slot: neck diff --git a/data/items/equipment/power_amulet.yaml b/data/items/equipment/power_amulet.yaml index 6039d03..c32063c 100644 --- a/data/items/equipment/power_amulet.yaml +++ b/data/items/equipment/power_amulet.yaml @@ -1,7 +1,9 @@ +color: DC +description: A pendant containing a miniature power cell that augments tech efficiency. +equipment: + other: + technology: 3 + slot: neck + type: armor name: Power Amulet -description: "A pendant containing a miniature power cell that augments tech efficiency." -color: "DC" value: 800 -equip_slot: neck -stats: - technology_bonus: 3 diff --git a/data/items/equipment/ring_of_dueling.yaml b/data/items/equipment/ring_of_dueling.yaml index 7b2f5a1..206d088 100644 --- a/data/items/equipment/ring_of_dueling.yaml +++ b/data/items/equipment/ring_of_dueling.yaml @@ -1,5 +1,7 @@ -name: ring of dueling color: "22" -description: "An enchanted emerald ring used for teleporting to dueling arenas." +description: An enchanted emerald ring used for teleporting to dueling arenas. +equipment: + slot: ring + type: armor +name: ring of dueling value: 1000 -equip_slot: ring diff --git a/data/items/equipment/ring_of_forging.yaml b/data/items/equipment/ring_of_forging.yaml index 0b76249..41770db 100644 --- a/data/items/equipment/ring_of_forging.yaml +++ b/data/items/equipment/ring_of_forging.yaml @@ -1,5 +1,7 @@ +color: C4 +description: An enchanted ruby ring that prevents ore from failing to smelt. +equipment: + slot: ring + type: armor name: ring of forging -color: "C4" -description: "An enchanted ruby ring that prevents ore from failing to smelt." value: 2000 -equip_slot: ring diff --git a/data/items/equipment/ring_of_life.yaml b/data/items/equipment/ring_of_life.yaml index fa831e4..5304578 100644 --- a/data/items/equipment/ring_of_life.yaml +++ b/data/items/equipment/ring_of_life.yaml @@ -1,5 +1,7 @@ +color: FF +description: An enchanted diamond ring that teleports you to safety when your HP drops critically low. +equipment: + slot: ring + type: armor name: ring of life -color: "FF" -description: "An enchanted diamond ring that teleports you to safety when your HP drops critically low." value: 5000 -equip_slot: ring diff --git a/data/items/equipment/ring_of_recoil.yaml b/data/items/equipment/ring_of_recoil.yaml index 337d4cd..b7d08ec 100644 --- a/data/items/equipment/ring_of_recoil.yaml +++ b/data/items/equipment/ring_of_recoil.yaml @@ -1,5 +1,7 @@ -name: ring of recoil color: "27" -description: "An enchanted sapphire ring that reflects a portion of melee damage back to the attacker." +description: An enchanted sapphire ring that reflects a portion of melee damage back to the attacker. +equipment: + slot: ring + type: armor +name: ring of recoil value: 500 -equip_slot: ring diff --git a/data/items/equipment/ruby_amulet_u.yaml b/data/items/equipment/ruby_amulet_u.yaml index 79cb716..261d2e9 100644 --- a/data/items/equipment/ruby_amulet_u.yaml +++ b/data/items/equipment/ruby_amulet_u.yaml @@ -1,6 +1,6 @@ color: "C4" craft: - consume: + ingredients: - items: - gold_bar quantity: 1 @@ -13,7 +13,6 @@ craft: - amulet_mould quantity: 1 level: 50 - skill: crafting station: - furnace type: crafting diff --git a/data/items/equipment/ruby_bracelet.yaml b/data/items/equipment/ruby_bracelet.yaml index 5964aa6..cc7a99a 100644 --- a/data/items/equipment/ruby_bracelet.yaml +++ b/data/items/equipment/ruby_bracelet.yaml @@ -1,25 +1,26 @@ -color: "C4" +color: C4 craft: - consume: - - items: - - gold_bar - quantity: 1 - - items: - - ruby - quantity: 1 - - byproducts: - - bracelet_mould - items: - - bracelet_mould - quantity: 1 - level: 42 - skill: crafting - station: - - furnace - type: crafting - wait: 4 - xp: 80 + ingredients: + - items: + - gold_bar + quantity: 1 + - items: + - ruby + quantity: 1 + - byproducts: + - bracelet_mould + items: + - bracelet_mould + quantity: 1 + level: 42 + station: + - furnace + type: crafting + wait: 4 + xp: 80 description: A bracelet set with a ruby. Can be enchanted. -equip_slot: hands +equipment: + slot: hands + type: armor name: ruby bracelet value: 800 diff --git a/data/items/equipment/ruby_necklace.yaml b/data/items/equipment/ruby_necklace.yaml index ec7250e..b4e6cfb 100644 --- a/data/items/equipment/ruby_necklace.yaml +++ b/data/items/equipment/ruby_necklace.yaml @@ -1,25 +1,26 @@ -color: "C4" +color: C4 craft: - consume: - - items: - - gold_bar - quantity: 1 - - items: - - ruby - quantity: 1 - - byproducts: - - necklace_mould - items: - - necklace_mould - quantity: 1 - level: 40 - skill: crafting - station: - - furnace - type: crafting - wait: 4 - xp: 75 + ingredients: + - items: + - gold_bar + quantity: 1 + - items: + - ruby + quantity: 1 + - byproducts: + - necklace_mould + items: + - necklace_mould + quantity: 1 + level: 40 + station: + - furnace + type: crafting + wait: 4 + xp: 75 description: A necklace set with a ruby. Can be enchanted. -equip_slot: neck +equipment: + slot: neck + type: armor name: ruby necklace value: 850 diff --git a/data/items/equipment/ruby_ring.yaml b/data/items/equipment/ruby_ring.yaml index a7159c8..812a969 100644 --- a/data/items/equipment/ruby_ring.yaml +++ b/data/items/equipment/ruby_ring.yaml @@ -1,25 +1,26 @@ -color: "C4" +color: C4 craft: - consume: - - items: - - gold_bar - quantity: 1 - - items: - - ruby - quantity: 1 - - byproducts: - - ring_mould - items: - - ring_mould - quantity: 1 - level: 63 - skill: crafting - station: - - furnace - type: crafting - wait: 4 - xp: 70 + ingredients: + - items: + - gold_bar + quantity: 1 + - items: + - ruby + quantity: 1 + - byproducts: + - ring_mould + items: + - ring_mould + quantity: 1 + level: 63 + station: + - furnace + type: crafting + wait: 4 + xp: 70 description: A ring set with a ruby. Can be enchanted. -equip_slot: ring +equipment: + slot: ring + type: armor name: ruby ring value: 800 diff --git a/data/items/equipment/rune_dagger.yaml b/data/items/equipment/rune_dagger.yaml index d96e2d2..005fdc2 100644 --- a/data/items/equipment/rune_dagger.yaml +++ b/data/items/equipment/rune_dagger.yaml @@ -1,28 +1,29 @@ -attack_type: stab color: "57" craft: - consume: - - items: - - runite_bar - quantity: 1 - level: 85 - skill: smithing - station: - - anvil - type: smithing - wait: 4 - xp: 75 + ingredients: + - items: + - runite_bar + quantity: 1 + level: 85 + station: + - anvil + type: smithing + wait: 4 + xp: 75 description: A small rune dagger. -equip_slot: main_hand +equipment: + attack: + crush: -1 + slash: 18 + stab: 30 + attack_type: stab + other: + strength: 24 + slot: main_hand + speed: 3 + type: melee_weapon name: rune dagger requirements: - accuracy: 40 -speed: 3 + accuracy: 40 stackable: false -stats: - crush_attack: -1 - slash_attack: 18 - stab_attack: 30 - strength_bonus: 24 value: 5000 -weapon_type: melee diff --git a/data/items/equipment/rune_full_helm.yaml b/data/items/equipment/rune_full_helm.yaml index e25f22e..92fe0d5 100644 --- a/data/items/equipment/rune_full_helm.yaml +++ b/data/items/equipment/rune_full_helm.yaml @@ -1,26 +1,27 @@ color: "57" craft: - consume: - - items: - - runite_bar - quantity: 2 - level: 92 - skill: smithing - station: - - anvil - type: smithing - wait: 4 - xp: 150 + ingredients: + - items: + - runite_bar + quantity: 2 + level: 92 + station: + - anvil + type: smithing + wait: 4 + xp: 150 description: A rune full helmet. -equip_slot: head +equipment: + defense: + crush: 22 + ranged: 30 + science: -11 + slash: 33 + stab: 30 + slot: head + type: armor name: rune full helm requirements: - defense: 40 + defense: 40 stackable: false -stats: - crush_defense: 22 - ranged_defense: 30 - science_defense: -11 - slash_defense: 33 - stab_defense: 30 value: 12000 diff --git a/data/items/equipment/rune_med_helm.yaml b/data/items/equipment/rune_med_helm.yaml index 0823947..24a8992 100644 --- a/data/items/equipment/rune_med_helm.yaml +++ b/data/items/equipment/rune_med_helm.yaml @@ -1,26 +1,27 @@ color: "57" craft: - consume: - - items: - - runite_bar - quantity: 1 - level: 88 - skill: smithing - station: - - anvil - type: smithing - wait: 4 - xp: 75 + ingredients: + - items: + - runite_bar + quantity: 1 + level: 88 + station: + - anvil + type: smithing + wait: 4 + xp: 75 description: A rune medium helmet. -equip_slot: head +equipment: + defense: + crush: 13 + ranged: 19 + science: -4 + slash: 22 + stab: 19 + slot: head + type: armor name: rune med helm requirements: - defense: 40 + defense: 40 stackable: false -stats: - crush_defense: 13 - ranged_defense: 19 - science_defense: -4 - slash_defense: 22 - stab_defense: 19 value: 5000 diff --git a/data/items/equipment/rune_platebody.yaml b/data/items/equipment/rune_platebody.yaml index 7702976..c5686d1 100644 --- a/data/items/equipment/rune_platebody.yaml +++ b/data/items/equipment/rune_platebody.yaml @@ -1,26 +1,27 @@ color: "57" craft: - consume: - - items: - - runite_bar - quantity: 5 - level: 99 - skill: smithing - station: - - anvil - type: smithing - wait: 4 - xp: 375 + ingredients: + - items: + - runite_bar + quantity: 5 + level: 99 + station: + - anvil + type: smithing + wait: 4 + xp: 375 description: A rune platebody. -equip_slot: torso +equipment: + defense: + crush: 52 + ranged: 65 + science: -30 + slash: 72 + stab: 65 + slot: torso + type: armor name: rune platebody requirements: - defense: 40 + defense: 40 stackable: false -stats: - crush_defense: 52 - ranged_defense: 65 - science_defense: -30 - slash_defense: 72 - stab_defense: 65 value: 40000 diff --git a/data/items/equipment/rune_sword.yaml b/data/items/equipment/rune_sword.yaml index f1c9f14..d0adcdb 100644 --- a/data/items/equipment/rune_sword.yaml +++ b/data/items/equipment/rune_sword.yaml @@ -1,28 +1,29 @@ -attack_type: slash color: "57" craft: - consume: - - items: - - runite_bar - quantity: 1 - level: 89 - skill: smithing - station: - - anvil - type: smithing - wait: 4 - xp: 75 + ingredients: + - items: + - runite_bar + quantity: 1 + level: 89 + station: + - anvil + type: smithing + wait: 4 + xp: 75 description: A rune sword. -equip_slot: main_hand +equipment: + attack: + crush: -2 + slash: 52 + stab: 27 + attack_type: slash + other: + strength: 36 + slot: main_hand + speed: 4 + type: melee_weapon name: rune sword requirements: - accuracy: 40 -speed: 4 + accuracy: 40 stackable: false -stats: - crush_attack: -2 - slash_attack: 52 - stab_attack: 27 - strength_bonus: 36 value: 10000 -weapon_type: melee diff --git a/data/items/equipment/sapphire_amulet_u.yaml b/data/items/equipment/sapphire_amulet_u.yaml index 20d7581..241d463 100644 --- a/data/items/equipment/sapphire_amulet_u.yaml +++ b/data/items/equipment/sapphire_amulet_u.yaml @@ -1,6 +1,6 @@ color: "45" craft: - consume: + ingredients: - items: - gold_bar quantity: 1 @@ -13,7 +13,6 @@ craft: - amulet_mould quantity: 1 level: 24 - skill: crafting station: - furnace type: crafting diff --git a/data/items/equipment/sapphire_bracelet.yaml b/data/items/equipment/sapphire_bracelet.yaml index e128639..f5cf3fb 100644 --- a/data/items/equipment/sapphire_bracelet.yaml +++ b/data/items/equipment/sapphire_bracelet.yaml @@ -1,25 +1,26 @@ color: "27" craft: - consume: - - items: - - gold_bar - quantity: 1 - - items: - - sapphire - quantity: 1 - - byproducts: - - bracelet_mould - items: - - bracelet_mould - quantity: 1 - level: 23 - skill: crafting - station: - - furnace - type: crafting - wait: 4 - xp: 60 + ingredients: + - items: + - gold_bar + quantity: 1 + - items: + - sapphire + quantity: 1 + - byproducts: + - bracelet_mould + items: + - bracelet_mould + quantity: 1 + level: 23 + station: + - furnace + type: crafting + wait: 4 + xp: 60 description: A bracelet set with a sapphire. Can be enchanted. -equip_slot: hands +equipment: + slot: hands + type: armor name: sapphire bracelet value: 200 diff --git a/data/items/equipment/sapphire_necklace.yaml b/data/items/equipment/sapphire_necklace.yaml index 5d59df6..cd93467 100644 --- a/data/items/equipment/sapphire_necklace.yaml +++ b/data/items/equipment/sapphire_necklace.yaml @@ -1,25 +1,26 @@ color: "27" craft: - consume: - - items: - - gold_bar - quantity: 1 - - items: - - sapphire - quantity: 1 - - byproducts: - - necklace_mould - items: - - necklace_mould - quantity: 1 - level: 22 - skill: crafting - station: - - furnace - type: crafting - wait: 4 - xp: 55 + ingredients: + - items: + - gold_bar + quantity: 1 + - items: + - sapphire + quantity: 1 + - byproducts: + - necklace_mould + items: + - necklace_mould + quantity: 1 + level: 22 + station: + - furnace + type: crafting + wait: 4 + xp: 55 description: A necklace set with a sapphire. Can be enchanted. -equip_slot: neck +equipment: + slot: neck + type: armor name: sapphire necklace value: 250 diff --git a/data/items/equipment/sapphire_ring.yaml b/data/items/equipment/sapphire_ring.yaml index aca01dc..da1cd43 100644 --- a/data/items/equipment/sapphire_ring.yaml +++ b/data/items/equipment/sapphire_ring.yaml @@ -1,25 +1,26 @@ color: "27" craft: - consume: - - items: - - gold_bar - quantity: 1 - - items: - - sapphire - quantity: 1 - - byproducts: - - ring_mould - items: - - ring_mould - quantity: 1 - level: 20 - skill: crafting - station: - - furnace - type: crafting - wait: 4 - xp: 40 + ingredients: + - items: + - gold_bar + quantity: 1 + - items: + - sapphire + quantity: 1 + - byproducts: + - ring_mould + items: + - ring_mould + quantity: 1 + level: 20 + station: + - furnace + type: crafting + wait: 4 + xp: 40 description: A ring set with a sapphire. Can be enchanted. -equip_slot: ring +equipment: + slot: ring + type: armor name: sapphire ring value: 200 diff --git a/data/items/equipment/shortbow.yaml b/data/items/equipment/shortbow.yaml index cec7661..cd79769 100644 --- a/data/items/equipment/shortbow.yaml +++ b/data/items/equipment/shortbow.yaml @@ -1,23 +1,23 @@ -attack_type: ranged color: "89" craft: - consume: - - items: - - shortbow_u - quantity: 1 - - items: - - bowstring - quantity: 1 - level: 5 - skill: fletching - type: fletching - wait: 2 - xp: 5 + ingredients: + - items: + - shortbow_u + quantity: 1 + - items: + - bowstring + quantity: 1 + level: 5 + type: fletching + wait: 2 + xp: 5 description: A shortbow. -equip_slot: main_hand +equipment: + attack: + ranged: 8 + attack_type: ranged + slot: main_hand + speed: 4 + type: ranged_weapon name: shortbow -speed: 4 -stats: - ranged_attack: 8 value: 10 -weapon_type: ranged diff --git a/data/items/equipment/shortbow_u.yaml b/data/items/equipment/shortbow_u.yaml index 07d5fb9..9715273 100644 --- a/data/items/equipment/shortbow_u.yaml +++ b/data/items/equipment/shortbow_u.yaml @@ -1,11 +1,10 @@ color: "89" craft: - consume: + ingredients: - items: - logs quantity: 1 level: 5 - skill: fletching tool: knife type: fletching wait: 3 diff --git a/data/items/equipment/spectral_visor.yaml b/data/items/equipment/spectral_visor.yaml index e69a785..79bd829 100644 --- a/data/items/equipment/spectral_visor.yaml +++ b/data/items/equipment/spectral_visor.yaml @@ -1,8 +1,8 @@ +color: 8D +description: A visor fitted with spectral frequency filters. Dampens psychic attacks from phantoms. +equipment: + slot: head + type: armor name: spectral visor -color: "8D" -description: "A visor fitted with spectral frequency filters. Dampens psychic attacks from phantoms." -value: 75 stackable: false -equip_slot: head -stats: - defense_bonus: 2 +value: 75 diff --git a/data/items/equipment/steel_dagger.yaml b/data/items/equipment/steel_dagger.yaml index 66265e2..4a1cbc5 100644 --- a/data/items/equipment/steel_dagger.yaml +++ b/data/items/equipment/steel_dagger.yaml @@ -1,28 +1,29 @@ -attack_type: stab -color: "FD" +color: FD craft: - consume: - - items: - - steel_bar - quantity: 1 - level: 30 - skill: smithing - station: - - anvil - type: smithing - wait: 4 - xp: 37 + ingredients: + - items: + - steel_bar + quantity: 1 + level: 30 + station: + - anvil + type: smithing + wait: 4 + xp: 37 description: A small steel dagger. -equip_slot: main_hand +equipment: + attack: + crush: -1 + slash: 7 + stab: 12 + attack_type: stab + other: + strength: 10 + slot: main_hand + speed: 3 + type: melee_weapon name: steel dagger requirements: - accuracy: 5 -speed: 3 + accuracy: 5 stackable: false -stats: - crush_attack: -1 - slash_attack: 7 - stab_attack: 12 - strength_bonus: 10 value: 60 -weapon_type: melee diff --git a/data/items/equipment/steel_full_helm.yaml b/data/items/equipment/steel_full_helm.yaml index 01c1e39..da282fa 100644 --- a/data/items/equipment/steel_full_helm.yaml +++ b/data/items/equipment/steel_full_helm.yaml @@ -1,26 +1,27 @@ -color: "FD" +color: FD craft: - consume: - - items: - - steel_bar - quantity: 2 - level: 37 - skill: smithing - station: - - anvil - type: smithing - wait: 4 - xp: 75 + ingredients: + - items: + - steel_bar + quantity: 2 + level: 37 + station: + - anvil + type: smithing + wait: 4 + xp: 75 description: A steel full helmet. -equip_slot: head +equipment: + defense: + crush: 9 + ranged: 12 + science: -5 + slash: 13 + stab: 12 + slot: head + type: armor name: steel full helm requirements: - defense: 5 + defense: 5 stackable: false -stats: - crush_defense: 9 - ranged_defense: 12 - science_defense: -5 - slash_defense: 13 - stab_defense: 12 value: 150 diff --git a/data/items/equipment/steel_med_helm.yaml b/data/items/equipment/steel_med_helm.yaml index 0c4b666..99186d0 100644 --- a/data/items/equipment/steel_med_helm.yaml +++ b/data/items/equipment/steel_med_helm.yaml @@ -1,26 +1,27 @@ -color: "FD" +color: FD craft: - consume: - - items: - - steel_bar - quantity: 1 - level: 33 - skill: smithing - station: - - anvil - type: smithing - wait: 4 - xp: 37 + ingredients: + - items: + - steel_bar + quantity: 1 + level: 33 + station: + - anvil + type: smithing + wait: 4 + xp: 37 description: A steel medium helmet. -equip_slot: head +equipment: + defense: + crush: 5 + ranged: 7 + science: -2 + slash: 9 + stab: 7 + slot: head + type: armor name: steel med helm requirements: - defense: 5 + defense: 5 stackable: false -stats: - crush_defense: 5 - ranged_defense: 7 - science_defense: -2 - slash_defense: 9 - stab_defense: 7 value: 60 diff --git a/data/items/equipment/steel_platebody.yaml b/data/items/equipment/steel_platebody.yaml index 6c6dfd2..cb80601 100644 --- a/data/items/equipment/steel_platebody.yaml +++ b/data/items/equipment/steel_platebody.yaml @@ -1,26 +1,27 @@ -color: "FD" +color: FD craft: - consume: - - items: - - steel_bar - quantity: 5 - level: 48 - skill: smithing - station: - - anvil - type: smithing - wait: 4 - xp: 187 + ingredients: + - items: + - steel_bar + quantity: 5 + level: 48 + station: + - anvil + type: smithing + wait: 4 + xp: 187 description: A steel platebody. -equip_slot: torso +equipment: + defense: + crush: 22 + ranged: 27 + science: -15 + slash: 32 + stab: 27 + slot: torso + type: armor name: steel platebody requirements: - defense: 5 + defense: 5 stackable: false -stats: - crush_defense: 22 - ranged_defense: 27 - science_defense: -15 - slash_defense: 32 - stab_defense: 27 value: 500 diff --git a/data/items/equipment/steel_sword.yaml b/data/items/equipment/steel_sword.yaml index 01ceb5c..b590210 100644 --- a/data/items/equipment/steel_sword.yaml +++ b/data/items/equipment/steel_sword.yaml @@ -1,28 +1,29 @@ -attack_type: slash -color: "FD" +color: FD craft: - consume: - - items: - - steel_bar - quantity: 1 - level: 34 - skill: smithing - station: - - anvil - type: smithing - wait: 4 - xp: 37 + ingredients: + - items: + - steel_bar + quantity: 1 + level: 34 + station: + - anvil + type: smithing + wait: 4 + xp: 37 description: A steel sword. -equip_slot: main_hand +equipment: + attack: + crush: -2 + slash: 22 + stab: 10 + attack_type: slash + other: + strength: 14 + slot: main_hand + speed: 4 + type: melee_weapon name: steel sword requirements: - accuracy: 5 -speed: 4 + accuracy: 5 stackable: false -stats: - crush_attack: -2 - slash_attack: 22 - stab_attack: 10 - strength_bonus: 14 value: 100 -weapon_type: melee diff --git a/data/items/equipment/willow_longbow.yaml b/data/items/equipment/willow_longbow.yaml index 90f8ba6..f177552 100644 --- a/data/items/equipment/willow_longbow.yaml +++ b/data/items/equipment/willow_longbow.yaml @@ -1,25 +1,25 @@ -attack_type: ranged -color: "6B" +color: 6B craft: - consume: - - items: - - willow_longbow_u - quantity: 1 - - items: - - bowstring - quantity: 1 - level: 40 - skill: fletching - type: fletching - wait: 2 - xp: 41 + ingredients: + - items: + - willow_longbow_u + quantity: 1 + - items: + - bowstring + quantity: 1 + level: 40 + type: fletching + wait: 2 + xp: 41 description: A willow longbow. -equip_slot: main_hand +equipment: + attack: + ranged: 20 + attack_type: ranged + slot: main_hand + speed: 6 + type: ranged_weapon name: willow longbow requirements: - ranged: 20 -speed: 6 -stats: - ranged_attack: 20 + ranged: 20 value: 320 -weapon_type: ranged diff --git a/data/items/equipment/willow_longbow_u.yaml b/data/items/equipment/willow_longbow_u.yaml index 9d4db3d..25194d1 100644 --- a/data/items/equipment/willow_longbow_u.yaml +++ b/data/items/equipment/willow_longbow_u.yaml @@ -1,11 +1,10 @@ color: "6B" craft: - consume: + ingredients: - items: - willow_logs quantity: 1 level: 40 - skill: fletching tool: knife type: fletching wait: 3 diff --git a/data/items/equipment/willow_shortbow.yaml b/data/items/equipment/willow_shortbow.yaml index a663353..f7028e4 100644 --- a/data/items/equipment/willow_shortbow.yaml +++ b/data/items/equipment/willow_shortbow.yaml @@ -1,25 +1,25 @@ -attack_type: ranged -color: "6B" +color: 6B craft: - consume: - - items: - - willow_shortbow_u - quantity: 1 - - items: - - bowstring - quantity: 1 - level: 35 - skill: fletching - type: fletching - wait: 2 - xp: 33 + ingredients: + - items: + - willow_shortbow_u + quantity: 1 + - items: + - bowstring + quantity: 1 + level: 35 + type: fletching + wait: 2 + xp: 33 description: A willow shortbow. -equip_slot: main_hand +equipment: + attack: + ranged: 20 + attack_type: ranged + slot: main_hand + speed: 4 + type: ranged_weapon name: willow shortbow requirements: - ranged: 20 -speed: 4 -stats: - ranged_attack: 20 + ranged: 20 value: 160 -weapon_type: ranged diff --git a/data/items/equipment/willow_shortbow_u.yaml b/data/items/equipment/willow_shortbow_u.yaml index e737292..534c50d 100644 --- a/data/items/equipment/willow_shortbow_u.yaml +++ b/data/items/equipment/willow_shortbow_u.yaml @@ -1,11 +1,10 @@ color: "6B" craft: - consume: + ingredients: - items: - willow_logs quantity: 1 level: 35 - skill: fletching tool: knife type: fletching wait: 3 diff --git a/data/items/equipment/yew_longbow.yaml b/data/items/equipment/yew_longbow.yaml index ee365d3..1deab6d 100644 --- a/data/items/equipment/yew_longbow.yaml +++ b/data/items/equipment/yew_longbow.yaml @@ -1,25 +1,25 @@ -attack_type: ranged -color: "5E" +color: 5E craft: - consume: - - items: - - yew_longbow_u - quantity: 1 - - items: - - bowstring - quantity: 1 - level: 65 - skill: fletching - type: fletching - wait: 2 - xp: 75 + ingredients: + - items: + - yew_longbow_u + quantity: 1 + - items: + - bowstring + quantity: 1 + level: 65 + type: fletching + wait: 2 + xp: 75 description: A yew longbow. -equip_slot: main_hand +equipment: + attack: + ranged: 47 + attack_type: ranged + slot: main_hand + speed: 6 + type: ranged_weapon name: yew longbow requirements: - ranged: 40 -speed: 6 -stats: - ranged_attack: 47 + ranged: 40 value: 2000 -weapon_type: ranged diff --git a/data/items/equipment/yew_longbow_u.yaml b/data/items/equipment/yew_longbow_u.yaml index ff15392..61eeac4 100644 --- a/data/items/equipment/yew_longbow_u.yaml +++ b/data/items/equipment/yew_longbow_u.yaml @@ -1,11 +1,10 @@ color: "5E" craft: - consume: + ingredients: - items: - yew_logs quantity: 1 level: 65 - skill: fletching tool: knife type: fletching wait: 3 diff --git a/data/items/equipment/yew_shortbow.yaml b/data/items/equipment/yew_shortbow.yaml index a94b78f..b9f3eb5 100644 --- a/data/items/equipment/yew_shortbow.yaml +++ b/data/items/equipment/yew_shortbow.yaml @@ -1,25 +1,25 @@ -attack_type: ranged -color: "5E" +color: 5E craft: - consume: - - items: - - yew_shortbow_u - quantity: 1 - - items: - - bowstring - quantity: 1 - level: 60 - skill: fletching - type: fletching - wait: 2 - xp: 67 + ingredients: + - items: + - yew_shortbow_u + quantity: 1 + - items: + - bowstring + quantity: 1 + level: 60 + type: fletching + wait: 2 + xp: 67 description: A yew shortbow. -equip_slot: main_hand +equipment: + attack: + ranged: 47 + attack_type: ranged + slot: main_hand + speed: 4 + type: ranged_weapon name: yew shortbow requirements: - ranged: 40 -speed: 4 -stats: - ranged_attack: 47 + ranged: 40 value: 1600 -weapon_type: ranged diff --git a/data/items/equipment/yew_shortbow_u.yaml b/data/items/equipment/yew_shortbow_u.yaml index 77cb117..ee4ed7d 100644 --- a/data/items/equipment/yew_shortbow_u.yaml +++ b/data/items/equipment/yew_shortbow_u.yaml @@ -1,11 +1,10 @@ color: "5E" craft: - consume: + ingredients: - items: - yew_logs quantity: 1 level: 60 - skill: fletching tool: knife type: fletching wait: 3 diff --git a/data/items/materials/adamant_nails.yaml b/data/items/materials/adamant_nails.yaml index e47e79c..25fb80b 100644 --- a/data/items/materials/adamant_nails.yaml +++ b/data/items/materials/adamant_nails.yaml @@ -1,12 +1,11 @@ color: "78" craft: - consume: + ingredients: - items: - adamantite_bar quantity: 1 level: 74 output_qty: 15 - skill: smithing station: - anvil type: smithing diff --git a/data/items/materials/adamantite_bar.yaml b/data/items/materials/adamantite_bar.yaml index d5095e2..4fed7fc 100644 --- a/data/items/materials/adamantite_bar.yaml +++ b/data/items/materials/adamantite_bar.yaml @@ -1,6 +1,6 @@ color: "47" craft: - consume: + ingredients: - items: - adamantite_ore quantity: 1 @@ -9,10 +9,10 @@ craft: quantity: 6 fail_message: You fail to smelt a usable bar. level: 65 - skill: smithing + subtype: smelt station: - furnace - type: smelting + type: smithing wait: 4 xp: 37 description: A bar of adamantite metal, extremely durable. diff --git a/data/items/materials/avantoe.yaml b/data/items/materials/avantoe.yaml index 340a8d0..75727af 100644 --- a/data/items/materials/avantoe.yaml +++ b/data/items/materials/avantoe.yaml @@ -1,12 +1,12 @@ color: "30" craft: - consume: + ingredients: - items: - grimy_avantoe quantity: 1 level: 48 - skill: pharmacy - type: clean + subtype: clean + type: pharmacy wait: 2 xp: 10 description: A clean avantoe leaf, ready for use in pharmacy. diff --git a/data/items/materials/ball_of_wool.yaml b/data/items/materials/ball_of_wool.yaml index de6bc98..d074203 100644 --- a/data/items/materials/ball_of_wool.yaml +++ b/data/items/materials/ball_of_wool.yaml @@ -1,12 +1,11 @@ color: "FF" craft: - consume: + ingredients: - items: - wool quantity: 1 level: 1 message: "You spin the wool into a %n." - skill: crafting station: - spinning_wheel type: crafting diff --git a/data/items/materials/bowstring.yaml b/data/items/materials/bowstring.yaml index 30b01ae..fab0510 100644 --- a/data/items/materials/bowstring.yaml +++ b/data/items/materials/bowstring.yaml @@ -1,12 +1,11 @@ color: "E6" craft: - consume: + ingredients: - items: - flax quantity: 1 level: 1 message: "You spin the flax into a %n." - skill: crafting station: - spinning_wheel type: crafting diff --git a/data/items/materials/bronze_bar.yaml b/data/items/materials/bronze_bar.yaml index fabdf07..c7a999e 100644 --- a/data/items/materials/bronze_bar.yaml +++ b/data/items/materials/bronze_bar.yaml @@ -1,6 +1,6 @@ color: "B2" craft: - consume: + ingredients: - items: - copper_ore quantity: 1 @@ -9,10 +9,10 @@ craft: quantity: 1 fail_message: You fail to smelt a usable bar. level: 1 - skill: smithing + subtype: smelt station: - furnace - type: smelting + type: smithing wait: 4 xp: 6 description: A bar of bronze metal, smelted from copper and tin ore. diff --git a/data/items/materials/bronze_nails.yaml b/data/items/materials/bronze_nails.yaml index 5b0ddfd..748f848 100644 --- a/data/items/materials/bronze_nails.yaml +++ b/data/items/materials/bronze_nails.yaml @@ -1,12 +1,11 @@ color: "B2" craft: - consume: + ingredients: - items: - bronze_bar quantity: 1 level: 4 output_qty: 15 - skill: smithing station: - anvil type: smithing diff --git a/data/items/materials/cadantine.yaml b/data/items/materials/cadantine.yaml index 6f97167..24513ce 100644 --- a/data/items/materials/cadantine.yaml +++ b/data/items/materials/cadantine.yaml @@ -1,12 +1,12 @@ color: "30" craft: - consume: + ingredients: - items: - grimy_cadantine quantity: 1 level: 65 - skill: pharmacy - type: clean + subtype: clean + type: pharmacy wait: 2 xp: 13 description: A clean cadantine leaf, ready for use in pharmacy. diff --git a/data/items/materials/diamond.yaml b/data/items/materials/diamond.yaml index 20e38b3..4bf610a 100644 --- a/data/items/materials/diamond.yaml +++ b/data/items/materials/diamond.yaml @@ -1,12 +1,11 @@ color: "FF" craft: - consume: + ingredients: - items: - uncut_diamond quantity: 1 level: 43 message: "You cut the %i1 into a beautiful %n." - skill: crafting tool: chisel type: crafting wait: 3 diff --git a/data/items/materials/dwarf_weed.yaml b/data/items/materials/dwarf_weed.yaml index 486ea18..edb1058 100644 --- a/data/items/materials/dwarf_weed.yaml +++ b/data/items/materials/dwarf_weed.yaml @@ -1,12 +1,12 @@ color: "30" craft: - consume: + ingredients: - items: - grimy_dwarf_weed quantity: 1 level: 70 - skill: pharmacy - type: clean + subtype: clean + type: pharmacy wait: 2 xp: 14 description: A clean dwarf weed leaf, ready for use in pharmacy. diff --git a/data/items/materials/emerald.yaml b/data/items/materials/emerald.yaml index 218a54a..5d729cd 100644 --- a/data/items/materials/emerald.yaml +++ b/data/items/materials/emerald.yaml @@ -1,12 +1,11 @@ color: "53" craft: - consume: + ingredients: - items: - uncut_emerald quantity: 1 level: 27 message: "You cut the %i1 into a beautiful %n." - skill: crafting tool: chisel type: crafting wait: 3 diff --git a/data/items/materials/gold_bar.yaml b/data/items/materials/gold_bar.yaml index 749584a..895db74 100644 --- a/data/items/materials/gold_bar.yaml +++ b/data/items/materials/gold_bar.yaml @@ -1,15 +1,15 @@ color: "DC" craft: - consume: + ingredients: - items: - gold_ore quantity: 1 fail_message: You fail to smelt a usable bar. level: 45 - skill: smithing + subtype: smelt station: - furnace - type: smelting + type: smithing wait: 4 xp: 22 description: A bar of gold metal. diff --git a/data/items/materials/guam.yaml b/data/items/materials/guam.yaml index c0b2592..c0ad838 100644 --- a/data/items/materials/guam.yaml +++ b/data/items/materials/guam.yaml @@ -1,12 +1,12 @@ color: "30" craft: - consume: + ingredients: - items: - grimy_guam quantity: 1 level: 1 - skill: pharmacy - type: clean + subtype: clean + type: pharmacy wait: 2 xp: 3 description: A clean guam leaf, ready for use in pharmacy. diff --git a/data/items/materials/harralander.yaml b/data/items/materials/harralander.yaml index b595db5..276c676 100644 --- a/data/items/materials/harralander.yaml +++ b/data/items/materials/harralander.yaml @@ -1,12 +1,12 @@ color: "30" craft: - consume: + ingredients: - items: - grimy_harralander quantity: 1 level: 20 - skill: pharmacy - type: clean + subtype: clean + type: pharmacy wait: 2 xp: 6 description: A clean harralander leaf, ready for use in pharmacy. diff --git a/data/items/materials/irit.yaml b/data/items/materials/irit.yaml index c6d5028..90f41b5 100644 --- a/data/items/materials/irit.yaml +++ b/data/items/materials/irit.yaml @@ -1,12 +1,12 @@ color: "30" craft: - consume: + ingredients: - items: - grimy_irit quantity: 1 level: 40 - skill: pharmacy - type: clean + subtype: clean + type: pharmacy wait: 2 xp: 9 description: A clean irit leaf, ready for use in pharmacy. diff --git a/data/items/materials/iron_bar.yaml b/data/items/materials/iron_bar.yaml index a6f89c8..4ef4c11 100644 --- a/data/items/materials/iron_bar.yaml +++ b/data/items/materials/iron_bar.yaml @@ -1,19 +1,19 @@ color: "FA" craft: - consume: + ingredients: - items: - iron_ore quantity: 1 fail_message: The iron is too impure to make a workable bar. level: 20 - skill: smithing + subtype: smelt station: - furnace success: base: 0.5 cap: 0.5 per_level: 0 - type: smelting + type: smithing wait: 4 xp: 12 description: A bar of iron metal. diff --git a/data/items/materials/iron_nails.yaml b/data/items/materials/iron_nails.yaml index 39384e8..dc647f5 100644 --- a/data/items/materials/iron_nails.yaml +++ b/data/items/materials/iron_nails.yaml @@ -1,12 +1,11 @@ color: "FA" craft: - consume: + ingredients: - items: - iron_bar quantity: 1 level: 24 output_qty: 15 - skill: smithing station: - anvil type: smithing diff --git a/data/items/materials/kwuarm.yaml b/data/items/materials/kwuarm.yaml index c31610a..77e0ead 100644 --- a/data/items/materials/kwuarm.yaml +++ b/data/items/materials/kwuarm.yaml @@ -1,12 +1,12 @@ color: "30" craft: - consume: + ingredients: - items: - grimy_kwuarm quantity: 1 level: 54 - skill: pharmacy - type: clean + subtype: clean + type: pharmacy wait: 2 xp: 11 description: A clean kwuarm leaf, ready for use in pharmacy. diff --git a/data/items/materials/lantadyme.yaml b/data/items/materials/lantadyme.yaml index 3ed6ef5..67663ac 100644 --- a/data/items/materials/lantadyme.yaml +++ b/data/items/materials/lantadyme.yaml @@ -1,12 +1,12 @@ color: "30" craft: - consume: + ingredients: - items: - grimy_lantadyme quantity: 1 level: 67 - skill: pharmacy - type: clean + subtype: clean + type: pharmacy wait: 2 xp: 13 description: A clean lantadyme leaf, ready for use in pharmacy. diff --git a/data/items/materials/mahogany_planks.yaml b/data/items/materials/mahogany_planks.yaml index a0e4ed7..a3f3e0b 100644 --- a/data/items/materials/mahogany_planks.yaml +++ b/data/items/materials/mahogany_planks.yaml @@ -1,12 +1,11 @@ color: "60" craft: - consume: + ingredients: - items: - mahogany_logs quantity: 1 level: 50 message: "You saw the mahogany logs into %n." - skill: construction station: - workbench tool: saw diff --git a/data/items/materials/marrentill.yaml b/data/items/materials/marrentill.yaml index cb37431..17730b7 100644 --- a/data/items/materials/marrentill.yaml +++ b/data/items/materials/marrentill.yaml @@ -1,12 +1,12 @@ color: "30" craft: - consume: + ingredients: - items: - grimy_marrentill quantity: 1 level: 5 - skill: pharmacy - type: clean + subtype: clean + type: pharmacy wait: 2 xp: 4 description: A clean marrentill leaf, ready for use in pharmacy. diff --git a/data/items/materials/mithril_bar.yaml b/data/items/materials/mithril_bar.yaml index f625c97..0cc0102 100644 --- a/data/items/materials/mithril_bar.yaml +++ b/data/items/materials/mithril_bar.yaml @@ -1,6 +1,6 @@ color: "4B" craft: - consume: + ingredients: - items: - mithril_ore quantity: 1 @@ -9,10 +9,10 @@ craft: quantity: 4 fail_message: You fail to smelt a usable bar. level: 50 - skill: smithing + subtype: smelt station: - furnace - type: smelting + type: smithing wait: 4 xp: 30 description: A bar of mithril metal, light and strong. diff --git a/data/items/materials/mithril_nails.yaml b/data/items/materials/mithril_nails.yaml index 43d39d2..f747da2 100644 --- a/data/items/materials/mithril_nails.yaml +++ b/data/items/materials/mithril_nails.yaml @@ -1,12 +1,11 @@ color: "4B" craft: - consume: + ingredients: - items: - mithril_bar quantity: 1 level: 54 output_qty: 15 - skill: smithing station: - anvil type: smithing diff --git a/data/items/materials/oak_planks.yaml b/data/items/materials/oak_planks.yaml index 6f6b793..82e5504 100644 --- a/data/items/materials/oak_planks.yaml +++ b/data/items/materials/oak_planks.yaml @@ -1,12 +1,11 @@ color: "66" craft: - consume: + ingredients: - items: - oak_logs quantity: 1 level: 15 message: "You saw the oak logs into %n." - skill: construction station: - workbench tool: saw diff --git a/data/items/materials/planks.yaml b/data/items/materials/planks.yaml index 1c1b8cf..d2ad6c2 100644 --- a/data/items/materials/planks.yaml +++ b/data/items/materials/planks.yaml @@ -1,12 +1,11 @@ color: "89" craft: - consume: + ingredients: - items: - logs quantity: 1 level: 1 message: "You saw the logs into %n." - skill: construction station: - workbench tool: saw diff --git a/data/items/materials/ranarr.yaml b/data/items/materials/ranarr.yaml index 94b36aa..4527c52 100644 --- a/data/items/materials/ranarr.yaml +++ b/data/items/materials/ranarr.yaml @@ -1,12 +1,12 @@ color: "30" craft: - consume: + ingredients: - items: - grimy_ranarr quantity: 1 level: 25 - skill: pharmacy - type: clean + subtype: clean + type: pharmacy wait: 2 xp: 8 description: A clean ranarr leaf, ready for use in pharmacy. diff --git a/data/items/materials/ruby.yaml b/data/items/materials/ruby.yaml index a2875f1..eb7968b 100644 --- a/data/items/materials/ruby.yaml +++ b/data/items/materials/ruby.yaml @@ -1,12 +1,11 @@ color: "C4" craft: - consume: + ingredients: - items: - uncut_ruby quantity: 1 level: 63 message: "You cut the %i1 into a beautiful %n." - skill: crafting tool: chisel type: crafting wait: 3 diff --git a/data/items/materials/rune_nails.yaml b/data/items/materials/rune_nails.yaml index c49949f..5cea6e0 100644 --- a/data/items/materials/rune_nails.yaml +++ b/data/items/materials/rune_nails.yaml @@ -1,12 +1,11 @@ color: "57" craft: - consume: + ingredients: - items: - runite_bar quantity: 1 level: 89 output_qty: 15 - skill: smithing station: - anvil type: smithing diff --git a/data/items/materials/runite_bar.yaml b/data/items/materials/runite_bar.yaml index d1c7bb0..1b4823d 100644 --- a/data/items/materials/runite_bar.yaml +++ b/data/items/materials/runite_bar.yaml @@ -1,6 +1,6 @@ color: "27" craft: - consume: + ingredients: - items: - runite_ore quantity: 1 @@ -9,10 +9,10 @@ craft: quantity: 8 fail_message: You fail to smelt a usable bar. level: 80 - skill: smithing + subtype: smelt station: - furnace - type: smelting + type: smithing wait: 4 xp: 50 description: A bar of runite metal, the finest alloy known. diff --git a/data/items/materials/sapphire.yaml b/data/items/materials/sapphire.yaml index fc11f76..bc73cd9 100644 --- a/data/items/materials/sapphire.yaml +++ b/data/items/materials/sapphire.yaml @@ -1,12 +1,11 @@ color: "45" craft: - consume: + ingredients: - items: - uncut_sapphire quantity: 1 level: 20 message: "You cut the %i1 into a beautiful %n." - skill: crafting tool: chisel type: crafting wait: 3 diff --git a/data/items/materials/silver_bar.yaml b/data/items/materials/silver_bar.yaml index ec4ae8d..cf85b31 100644 --- a/data/items/materials/silver_bar.yaml +++ b/data/items/materials/silver_bar.yaml @@ -1,15 +1,15 @@ color: "FF" craft: - consume: + ingredients: - items: - silver_ore quantity: 1 fail_message: You fail to smelt a usable bar. level: 25 - skill: smithing + subtype: smelt station: - furnace - type: smelting + type: smithing wait: 4 xp: 14 description: A bar of silver metal. diff --git a/data/items/materials/snapdragon.yaml b/data/items/materials/snapdragon.yaml index dec19d6..a05c87d 100644 --- a/data/items/materials/snapdragon.yaml +++ b/data/items/materials/snapdragon.yaml @@ -1,12 +1,12 @@ color: "30" craft: - consume: + ingredients: - items: - grimy_snapdragon quantity: 1 level: 59 - skill: pharmacy - type: clean + subtype: clean + type: pharmacy wait: 2 xp: 12 description: A clean snapdragon leaf, ready for use in pharmacy. diff --git a/data/items/materials/soft_clay.yaml b/data/items/materials/soft_clay.yaml index b55ed16..d9935dd 100644 --- a/data/items/materials/soft_clay.yaml +++ b/data/items/materials/soft_clay.yaml @@ -1,7 +1,7 @@ color: "AD" craft: type: combine - consume: + ingredients: - items: - clay quantity: 1 diff --git a/data/items/materials/steel_bar.yaml b/data/items/materials/steel_bar.yaml index 5788911..31d8224 100644 --- a/data/items/materials/steel_bar.yaml +++ b/data/items/materials/steel_bar.yaml @@ -1,6 +1,6 @@ color: "FE" craft: - consume: + ingredients: - items: - iron_ore quantity: 1 @@ -9,10 +9,10 @@ craft: quantity: 2 fail_message: You fail to smelt a usable bar. level: 40 - skill: smithing + subtype: smelt station: - furnace - type: smelting + type: smithing wait: 4 xp: 17 description: A bar of steel, forged from iron ore and coal. diff --git a/data/items/materials/steel_nails.yaml b/data/items/materials/steel_nails.yaml index ef1fe33..12bab1e 100644 --- a/data/items/materials/steel_nails.yaml +++ b/data/items/materials/steel_nails.yaml @@ -1,12 +1,11 @@ color: "FD" craft: - consume: + ingredients: - items: - steel_bar quantity: 1 level: 34 output_qty: 15 - skill: smithing station: - anvil type: smithing diff --git a/data/items/materials/stim_cell.yaml b/data/items/materials/stim_cell.yaml index c04bc05..6637cc7 100644 --- a/data/items/materials/stim_cell.yaml +++ b/data/items/materials/stim_cell.yaml @@ -1,6 +1,6 @@ color: "E2" craft: - consume: + ingredients: - items: - harralander_potion_unf quantity: 1 @@ -8,7 +8,6 @@ craft: - chocolate_dust quantity: 1 level: 26 - skill: pharmacy type: pharmacy wait: 4 xp: 68 diff --git a/data/items/materials/tarromin.yaml b/data/items/materials/tarromin.yaml index fd77fcd..4783bed 100644 --- a/data/items/materials/tarromin.yaml +++ b/data/items/materials/tarromin.yaml @@ -1,12 +1,12 @@ color: "30" craft: - consume: + ingredients: - items: - grimy_tarromin quantity: 1 level: 11 - skill: pharmacy - type: clean + subtype: clean + type: pharmacy wait: 2 xp: 5 description: A clean tarromin leaf, ready for use in pharmacy. diff --git a/data/items/materials/teak_planks.yaml b/data/items/materials/teak_planks.yaml index 3d41e0b..400c9e5 100644 --- a/data/items/materials/teak_planks.yaml +++ b/data/items/materials/teak_planks.yaml @@ -1,12 +1,11 @@ color: "64" craft: - consume: + ingredients: - items: - teak_logs quantity: 1 level: 35 message: "You saw the teak logs into %n." - skill: construction station: - workbench tool: saw diff --git a/data/items/materials/toadflax.yaml b/data/items/materials/toadflax.yaml index ba63139..9405301 100644 --- a/data/items/materials/toadflax.yaml +++ b/data/items/materials/toadflax.yaml @@ -1,12 +1,12 @@ color: "30" craft: - consume: + ingredients: - items: - grimy_toadflax quantity: 1 level: 30 - skill: pharmacy - type: clean + subtype: clean + type: pharmacy wait: 2 xp: 8 description: A clean toadflax leaf, ready for use in pharmacy. diff --git a/data/items/materials/torstol.yaml b/data/items/materials/torstol.yaml index c2cc1e8..f220b28 100644 --- a/data/items/materials/torstol.yaml +++ b/data/items/materials/torstol.yaml @@ -1,12 +1,12 @@ color: "30" craft: - consume: + ingredients: - items: - grimy_torstol quantity: 1 level: 75 - skill: pharmacy - type: clean + subtype: clean + type: pharmacy wait: 2 xp: 15 description: A clean torstol leaf, ready for use in pharmacy. diff --git a/data/items/misc/christmas_cracker.yaml b/data/items/misc/christmas_cracker.yaml index 21b63be..c3eeba3 100644 --- a/data/items/misc/christmas_cracker.yaml +++ b/data/items/misc/christmas_cracker.yaml @@ -4,6 +4,5 @@ description: "A festive party cracker. Pull it apart to see what's inside!" value: 10 stackable: true search_table: christmas_cracker_hat -search_misc_table: christmas_cracker_misc search_ticks: 3 search_message: "digging through the christmas cracker" diff --git a/data/items/misc/mahogany_table.yaml b/data/items/misc/mahogany_table.yaml index d5b23b8..aa31b1f 100644 --- a/data/items/misc/mahogany_table.yaml +++ b/data/items/misc/mahogany_table.yaml @@ -1,11 +1,10 @@ color: "60" craft: - consume: + ingredients: - items: - mahogany_planks quantity: 3 level: 52 - skill: construction station: - workbench type: construction diff --git a/data/items/misc/oak_shelf.yaml b/data/items/misc/oak_shelf.yaml index 422e2eb..94c9a7e 100644 --- a/data/items/misc/oak_shelf.yaml +++ b/data/items/misc/oak_shelf.yaml @@ -1,11 +1,10 @@ color: "5E" craft: - consume: + ingredients: - items: - oak_planks quantity: 2 level: 18 - skill: construction station: - workbench type: construction diff --git a/data/items/misc/oak_table.yaml b/data/items/misc/oak_table.yaml index d3c66b7..f096c3b 100644 --- a/data/items/misc/oak_table.yaml +++ b/data/items/misc/oak_table.yaml @@ -1,11 +1,10 @@ color: "5E" craft: - consume: + ingredients: - items: - oak_planks quantity: 3 level: 20 - skill: construction station: - workbench type: construction diff --git a/data/items/misc/teak_table.yaml b/data/items/misc/teak_table.yaml index e0dba33..b75f506 100644 --- a/data/items/misc/teak_table.yaml +++ b/data/items/misc/teak_table.yaml @@ -1,11 +1,10 @@ color: "64" craft: - consume: + ingredients: - items: - teak_planks quantity: 3 level: 38 - skill: construction station: - workbench type: construction diff --git a/data/items/misc/wooden_chair.yaml b/data/items/misc/wooden_chair.yaml index 128ab98..77de78d 100644 --- a/data/items/misc/wooden_chair.yaml +++ b/data/items/misc/wooden_chair.yaml @@ -1,11 +1,10 @@ color: "82" craft: - consume: + ingredients: - items: - planks quantity: 2 level: 8 - skill: construction station: - workbench type: construction diff --git a/data/items/misc/wooden_shelf.yaml b/data/items/misc/wooden_shelf.yaml index 5363790..bb04fc8 100644 --- a/data/items/misc/wooden_shelf.yaml +++ b/data/items/misc/wooden_shelf.yaml @@ -1,11 +1,10 @@ color: "82" craft: - consume: + ingredients: - items: - planks quantity: 2 level: 4 - skill: construction station: - workbench type: construction diff --git a/data/items/misc/wooden_table.yaml b/data/items/misc/wooden_table.yaml index f76deaa..88a996f 100644 --- a/data/items/misc/wooden_table.yaml +++ b/data/items/misc/wooden_table.yaml @@ -1,11 +1,10 @@ color: "82" craft: - consume: + ingredients: - items: - planks quantity: 3 level: 6 - skill: construction station: - workbench type: construction diff --git a/data/items/tools/adamant_axe.yaml b/data/items/tools/adamant_axe.yaml index 865bec0..78118be 100644 --- a/data/items/tools/adamant_axe.yaml +++ b/data/items/tools/adamant_axe.yaml @@ -1,18 +1,21 @@ -name: adamant axe color: "78" -description: "A sturdy adamant axe, good for woodcutting." -value: 500 -stackable: false -equip_slot: main_hand -weapon_type: melee -attack_type: slash -stats: - stab_attack: -2 - slash_attack: 29 - crush_attack: 22 - strength_bonus: 24 -speed: 5 -tool_type: axe -tool_speed: 2 +description: A sturdy adamant axe, good for woodcutting. +equipment: + attack: + crush: 22 + slash: 29 + stab: -2 + attack_type: slash + other: + strength: 24 + slot: main_hand + speed: 5 + type: melee_weapon +name: adamant axe requirements: accuracy: 30 +stackable: false +tool: + speed: 2 + type: axe +value: 500 diff --git a/data/items/tools/adamant_pickaxe.yaml b/data/items/tools/adamant_pickaxe.yaml index d2ea9bb..95ca1f5 100644 --- a/data/items/tools/adamant_pickaxe.yaml +++ b/data/items/tools/adamant_pickaxe.yaml @@ -1,18 +1,21 @@ -name: adamant pickaxe color: "78" -description: "A sturdy adamant pickaxe, good for mining." -value: 500 -stackable: false -equip_slot: main_hand -weapon_type: melee -attack_type: stab -stats: - stab_attack: 23 - slash_attack: -2 - crush_attack: 10 - strength_bonus: 16 -speed: 5 -tool_type: pickaxe -tool_speed: 0.75 +description: A sturdy adamant pickaxe, good for mining. +equipment: + attack: + crush: 10 + slash: -2 + stab: 23 + attack_type: stab + other: + strength: 16 + slot: main_hand + speed: 5 + type: melee_weapon +name: adamant pickaxe requirements: accuracy: 30 +stackable: false +tool: + speed: 0.75 + type: pickaxe +value: 500 diff --git a/data/items/tools/big_fishing_net.yaml b/data/items/tools/big_fishing_net.yaml index 4398587..10f3f57 100644 --- a/data/items/tools/big_fishing_net.yaml +++ b/data/items/tools/big_fishing_net.yaml @@ -1,14 +1,14 @@ +color: E6 +description: A larger fishing net for catching bigger fish. +equipment: + other: + strength: 0 + slot: main_hand + speed: 5 + type: melee_weapon name: big fishing net -color: "E6" -description: "A larger fishing net for catching bigger fish." -value: 20 stackable: false -equip_slot: main_hand -weapon_type: melee -stats: - attack_bonus: 0 - strength_bonus: 0 - defense_bonus: 0 -speed: 5 -tool_type: big_net -tool_speed: 1 +tool: + speed: 1 + type: big_net +value: 20 diff --git a/data/items/tools/black_pickaxe.yaml b/data/items/tools/black_pickaxe.yaml index 22d5363..5b06f32 100644 --- a/data/items/tools/black_pickaxe.yaml +++ b/data/items/tools/black_pickaxe.yaml @@ -1,18 +1,21 @@ +color: F0 +description: A black pickaxe, good for mining. +equipment: + attack: + crush: 6 + slash: -2 + stab: 14 + attack_type: stab + other: + strength: 9 + slot: main_hand + speed: 5 + type: melee_weapon name: black pickaxe -color: "F0" -description: "A black pickaxe, good for mining." -value: 150 -stackable: false -equip_slot: main_hand -weapon_type: melee -attack_type: stab -stats: - stab_attack: 14 - slash_attack: -2 - crush_attack: 6 - strength_bonus: 9 -speed: 5 -tool_type: pickaxe -tool_speed: 1 requirements: accuracy: 10 +stackable: false +tool: + speed: 1 + type: pickaxe +value: 150 diff --git a/data/items/tools/bronze_axe.yaml b/data/items/tools/bronze_axe.yaml index 863c34a..91c0b43 100644 --- a/data/items/tools/bronze_axe.yaml +++ b/data/items/tools/bronze_axe.yaml @@ -1,16 +1,19 @@ +color: B2 +description: A sturdy bronze axe, good for woodcutting. +equipment: + attack: + crush: 5 + slash: 7 + stab: -2 + attack_type: slash + other: + strength: 5 + slot: main_hand + speed: 5 + type: melee_weapon name: bronze axe -color: "B2" -description: "A sturdy bronze axe, good for woodcutting." -value: 10 stackable: false -equip_slot: main_hand -weapon_type: melee -attack_type: slash -stats: - stab_attack: -2 - slash_attack: 7 - crush_attack: 5 - strength_bonus: 5 -speed: 5 -tool_type: axe -tool_speed: 4 +tool: + speed: 4 + type: axe +value: 10 diff --git a/data/items/tools/bronze_pickaxe.yaml b/data/items/tools/bronze_pickaxe.yaml index e280020..807cadb 100644 --- a/data/items/tools/bronze_pickaxe.yaml +++ b/data/items/tools/bronze_pickaxe.yaml @@ -1,16 +1,19 @@ +color: B2 +description: A sturdy bronze pickaxe, good for mining. +equipment: + attack: + crush: 2 + slash: -2 + stab: 4 + attack_type: stab + other: + strength: 3 + slot: main_hand + speed: 5 + type: melee_weapon name: bronze pickaxe -color: "B2" -description: "A sturdy bronze pickaxe, good for mining." -value: 10 stackable: false -equip_slot: main_hand -weapon_type: melee -attack_type: stab -stats: - stab_attack: 4 - slash_attack: -2 - crush_attack: 2 - strength_bonus: 3 -speed: 5 -tool_type: pickaxe -tool_speed: 2 +tool: + speed: 2 + type: pickaxe +value: 10 diff --git a/data/items/tools/chisel.yaml b/data/items/tools/chisel.yaml index c4d67b7..c5b9ca6 100644 --- a/data/items/tools/chisel.yaml +++ b/data/items/tools/chisel.yaml @@ -1,5 +1,6 @@ +color: FA +description: A chisel used for cutting gems. name: chisel -color: "FA" -description: "A chisel used for cutting gems." +tool: + type: chisel value: 5 -tool_type: chisel diff --git a/data/items/tools/dragon_pickaxe.yaml b/data/items/tools/dragon_pickaxe.yaml index 0dd3cd4..25c5cce 100644 --- a/data/items/tools/dragon_pickaxe.yaml +++ b/data/items/tools/dragon_pickaxe.yaml @@ -1,18 +1,21 @@ +color: C4 +description: A powerful dragon pickaxe. +equipment: + attack: + crush: 16 + slash: -2 + stab: 34 + attack_type: stab + other: + strength: 26 + slot: main_hand + speed: 5 + type: melee_weapon name: dragon pickaxe -color: "C4" -description: "A powerful dragon pickaxe." -value: 50000 -stackable: false -equip_slot: main_hand -weapon_type: melee -attack_type: stab -stats: - stab_attack: 34 - slash_attack: -2 - crush_attack: 16 - strength_bonus: 26 -speed: 5 -tool_type: pickaxe -tool_speed: 0.25 requirements: accuracy: 60 +stackable: false +tool: + speed: 0.25 + type: pickaxe +value: 50000 diff --git a/data/items/tools/empty_pot.yaml b/data/items/tools/empty_pot.yaml index 93c9a04..371a783 100644 --- a/data/items/tools/empty_pot.yaml +++ b/data/items/tools/empty_pot.yaml @@ -1,13 +1,12 @@ color: "82" craft: - consume: + ingredients: - items: - unfired_pot quantity: 1 fail_message: The pot cracks in the oven and is ruined. level: 1 message: "You fire the %i1 in the oven." - skill: crafting station: - pottery_oven success: diff --git a/data/items/tools/firesteel.yaml b/data/items/tools/firesteel.yaml index bccd390..861e879 100644 --- a/data/items/tools/firesteel.yaml +++ b/data/items/tools/firesteel.yaml @@ -1,7 +1,8 @@ +color: FA +description: A rugged firesteel that never wears out. name: firesteel -color: "FA" -description: "A rugged firesteel that never wears out." -value: 20 stackable: false -tool_type: fire -tool_speed: 4 +tool: + speed: 4 + type: fire +value: 20 diff --git a/data/items/tools/fishing_rod.yaml b/data/items/tools/fishing_rod.yaml index e7e3023..b9e5610 100644 --- a/data/items/tools/fishing_rod.yaml +++ b/data/items/tools/fishing_rod.yaml @@ -1,14 +1,14 @@ +color: 6B +description: A simple fishing rod. Use with fishing bait. +equipment: + other: + strength: 0 + slot: main_hand + speed: 5 + type: melee_weapon name: fishing rod -color: "6B" -description: "A simple fishing rod. Use with fishing bait." -value: 5 stackable: false -equip_slot: main_hand -weapon_type: melee -stats: - attack_bonus: 0 - strength_bonus: 0 - defense_bonus: 0 -speed: 5 -tool_type: fishing_rod -tool_speed: 0 +tool: + speed: 0 + type: fishing_rod +value: 5 diff --git a/data/items/tools/fly_fishing_rod.yaml b/data/items/tools/fly_fishing_rod.yaml index a65b90c..fc4655d 100644 --- a/data/items/tools/fly_fishing_rod.yaml +++ b/data/items/tools/fly_fishing_rod.yaml @@ -1,14 +1,14 @@ +color: 6B +description: A flexible rod for fly fishing with artificial flies. +equipment: + other: + strength: 0 + slot: main_hand + speed: 5 + type: melee_weapon name: fly fishing rod -color: "6B" -description: "A flexible rod for fly fishing with artificial flies." -value: 20 stackable: false -equip_slot: main_hand -weapon_type: melee -stats: - attack_bonus: 0 - strength_bonus: 0 - defense_bonus: 0 -speed: 5 -tool_type: fly_rod -tool_speed: 1 +tool: + speed: 1 + type: fly_rod +value: 20 diff --git a/data/items/tools/hammer.yaml b/data/items/tools/hammer.yaml index a017160..3f156aa 100644 --- a/data/items/tools/hammer.yaml +++ b/data/items/tools/hammer.yaml @@ -1,6 +1,7 @@ +color: FA +description: A sturdy hammer for smithing metal on an anvil. name: hammer -color: "FA" -description: "A sturdy hammer for smithing metal on an anvil." -value: 10 stackable: false -tool_type: hammer +tool: + type: hammer +value: 10 diff --git a/data/items/tools/harpoon.yaml b/data/items/tools/harpoon.yaml index 639f978..51163f5 100644 --- a/data/items/tools/harpoon.yaml +++ b/data/items/tools/harpoon.yaml @@ -1,14 +1,14 @@ +color: FA +description: A barbed harpoon for spearing large fish. +equipment: + other: + strength: 0 + slot: main_hand + speed: 5 + type: melee_weapon name: harpoon -color: "FA" -description: "A barbed harpoon for spearing large fish." -value: 30 stackable: false -equip_slot: main_hand -weapon_type: melee -stats: - attack_bonus: 0 - strength_bonus: 0 - defense_bonus: 0 -speed: 5 -tool_type: harpoon -tool_speed: 0 +tool: + speed: 0 + type: harpoon +value: 30 diff --git a/data/items/tools/iron_axe.yaml b/data/items/tools/iron_axe.yaml index bac2530..bb633f5 100644 --- a/data/items/tools/iron_axe.yaml +++ b/data/items/tools/iron_axe.yaml @@ -1,16 +1,19 @@ +color: FA +description: A sturdy iron axe, good for woodcutting. +equipment: + attack: + crush: 7 + slash: 10 + stab: -2 + attack_type: slash + other: + strength: 8 + slot: main_hand + speed: 5 + type: melee_weapon name: iron axe -color: "FA" -description: "A sturdy iron axe, good for woodcutting." -value: 25 stackable: false -equip_slot: main_hand -weapon_type: melee -attack_type: slash -stats: - stab_attack: -2 - slash_attack: 10 - crush_attack: 7 - strength_bonus: 8 -speed: 5 -tool_type: axe -tool_speed: 3.5 +tool: + speed: 3.5 + type: axe +value: 25 diff --git a/data/items/tools/iron_pickaxe.yaml b/data/items/tools/iron_pickaxe.yaml index bdb4531..e003c93 100644 --- a/data/items/tools/iron_pickaxe.yaml +++ b/data/items/tools/iron_pickaxe.yaml @@ -1,16 +1,19 @@ +color: FA +description: A sturdy iron pickaxe, good for mining. +equipment: + attack: + crush: 3 + slash: -2 + stab: 7 + attack_type: stab + other: + strength: 5 + slot: main_hand + speed: 5 + type: melee_weapon name: iron pickaxe -color: "FA" -description: "A sturdy iron pickaxe, good for mining." -value: 25 stackable: false -equip_slot: main_hand -weapon_type: melee -attack_type: stab -stats: - stab_attack: 7 - slash_attack: -2 - crush_attack: 3 - strength_bonus: 5 -speed: 5 -tool_type: pickaxe -tool_speed: 1.5 +tool: + speed: 1.5 + type: pickaxe +value: 25 diff --git a/data/items/tools/knife.yaml b/data/items/tools/knife.yaml index ce27095..353d859 100644 --- a/data/items/tools/knife.yaml +++ b/data/items/tools/knife.yaml @@ -1,5 +1,6 @@ +color: FA +description: A small knife used for cutting wood and fletching. name: knife -color: "FA" -description: "A small knife used for cutting wood and fletching." +tool: + type: knife value: 5 -tool_type: knife diff --git a/data/items/tools/lighter.yaml b/data/items/tools/lighter.yaml index ff38aa4..9f47a45 100644 --- a/data/items/tools/lighter.yaml +++ b/data/items/tools/lighter.yaml @@ -1,10 +1,13 @@ -name: lighter color: "51" -description: "A reliable butane lighter." -value: 15 -stackable: false -equip_slot: main_hand -tool_type: fire -tool_speed: 4 -quality: 100 +description: A reliable butane lighter. +equipment: + slot: main_hand + type: tool max_quality: 100 +name: lighter +quality: 100 +stackable: false +tool: + speed: 4 + type: fire +value: 15 diff --git a/data/items/tools/lobster_pot.yaml b/data/items/tools/lobster_pot.yaml index 6e4a1d4..56760de 100644 --- a/data/items/tools/lobster_pot.yaml +++ b/data/items/tools/lobster_pot.yaml @@ -1,14 +1,14 @@ +color: FA +description: A wire cage for trapping lobsters. +equipment: + other: + strength: 0 + slot: main_hand + speed: 5 + type: melee_weapon name: lobster pot -color: "FA" -description: "A wire cage for trapping lobsters." -value: 20 stackable: false -equip_slot: main_hand -weapon_type: melee -stats: - attack_bonus: 0 - strength_bonus: 0 - defense_bonus: 0 -speed: 5 -tool_type: lobster_pot -tool_speed: 0 +tool: + speed: 0 + type: lobster_pot +value: 20 diff --git a/data/items/tools/matches.yaml b/data/items/tools/matches.yaml index c7cf9dd..75f8c1a 100644 --- a/data/items/tools/matches.yaml +++ b/data/items/tools/matches.yaml @@ -1,8 +1,11 @@ +color: C4 +description: A small box of matches for starting fires. +equipment: + slot: main_hand + type: tool name: matches -color: "C4" -description: "A small box of matches for starting fires." -value: 5 stackable: true -equip_slot: main_hand -tool_type: fire -tool_speed: 4 +tool: + speed: 4 + type: fire +value: 5 diff --git a/data/items/tools/mithril_axe.yaml b/data/items/tools/mithril_axe.yaml index f0976a9..31aef89 100644 --- a/data/items/tools/mithril_axe.yaml +++ b/data/items/tools/mithril_axe.yaml @@ -1,18 +1,21 @@ +color: 4B +description: A sturdy mithril axe, good for woodcutting. +equipment: + attack: + crush: 16 + slash: 21 + stab: -2 + attack_type: slash + other: + strength: 17 + slot: main_hand + speed: 5 + type: melee_weapon name: mithril axe -color: "4B" -description: "A sturdy mithril axe, good for woodcutting." -value: 200 -stackable: false -equip_slot: main_hand -weapon_type: melee -attack_type: slash -stats: - stab_attack: -2 - slash_attack: 21 - crush_attack: 16 - strength_bonus: 17 -speed: 5 -tool_type: axe -tool_speed: 2.5 requirements: accuracy: 20 +stackable: false +tool: + speed: 2.5 + type: axe +value: 200 diff --git a/data/items/tools/mithril_pickaxe.yaml b/data/items/tools/mithril_pickaxe.yaml index e525c21..ab2996d 100644 --- a/data/items/tools/mithril_pickaxe.yaml +++ b/data/items/tools/mithril_pickaxe.yaml @@ -1,18 +1,21 @@ +color: 4B +description: A sturdy mithril pickaxe, good for mining. +equipment: + attack: + crush: 8 + slash: -2 + stab: 17 + attack_type: stab + other: + strength: 12 + slot: main_hand + speed: 5 + type: melee_weapon name: mithril pickaxe -color: "4B" -description: "A sturdy mithril pickaxe, good for mining." -value: 200 -stackable: false -equip_slot: main_hand -weapon_type: melee -attack_type: stab -stats: - stab_attack: 17 - slash_attack: -2 - crush_attack: 8 - strength_bonus: 12 -speed: 5 -tool_type: pickaxe -tool_speed: 1 requirements: accuracy: 20 +stackable: false +tool: + speed: 1 + type: pickaxe +value: 200 diff --git a/data/items/tools/needle.yaml b/data/items/tools/needle.yaml index a5adf2a..bc12202 100644 --- a/data/items/tools/needle.yaml +++ b/data/items/tools/needle.yaml @@ -1,5 +1,6 @@ +color: FA +description: A needle for crafting leather goods. name: needle -color: "FA" -description: "A needle for crafting leather goods." +tool: + type: needle value: 5 -tool_type: needle diff --git a/data/items/tools/plant_pot.yaml b/data/items/tools/plant_pot.yaml index ede859c..e758167 100644 --- a/data/items/tools/plant_pot.yaml +++ b/data/items/tools/plant_pot.yaml @@ -1,13 +1,12 @@ color: "82" craft: - consume: + ingredients: - items: - unfired_plant_pot quantity: 1 fail_message: The plant pot cracks in the oven and is ruined. level: 19 message: "You fire the %i1 in the oven." - skill: crafting station: - pottery_oven success: diff --git a/data/items/tools/rake.yaml b/data/items/tools/rake.yaml index 3848104..ca5e44b 100644 --- a/data/items/tools/rake.yaml +++ b/data/items/tools/rake.yaml @@ -1,6 +1,7 @@ +color: 5E +description: A sturdy rake for clearing weeds and dead plants from farming patches. name: rake -color: "5E" -description: "A sturdy rake for clearing weeds and dead plants from farming patches." -value: 8 stackable: false -tool_type: rake +tool: + type: rake +value: 8 diff --git a/data/items/tools/rune_axe.yaml b/data/items/tools/rune_axe.yaml index e239a0a..46cc948 100644 --- a/data/items/tools/rune_axe.yaml +++ b/data/items/tools/rune_axe.yaml @@ -1,18 +1,21 @@ -name: rune axe color: "57" -description: "A sturdy rune axe, good for woodcutting." -value: 5000 -stackable: false -equip_slot: main_hand -weapon_type: melee -attack_type: slash -stats: - stab_attack: -2 - slash_attack: 38 - crush_attack: 29 - strength_bonus: 32 -speed: 5 -tool_type: axe -tool_speed: 1.5 +description: A sturdy rune axe, good for woodcutting. +equipment: + attack: + crush: 29 + slash: 38 + stab: -2 + attack_type: slash + other: + strength: 32 + slot: main_hand + speed: 5 + type: melee_weapon +name: rune axe requirements: accuracy: 40 +stackable: false +tool: + speed: 1.5 + type: axe +value: 5000 diff --git a/data/items/tools/rune_pickaxe.yaml b/data/items/tools/rune_pickaxe.yaml index b4e9ac1..d580df5 100644 --- a/data/items/tools/rune_pickaxe.yaml +++ b/data/items/tools/rune_pickaxe.yaml @@ -1,18 +1,21 @@ -name: rune pickaxe color: "57" -description: "A sturdy rune pickaxe, good for mining." -value: 5000 -stackable: false -equip_slot: main_hand -weapon_type: melee -attack_type: stab -stats: - stab_attack: 30 - slash_attack: -2 - crush_attack: 14 - strength_bonus: 22 -speed: 5 -tool_type: pickaxe -tool_speed: 0.5 +description: A sturdy rune pickaxe, good for mining. +equipment: + attack: + crush: 14 + slash: -2 + stab: 30 + attack_type: stab + other: + strength: 22 + slot: main_hand + speed: 5 + type: melee_weapon +name: rune pickaxe requirements: accuracy: 40 +stackable: false +tool: + speed: 0.5 + type: pickaxe +value: 5000 diff --git a/data/items/tools/saw.yaml b/data/items/tools/saw.yaml index d671923..8f6a287 100644 --- a/data/items/tools/saw.yaml +++ b/data/items/tools/saw.yaml @@ -1,6 +1,7 @@ -name: saw -tool_type: saw color: "98" -description: "A sharp-toothed saw for cutting planks from logs at a workbench." -value: 30 +description: A sharp-toothed saw for cutting planks from logs at a workbench. +name: saw stackable: false +tool: + type: saw +value: 30 diff --git a/data/items/tools/shears.yaml b/data/items/tools/shears.yaml index 0fbbafb..c9739f4 100644 --- a/data/items/tools/shears.yaml +++ b/data/items/tools/shears.yaml @@ -1,5 +1,6 @@ +color: FA +description: A pair of shears for shearing sheep. name: shears -color: "FA" -description: "A pair of shears for shearing sheep." +tool: + type: shears value: 5 -tool_type: shears diff --git a/data/items/tools/small_fishing_net.yaml b/data/items/tools/small_fishing_net.yaml index 2d3c6bd..9b127b6 100644 --- a/data/items/tools/small_fishing_net.yaml +++ b/data/items/tools/small_fishing_net.yaml @@ -1,14 +1,14 @@ +color: E6 +description: A small hand-held fishing net. +equipment: + other: + strength: 0 + slot: main_hand + speed: 5 + type: melee_weapon name: small fishing net -color: "E6" -description: "A small hand-held fishing net." -value: 5 stackable: false -equip_slot: main_hand -weapon_type: melee -stats: - attack_bonus: 0 - strength_bonus: 0 - defense_bonus: 0 -speed: 5 -tool_type: small_net -tool_speed: 0 +tool: + speed: 0 + type: small_net +value: 5 diff --git a/data/items/tools/spade.yaml b/data/items/tools/spade.yaml index aab5ee8..e755981 100644 --- a/data/items/tools/spade.yaml +++ b/data/items/tools/spade.yaml @@ -1,6 +1,7 @@ +color: F1 +description: A metal spade used for planting seeds and harvesting crops. name: spade -color: "F1" -description: "A metal spade used for planting seeds and harvesting crops." -value: 8 stackable: false -tool_type: spade +tool: + type: spade +value: 8 diff --git a/data/items/tools/steel_axe.yaml b/data/items/tools/steel_axe.yaml index 929bc9e..c0f5a7f 100644 --- a/data/items/tools/steel_axe.yaml +++ b/data/items/tools/steel_axe.yaml @@ -1,18 +1,21 @@ +color: FD +description: A sturdy steel axe, good for woodcutting. +equipment: + attack: + crush: 11 + slash: 15 + stab: -2 + attack_type: slash + other: + strength: 12 + slot: main_hand + speed: 5 + type: melee_weapon name: steel axe -color: "FD" -description: "A sturdy steel axe, good for woodcutting." -value: 75 -stackable: false -equip_slot: main_hand -weapon_type: melee -attack_type: slash -stats: - stab_attack: -2 - slash_attack: 15 - crush_attack: 11 - strength_bonus: 12 -speed: 5 -tool_type: axe -tool_speed: 3 requirements: accuracy: 5 +stackable: false +tool: + speed: 3 + type: axe +value: 75 diff --git a/data/items/tools/steel_pickaxe.yaml b/data/items/tools/steel_pickaxe.yaml index 2acd5e5..7560612 100644 --- a/data/items/tools/steel_pickaxe.yaml +++ b/data/items/tools/steel_pickaxe.yaml @@ -1,18 +1,21 @@ +color: FD +description: A sturdy steel pickaxe, good for mining. +equipment: + attack: + crush: 4 + slash: -2 + stab: 10 + attack_type: stab + other: + strength: 7 + slot: main_hand + speed: 5 + type: melee_weapon name: steel pickaxe -color: "FD" -description: "A sturdy steel pickaxe, good for mining." -value: 75 -stackable: false -equip_slot: main_hand -weapon_type: melee -attack_type: stab -stats: - stab_attack: 10 - slash_attack: -2 - crush_attack: 4 - strength_bonus: 7 -speed: 5 -tool_type: pickaxe -tool_speed: 1.25 requirements: accuracy: 5 +stackable: false +tool: + speed: 1.25 + type: pickaxe +value: 75 diff --git a/data/items/tools/unfired_pie_dish.yaml b/data/items/tools/unfired_pie_dish.yaml index eb5d2b6..bc0c5a5 100644 --- a/data/items/tools/unfired_pie_dish.yaml +++ b/data/items/tools/unfired_pie_dish.yaml @@ -1,12 +1,11 @@ color: "AD" craft: - consume: + ingredients: - items: - soft_clay quantity: 1 level: 7 message: "You shape the clay into a %n." - skill: crafting station: - pottery_wheel type: crafting diff --git a/data/items/tools/unfired_plant_pot.yaml b/data/items/tools/unfired_plant_pot.yaml index 3c6c28f..30ccd83 100644 --- a/data/items/tools/unfired_plant_pot.yaml +++ b/data/items/tools/unfired_plant_pot.yaml @@ -1,12 +1,11 @@ color: "AD" craft: - consume: + ingredients: - items: - soft_clay quantity: 1 level: 19 message: "You shape the clay into a %n." - skill: crafting station: - pottery_wheel type: crafting diff --git a/data/items/tools/unfired_pot.yaml b/data/items/tools/unfired_pot.yaml index 26e8771..9dc2406 100644 --- a/data/items/tools/unfired_pot.yaml +++ b/data/items/tools/unfired_pot.yaml @@ -1,12 +1,11 @@ color: "AD" craft: - consume: + ingredients: - items: - soft_clay quantity: 1 level: 1 message: "You shape the clay into a %n." - skill: crafting station: - pottery_wheel type: crafting diff --git a/data/items/tools/watering_can.yaml b/data/items/tools/watering_can.yaml index eab9b0d..4d747a6 100644 --- a/data/items/tools/watering_can.yaml +++ b/data/items/tools/watering_can.yaml @@ -1,6 +1,7 @@ -name: watering can color: "27" -description: "A watering can for hydrating farming patches. Watering eliminates disease risk." -value: 12 +description: A watering can for hydrating farming patches. Watering eliminates disease risk. +name: watering can stackable: false -tool_type: watering_can +tool: + type: watering_can +value: 12 diff --git a/data/rooms/intro/2001.yaml b/data/rooms/intro/2001.yaml index 0bb9c16..4b21ab8 100644 --- a/data/rooms/intro/2001.yaml +++ b/data/rooms/intro/2001.yaml @@ -17,6 +17,12 @@ item_spawns: - id: bronze_axe quantity: 1 respawn_ticks: 1 + - id: pot_of_flour + quantity: 1 + respawn_ticks: 0 + - id: bucket_of_water + quantity: 1 + respawn_ticks: 0 mobs: [] name: Test Room objects: diff --git a/internal/admin/api_items.go b/internal/admin/api_items.go index d5e707e..721a6f8 100644 --- a/internal/admin/api_items.go +++ b/internal/admin/api_items.go @@ -95,6 +95,7 @@ func (s *AdminServer) updateItem(w http.ResponseWriter, r *http.Request, id stri http.Error(w, `{"error":"failed to write item"}`, http.StatusInternalServerError) return } + m["_raw"] = string(newContent) s.undoStack.Push(ChangeDesc{ Description: fmt.Sprintf("Update item %s", id), diff --git a/internal/admin/server.go b/internal/admin/server.go index df6d5d9..ff2bebd 100644 --- a/internal/admin/server.go +++ b/internal/admin/server.go @@ -403,7 +403,7 @@ func (s *AdminServer) doUndo(w http.ResponseWriter, r *http.Request) { return } s.rebuildAfterUndo(change) - writeJSON(w, map[string]any{"message": "Undid: " + change.Description}) + writeJSON(w, map[string]any{"message": "Undid: " + change.ShortDesc()}) } func (s *AdminServer) doRedo(w http.ResponseWriter, r *http.Request) { @@ -417,7 +417,7 @@ func (s *AdminServer) doRedo(w http.ResponseWriter, r *http.Request) { return } s.rebuildAfterUndo(change) - writeJSON(w, map[string]any{"message": "Redid: " + change.Description}) + writeJSON(w, map[string]any{"message": "Redid: " + change.ShortDesc()}) } func (s *AdminServer) rebuildAfterUndo(change *ChangeDesc) { diff --git a/internal/admin/static/admin.css b/internal/admin/static/admin.css index 6da338e..bdf9b60 100644 --- a/internal/admin/static/admin.css +++ b/internal/admin/static/admin.css @@ -11,6 +11,7 @@ body{font-family:monospace;background:var(--bg);color:var(--text);min-height:100 .nav .undo-bar span{color:#888;flex:1;text-align:right;margin-right:8px} .layout{display:flex;height:calc(100vh - 38px)} .main{flex:1;overflow:auto;position:relative;user-select:none;-webkit-user-select:none} +#mapSvg{display:block} .panel{width:300px;background:var(--panel);border-left:1px solid var(--border);overflow-y:auto;padding:16px;flex-shrink:0;position:relative} .panel-resize-handle{position:absolute;left:-3px;top:0;bottom:0;width:6px;cursor:col-resize;z-index:5;background:transparent} .panel-resize-handle:hover{background:rgba(255,255,255,.06)} @@ -153,6 +154,7 @@ g.ud-hover:hover text{font-weight:bold} .panel-tab-content .mini-label{font-size:9px;color:#888;display:block;margin-bottom:1px;margin-top:3px} .panel-tab-content .mini-input{width:60px!important;display:inline-block;margin-right:4px} .obj-card{background:rgba(255,255,255,.02);border:1px solid var(--border);border-radius:5px;margin-bottom:10px;overflow:hidden;flex:1 1 calc(50% - 5px);min-width:340px;max-width:calc(50% - 5px)} +.obj-card.obj-card-full{flex:1 1 100%;max-width:100%} .obj-fields-wrap{display:flex;flex-wrap:wrap;gap:10px} .obj-card-header{display:flex;align-items:center;gap:8px;padding:8px 12px;background:rgba(15,52,96,.3);cursor:pointer;user-select:none;font-size:13px;font-weight:bold} .obj-card-header:hover{background:rgba(15,52,96,.5)} @@ -166,7 +168,7 @@ g.ud-hover:hover text{font-weight:bold} .obj-field input,.obj-field textarea,.obj-field select{padding:4px 6px;font-size:11px;background:var(--input-bg);color:var(--text);border:1px solid var(--input-border);border-radius:3px;font-family:monospace;width:100%} .obj-field textarea{resize:vertical;min-height:28px} .obj-field.obj-wide{grid-column:1/-1} -.obj-field.obj-check{flex-direction:row;align-items:flex-end;gap:4px;padding-bottom:3px} +.obj-field.obj-check{flex-direction:row;align-items:center;gap:4px;padding-bottom:3px} .obj-field.obj-check input{width:auto} .obj-field.obj-check span{font-size:11px;color:var(--text)} .obj-color-row{display:flex;align-items:center;gap:4px} @@ -210,3 +212,16 @@ g.ud-hover:hover text{font-weight:bold} .obj-sub-row-line+.obj-sub-row-line{margin-top:4px} .obj-inline-compact .obj-card-grid{grid-template-columns:repeat(auto-fill,minmax(60px,1fr))!important} .obj-inline-compact .obj-narrow input{width:50px} +.ingredients-table{border:1px solid var(--border);border-radius:4px;overflow:hidden;margin-top:4px} +.ingredients-header-row{display:flex;gap:4px;padding:4px 6px;background:rgba(255,255,255,.03);font-size:9px;color:#888;text-transform:uppercase;letter-spacing:.5px;border-bottom:1px solid var(--border)} +.ingredients-ingredient{border-bottom:1px solid rgba(255,255,255,.04)} +.ingredients-ingredient:last-child{border-bottom:none} +.ingredients-pair{display:flex;gap:4px;padding:3px 6px;align-items:center;border-top:1px solid rgba(255,255,255,.03)} +.ingredients-pair:first-child{border-top:none} +.ingredients-pair-add{padding:2px 6px 4px} +.ingredients-col{flex-shrink:0} +.ingredients-col-qty{width:48px;display:flex;align-items:center} +.ingredients-col-items{flex:1;min-width:0} +.ingredients-col-byproducts{flex:1;min-width:0} +.ingredients-col-x{width:26px;display:flex;align-items:center;justify-content:center} +.ingredients-col-num{width:24px;text-align:center;color:#888;font-size:10px;display:flex;align-items:center;justify-content:center;flex-shrink:0} diff --git a/internal/admin/static/editor.js b/internal/admin/static/editor.js index 1ed0653..37bc797 100644 --- a/internal/admin/static/editor.js +++ b/internal/admin/static/editor.js @@ -59,7 +59,7 @@ function renderDirGroup(name, ids, filter) { displayIds = ids.filter(function(id) { return String(id).toLowerCase().indexOf(filter) >= 0; }); if (displayIds.length === 0) return ''; } - var expanded = isFiltering ? true : (collapsedDirs[name] === false || (!name && collapsedDirs[''] === undefined)); + var expanded = isFiltering ? true : (collapsedDirs[name] === true); var displayName = name || editorType.charAt(0).toUpperCase() + editorType.slice(1); var h = '<div class="dir-group">'; if (name) { @@ -79,7 +79,7 @@ function renderDirGroup(name, ids, filter) { } function toggleDir(name) { - collapsedDirs[name] = collapsedDirs[name] === false ? true : false; + collapsedDirs[name] = collapsedDirs[name] !== true; renderList(''); } @@ -206,6 +206,13 @@ function switchTab(e, tab) { tabs.forEach(function(t) { t.style.display = 'none'; }); var target = document.getElementById('tab' + tab.charAt(0).toUpperCase() + tab.slice(1)); if (target) target.style.display = 'block'; + + if (tab === 'yaml' && currentID) { + API.get('/api/' + editorType + '/' + encodeURIComponent(currentID)).then(function(data) { + var pre = document.querySelector('#tabYaml pre'); + if (pre) pre.textContent = data._raw || JSON.stringify(data, null, 2); + }); + } } function getNested(obj, path) { diff --git a/internal/admin/static/itemeditor.js b/internal/admin/static/itemeditor.js new file mode 100644 index 0000000..d02e7ab --- /dev/null +++ b/internal/admin/static/itemeditor.js @@ -0,0 +1,1557 @@ +var itemData = null; +var itemID = null; +var expandedCards = {}; +var addedSections = {}; + +var SECTIONS = [ + { + id: 'core', label: 'Core', always: true, + fields: [ + ['name', 'Name', 'text', 'Copper Ore'], + ['color', 'Color', 'color', 'B2'], + ['value', 'Value', 'number', '0'], + ['stackable', 'Stackable', 'checkbox'], + ['quality', 'Quality', 'number', ''], + ['max_quality', 'Max Quality', 'number', ''], + ['aliases', 'Aliases', 'text', 'comma separated'], + ['description', 'Description', 'textarea', 'A chunk of copper ore.'], + ] + }, + { + id: 'equipment', label: 'Equipment', path: 'equipment', + detect: function(d) { return d.equipment; }, + fields: [] + }, + { + id: 'tool', label: 'Tool', path: 'tool', + detect: function(d) { return d.tool; }, + fields: [ + ['type', 'Type', 'text', 'pickaxe, axe, hammer'], + ['speed', 'Speed', 'number', '1.0', 'narrow'], + ] + }, + { + id: 'firemaking', label: 'Firemaking', + detect: function(d) { return d.burn_ticks || d.fire_level || d.fire_xp; }, + fields: [ + ['burn_ticks', 'Burn Ticks', 'number', '100', 'narrow'], + ['fire_level', 'Fire Level', 'number', '1', 'narrow'], + ['fire_xp', 'Fire XP', 'number', '40', 'narrow'], + ] + }, + { + id: 'crafting', label: 'Crafting', + detect: function(d) { return d.craft; }, + fields: [], + subtables: [ + { + label: 'Recipes to Craft This Item', key: 'craft', + fields: [ + ['type', 'Type', 'select', 'smithing|cooking|crafting|fletching|combine|pharmacy|construction'], + ['subtype', 'Subtype', 'select', '|smelt|clean'], + ['level', 'Level', 'number', '', 'narrow'], + ['xp', 'XP', 'number', '', 'narrow'], + ['wait', 'Wait', 'number', '', 'narrow'], + ['output_qty', 'Output Qty', 'number', '', 'narrow'], + ['station', 'Station', 'select', '|anvil|cooking_range|fire|furnace|pottery_oven|pottery_wheel|spinning_wheel|workbench'], + ['tool', 'Tool', 'select', '|pickaxe|axe|fire|chisel|hammer|knife|needle|rake|saw|shears|spade|watering_can|fishing_rod|fly_rod|harpoon|small_net|big_net|lobster_pot'], + ['fail', 'Fail Item', 'search', '', '', null, 'items'], + ['success_base', 'Base', 'number', '', 'narrow'], + ['success_per_level', 'Per Lvl', 'number', '', 'narrow'], + ['success_cap', 'Cap', 'number', '', 'narrow'], + ['start_message', 'Start Message', 'text', '', 'wide'], + ['message', 'Message', 'text', '', 'wide'], + ['fail_message', 'Fail Message', 'text', '', 'wide', function(item) { return item.type === 'cooking' || item.subtype === 'smelt'; }], + ['end_message', 'End Message', 'text', '', 'wide'], + ], + fieldGroups: [ + ['type', 'subtype', 'level', 'xp', 'wait', 'output_qty'], + {fields: ['station', 'tool'], right: true}, + {label: 'Success', fields: ['success_base', 'success_per_level', 'success_cap', 'fail']}, + ['start_message', 'message', 'fail_message', 'end_message'], + ], + subSubtables: [ + {label:'Ingredients', key:'ingredients', fields:[ + ['quantity', 'Qty', 'number', '1', 'narrow'], + ]}, + {label:'Steps', key:'steps', fields:[ + ['tick', 'Ticks', 'number', '', 'narrow'], + ['message', 'Message', 'text', '', 'wide'], + ]}, + ], + } + ] + }, + { + id: 'search', label: 'Search', + detect: function(d) { return d.search_table || d.search_ticks; }, + fields: [ + ['search_table', 'Search Table', 'search', '', '', null, 'drops'], + ['search_ticks', 'Search Ticks', 'number', '', 'narrow'], + ['search_message', 'Search Message', 'text', 'You search...', 'wide'], + ] + }, + { + id: 'food', label: 'Food', + detect: function(d) { return d.heal_value || d.eat_message; }, + fields: [ + ['heal_value', '+HP', 'number', '', 'narrow'], + ['eat_message', 'Eat Message', 'text', 'You eat the...', 'wide'], + ] + }, + { + id: 'farming', label: 'Farming', + detect: function(d) { return d.farm_patch_type; }, + fields: [ + ['farm_patch_type', 'Patch Type', 'select', 'herb|allotment|flower|bush|tree'], + ['farm_level', 'Farm Level', 'number', '', 'narrow'], + ['farm_plant_xp', 'Plant XP', 'number', '', 'narrow'], + ['farm_harvest_xp', 'Harvest XP', 'number', '', 'narrow'], + ['farm_stages', 'Stages', 'number', '', 'narrow'], + ['farm_product', 'Product', 'search', '', '', null, 'items'], + ['farm_min_yield', 'Min Yield', 'number', '', 'narrow'], + ['farm_max_yield', 'Max Yield', 'number', '', 'narrow'], + ] + }, + { + id: 'potions', label: 'Potions', + detect: function(d) { return d.potion_effect; }, + fields: [ + ['potion_effect', 'Effect', 'text', 'strength, accuracy, heal'], + ['potion_bonus', 'Bonus', 'number', '', 'narrow'], + ['potion_duration', 'Duration', 'number', '', 'narrow'], + ] + }, +]; + +function initItemEditor() { + editorType = 'items'; + editorFields = []; + loadList(); + if (window.location.hash) loadItemEditor(window.location.hash.substring(1)); +} + +function cardPath(sec) { + return sec.path || ''; +} + +function getVal(data, sec, key) { + var p = cardPath(sec); + if (sec.isArray) { + return data[p] && data[p][key] !== undefined ? data[p][key] : ''; + } + var fp = p ? p + '.' + key : key; + var v = getNested(data, fp); + return v === undefined || v === null ? '' : v; +} + +function fieldID(sec, key, idx) { + if (idx !== undefined && idx >= 0) return 'f_' + sec.id + '_' + idx + '_' + key.replace(/\./g, '_'); + return 'f_' + sec.id + '_' + key.replace(/\./g, '_'); +} + +function fieldIDSub(sec, subKey, idx, fieldKey) { + return 'f_' + sec.id + '_' + subKey + '_' + idx + '_' + fieldKey; +} + +function fieldIDSubSub(sec, subKey, rowIdx, subSubKey, subSubIdx, fieldKey) { + return 'f_' + sec.id + '_' + subKey + '_' + rowIdx + '__' + subSubKey + '_' + subSubIdx + '_' + fieldKey; +} + +function loadItemEditor(id) { + itemID = id; + currentID = id; + renderList(''); + window.location.hash = id; + API.get('/api/items/' + encodeURIComponent(id)).then(function(data) { + itemData = data; + renderItemEditor(id, data); + }).catch(function(e) { + $('#editorMain').innerHTML = '<p style="color:var(--danger)">Failed to load: ' + esc(e.message) + '</p>'; + }); +} + +function renderItemEditor(id, data) { + var html = '<h2>Item: ' + esc(id) + '</h2>'; + html += '<div class="tabs"><button class="tab active" onclick="switchTab(event,\'fields\')">Fields</button>'; + html += '<button class="tab" onclick="switchTab(event,\'yaml\')">Raw YAML</button></div>'; + + html += '<div class="tab-content" id="tabFields">'; + html += '<div class="obj-fields-wrap">'; + + SECTIONS.forEach(function(sec) { + if (!sec.always && sec.detect && !sec.detect(data) && !addedSections[sec.id]) return; + html += renderCard(sec, data); + }); + + html += '</div>'; + + html += '<div class="add-section-bar">'; + html += '<select id="addSectionSelect">'; + html += '<option value="">+ Add Section...</option>'; + SECTIONS.forEach(function(sec) { + if (sec.always) return; + if (sec.detect && sec.detect(data)) return; + if (addedSections[sec.id]) return; + html += '<option value="' + sec.id + '">' + esc(sec.label) + '</option>'; + }); + html += '</select>'; + html += '<button class="btn btn-primary btn-sm" onclick="addSection()">Add</button>'; + html += '</div>'; + html += '</div>'; + + html += '<div class="tab-content" id="tabYaml" style="display:none">'; + html += '<pre>' + esc(data._raw || JSON.stringify(data, null, 2)) + '</pre>'; + html += '</div>'; + + html += '<div class="btn-row">'; + html += '<button class="btn btn-primary" onclick="saveItem()">Save</button>'; + html += '<button class="btn" onclick="duplicateItem()">Duplicate</button>'; + html += '<button class="btn btn-danger" onclick="deleteItem()">Delete Item</button>'; + html += '</div>'; + + $('#editorMain').innerHTML = html; + setupSearchFields(); + setupCraftTypeChange(); + setTimeout(function() { + document.querySelectorAll('.color-field').forEach(function(el) { bindColorField(el); }); + }, 50); +} + +function renderCurrent() { + if (!itemData || !itemID) return; + renderItemEditor(itemID, itemData); +} + +// ========================================================================= +// Card rendering +// ========================================================================= + +function renderCard(sec, data) { + var collapsed = expandedCards[sec.id] === false; + var h = '<div class="obj-card' + (sec.id === 'crafting' ? ' obj-card-full' : '') + '" data-card="' + sec.id + '">'; + h += '<div class="obj-card-header" onclick="toggleCard(\'' + sec.id + '\')">'; + h += '<span class="obj-card-arrow">' + (collapsed ? '▶' : '▼') + '</span>'; + h += '<span class="obj-card-label">' + sec.label + '</span>'; + if (!sec.always) { + h += '<button class="btn btn-sm btn-danger obj-card-remove" onclick="event.stopPropagation();removeSection(\'' + sec.id + '\')">X</button>'; + } + h += '</div>'; + if (!collapsed) { + h += '<div class="obj-card-body">'; + + if (sec.isArray) { + h += renderArraySection(sec, data); + } else if (sec.id === 'core') { + h += renderCoreCard(data); + } else if (sec.id === 'equipment') { + h += renderEquipmentCard(data); + } else { + h += '<div class="obj-card-grid">'; + if (sec.fields) sec.fields.forEach(function(f) { + h += renderField(sec, f, data, -1); + }); + h += '</div>'; + + if (sec.inline) { + sec.inline.forEach(function(il) { + if (il.type === 'tags') { + h += renderTags(sec, il, data); + } else if (il.type === 'kv') { + h += renderKV(sec, il, data); + } else { + h += '<div class="obj-inline-group">'; + h += '<span class="obj-inline-label">' + esc(il.label) + '</span>'; + h += '<div style="display:flex;gap:8px;flex-wrap:nowrap;margin-top:4px">'; + il.fields.forEach(function(f) { + h += renderField(sec, f, data, -1, il.path); + }); + h += '</div>'; + h += '</div>'; + } + }); + } + + if (sec.subtables) { + sec.subtables.forEach(function(st) { + h += renderSubtable(sec, st, data); + }); + } + } + h += '</div>'; + } + h += '</div>'; + return h; +} + +function renderCoreCard(data) { + var sec = SECTIONS[0]; + var h = '<div class="obj-core-row">'; + h += renderField(sec, sec.fields[0], data, -1, null, 'flex:1'); + h += renderField(sec, sec.fields[1], data, -1); + h += renderField(sec, sec.fields[6], data, -1, null, 'flex:1'); + h += '</div>'; + h += '<div class="obj-core-row" style="align-items:center">'; + h += renderField(sec, sec.fields[2], data, -1); + h += '<div style="display:flex;align-items:center;gap:6px">'; + h += renderField(sec, sec.fields[3], data, -1); + h += '</div>'; + h += '<div style="display:flex;gap:8px;margin-left:auto">'; + h += renderField(sec, sec.fields[4], data, -1); + h += renderField(sec, sec.fields[5], data, -1); + h += '</div>'; + h += '</div>'; + var descFid = fieldID(sec, 'description', -1); + var descVal = getVal(itemData, sec, 'description'); + var dstr = typeof descVal === 'object' ? (Array.isArray(descVal) ? descVal.map(function(v){return v.text||'';}).join('\n') : JSON.stringify(descVal)) : String(descVal); + h += '<label class="obj-field obj-wide"><span>Description</span><textarea id="' + descFid + '" rows="6" style="min-height:56px">' + esc(dstr) + '</textarea></label>'; + return h; +} + +// ========================================================================= +// Equipment card (custom render with 3 stat blocks) +// ========================================================================= + +var EQUIP_STAT_FIELDS = { + attack: [ + ['stab', 'Stab', 'number', '', 'narrow'], + ['slash', 'Slash', 'number', '', 'narrow'], + ['crush', 'Crush', 'number', '', 'narrow'], + ['ranged', 'Ranged', 'number', '', 'narrow'], + ['science', 'Science', 'number', '', 'narrow'], + ], + defense: [ + ['stab', 'Stab', 'number', '', 'narrow'], + ['slash', 'Slash', 'number', '', 'narrow'], + ['crush', 'Crush', 'number', '', 'narrow'], + ['ranged', 'Ranged', 'number', '', 'narrow'], + ['science', 'Science', 'number', '', 'narrow'], + ], + other: [ + ['strength', 'Strength', 'number', '', 'narrow'], + ['ranged', 'Ranged', 'number', '', 'narrow'], + ['science', 'Science', 'number', '', 'narrow'], + ['technology', 'Tech', 'number', '', 'narrow'], + ], +}; + +function equipFieldID(key) { + return 'f_equipment_' + key; +} + +function renderEquipField(key, label, type, hint, val, wide, searchEntity) { + var fid = equipFieldID(key); + val = val === undefined || val === null ? '' : val; + + function wrap(cls, inner) { + var w = (wide === 'wide') ? ' obj-wide' : ''; + if (wide === 'narrow') w = ' obj-narrow'; + return '<label class="' + cls + w + '">' + inner + '</label>'; + } + + if (type === 'select') { + var opts = hint ? hint.split('|') : []; + var inner = '<span>' + esc(label) + '</span><select id="' + fid + '">'; + opts.forEach(function(o) { + inner += '<option value="' + escAttr(o) + '"' + (String(val) === o ? ' selected' : '') + '>' + esc(o) + '</option>'; + }); + inner += '</select>'; + return wrap('obj-field', inner); + } + if (type === 'search') { + var entity = searchEntity || 'items'; + var ph = hint ? ' placeholder="' + esc(hint) + '"' : ' placeholder="Search ' + entity + '..."'; + return wrap('obj-field obj-search', '<span>' + esc(label) + '</span><div style="position:relative;width:100%"><input id="' + fid + '" value="' + escAttr(String(val)) + '" class="search-input" data-search-type="' + entity + '"' + ph + '><div class="search-results" style="display:none"></div></div>'); + } + var ph = hint ? ' placeholder="' + esc(hint) + '"' : ''; + return wrap('obj-field', '<span>' + esc(label) + '</span><input id="' + fid + '" value="' + escAttr(String(val)) + '"' + ph + '>'); +} + +function renderEquipmentCard(data) { + var eq = data.equipment || {}; + var h = ''; + var isAmmo = eq.type === 'ammo'; + + // Row 1: type, slot + h += '<div class="obj-core-row">'; + h += renderEquipField('type', 'Type', 'select', 'melee_weapon|ranged_weapon|tech_weapon|armor|tool|ammo', eq.type); + if (!isAmmo) { + h += renderEquipField('slot', 'Slot', 'select', 'head|neck|torso|legs|hands|feet|back|ammo|main_hand|off_hand|ring', eq.slot); + } else { + h += '<input type="hidden" id="' + equipFieldID('slot') + '" value="ammo">'; + } + h += '</div>'; + + // Ammo: recoverable checkbox + if (isAmmo) { + h += '<label class="obj-field obj-check" style="margin-top:4px"><input type="checkbox" id="f_core_recoverable"' + (data.recoverable ? ' checked' : '') + '> <span>Recoverable</span></label>'; + } + + // Row 2: attack_type, speed, junk + var isMelee = eq.type === 'melee_weapon'; + var isWeapon = ['melee_weapon', 'ranged_weapon', 'tech_weapon'].indexOf(eq.type) >= 0; + h += '<div class="obj-core-row"' + (!isMelee && !isWeapon ? ' style="display:none"' : '') + '>'; + if (isMelee) { + h += renderEquipField('attack_type', 'Attack Type', 'select', 'stab|slash|crush', eq.attack_type); + } + if (isWeapon) { + h += renderEquipField('speed', 'Speed', 'number', '', eq.speed, 'narrow'); + } + h += renderEquipField('junk', 'Junk', 'search', '', eq.junk, '', 'items'); + h += '</div>'; + + // 3 buttons row + var btns = []; + if (!eq.attack) btns.push('<button class="btn btn-sm obj-sub-add" style="flex:1" onclick="addEquipBlock(\'attack\')">+ Add Attack Stats</button>'); + if (!eq.defense) btns.push('<button class="btn btn-sm obj-sub-add" style="flex:1" onclick="addEquipBlock(\'defense\')">+ Add Defense Stats</button>'); + if (!eq.other) btns.push('<button class="btn btn-sm obj-sub-add" style="flex:1" onclick="addEquipBlock(\'other\')">+ Add Other Stats</button>'); + if (btns.length > 0) { + h += '<div style="display:flex;gap:6px;margin-top:10px">' + btns.join('') + '</div>'; + } + + // Stat blocks + if (eq.attack) h += renderEquipStatBlock('Attack Stats', 'attack', eq.attack, EQUIP_STAT_FIELDS.attack); + if (eq.defense) h += renderEquipStatBlock('Defense Stats', 'defense', eq.defense, EQUIP_STAT_FIELDS.defense); + if (eq.other) h += renderEquipStatBlock('Other Stats', 'other', eq.other, EQUIP_STAT_FIELDS.other); + + // Requirements KV (at root level, stored in itemData.requirements) + h += '<div style="margin-top:8px">'; + h += renderKV({id: 'equipment_req'}, {label:'Requirements', key:'requirements', type:'kv', valType:'number'}, data); + h += '</div>'; + + return h; +} + +function renderEquipStatBlock(label, blockKey, blockData, fields) { + var h = '<div class="obj-inline-group" style="margin-top:8px">'; + h += '<div style="display:flex;align-items:center;gap:8px;margin-bottom:4px">'; + h += '<span class="obj-inline-label" style="margin-bottom:0;flex:1">' + esc(label) + '</span>'; + h += '<button class="btn btn-sm btn-danger" onclick="removeEquipBlock(\'' + blockKey + '\')">X</button>'; + h += '</div>'; + h += '<div style="display:flex;gap:8px;flex-wrap:nowrap;margin-top:4px">'; + fields.forEach(function(f) { + var fid = 'f_equipment_' + blockKey + '_' + f[0]; + var val = blockData[f[0]]; + val = val === undefined || val === null ? '' : val; + var extraCls = f[4] === 'narrow' ? ' obj-narrow' : ''; + h += '<label class="obj-field' + extraCls + '"><span>' + esc(f[1]) + '</span><input id="' + fid + '" value="' + escAttr(String(val)) + '"></label>'; + }); + h += '</div>'; + h += '</div>'; + return h; +} + +function addEquipBlock(blockKey) { + if (!itemData.equipment) itemData.equipment = {}; + var empty = {}; + EQUIP_STAT_FIELDS[blockKey].forEach(function(f) { empty[f[0]] = 0; }); + itemData.equipment[blockKey] = empty; + renderCurrent(); +} + +function removeEquipBlock(blockKey) { + if (itemData.equipment) delete itemData.equipment[blockKey]; + renderCurrent(); +} + +// ========================================================================= +// Generic field render (unchanged) +// ========================================================================= + +function renderField(sec, f, data, idx, subPath, optStyle) { + var key = f[0], label = f[1], type = f[2], hint = f[3], wide = f[4], showIf = f[5], searchEntity = f[6]; + var fp = subPath ? subPath + '.' + key : key; + var fid = fieldID(sec, fp, idx); + var val; + + if (sec.isArray && idx >= 0) { + var arr = itemData[cardPath(sec)] || []; + var item = arr[idx] || {}; + val = item[key]; + } else if (subPath) { + var sectionRoot = itemData[cardPath(sec)] || {}; + var subObj = sectionRoot[subPath] || {}; + val = subObj[key]; + } else { + val = getVal(itemData, sec, key); + } + val = val === undefined || val === null ? '' : val; + + var hiddenStyle = ''; + if (showIf) { + var sectionData = itemData[cardPath(sec)] || {}; + if (!showIf(sectionData)) hiddenStyle = ' style="display:none"'; + } + + function wrap(cls, inner) { + var w = (wide === 'wide') ? ' obj-wide' : ''; + if (wide === 'narrow') w = ' obj-narrow'; + var s = optStyle ? ' style="' + optStyle + '"' : ''; + return '<label class="' + cls + w + '"' + hiddenStyle + s + '>' + inner + '</label>'; + } + + if (type === 'checkbox') { + return wrap('obj-field obj-check', '<input type="checkbox" id="' + fid + '"' + (val ? ' checked' : '') + '> <span>' + esc(label) + '</span>'); + } + if (type === 'json') { + var jstr = typeof val === 'object' ? JSON.stringify(val) : String(val); + return wrap('obj-field', '<span>' + esc(label) + '</span><textarea id="' + fid + '" rows="2" placeholder="{}">' + esc(jstr) + '</textarea>'); + } + if (type === 'textarea') { + var dstr = typeof val === 'object' ? (Array.isArray(val) ? val.map(function(v){return v.text||'';}).join('\n') : JSON.stringify(val)) : String(val); + return wrap('obj-field', '<span>' + esc(label) + '</span><textarea id="' + fid + '" rows="3">' + esc(dstr) + '</textarea>'); + } + if (type === 'select') { + var opts = hint ? hint.split('|') : []; + var inner = '<span>' + esc(label) + '</span><select id="' + fid + '">'; + opts.forEach(function(o) { + inner += '<option value="' + escAttr(o) + '"' + (String(val) === o ? ' selected' : '') + '>' + esc(o) + '</option>'; + }); + inner += '</select>'; + return wrap('obj-field', inner); + } + if (type === 'color') { + var swatch = '<span class="color-swatch" style="background:#' + escAttr(String(val) || '808080') + '"></span>'; + return wrap('obj-field color-field', '<span>' + esc(label) + '</span><div class="obj-color-row">' + swatch + '<input id="' + fid + '" value="' + escAttr(String(val)) + '" class="color-input"></div>'); + } + if (type === 'search') { + var entity = searchEntity || 'items'; + var ph = hint ? ' placeholder="' + esc(hint) + '"' : ' placeholder="Search ' + entity + '..."'; + return wrap('obj-field obj-search', '<span>' + esc(label) + '</span><div style="position:relative;width:100%"><input id="' + fid + '" value="' + escAttr(String(val)) + '" class="search-input" data-search-type="' + entity + '"' + ph + '><div class="search-results" style="display:none"></div></div>'); + } + var ph = hint ? ' placeholder="' + esc(hint) + '"' : ''; + return wrap('obj-field', '<span>' + esc(label) + '</span><input id="' + fid + '" value="' + escAttr(String(val)) + '"' + ph + '>'); +} + +// ========================================================================= +// Array section rendering +// ========================================================================= + +function renderArraySection(sec, data) { + var arr = data[cardPath(sec)] || []; + var h = ''; + arr.forEach(function(item, idx) { + h += '<div class="obj-sub-row" data-idx="' + idx + '">'; + h += '<div class="obj-card-grid">'; + sec.fields.forEach(function(f) { + h += renderField(sec, f, data, idx); + }); + h += '</div>'; + h += '<button class="btn btn-sm btn-danger obj-sub-remove" onclick="removeArrayItem(\'' + sec.id + '\',' + idx + ')">X</button>'; + h += '</div>'; + }); + h += '<button class="btn btn-sm obj-sub-add" onclick="addArrayItem(\'' + sec.id + '\')">+ Add ' + esc(sec.label).slice(0,-1) + '</button>'; + return h; +} + +// ========================================================================= +// Subtable rendering +// ========================================================================= + +function renderSubFieldHTML(sec, stKey, idx, f, val) { + var fid = fieldIDSub(sec, stKey, idx, f[0]); + val = val === undefined || val === null ? '' : val; + var extraCls = ''; + var extraStyle = ''; + if (f[4] === 'narrow') extraCls = ' obj-narrow'; + else if (f[4] === 'grow') extraCls = ' obj-grow'; + if (f[4] === 'wide') extraStyle = ' style="flex:1 1 100%"'; + if (f[2] === 'search') { + var entity = f[6] || 'items'; + var ph = f[3] ? ' placeholder="' + escAttr(f[3]) + '"' : ' placeholder="Search ' + entity + '..."'; + return '<label class="obj-field obj-search' + extraCls + '"' + extraStyle + '><span>' + esc(f[1]) + '</span><div style="position:relative;width:100%"><input id="' + fid + '" value="' + escAttr(String(val)) + '" class="search-input" data-search-type="' + entity + '"' + ph + '><div class="search-results" style="display:none"></div></div></label>'; + } + if (f[2] === 'checkbox') { + return '<label class="obj-field obj-check' + extraCls + '"' + extraStyle + '><input type="checkbox" id="' + fid + '"' + (val ? ' checked' : '') + '> <span>' + esc(f[1]) + '</span></label>'; + } + if (f[2] === 'select') { + var opts = f[3] ? f[3].split('|') : []; + var sel = '<label class="obj-field' + extraCls + '"' + extraStyle + '><span>' + esc(f[1]) + '</span><select id="' + fid + '">'; + opts.forEach(function(o) { + sel += '<option value="' + escAttr(o) + '"' + (String(val) === o ? ' selected' : '') + '>' + esc(o || '(none)') + '</option>'; + }); + sel += '</select></label>'; + return sel; + } + return '<label class="obj-field' + extraCls + '"' + extraStyle + '><span>' + esc(f[1]) + '</span><input id="' + fid + '" value="' + escAttr(String(val)) + '"></label>'; +} + +function renderSubtable(sec, st, data) { + var p = cardPath(sec); + var sectionRoot = p ? (itemData[p] || {}) : itemData; + var raw = sectionRoot[st.key]; + var arr; + if (st.single) { + arr = raw ? [raw] : []; + } else if (Array.isArray(raw)) { + arr = raw; + } else if (raw && typeof raw === 'object') { + arr = [raw]; + } else { + arr = []; + } + var hasSubSubtables = st.subSubtables && st.subSubtables.length > 0; + var h = '<div class="obj-subtable">'; + h += '<div class="obj-subtable-header">' + esc(st.label) + '</div>'; + arr.forEach(function(item, idx) { + h += '<div class="obj-sub-row" style="flex-direction:column;align-items:stretch">'; + + function renderGroup(fieldKeys) { + fieldKeys.forEach(function(fieldKey) { + var f = st.fields.find(function(sf) { return sf[0] === fieldKey; }); + if (!f) return; + if (f[5] && !f[5](item)) return; + var val = item[f[0]]; + h += renderSubFieldHTML(sec, st.key, idx, f, val); + }); + } + + if (st.fieldGroups) { + st.fieldGroups.forEach(function(group) { + if (group.label) { + if (group.label === 'Success') { + var hasSuccess = !!(item.fail || item.success_base || item.success_per_level || item.success_cap); + var gid = 'sg_' + sec.id + '_' + st.key + '_' + idx; + h += '<div class="obj-inline-group success-group" id="' + gid + '" style="margin:2px 0;padding:4px 8px' + (hasSuccess ? '' : ';display:none') + '">'; + h += '<div style="display:flex;align-items:center;margin-bottom:2px">'; + h += '<span class="obj-inline-label" style="margin-bottom:0;flex:1">Success</span>'; + h += '<button class="btn btn-sm btn-danger" style="padding:2px 6px;font-size:10px;min-width:auto" onclick="var g=document.getElementById(\'' + gid + '\');g.style.display=\'none\';var b=document.getElementById(\'' + gid + '_btn\');b.style.display=\'\'">X</button>'; + h += '</div>'; + h += '<div class="obj-sub-row-line">'; + renderGroup(group.fields); + h += '</div>'; + h += '</div>'; + h += '<button class="btn btn-sm obj-sub-add" id="' + gid + '_btn" style="margin:2px 0' + (hasSuccess ? ';display:none' : '') + '" onclick="var b=document.getElementById(\'' + gid + '_btn\');b.style.display=\'none\';var g=document.getElementById(\'' + gid + '\');g.style.display=\'\'">+ Add Success Rates</button>'; + } else { + h += '<div class="obj-inline-group" style="margin:2px 0;padding:4px 8px">'; + h += '<span class="obj-inline-label" style="margin-bottom:2px">' + esc(group.label) + '</span>'; + h += '<div class="obj-sub-row-line">'; + renderGroup(group.fields); + h += '</div>'; + h += '</div>'; + } + } else { + var rightStyle = (group && group.right) ? ' style="justify-content:flex-end"' : ''; + h += '<div class="obj-sub-row-line"' + rightStyle + '>'; + var keys = Array.isArray(group) ? group : group.fields; + renderGroup(keys); + h += '</div>'; + } + }); + } else { + h += '<div class="obj-sub-row-line">'; + st.fields.forEach(function(f) { + if (f[5] && !f[5](item)) return; + var val = item[f[0]]; + h += renderSubFieldHTML(sec, st.key, idx, f, val); + }); + h += '</div>'; + } + + if (hasSubSubtables) { + st.subSubtables.forEach(function(sst) { + if (sst.key === 'steps') { + var stepsArr = item[sst.key]; + if (!stepsArr || !Array.isArray(stepsArr) || stepsArr.length === 0) { + h += '<button class="btn btn-sm obj-sub-add" style="margin-top:4px" onclick="addSubSubRow(\'' + sec.id + '\',\'' + st.key + '\',' + idx + ',\'' + sst.key + '\')">+ Add Custom Delay/Message</button>'; + return; + } + } + h += renderSubSubtable(sec, st, idx, sst, item); + }); + } + + if (!st.single) { + h += '<button class="btn btn-sm btn-danger obj-sub-remove" style="align-self:flex-end;margin:6px 10px" onclick="removeSubRow(\'' + sec.id + '\',\'' + st.key + '\',' + idx + ')">Remove Recipe</button>'; + } + h += '</div>'; + }); + if (!st.single || arr.length === 0) { + h += '<button class="btn btn-sm obj-sub-add" onclick="addSubRow(\'' + sec.id + '\',\'' + st.key + '\')">+ Add Recipe</button>'; + } + h += '</div>'; + return h; +} + +function ingredientPairID(sec, subKey, rowIdx, subSubKey, subIdx, pairIdx, fieldKey) { + return 'f_' + sec.id + '_' + subKey + '_' + rowIdx + '__' + subSubKey + '_' + subIdx + '_' + fieldKey + '_' + pairIdx; +} + +function renderConsumeSearchHTML(fid, val, entity, placeholder) { + val = val === undefined || val === null ? '' : val; + return '<div class="obj-field obj-search" style="flex:1;min-width:0"><div style="position:relative;width:100%"><input id="' + fid + '" value="' + escAttr(String(val)) + '" class="search-input" data-search-type="' + entity + '" placeholder="' + escAttr(placeholder) + '"><div class="search-results" style="display:none"></div></div></div>'; +} + +function addConsumePair(secID, subKey, rowIdx, subSubKey, subIdx) { + var sec = SECTIONS.find(function(s) { return s.id === secID; }); + var existing = document.querySelectorAll('.ingredients-pair[data-sec="' + secID + '"][data-subkey="' + subKey + '"][data-row="' + rowIdx + '"][data-subsub="' + subSubKey + '"][data-subidx="' + subIdx + '"]'); + var pairIdx = existing.length; + var btnRow = document.querySelector('.ingredients-pair-add[data-sec="' + secID + '"][data-subkey="' + subKey + '"][data-row="' + rowIdx + '"][data-subsub="' + subSubKey + '"][data-subidx="' + subIdx + '"]'); + var itemFid = ingredientPairID(sec, subKey, rowIdx, subSubKey, subIdx, pairIdx, 'items'); + var bypFid = ingredientPairID(sec, subKey, rowIdx, subSubKey, subIdx, pairIdx, 'byproducts'); + var row = document.createElement('div'); + row.className = 'ingredients-pair'; + row.setAttribute('data-sec', secID); + row.setAttribute('data-subkey', subKey); + row.setAttribute('data-row', rowIdx); + row.setAttribute('data-subsub', subSubKey); + row.setAttribute('data-subidx', subIdx); + row.setAttribute('data-pair', pairIdx); + row.innerHTML = '<div class="ingredients-col ingredients-col-num"></div>' + + '<div class="ingredients-col ingredients-col-qty"></div>' + + '<div class="ingredients-col ingredients-col-items">' + renderConsumeSearchHTML(itemFid, '', 'items', 'Search items...') + '</div>' + + '<div class="ingredients-col ingredients-col-byproducts">' + renderConsumeSearchHTML(bypFid, '', 'items', '(optional)') + '</div>' + + '<div class="ingredients-col ingredients-col-x"><button class="btn btn-sm btn-danger" style="padding:2px 6px;font-size:10px;background:var(--danger);color:#fff;border:none;border-radius:3px;cursor:pointer" onclick="removeConsumePair(\'' + secID + '\',\'' + subKey + '\',' + rowIdx + ',\'' + subSubKey + '\',' + subIdx + ',' + pairIdx + ')">X</button></div>'; + btnRow.parentNode.insertBefore(row, btnRow); + setupSearchFields(); +} + +function removeConsumePair(secID, subKey, rowIdx, subSubKey, subIdx, pairIdx) { + var el = document.querySelector('.ingredients-pair[data-sec="' + secID + '"][data-subkey="' + subKey + '"][data-row="' + rowIdx + '"][data-subsub="' + subSubKey + '"][data-subidx="' + subIdx + '"][data-pair="' + pairIdx + '"]'); + if (!el) return; + var ingredient = el.parentElement; + var remaining = ingredient.querySelectorAll('.ingredients-pair'); + if (remaining.length <= 1) { + ingredient.remove(); + } else { + el.remove(); + } +} + +function renderSubSubtable(sec, st, rowIdx, sst, parentItem) { + var arr = parentItem[sst.key] || []; + var isIngredients = sst.key === 'ingredients'; + var h = '<div class="obj-subtable" style="margin:6px 0 6px 12px;border-left:2px solid var(--accent)">'; + if (!isIngredients) { + h += '<div class="obj-subtable-header">' + esc(sst.label) + '</div>'; + } + + if (isIngredients) { + h += '<div class="ingredients-table">'; + h += '<div class="ingredients-header-row">'; + h += '<div class="ingredients-col ingredients-col-num">#</div>'; + h += '<div class="ingredients-col ingredients-col-qty">Qty</div>'; + h += '<div class="ingredients-col ingredients-col-items">Items</div>'; + h += '<div class="ingredients-col ingredients-col-byproducts">Byproducts</div>'; + h += '<div class="ingredients-col ingredients-col-x"></div>'; + h += '</div>'; + + var ingredientNum = 0; + arr.forEach(function(subItem, subIdx) { + ingredientNum++; + var itemsArr = Array.isArray(subItem.items) ? subItem.items : (subItem.items ? [subItem.items] : ['']); + var bypArr = Array.isArray(subItem.byproducts) ? subItem.byproducts : []; + var pairs = Math.max(itemsArr.length, bypArr.length, 1); + + h += '<div class="ingredients-ingredient" data-click-pair="' + subIdx + '">'; + + var qtyVal = subItem.quantity !== undefined && subItem.quantity !== null ? subItem.quantity : ''; + var qtyFid = fieldIDSubSub(sec, st.key, rowIdx, sst.key, subIdx, 'quantity'); + + for (var p = 0; p < pairs; p++) { + h += '<div class="ingredients-pair" data-sec="' + sec.id + '" data-subkey="' + st.key + '" data-row="' + rowIdx + '" data-subsub="' + sst.key + '" data-subidx="' + subIdx + '" data-pair="' + p + '">'; + + if (p === 0) { + h += '<div class="ingredients-col ingredients-col-num">' + ingredientNum + '</div>'; + } else { + h += '<div class="ingredients-col ingredients-col-num"></div>'; + } + + if (p === 0) { + h += '<div class="ingredients-col ingredients-col-qty"><label class="obj-field obj-narrow"><input id="' + qtyFid + '" value="' + escAttr(String(qtyVal)) + '" style="width:36px"></label></div>'; + } else { + h += '<div class="ingredients-col ingredients-col-qty"></div>'; + } + + var itemVal = itemsArr[p] || ''; + var itemFid = ingredientPairID(sec, st.key, rowIdx, sst.key, subIdx, p, 'items'); + h += '<div class="ingredients-col ingredients-col-items">' + renderConsumeSearchHTML(itemFid, itemVal, 'items', 'Search items...') + '</div>'; + + var bypVal = bypArr[p] || ''; + var bypFid = ingredientPairID(sec, st.key, rowIdx, sst.key, subIdx, p, 'byproducts'); + h += '<div class="ingredients-col ingredients-col-byproducts">' + renderConsumeSearchHTML(bypFid, bypVal, 'items', '(optional)') + '</div>'; + + h += '<div class="ingredients-col ingredients-col-x"><button class="btn btn-sm btn-danger" style="padding:2px 6px;font-size:10px;background:var(--danger);color:#fff;border:none;border-radius:3px;cursor:pointer" onclick="removeConsumePair(\'' + sec.id + '\',\'' + st.key + '\',' + rowIdx + ',\'' + sst.key + '\',' + subIdx + ',' + p + ')">X</button></div>'; + + h += '</div>'; + } + + h += '<div class="ingredients-pair-add" data-sec="' + sec.id + '" data-subkey="' + st.key + '" data-row="' + rowIdx + '" data-subsub="' + sst.key + '" data-subidx="' + subIdx + '">'; + h += '<button class="btn btn-sm" style="padding:2px 8px;font-size:11px;background:var(--accent);color:var(--text);border:1px solid #1a5a8e;border-radius:3px;cursor:pointer;margin-left:76px" onclick="addConsumePair(\'' + sec.id + '\',\'' + st.key + '\',' + rowIdx + ',\'' + sst.key + '\',' + subIdx + ')">+ Add Alternative Item</button>'; + h += '</div>'; + + h += '</div>'; + }); + + h += '</div>'; + h += '<button class="btn btn-sm obj-sub-add" onclick="addSubSubRow(\'' + sec.id + '\',\'' + st.key + '\',' + rowIdx + ',\'' + sst.key + '\')">+ Add New Ingredient</button>'; + } else { + arr.forEach(function(subItem, subIdx) { + h += '<div class="obj-sub-row" style="align-items:flex-start">'; + h += '<div class="obj-sub-row-line" style="flex:1">'; + sst.fields.forEach(function(f) { + var fid = fieldIDSubSub(sec, st.key, rowIdx, sst.key, subIdx, f[0]); + var val = subItem[f[0]]; + val = val === undefined || val === null ? '' : val; + var extraCls = ''; + if (f[4] === 'narrow') extraCls = ' obj-narrow'; + if (f[2] === 'search') { + var entity = f[6] || 'items'; + var ph = f[3] ? ' placeholder="' + escAttr(f[3]) + '"' : ' placeholder="Search ' + entity + '..."'; + h += '<label class="obj-field obj-search' + extraCls + '"><span>' + esc(f[1]) + '</span><div style="position:relative;width:100%"><input id="' + fid + '" value="' + escAttr(String(val)) + '" class="search-input" data-search-type="' + entity + '"' + ph + '><div class="search-results" style="display:none"></div></div></label>'; + } else if (f[2] === 'checkbox') { + h += '<label class="obj-field obj-check' + extraCls + '"><input type="checkbox" id="' + fid + '"' + (val ? ' checked' : '') + '> <span>' + esc(f[1]) + '</span></label>'; + } else { + h += '<label class="obj-field' + extraCls + '"><span>' + esc(f[1]) + '</span><input id="' + fid + '" value="' + escAttr(String(val)) + '"></label>'; + } + }); + h += '</div>'; + h += '<button class="btn btn-sm btn-danger" style="align-self:flex-start;padding:2px 6px;font-size:10px;background:var(--danger);color:#fff;border:none;border-radius:3px;cursor:pointer;margin-top:2px" onclick="removeSubSubRow(\'' + sec.id + '\',\'' + st.key + '\',' + rowIdx + ',\'' + sst.key + '\',' + subIdx + ')">X</button>'; + h += '</div>'; + }); + h += '<button class="btn btn-sm obj-sub-add" onclick="addSubSubRow(\'' + sec.id + '\',\'' + st.key + '\',' + rowIdx + ',\'' + sst.key + '\')">+ Add Custom Delay/Message</button>'; + } + + h += '</div>'; + return h; +} + +// ========================================================================= +// Tags / KV rendering +// ========================================================================= + +function renderTags(sec, il, data) { + var p = cardPath(sec); + var sectionRoot = p ? (itemData[p] || {}) : itemData; + var arr = sectionRoot[il.key] || []; + var str = Array.isArray(arr) ? arr.join(', ') : String(arr || ''); + var fid = fieldID(sec, il.key); + return '<label class="obj-field obj-wide"><span>' + esc(il.label) + '</span><input id="' + fid + '" value="' + escAttr(str) + '" placeholder="comma separated"></label>'; +} + +function renderKV(sec, il, data) { + var p = cardPath(sec); + var sectionRoot = p ? (itemData[p] || {}) : itemData; + var map = sectionRoot[il.key] || {}; + var h = '<div class="obj-inline-group">'; + h += '<span class="obj-inline-label">' + esc(il.label) + '</span>'; + h += '<div class="obj-kv-list" data-sec="' + sec.id + '" data-key="' + il.key + '">'; + Object.keys(map).forEach(function(k, idx) { + h += '<div class="obj-kv-row"><input value="' + escAttr(k) + '" placeholder="key" class="obj-kv-key">'; + h += '<input value="' + escAttr(String(map[k])) + '" placeholder="val" class="obj-kv-val">'; + h += '<button class="btn btn-sm btn-danger" onclick="this.parentElement.remove()">X</button></div>'; + }); + h += '</div>'; + h += '<button class="btn btn-sm obj-sub-add" onclick="addKVRow(\'' + sec.id + '\',\'' + il.key + '\')">+ Add</button>'; + h += '</div>'; + return h; +} + +// ========================================================================= +// Card toggle / section add-remove +// ========================================================================= + +function toggleCard(id) { + expandedCards[id] = expandedCards[id] === false ? true : false; + renderCurrent(); +} + +function removeSection(id) { + var sec = SECTIONS.find(function(s) { return s.id === id; }); + if (!sec) return; + if (sec.path) { + delete itemData[sec.path]; + } else { + if (sec.fields) sec.fields.forEach(function(f) { delete itemData[f[0]]; }); + if (sec.inline) sec.inline.forEach(function(il) { if (il.key) delete itemData[il.key]; }); + if (sec.subtables) sec.subtables.forEach(function(st) { delete itemData[st.key]; }); + } + delete addedSections[id]; + renderCurrent(); +} + +function addSection() { + var sel = $('#addSectionSelect'); + var id = sel.value; + if (!id) return; + var sec = SECTIONS.find(function(s) { return s.id === id; }); + if (!sec) return; + + if (sec.path) { + if (sec.id === 'equipment') { + itemData.equipment = {type:'', slot:'', attack_type:'', speed:0, junk:''}; + } else { + itemData[sec.path] = {}; + } + } + addedSections[id] = true; + expandedCards[id] = true; + renderCurrent(); +} + +// ========================================================================= +// Array item add/remove +// ========================================================================= + +function addArrayItem(cardID) { + var sec = SECTIONS.find(function(s) { return s.id === cardID; }); + if (!sec || !sec.isArray) return; + var arr = itemData[sec.path] || []; + var empty = {}; + sec.fields.forEach(function(f) { + empty[f[0]] = f[2] === 'checkbox' ? false : (f[2] === 'number' ? 0 : ''); + }); + arr.push(empty); + itemData[sec.path] = arr; + renderCurrent(); +} + +function removeArrayItem(cardID, idx) { + var sec = SECTIONS.find(function(s) { return s.id === cardID; }); + if (!sec || !sec.isArray) return; + var arr = itemData[sec.path] || []; + arr.splice(idx, 1); + renderCurrent(); +} + +// ========================================================================= +// Subtable row add/remove +// ========================================================================= + +function addSubRow(cardID, subKey) { + var sec = SECTIONS.find(function(s) { return s.id === cardID; }); + if (!sec) return; + var p = cardPath(sec); + var sectionRoot = p ? (itemData[p] || {}) : itemData; + var raw = sectionRoot[subKey]; + var arr; + if (Array.isArray(raw)) { + arr = raw; + } else if (raw && typeof raw === 'object') { + arr = [raw]; + } else { + arr = []; + } + var empty = {}; + var st = (sec.subtables || []).find(function(s) { return s.key === subKey; }); + if (st) { + st.fields.forEach(function(f) { + empty[f[0]] = f[2] === 'checkbox' ? false : (f[2] === 'number' ? 0 : ''); + }); + } + arr.push(empty); + sectionRoot[subKey] = arr; + if (sectionRoot === itemData) { delete itemData._raw; delete itemData._path; } + renderCurrent(); +} + +function removeSubRow(cardID, subKey, idx) { + var sec = SECTIONS.find(function(s) { return s.id === cardID; }); + if (!sec) return; + var p = cardPath(sec); + var sectionRoot = p ? (itemData[p] || {}) : itemData; + var raw = sectionRoot[subKey]; + var arr; + if (Array.isArray(raw)) { + arr = raw; + } else if (raw && typeof raw === 'object') { + arr = [raw]; + } else { + arr = []; + } + arr.splice(idx, 1); + sectionRoot[subKey] = arr; + renderCurrent(); +} + +// ========================================================================= +// Sub-subtable row add/remove +// ========================================================================= + +function addSubSubRow(cardID, subKey, rowIdx, subSubKey) { + try { + var sec = SECTIONS.find(function(s) { return s.id === cardID; }); + if (!sec) { console.warn('addSubSubRow: section not found', cardID); return; } + var p = cardPath(sec); + var sectionRoot = p ? (itemData[p] || {}) : itemData; + var arr = sectionRoot[subKey] || []; + if (rowIdx >= arr.length) { console.warn('addSubSubRow: row index out of range', rowIdx, arr.length); return; } + if (!arr[rowIdx]) { arr[rowIdx] = {}; } + var subArr = arr[rowIdx][subSubKey] || []; + var empty = {}; + var st = (sec.subtables || []).find(function(s) { return s.key === subKey; }); + if (st && st.subSubtables) { + var sst = st.subSubtables.find(function(ss) { return ss.key === subSubKey; }); + if (sst) { + sst.fields.forEach(function(f) { + empty[f[0]] = f[2] === 'checkbox' ? false : (f[2] === 'number' ? 0 : ''); + }); + } + } + subArr.push(empty); + arr[rowIdx][subSubKey] = subArr; + sectionRoot[subKey] = arr; + renderCurrent(); + } catch(e) { + console.error('addSubSubRow error:', e); + notify('Failed to add row: ' + e.message, 'error'); + } +} + +function removeSubSubRow(cardID, subKey, rowIdx, subSubKey, subSubIdx) { + var sec = SECTIONS.find(function(s) { return s.id === cardID; }); + if (!sec) return; + var p = cardPath(sec); + var sectionRoot = p ? (itemData[p] || {}) : itemData; + var arr = sectionRoot[subKey] || []; + if (rowIdx >= arr.length) return; + var subArr = arr[rowIdx][subSubKey] || []; + subArr.splice(subSubIdx, 1); + renderCurrent(); +} + +// ========================================================================= +// KV row add +// ========================================================================= + +function addKVRow(cardID, subKey) { + var el = document.querySelector('.obj-kv-list[data-sec="' + cardID + '"][data-key="' + subKey + '"]'); + if (!el) return; + var row = document.createElement('div'); + row.className = 'obj-kv-row'; + row.innerHTML = '<input value="" placeholder="key" class="obj-kv-key"><input value="0" placeholder="val" class="obj-kv-val"><button class="btn btn-sm btn-danger" onclick="this.parentElement.remove()">X</button>'; + el.appendChild(row); +} + +// ========================================================================= +// Search autocomplete +// ========================================================================= + +function setupCraftTypeChange() { + document.querySelectorAll('.obj-subtable select[id$="_type"]').forEach(function(typeSelect) { + var id = typeSelect.id; + var subtypeSel = document.getElementById(id.replace(/_type$/, '_subtype')); + var levelField = document.getElementById(id.replace(/_type$/, '_level')); + var xpField = document.getElementById(id.replace(/_type$/, '_xp')); + var stationField = document.getElementById(id.replace(/_type$/, '_station')); + + function update() { + var t = typeSelect.value; + + [levelField, xpField].forEach(function(el) { + if (!el) return; + var lbl = el.closest('.obj-field'); + if (lbl) lbl.style.display = t === 'combine' ? 'none' : ''; + }); + + if (stationField) { + var sLbl = stationField.closest('.obj-field'); + if (sLbl) sLbl.style.display = (t === 'fletching' || t === 'combine' || t === 'pharmacy') ? 'none' : ''; + } + + if (subtypeSel) { + var sLbl = subtypeSel.closest('.obj-field'); + if (t === 'smithing') { + if (sLbl) sLbl.style.display = ''; + subtypeSel.innerHTML = '<option value="">none</option><option value="smelt">smelt</option>'; + } else if (t === 'pharmacy') { + if (sLbl) sLbl.style.display = ''; + subtypeSel.innerHTML = '<option value="">none</option><option value="clean">clean</option>'; + } else { + if (sLbl) sLbl.style.display = 'none'; + subtypeSel.value = ''; + } + } + } + + typeSelect.addEventListener('change', update); + update(); + }); +} + +function setupSearchFields() { + document.querySelectorAll('.search-input').forEach(function(input) { + if (input._searchSetup) return; + input._searchSetup = true; + var entityType = input.getAttribute('data-search-type') || 'items'; + var results = input.parentElement.querySelector('.search-results'); + if (!results) return; + + results._targetInput = input; + + input.addEventListener('input', function() { + var val = input.value.trim(); + if (!val) { results.style.display = 'none'; results.innerHTML = ''; return; } + API.get('/api/search?q=' + encodeURIComponent(val)).then(function(data) { + var items = []; + if (entityType === 'items' && data.items) items = data.items; + if (entityType === 'objects' && data.objects) items = data.objects; + if (entityType === 'mobs' && data.mobs) items = data.mobs; + if (entityType === 'drops' && data.drops) items = data.drops; + if (items.length === 0) { + results.style.display = 'block'; + results.innerHTML = '<div class="sr-item" style="color:#888">No results</div>'; + return; + } + results.style.display = 'block'; + results.innerHTML = items.map(function(r) { + return '<div class="sr-item" onclick="event.stopPropagation();selectSearchResult(this)">' + esc(r.id) + ' <span style="color:#aaa">' + esc(r.name || '') + '</span></div>'; + }).join(''); + results._items = items; + }).catch(function() { + results.style.display = 'none'; + }); + }); + + input.addEventListener('focus', function() { + if (input.value.trim()) { + input.dispatchEvent(new Event('input')); + } + }); + + input.addEventListener('blur', function() { + setTimeout(function() { results.style.display = 'none'; }, 200); + }); + }); + + document.addEventListener('click', function(e) { + if (!e.target.closest('.search-results') && !e.target.closest('.search-input')) { + document.querySelectorAll('.search-results').forEach(function(r) { r.style.display = 'none'; }); + } + }); +} + +function selectSearchResult(el) { + var results = el.parentElement; + var idx = Array.prototype.indexOf.call(results.children, el); + if (results._items && results._items[idx] && results._targetInput) { + results._targetInput.value = results._items[idx].id; + results._targetInput.dispatchEvent(new Event('input')); + results.style.display = 'none'; + results.innerHTML = ''; + } +} + +// ========================================================================= +// Validation +// ========================================================================= + +function validateFields() { + var errors = []; + document.querySelectorAll('.obj-field-error').forEach(function(field) { + field.classList.remove('obj-field-error'); + }); + + document.querySelectorAll('input[id]:not([type="checkbox"])').forEach(function(input) { + var id = input.id; + if (!id) return; + var labelEl = input.closest('.obj-field'); + if (!labelEl) return; + + if (input.classList.contains('search-input') || input.classList.contains('color-input')) return; + + var isNumber = false; + var labelText = ''; + + var fieldDiv = labelEl.closest('[data-card]'); + var cardID = fieldDiv ? fieldDiv.getAttribute('data-card') : ''; + var sec = SECTIONS.find(function(s) { return s.id === cardID; }); + if (!sec) return; + + var baseMatch = id.match(/^f_(\w+)_(\w+)$/); + var subMatch = id.match(/^f_(\w+)_(\w+)_(\d+)_(\w.+)$/); + var subSubMatch = id.match(/^f_(\w+)_(\w+)_(\d+)__(\w+)_(\d+)_(\w+)$/); + var equipStatMatch = id.match(/^f_equipment_(\w+)_(\w+)$/); + + if (subSubMatch) { + var ssSecId = subSubMatch[1], ssSubKey = subSubMatch[2]; + var ssSubSubKey = subSubMatch[4], ssFieldKey = subSubMatch[6]; + var st = (sec.subtables || []).find(function(s) { return s.key === ssSubKey; }); + if (st && st.subSubtables) { + var sst = st.subSubtables.find(function(ss) { return ss.key === ssSubSubKey; }); + if (sst) { + var nf = sst.fields.find(function(f) { return f[0] === ssFieldKey && f[2] === 'number'; }); + if (nf) { isNumber = true; labelText = nf[1]; } + } + } + } else if (subMatch) { + var subKey = subMatch[2], fieldKey = subMatch[4]; + var st = (sec.subtables || []).find(function(s) { return s.key === subKey; }); + if (st) { + var nf = st.fields.find(function(f) { return f[0] === fieldKey && f[2] === 'number'; }); + if (nf) { isNumber = true; labelText = nf[1]; } + } + } else if (equipStatMatch) { + var blockKey = equipStatMatch[1], statField = equipStatMatch[2]; + var fields = EQUIP_STAT_FIELDS[blockKey]; + if (fields) { + var nf = fields.find(function(f) { return f[0] === statField; }); + if (nf) { isNumber = true; labelText = nf[1]; } + } + } else if (baseMatch) { + var fieldKey = baseMatch[2]; + var nf = sec.fields ? sec.fields.find(function(f) { + var fid = fieldID(sec, f[0], -1); + return fid === id && f[2] === 'number'; + }) : null; + if (!nf && sec.inline) { + sec.inline.forEach(function(il) { + if (il.fields) { + var inf = il.fields.find(function(f) { + var fid = fieldID(sec, il.path + '.' + f[0], -1); + return fid === id && f[2] === 'number'; + }); + if (inf) nf = inf; + } + }); + } + if (nf) { isNumber = true; labelText = nf[1]; } + } + + if (isNumber) { + var rawVal = input.value.trim(); + if (rawVal !== '' && !/^-?\d*\.?\d*$/.test(rawVal)) { + labelEl.classList.add('obj-field-error'); + input.focus(); + input.select(); + labelText = labelText || (labelEl.querySelector('span') || {}).textContent || ''; + errors.push('Invalid value in "' + esc(labelText) + '": "' + esc(rawVal) + '"'); + } + } + }); + + if (errors.length > 0) { + notify(errors.join('; '), 'error'); + return false; + } + return true; +} + +// ========================================================================= +// Field value collector +// ========================================================================= + +function collectFieldValue(el, type) { + if (type === 'checkbox') return el.checked; + if (type === 'select') return el.value; + if (type === 'search') return el.value; + if (type === 'number') { var n = parseFloat(el.value); return isNaN(n) ? 0 : n; } + if (type === 'json') { + var raw = el.value.trim(); + if (!raw) return null; + try { return JSON.parse(raw); } catch(e) { return raw; } + } + if (type === 'textarea') return el.value; + return el.value; +} + +// ========================================================================= +// Save +// ========================================================================= + +function saveItem() { + if (!validateFields()) return; + + var out = {}; + + SECTIONS.forEach(function(sec) { + if (sec.isArray) { + var arr = []; + var card = document.querySelector('.obj-card[data-card="' + sec.id + '"]'); + if (!card) return; + var rows = card.querySelectorAll('.obj-sub-row'); + rows.forEach(function(row, idx) { + var item = {}; + sec.fields.forEach(function(f) { + var fid = fieldID(sec, f[0], idx); + var el = document.getElementById(fid); + if (el) item[f[0]] = collectFieldValue(el, f[2]); + }); + if (Object.keys(item).length > 0) arr.push(item); + }); + if (arr.length > 0) out[sec.path] = arr; + return; + } + + if (sec.id === 'equipment') { + var eq = {}; + var hasEq = false; + + ['type', 'slot', 'attack_type', 'junk'].forEach(function(k) { + var el = document.getElementById('f_equipment_' + k); + if (!el) return; + var val = collectFieldValue(el, k === 'type' || k === 'slot' ? 'select' : (k === 'junk' ? 'search' : 'text')); + if (val !== '' && val !== false && val !== 0 && val !== null) hasEq = true; + eq[k] = val; + }); + + if (eq.type === 'ammo') eq.slot = 'ammo'; + + var speedEl = document.getElementById('f_equipment_speed'); + if (speedEl) { + var spd = parseFloat(speedEl.value); + if (!isNaN(spd) && spd !== 0) { eq.speed = spd; hasEq = true; } + } + + EQUIP_STAT_FIELDS.attack.forEach(function(f) { saveEquipBlock(eq, 'attack', f[0]); }); + EQUIP_STAT_FIELDS.defense.forEach(function(f) { saveEquipBlock(eq, 'defense', f[0]); }); + EQUIP_STAT_FIELDS.other.forEach(function(f) { saveEquipBlock(eq, 'other', f[0]); }); + + if (hasEq && Object.keys(eq).length > 0) out.equipment = eq; + + var recovEl = document.getElementById('f_core_recoverable'); + if (recovEl) out.recoverable = recovEl.checked; + + var kvEl = document.querySelector('.obj-kv-list[data-sec="equipment_req"][data-key="requirements"]'); + if (kvEl) { + var map = {}; + kvEl.querySelectorAll('.obj-kv-row').forEach(function(row) { + var keyEl = row.querySelector('.obj-kv-key'); + var valEl = row.querySelector('.obj-kv-val'); + if (keyEl && keyEl.value.trim() && valEl) { + map[keyEl.value.trim()] = parseFloat(valEl.value) || 0; + } + }); + if (Object.keys(map).length > 0) out.requirements = map; + } + return; + } + + var sectionObj = {}; + var hasValues = sec.always; + + if (sec.fields) sec.fields.forEach(function(f) { + var fid = fieldID(sec, f[0]); + var el = document.getElementById(fid); + if (!el) return; + var val = collectFieldValue(el, f[2]); + if (val !== '' && val !== false && val !== 0 && val !== null) hasValues = true; + sectionObj[f[0]] = val; + }); + + if (sec.subtables) { + sec.subtables.forEach(function(st) { + var items = []; + for (var i = 0; ; i++) { + var item = {}; + var found = false; + st.fields.forEach(function(f) { + var fid = fieldIDSub(sec, st.key, i, f[0]); + var el = document.getElementById(fid); + if (el) found = true; + if (el) item[f[0]] = collectFieldValue(el, f[2]); + }); + if (!found) break; + + if (item.success_base !== undefined || item.success_per_level !== undefined || item.success_cap !== undefined) { + var sBase = Number(item.success_base) || 0; + var sPer = Number(item.success_per_level) || 0; + var sCap = Number(item.success_cap) || 0; + delete item.success_base; + delete item.success_per_level; + delete item.success_cap; + if (sBase || sPer || sCap) { + item.success = {base: sBase, per_level: sPer, cap: sCap}; + } + } + + if (item.station !== undefined && typeof item.station === 'string') { + item.station = item.station.split(',').map(function(s) { return s.trim(); }).filter(function(s) { return s; }); + } + + if (st.subSubtables) { + st.subSubtables.forEach(function(sst) { + var isIngredients = sst.key === 'ingredients'; + var subItems = []; + for (var j = 0; ; j++) { + var subItem = {}; + var subFound = false; + sst.fields.forEach(function(f) { + var fid = fieldIDSubSub(sec, st.key, i, sst.key, j, f[0]); + var el = document.getElementById(fid); + if (el) subFound = true; + if (el) subItem[f[0]] = collectFieldValue(el, f[2]); + }); + if (!subFound) break; + + if (isIngredients) { + var itemsArr = []; + var bypArr = []; + for (var k = 0; ; k++) { + var itemFid = ingredientPairID(sec, st.key, i, sst.key, j, k, 'items'); + var itemEl = document.getElementById(itemFid); + if (!itemEl) break; + var itemVal = itemEl.value.trim(); + itemsArr.push(itemVal); + + var bypFid = ingredientPairID(sec, st.key, i, sst.key, j, k, 'byproducts'); + var bypEl = document.getElementById(bypFid); + var bypVal = bypEl ? bypEl.value.trim() : ''; + bypArr.push(bypVal); + } + var hasItems = itemsArr.some(function(v) { return v !== ''; }); + if (hasItems) { + subItem.items = itemsArr.filter(function(v) { return v !== ''; }); + if (bypArr.some(function(v) { return v !== ''; })) subItem.byproducts = bypArr; + } + if (!subItem.items) { subFound = false; } + } else { + if (subItem.items !== undefined && typeof subItem.items === 'string') { + subItem.items = subItem.items.split(',').map(function(s) { return s.trim(); }).filter(function(s) { return s; }); + } + if (subItem.byproducts !== undefined && typeof subItem.byproducts === 'string') { + subItem.byproducts = subItem.byproducts.split(',').map(function(s) { return s.trim(); }).filter(function(s) { return s; }); + } + } + + if (Object.keys(subItem).length > 0) subItems.push(subItem); + } + if (subItems.length > 0) item[sst.key] = subItems; + }); + } + + if (Object.keys(item).length > 0) items.push(item); + } + if (st.single) { + if (items.length > 0) { sectionObj[st.key] = items[0]; hasValues = true; } + } else { + if (items.length > 0) { sectionObj[st.key] = items; hasValues = true; } + } + }); + } + + if (sec.inline) { + sec.inline.forEach(function(il) { + if (il.type === 'tags') { + var fid = fieldID(sec, il.key); + var el = document.getElementById(fid); + if (el && el.value.trim()) { + sectionObj[il.key] = el.value.split(',').map(function(s) { return s.trim(); }).filter(function(s) { return s; }); + hasValues = true; + } + } else if (il.type === 'kv') { + var kvEl = document.querySelector('.obj-kv-list[data-sec="' + sec.id + '"][data-key="' + il.key + '"]'); + if (kvEl) { + var map = {}; + kvEl.querySelectorAll('.obj-kv-row').forEach(function(row) { + var keyEl = row.querySelector('.obj-kv-key'); + var valEl = row.querySelector('.obj-kv-val'); + if (keyEl && keyEl.value.trim() && valEl) { + map[keyEl.value.trim()] = parseFloat(valEl.value) || 0; + } + }); + if (Object.keys(map).length > 0) { sectionObj[il.key] = map; hasValues = true; } + } + } else { + var ssec = {}; + var sHas = false; + il.fields.forEach(function(f) { + var fp = il.path + '.' + f[0]; + var fid = fieldID(sec, fp); + var el = document.getElementById(fid); + if (el) sHas = true; + if (el) ssec[f[0]] = collectFieldValue(el, f[2]); + }); + if (sHas) { sectionObj[il.path] = ssec; hasValues = true; } + } + }); + } + + if (sec.always) { + Object.keys(sectionObj).forEach(function(k) { out[k] = sectionObj[k]; }); + } else if (hasValues && sec.path) { + out[sec.path] = sectionObj; + } else if (hasValues && !sec.path) { + Object.keys(sectionObj).forEach(function(k) { out[k] = sectionObj[k]; }); + } + }); + + cleanOutput(out); + out.id = itemID; + + API.put('/api/items/' + encodeURIComponent(itemID), out).then(function(resp) { + notify('Item ' + itemID + ' saved', 'success'); + updateUndoBar(); + if (resp && resp._raw) itemData._raw = resp._raw; + }).catch(function(e) { notify('Save failed: ' + e.message, 'error'); }); +} + +function saveEquipBlock(eq, blockKey, fieldKey) { + var fid = 'f_equipment_' + blockKey + '_' + fieldKey; + var el = document.getElementById(fid); + if (!el) return; + var val = parseFloat(el.value); + if (isNaN(val)) return; + if (!eq[blockKey]) eq[blockKey] = {}; + eq[blockKey][fieldKey] = val; +} + +function cleanOutput(obj) { + for (var key in obj) { + var val = obj[key]; + if (val === '' || val === null || val === undefined) { + delete obj[key]; + } else if (typeof val === 'object' && val !== null && !Array.isArray(val)) { + cleanOutput(val); + if (Object.keys(val).length === 0) delete obj[key]; + } else if (Array.isArray(val) && val.length === 0) { + delete obj[key]; + } + } +} + +// ========================================================================= +// Duplicate +// ========================================================================= + +function duplicateItem() { + var baseID = itemID + '_copy'; + var newID = baseID; + var counter = 2; + while (true) { + var exists = false; + for (var i = 0; i < allIDs.length; i++) { + if (allIDs[i] === newID) { exists = true; break; } + } + if (!exists) break; + newID = baseID + '_' + counter; + counter++; + } + + var copy = JSON.parse(JSON.stringify(itemData)); + delete copy._raw; + delete copy._path; + copy.id = newID; + + API.post('/api/items', {id: newID}).then(function() { + return API.put('/api/items/' + encodeURIComponent(newID), copy); + }).then(function() { + notify('Duplicated as ' + newID, 'success'); + updateUndoBar(); + loadList(); + loadItem(newID); + }).catch(function(e) { notify('Duplicate failed: ' + e.message, 'error'); }); +} + +// ========================================================================= +// Delete +// ========================================================================= + +function deleteItem() { + if (!confirm('Delete item "' + itemID + '"?')) return; + API.del('/api/items/' + encodeURIComponent(itemID)).then(function() { + notify('Item ' + itemID + ' deleted', 'success'); + updateUndoBar(); + itemID = null; + currentID = null; + itemData = null; + $('#editorMain').innerHTML = '<p style="color:#888;text-align:center;margin-top:60px">Deleted</p>'; + loadList(); + }).catch(function(e) { notify('Delete failed: ' + e.message, 'error'); }); +} + +// ========================================================================= +// Editor.js compatibility re-exports +// ========================================================================= + +function loadItem(id) { loadItemEditor(id); } diff --git a/internal/admin/static/map.js b/internal/admin/static/map.js index 5bff9d7..e5d9a19 100644 --- a/internal/admin/static/map.js +++ b/internal/admin/static/map.js @@ -595,8 +595,10 @@ function renderItemsTab(spawns) { h += '<div class="entry-row" data-idx="' + i + '">'; h += '<div class="entry-fields">'; h += '<span class="entry-id">' + esc(spawn.id || '') + '</span>'; - h += '<label class="mini-label">Qty</label><input class="mini-input spawn-qty" type="number" value="' + (spawn.quantity || 0) + '" onchange="updateSpawn(' + i + ')">'; - h += '<label class="mini-label">Respawn</label><input class="mini-input spawn-respawn" type="number" value="' + (spawn.respawn_ticks || 0) + '" onchange="updateSpawn(' + i + ')">'; + h += '<div style="display:flex;gap:8px;align-items:center;">'; + h += '<div><label class="mini-label">Quantity</label><input class="mini-input spawn-qty" type="text" inputmode="numeric" pattern="[0-9]*" value="' + (spawn.quantity || 0) + '" onchange="updateSpawn(' + i + ')"></div>'; + h += '<div><label class="mini-label">Respawn</label><input class="mini-input spawn-respawn" type="text" inputmode="numeric" pattern="[0-9]*" value="' + (spawn.respawn_ticks || 0) + '" onchange="updateSpawn(' + i + ')"></div>'; + h += '</div>'; h += '</div>'; h += '<button class="btn btn-sm" onclick="openEditor(\'items\', \'' + escAttr(spawn.id || '') + '\')">Edit</button>'; h += '<button class="btn btn-sm btn-danger" onclick="removeSpawn(' + i + ')">X</button>'; @@ -666,7 +668,7 @@ function editExitCondition(dir) { overlay.className = 'cm-overlay exit-overlay'; var menu = document.createElement('div'); menu.className = 'cm-menu exit-modal'; - menu.style.cssText = 'position:fixed;top:50%;left:50%;transform:translate(-50%,-50%);min-width:420px;max-width:90vw;max-height:85vh;overflow-y:auto;overflow-x:hidden;padding:14px;z-index:201'; + menu.style.cssText = 'position:fixed;top:50%;left:50%;transform:translate(-50%,-50%);min-width:520px;max-width:90vw;max-height:85vh;overflow-y:auto;overflow-x:hidden;padding:14px;z-index:201'; var h = '<h3 style="margin-bottom:8px;font-size:13px">Exit: ' + esc(dir) + ' → #' + exit.room + '</h3>'; h += '<div class="form-group"><label>Set Flags (key=value, comma separated)</label><input id="exitFlags" value="' + escAttr(flagsStr) + '"></div>'; @@ -742,7 +744,7 @@ function renderConditionClauses(menu) { } else { h += '<input class="cond-val" value="' + escAttr(clause.value || '') + '" onchange="updateClauseData(this)" style="flex:1">'; } - h += '<label style="font-size:10px;color:#aaa;white-space:nowrap"><input type="checkbox" class="cond-not"' + (clause.not ? ' checked' : '') + ' onchange="updateClauseData(this)"> not</label>'; + h += '<label style="font-size:10px;color:#aaa;white-space:nowrap"><input type="checkbox" class="cond-not"' + (clause.not ? ' checked' : '') + ' onchange="updateClauseData(this)"> =Not True</label>'; h += '<button class="btn btn-sm btn-danger" onclick="removeConditionClause(this)" style="flex-shrink:0">X</button>'; h += '</div>'; }); @@ -833,7 +835,8 @@ function saveExitCondition() { } function buildSingleCondition(clause) { - var obj = {not: !!clause.not}; + var obj = {}; + if (clause.not) obj.not = true; if (clause.type === 'value') { var parts = (clause.value || '').split('=', 2); obj.value = {key: (parts[0] || '').trim(), value: (parts[1] || '').trim()}; diff --git a/internal/admin/static/objecteditor.js b/internal/admin/static/objecteditor.js index 3e944c4..13a983e 100644 --- a/internal/admin/static/objecteditor.js +++ b/internal/admin/static/objecteditor.js @@ -588,7 +588,7 @@ function addArrayItem(cardID) { var arr = objectData[sec.path] || []; var empty = {}; sec.fields.forEach(function(f) { - empty[f[0]] = f[2] === 'checkbox' ? false : (f[2] === 'number' || f[2] === 'search' ? 0 : ''); + empty[f[0]] = f[2] === 'checkbox' ? false : (f[2] === 'number' ? 0 : ''); }); arr.push(empty); objectData[sec.path] = arr; @@ -612,7 +612,7 @@ function addSubRow(cardID, subKey) { var st = (sec.subtables || []).find(function(s) { return s.key === subKey; }); if (st) { st.fields.forEach(function(f) { - empty[f[0]] = f[2] === 'checkbox' ? false : (f[2] === 'number' || f[2] === 'search' ? 0 : ''); + empty[f[0]] = f[2] === 'checkbox' ? false : (f[2] === 'number' ? 0 : ''); }); } arr.push(empty); diff --git a/internal/admin/templates/items.html b/internal/admin/templates/items.html index f8f3b66..4a74ff5 100644 --- a/internal/admin/templates/items.html +++ b/internal/admin/templates/items.html @@ -10,36 +10,8 @@ </div> </div> <script src="/static/editor.js"></script> +<script src="/static/itemeditor.js"></script> <script> -initEditor('items', [ - {key:'name',label:'Name',type:'text'}, - {key:'color',label:'Color',type:'color'}, - {key:'description',label:'Description',type:'textarea'}, - {key:'value',label:'Value',type:'number'}, - {key:'stackable',label:'Stackable',type:'checkbox'}, - {key:'equip_slot',label:'Equip Slot',type:'text'}, - {key:'weapon_type',label:'Weapon Type',type:'text'}, - {key:'attack_type',label:'Attack Type',type:'text'}, - {key:'speed',label:'Speed',type:'number'}, - {key:'tool_type',label:'Tool Type',type:'text'}, - {key:'tool_speed',label:'Tool Speed',type:'number'}, - {key:'burn_ticks',label:'Burn Ticks',type:'number'}, - {key:'fire_level',label:'Fire Level',type:'number'}, - {key:'fire_xp',label:'Fire XP',type:'number'}, - {key:'quality',label:'Quality',type:'number'}, - {key:'max_quality',label:'Max Quality',type:'number'}, - {key:'search_table',label:'Search Table',type:'text'}, - {key:'search_ticks',label:'Search Ticks',type:'number'}, - {key:'heal_value',label:'Heal Value',type:'number'}, - {key:'eat_message',label:'Eat Message',type:'text'}, - {key:'farm_patch_type',label:'Farm Patch',type:'text'}, - {key:'farm_level',label:'Farm Level',type:'number'}, - {key:'farm_stages',label:'Farm Stages',type:'number'}, - {key:'farm_product',label:'Farm Product',type:'text'}, - {key:'potion_effect',label:'Potion Effect',type:'text'}, - {key:'potion_bonus',label:'Potion Bonus',type:'number'}, - {key:'potion_duration',label:'Potion Duration',type:'number'}, - {key:'recoverable',label:'Recoverable',type:'checkbox'} -]); +initItemEditor(); </script> {{end}} diff --git a/internal/admin/undo.go b/internal/admin/undo.go index 4921ae5..bec3c35 100644 --- a/internal/admin/undo.go +++ b/internal/admin/undo.go @@ -2,6 +2,7 @@ package admin import ( "encoding/json" + "fmt" "log" "os" "path/filepath" @@ -27,6 +28,19 @@ type ChangeDesc struct { ExtraFiles []ExtraFile `json:"extra_files,omitempty"` } +func (c ChangeDesc) ShortDesc() string { + switch { + case c.IsCreate: + return fmt.Sprintf("Created %s", filepath.Base(c.FilePath)) + case c.IsDelete: + return fmt.Sprintf("Deleted %s", filepath.Base(c.FilePath)) + case c.NewFilePath != "": + return fmt.Sprintf("Renamed %s", filepath.Base(c.NewFilePath)) + default: + return fmt.Sprintf("Edited %s", filepath.Base(c.FilePath)) + } +} + type UndoInfo struct { CanUndo bool `json:"can_undo"` CanRedo bool `json:"can_redo"` @@ -52,6 +66,7 @@ func NewUndoStack(dataDir string) *UndoStack { filePath: filepath.Join(dataDir, ".admin_history.json"), } us.load() + us.redo = nil return us } @@ -65,6 +80,7 @@ func (us *UndoStack) Push(desc ChangeDesc) { us.history = us.history[len(us.history)-us.maxSize:] } us.save() + log.Printf("undo: push %s", desc.ShortDesc()) } func (us *UndoStack) Undo() *ChangeDesc { @@ -74,47 +90,16 @@ func (us *UndoStack) Undo() *ChangeDesc { return nil } last := us.history[len(us.history)-1] - us.history = us.history[:len(us.history)-1] - if last.NewFilePath != "" { - os.Remove(last.NewFilePath) - } - if last.IsDelete { - if err := os.WriteFile(last.FilePath, last.OldContent, 0644); err != nil { - log.Printf("undo: failed to restore deleted file %s: %v", last.FilePath, err) - return nil - } - for _, ef := range last.ExtraFiles { - if err := os.WriteFile(ef.FilePath, ef.OldContent, 0644); err != nil { - log.Printf("undo: failed to restore extra file %s: %v", ef.FilePath, err) - } - } - } else if last.IsCreate { - os.Remove(last.FilePath) - for _, ef := range last.ExtraFiles { - os.Remove(ef.FilePath) - } - } else { - if last.NewFilePath != "" { - if err := os.WriteFile(last.FilePath, last.OldContent, 0644); err != nil { - log.Printf("undo: failed to revert move %s: %v", last.FilePath, err) - return nil - } - } else { - if err := os.WriteFile(last.FilePath, last.OldContent, 0644); err != nil { - log.Printf("undo: failed to revert file %s: %v", last.FilePath, err) - return nil - } - } - for _, ef := range last.ExtraFiles { - if err := os.WriteFile(ef.FilePath, ef.OldContent, 0644); err != nil { - log.Printf("undo: failed to restore extra file %s: %v", ef.FilePath, err) - } - } + if err := us.applyUndo(last); err != nil { + log.Printf("undo: failed %s: %v", last.ShortDesc(), err) + return nil } + us.history = us.history[:len(us.history)-1] us.redo = append(us.redo, last) us.save() + log.Printf("undo: undid %s", last.ShortDesc()) return &last } @@ -125,57 +110,88 @@ func (us *UndoStack) Redo() *ChangeDesc { return nil } last := us.redo[len(us.redo)-1] + + if err := us.applyRedo(last); err != nil { + log.Printf("redo: failed %s: %v", last.ShortDesc(), err) + return nil + } + us.redo = us.redo[:len(us.redo)-1] + us.history = append(us.history, last) + us.save() + log.Printf("redo: redid %s", last.ShortDesc()) + return &last +} - if last.NewFilePath != "" { - os.Remove(last.FilePath) +func (us *UndoStack) applyUndo(c ChangeDesc) error { + if c.NewFilePath != "" { + os.Remove(c.NewFilePath) } - if last.IsCreate { - if last.NewFilePath != "" { - if err := os.WriteFile(last.NewFilePath, last.NewContent, 0644); err != nil { - log.Printf("redo: failed to recreate file %s: %v", last.NewFilePath, err) - return nil - } - } else { - if err := os.WriteFile(last.FilePath, last.NewContent, 0644); err != nil { - log.Printf("redo: failed to recreate file %s: %v", last.FilePath, err) - return nil - } + if c.IsDelete { + if c.OldContent == nil { + return fmt.Errorf("no backup content to restore for %s", c.FilePath) } - for _, ef := range last.ExtraFiles { - if err := os.WriteFile(ef.FilePath, ef.NewContent, 0644); err != nil { - log.Printf("redo: failed to create extra file %s: %v", ef.FilePath, err) - } + if err := os.WriteFile(c.FilePath, c.OldContent, 0644); err != nil { + return fmt.Errorf("restore deleted %s: %w", c.FilePath, err) } - } else if last.IsDelete { - os.Remove(last.FilePath) - for _, ef := range last.ExtraFiles { - if err := os.WriteFile(ef.FilePath, ef.NewContent, 0644); err != nil { - log.Printf("redo: failed to write extra file %s: %v", ef.FilePath, err) - } + for _, ef := range c.ExtraFiles { + os.WriteFile(ef.FilePath, ef.OldContent, 0644) + } + } else if c.IsCreate { + os.Remove(c.FilePath) + for _, ef := range c.ExtraFiles { + os.Remove(ef.FilePath) } } else { - if last.NewFilePath != "" { - if err := os.WriteFile(last.NewFilePath, last.NewContent, 0644); err != nil { - log.Printf("redo: failed to reapply move %s: %v", last.NewFilePath, err) - return nil - } - } else { - if err := os.WriteFile(last.FilePath, last.NewContent, 0644); err != nil { - log.Printf("redo: failed to reapply file %s: %v", last.FilePath, err) - return nil - } + target := c.FilePath + content := c.OldContent + if c.NewFilePath != "" { + target = c.FilePath } - for _, ef := range last.ExtraFiles { - if err := os.WriteFile(ef.FilePath, ef.NewContent, 0644); err != nil { - log.Printf("redo: failed to write extra file %s: %v", ef.FilePath, err) - } + if err := os.WriteFile(target, content, 0644); err != nil { + return fmt.Errorf("revert %s: %w", target, err) + } + for _, ef := range c.ExtraFiles { + os.WriteFile(ef.FilePath, ef.OldContent, 0644) } } + return nil +} - us.history = append(us.history, last) - us.save() - return &last +func (us *UndoStack) applyRedo(c ChangeDesc) error { + if c.NewFilePath != "" { + os.Remove(c.FilePath) + } + if c.IsCreate { + target := c.FilePath + if c.NewFilePath != "" { + target = c.NewFilePath + } + if err := os.WriteFile(target, c.NewContent, 0644); err != nil { + return fmt.Errorf("recreate %s: %w", target, err) + } + for _, ef := range c.ExtraFiles { + os.WriteFile(ef.FilePath, ef.NewContent, 0644) + } + } else if c.IsDelete { + os.Remove(c.FilePath) + for _, ef := range c.ExtraFiles { + os.WriteFile(ef.FilePath, ef.NewContent, 0644) + } + } else { + target := c.FilePath + content := c.NewContent + if c.NewFilePath != "" { + target = c.NewFilePath + } + if err := os.WriteFile(target, content, 0644); err != nil { + return fmt.Errorf("reapply %s: %w", target, err) + } + for _, ef := range c.ExtraFiles { + os.WriteFile(ef.FilePath, ef.NewContent, 0644) + } + } + return nil } func (us *UndoStack) Info() UndoInfo { @@ -187,11 +203,11 @@ func (us *UndoStack) Info() UndoInfo { } if len(us.history) > 0 { info.CanUndo = true - info.UndoDesc = us.history[len(us.history)-1].Description + info.UndoDesc = us.history[len(us.history)-1].ShortDesc() } if len(us.redo) > 0 { info.CanRedo = true - info.RedoDesc = us.redo[len(us.redo)-1].Description + info.RedoDesc = us.redo[len(us.redo)-1].ShortDesc() } return info } @@ -251,7 +267,9 @@ func (us *UndoStack) save() { log.Printf("undo: failed to marshal history: %v", err) return } - os.WriteFile(us.filePath, b, 0644) + if err := os.WriteFile(us.filePath, b, 0644); err != nil { + log.Printf("undo: failed to write history file: %v", err) + } } func (us *UndoStack) load() { @@ -259,6 +277,7 @@ func (us *UndoStack) load() { if err != nil { return } + log.Printf("undo: loaded history from %s", us.filePath) type extraEntry struct { FilePath string `json:"file_path"` OldContent string `json:"old_content"` @@ -280,6 +299,7 @@ func (us *UndoStack) load() { Redo []entry `json:"redo"` } if err := json.Unmarshal(data, &saveData); err != nil { + log.Printf("undo: failed to unmarshal history: %v", err) return } fromEntries := func(entries []entry) []ChangeDesc { @@ -308,5 +328,5 @@ func (us *UndoStack) load() { return changes } us.history = fromEntries(saveData.History) - us.redo = fromEntries(saveData.Redo) + log.Printf("undo: loaded %d history entries", len(us.history)) } diff --git a/internal/admin/yaml_util.go b/internal/admin/yaml_util.go index 0bc2b4a..4d0a814 100644 --- a/internal/admin/yaml_util.go +++ b/internal/admin/yaml_util.go @@ -145,7 +145,7 @@ func listYAMLFilesDeep(dataDir, subdir string) ([]string, error) { func backupFile(path string) []byte { data, err := os.ReadFile(path) if err != nil { - log.Printf("backup: failed to read %s: %v", path, err) + log.Printf("backup: WARNING failed to read %s: %v (undo will not be able to restore this file)", path, err) return nil } return data diff --git a/internal/behavior/behavior.go b/internal/behavior/behavior.go index f64b4b2..8333a05 100644 --- a/internal/behavior/behavior.go +++ b/internal/behavior/behavior.go @@ -73,7 +73,7 @@ type ShopItem struct { type Condition struct { Flag string `yaml:"flag"` Value any `yaml:"value"` - Not bool `yaml:"not"` + Not bool `yaml:"not"` PlayerFlag string `yaml:"player_flag"` HasItem string `yaml:"has_item"` MinCredits int `yaml:"min_credits"` diff --git a/internal/game/act_burn.go b/internal/game/act_burn.go index 7420dff..c24d3d7 100644 --- a/internal/game/act_burn.go +++ b/internal/game/act_burn.go @@ -309,8 +309,8 @@ func (g *Game) findFireTool(sess *net.Session, p *player.Player) (toolSpeed floa if itemID, equipped := p.Equipment[item.SlotMainHand]; equipped { def, err := g.ItemStore.Load(itemID) - if err == nil && def.ToolType == "fire" { - toolSpeed = def.ToolSpeed + if err == nil && def.ToolType() == "fire" { + toolSpeed = def.ToolSpeed() toolItemID = itemID } } @@ -321,10 +321,10 @@ func (g *Game) findFireTool(sess *net.Session, p *player.Player) (toolSpeed floa continue } def, err := g.ItemStore.Load(slot.ItemID) - if err != nil || def.ToolType != "fire" { + if err != nil || def.ToolType() != "fire" { continue } - toolSpeed = def.ToolSpeed + toolSpeed = def.ToolSpeed() toolItemID = slot.ItemID break } diff --git a/internal/game/act_clean.go b/internal/game/act_clean.go index 0c128a1..021a07c 100644 --- a/internal/game/act_clean.go +++ b/internal/game/act_clean.go @@ -25,16 +25,16 @@ func (g *Game) advanceClean(sess *net.Session, p *player.Player) { return } - items := g.CraftIndex.ByType("clean") + items := g.CraftIndex.BySubtype("clean") var matchItem *item.ItemDef for _, item := range items { c := item.FirstCraft() if filter != "" { - if len(c.Consume) == 0 || len(c.Consume[0].Items) == 0 { + if len(c.Ingredients) == 0 || len(c.Ingredients[0].Items) == 0 { continue } - if !strings.Contains(c.Consume[0].Items[0], filter) && + if !strings.Contains(c.Ingredients[0].Items[0], filter) && !strings.Contains(item.ID, filter) { continue } @@ -56,7 +56,7 @@ func (g *Game) advanceClean(sess *net.Session, p *player.Player) { } craft := matchItem.FirstCraft() - consumeID := craft.Consume[0].Items[0] + consumeID := craft.Ingredients[0].Items[0] for i := 0; i < 28; i++ { slot := p.InvSlot(i) @@ -81,10 +81,10 @@ func (g *Game) advanceClean(sess *net.Session, p *player.Player) { for _, item := range items { c := item.FirstCraft() if filter != "" { - if len(c.Consume) == 0 || len(c.Consume[0].Items) == 0 { + if len(c.Ingredients) == 0 || len(c.Ingredients[0].Items) == 0 { continue } - if !strings.Contains(c.Consume[0].Items[0], filter) && + if !strings.Contains(c.Ingredients[0].Items[0], filter) && !strings.Contains(item.ID, filter) { continue } diff --git a/internal/game/act_fletch.go b/internal/game/act_fletch.go index e85f2c1..800bc8e 100644 --- a/internal/game/act_fletch.go +++ b/internal/game/act_fletch.go @@ -44,7 +44,7 @@ func (g *Game) doInstantFletch(sess *net.Session, p *player.Player, def *item.It for i := 0; i < 28; i++ { slot := p.InvSlot(i) if slot != nil && slot.ItemID == def.ID { - craftConsumeAll(c, p.HasItem, p.RemoveItem) + consumeIngredients(c, p.HasItem, p.RemoveItem) slot.Quantity += outputQty placed = true break @@ -52,7 +52,7 @@ func (g *Game) doInstantFletch(sess *net.Session, p *player.Player, def *item.It } } if !placed { - craftConsumeAll(c, p.HasItem, p.RemoveItem) + consumeIngredients(c, p.HasItem, p.RemoveItem) freeSlot := p.FirstFreeSlot() if freeSlot == -1 { break @@ -165,7 +165,7 @@ func (g *Game) advanceFletch(sess *net.Session, p *player.Player) { for i := 0; i < 28; i++ { slot := p.InvSlot(i) if slot != nil && slot.ItemID == def.ID { - craftConsumeAll(c, p.HasItem, p.RemoveItem) + consumeIngredients(c, p.HasItem, p.RemoveItem) slot.Quantity += outputQty placed = true break @@ -173,7 +173,7 @@ func (g *Game) advanceFletch(sess *net.Session, p *player.Player) { } } if !placed { - craftConsumeAll(c, p.HasItem, p.RemoveItem) + consumeIngredients(c, p.HasItem, p.RemoveItem) freeSlot := p.FirstFreeSlot() if freeSlot == -1 { sess.WriteLine("Your inventory is too full!") diff --git a/internal/game/act_search.go b/internal/game/act_search.go index 6f5fa65..83ea534 100644 --- a/internal/game/act_search.go +++ b/internal/game/act_search.go @@ -82,16 +82,6 @@ func (g *Game) advanceSearch(sess *net.Session, p *player.Player) { } } - if def.SearchMiscTable != "" { - dt2, err := behavior.LoadDropTable(g.DataDir, def.SearchMiscTable) - if err == nil && len(dt2.Drops) > 0 { - drop := behavior.ResolveDrop(g.DataDir, dt2.Drops) - if drop != nil && drop.ItemID != "" { - g.giveSearchLoot(sess, p, drop) - } - } - } - g.AccountStore.SaveCharacter(p) g.cancelAction(p) } diff --git a/internal/game/cmd_clean.go b/internal/game/cmd_clean.go index a43295a..f77ff57 100644 --- a/internal/game/cmd_clean.go +++ b/internal/game/cmd_clean.go @@ -22,7 +22,7 @@ func (g *Game) doClean(sess *net.Session, input string) { return } - items := g.CraftIndex.ByType("clean") + items := g.CraftIndex.BySubtype("clean") filter := strings.TrimSpace(input) @@ -78,8 +78,8 @@ func (g *Game) doClean(sess *net.Session, input string) { } func matchesCleanFilter(item *item.ItemDef, filter string) bool { - if len(item.Craft) > 0 && len(item.FirstCraft().Consume) > 0 && len(item.FirstCraft().Consume[0].Items) > 0 { - if strings.Contains(item.FirstCraft().Consume[0].Items[0], filter) { + if len(item.Craft) > 0 && len(item.FirstCraft().Ingredients) > 0 && len(item.FirstCraft().Ingredients[0].Items) > 0 { + if strings.Contains(item.FirstCraft().Ingredients[0].Items[0], filter) { return true } } diff --git a/internal/game/cmd_craft.go b/internal/game/cmd_craft.go index 0fe3d5b..3d23f85 100644 --- a/internal/game/cmd_craft.go +++ b/internal/game/cmd_craft.go @@ -171,7 +171,7 @@ func (g *Game) startItem(sess *net.Session, p *player.Player, def *item.ItemDef, } func (g *Game) hasGrimyHerbs(p *player.Player) bool { - items := g.CraftIndex.ByType("clean") + items := g.CraftIndex.BySubtype("clean") for _, def := range items { if def.FindCraft(func(c item.CraftDef) bool { return craftHasAllItems(&c, p.HasItem) @@ -188,10 +188,10 @@ func (g *Game) findCraftItems(p *player.Player, itemAID, itemBID string) []*item toolTypeA := "" toolTypeB := "" if defA, _ := g.ItemStore.Load(itemAID); defA != nil { - toolTypeA = defA.ToolType + toolTypeA = defA.ToolType() } if defB, _ := g.ItemStore.Load(itemBID); defB != nil { - toolTypeB = defB.ToolType + toolTypeB = defB.ToolType() } var matched []*item.ItemDef diff --git a/internal/game/cmd_fletch.go b/internal/game/cmd_fletch.go index 0da8129..d638bc0 100644 --- a/internal/game/cmd_fletch.go +++ b/internal/game/cmd_fletch.go @@ -28,7 +28,7 @@ func fletchNeedsKnife(def *item.ItemDef) bool { if c.Tool == "knife" { return true } - for _, e := range c.Consume { + for _, e := range c.Ingredients { for _, id := range e.Items { if fletchLogItems[id] { if strings.Contains(def.ID, "shaft") || strings.Contains(def.ID, "bow") { @@ -46,7 +46,7 @@ func fletchNeedsChisel(def *item.ItemDef) bool { if c.Tool == "chisel" { return true } - for _, e := range c.Consume { + for _, e := range c.Ingredients { for _, id := range e.Items { if fletchGemItems[id] { return true @@ -179,10 +179,10 @@ func (g *Game) findFletchItems(p *player.Player, itemAID, itemBID string) []*ite toolTypeA := "" toolTypeB := "" if defA, _ := g.ItemStore.Load(itemAID); defA != nil { - toolTypeA = defA.ToolType + toolTypeA = defA.ToolType() } if defB, _ := g.ItemStore.Load(itemBID); defB != nil { - toolTypeB = defB.ToolType + toolTypeB = defB.ToolType() } isToolA := toolTypeA == "knife" || toolTypeA == "chisel" isToolB := toolTypeB == "knife" || toolTypeB == "chisel" @@ -204,7 +204,7 @@ func (g *Game) findFletchItems(p *player.Player, itemAID, itemBID string) []*ite aMatch := false bMatch := false - for _, e := range c.Consume { + for _, e := range c.Ingredients { for _, id := range e.Items { if id == itemAID { aMatch = true diff --git a/internal/game/cmd_smelt.go b/internal/game/cmd_smelt.go index 59e52db..b551e76 100644 --- a/internal/game/cmd_smelt.go +++ b/internal/game/cmd_smelt.go @@ -23,7 +23,7 @@ func (g *Game) doSmelt(sess *net.Session, input string) { return } - items := g.CraftIndex.ByType("smelting") + items := g.CraftIndex.BySubtype("smelt") if input == "" { g.showSmeltMenu(sess, p, items, stationDefID, stationName) diff --git a/internal/game/cmd_smith.go b/internal/game/cmd_smith.go index 9722896..4330b1d 100644 --- a/internal/game/cmd_smith.go +++ b/internal/game/cmd_smith.go @@ -118,7 +118,7 @@ func hasSmithingItems(items []*item.ItemDef, barID string) bool { func findSmithableBars(items []*item.ItemDef, p *player.Player) []string { barSet := make(map[string]bool) for _, item := range items { - for _, e := range item.FirstCraft().Consume { + for _, e := range item.FirstCraft().Ingredients { for _, id := range e.Items { if p.HasItem(id) { barSet[id] = true diff --git a/internal/game/cmd_stats.go b/internal/game/cmd_stats.go index ef5e2ba..0430c6e 100644 --- a/internal/game/cmd_stats.go +++ b/internal/game/cmd_stats.go @@ -19,18 +19,18 @@ func (g *Game) doStats(sess *net.Session) { attackType := "crush" weaponName := "unarmed" - var weaponType item.WeaponType + var weaponType item.EquipmentType var weaponDef *item.ItemDef if itemID, ok := p.Equipment[item.SlotMainHand]; ok { if def, err := g.ItemStore.Load(itemID); err == nil { weaponDef = def weaponName = def.Name - weaponType = def.WeaponType - if def.AttackType != "" { - attackType = def.AttackType - } else if def.WeaponType == item.WeaponRanged { + weaponType = def.EquipmentType() + if def.AttackType() != "" { + attackType = def.AttackType() + } else if def.EquipmentType() == item.EquipRangedWeapon { attackType = "ranged" - } else if def.WeaponType == item.WeaponScience { + } else if def.EquipmentType() == item.EquipScienceWeapon { attackType = "science" } } @@ -58,7 +58,7 @@ func (g *Game) doStats(sess *net.Session) { ) var attRoll, maxHitVal int - if weaponType == item.WeaponRanged { + if weaponType == item.EquipRangedWeapon { rangedBonus, _ := combat.RangedStyleBonus(string(p.AttackStyle)) attRoll = combat.EffectiveRoll(p.Level(player.Ranged), rangedBonus, totals.RangedAttack) maxHitVal = combat.MaxHit(p.Level(player.Ranged), rangedBonus, totals.RangedStrength) diff --git a/internal/game/cmd_trigger_utility.go b/internal/game/cmd_trigger_utility.go index 0dae505..1697417 100644 --- a/internal/game/cmd_trigger_utility.go +++ b/internal/game/cmd_trigger_utility.go @@ -170,7 +170,7 @@ func (g *Game) triggerSuperheat(sess *net.Session, p *player.Player, mod *ModDef } var match *item.ItemDef - for _, item := range g.CraftIndex.ByType("smelting") { + for _, item := range g.CraftIndex.BySubtype("smelt") { if craftMatchesEntry(item.FirstCraft(), inv.ItemID) { match = item break @@ -182,12 +182,12 @@ func (g *Game) triggerSuperheat(sess *net.Session, p *player.Player, mod *ModDef } c := match.FirstCraft() - if c.Level > 0 && p.Level(player.SkillName(c.Skill)) < c.Level { - sess.WriteLine(fmt.Sprintf("You need level %d %s to smelt that.", c.Level, c.Skill)) + if c.Level > 0 && p.Level(player.SkillName(c.Type)) < c.Level { + sess.WriteLine(fmt.Sprintf("You need level %d %s to smelt that.", c.Level, c.Type)) return } - for _, e := range c.Consume { + for _, e := range c.Ingredients { for _, itemID := range e.Items { qty := e.Quantity if qty <= 0 { @@ -209,7 +209,7 @@ func (g *Game) triggerSuperheat(sess *net.Session, p *player.Player, mod *ModDef g.cancelAction(p) } - craftConsumeAll(c, p.HasItem, p.RemoveItem) + consumeIngredients(c, p.HasItem, p.RemoveItem) outputQty := c.OutputQty if outputQty <= 0 { diff --git a/internal/game/cmd_use.go b/internal/game/cmd_use.go index d399e8f..033fd62 100644 --- a/internal/game/cmd_use.go +++ b/internal/game/cmd_use.go @@ -137,6 +137,19 @@ func (g *Game) stationRecipes(p *player.Player, stationDefID string) []*item.Ite return results } +func craftLabel(c *item.CraftDef) string { + if c == nil { + return "" + } + if c.Subtype != "" { + return c.Subtype + } + if c.Type != "" { + return c.Type + } + return "combine" +} + func (g *Game) showRecipeMenu(sess *net.Session, p *player.Player, items []*item.ItemDef, stationName string) { if len(items) == 0 { sess.WriteLine(fmt.Sprintf("You don't have anything you can make at the %s.", stationName)) @@ -149,7 +162,7 @@ func (g *Game) showRecipeMenu(sess *net.Session, p *player.Player, items []*item needTypes := false for i := range items { for j := i + 1; j < len(items); j++ { - if len(items[i].Craft) > 0 && len(items[j].Craft) > 0 && items[i].FirstCraft().Type != items[j].FirstCraft().Type { + if craftLabel(items[i].FirstCraft()) != craftLabel(items[j].FirstCraft()) { needTypes = true break } @@ -163,14 +176,8 @@ func (g *Game) showRecipeMenu(sess *net.Session, p *player.Player, items []*item sess.State = net.StateRecipeChoice var names []string for _, item := range items { - cType := "" - if len(item.Craft) > 0 { - cType = item.FirstCraft().Type - } - if cType == "" { - cType = "combine" - } - typeLabel := strings.ToUpper(cType[:1]) + cType[1:] + label := craftLabel(item.FirstCraft()) + typeLabel := strings.ToUpper(label[:1]) + label[1:] if needTypes { names = append(names, fmt.Sprintf("%s (%s)", g.itemName(sess, item), typeLabel)) } else { @@ -209,15 +216,15 @@ func (g *Game) doUseItemOnTarget(sess *net.Session, p *player.Player, itemAName, recipes := g.CraftIndex.FindByStationInput(def.ID, itemAID) if len(recipes) > 0 { - cType := "" + var firstSubtype string if len(recipes[0].Craft) > 0 { - cType = recipes[0].FirstCraft().Type + firstSubtype = recipes[0].FirstCraft().Subtype } - if cType == "smelting" { + if firstSubtype == "smelt" { var filtered []*item.ItemDef for _, item := range recipes { c := item.FirstCraft() - if c.Type != "smelting" { + if c.Subtype != "smelt" { continue } if !craftHasAllItemsQty(c, p.CountItem) { @@ -246,6 +253,10 @@ func (g *Game) doUseItemOnTarget(sess *net.Session, p *player.Player, itemAName, g.showMenuTable(sess, "What would you like to smelt?", names) return } + var cType string + if len(recipes[0].Craft) > 0 { + cType = recipes[0].FirstCraft().Type + } if cType == "smithing" { if !g.hasToolType(p, "hammer") { sess.WriteLine("You need a hammer to smith.") @@ -396,9 +407,9 @@ func (g *Game) doUseItemOnTarget(sess *net.Session, p *player.Player, itemAName, } func (g *Game) isGrimyHerb(itemID string) bool { - items := g.CraftIndex.ByType("clean") + items := g.CraftIndex.BySubtype("clean") for _, item := range items { - for _, e := range item.FirstCraft().Consume { + for _, e := range item.FirstCraft().Ingredients { for _, id := range e.Items { if id == itemID { return true diff --git a/internal/game/cmd_verbs.go b/internal/game/cmd_verbs.go index 70b2fb2..cad90c5 100644 --- a/internal/game/cmd_verbs.go +++ b/internal/game/cmd_verbs.go @@ -90,12 +90,17 @@ func (g *Game) executeVerbs(sess *net.Session, args []string, rawInput string) { if len(recipes) > 0 { addUnique(§ionObjs, &seen, "use "+name) for _, r := range recipes { - if info, ok := productionTypes[r.FirstCraft().Type]; ok { + c := r.FirstCraft() + key := c.Subtype + if key == "" { + key = c.Type + } + if info, ok := productionTypes[key]; ok { if info.ActionType != behavior.TypeCombine && info.ActionType != behavior.TypeFletch && info.ActionType != behavior.TypeMix { addUnique(§ionObjs, &seen, string(info.ActionType)) } } - for _, c := range r.FirstCraft().Consume { + for _, c := range r.FirstCraft().Ingredients { for _, itemID := range c.Items { if itemDef, err := g.ItemStore.Load(itemID); err == nil { addUnique(§ionObjs, &seen, "use "+itemDef.Name+" on "+name) diff --git a/internal/game/cmd_wear.go b/internal/game/cmd_wear.go index 64069bc..c52321c 100644 --- a/internal/game/cmd_wear.go +++ b/internal/game/cmd_wear.go @@ -75,7 +75,7 @@ func (g *Game) doWear(sess *net.Session, input string) { } def, err := g.ItemStore.Load(slot.ItemID) - if err != nil || def.EquipSlot == "" { + if err != nil || def.EquipSlot() == "" { sess.WriteLine(fmt.Sprintf("You can't wear %s.", g.itemColorize(sess, def, match.Name))) return } @@ -85,12 +85,12 @@ func (g *Game) doWear(sess *net.Session, input string) { return } - if def.EquipSlot == item.SlotAmmo && def.Stackable { + if def.EquipSlot() == item.SlotAmmo && def.Stackable { g.equipAmmo(sess, p, match.Slot, slot, def, qty) return } - existingItemID, slotOccupied := p.Equipment[def.EquipSlot] + existingItemID, slotOccupied := p.Equipment[def.EquipSlot()] if slotOccupied { freeSlot := p.FirstFreeSlot() @@ -116,11 +116,11 @@ func (g *Game) doWear(sess *net.Session, input string) { p.EquipQuality[slot.ItemID] = slot.Quality } - p.Equipment[def.EquipSlot] = slot.ItemID + p.Equipment[def.EquipSlot()] = slot.ItemID g.AccountStore.SaveCharacter(p) verb := "wear" - if def.WeaponType != "" { + if def.EquipmentType() != "" { verb = "wield" } sess.WriteLine(fmt.Sprintf("You %s %s.", verb, g.itemColorize(sess, def, match.Name))) @@ -193,19 +193,19 @@ func (g *Game) doWearAll(sess *net.Session) { continue } def, err := g.ItemStore.Load(slot.ItemID) - if err != nil || def.EquipSlot == "" { + if err != nil || def.EquipSlot() == "" { continue } if g.checkRequirements(sess, p, def) != "" { continue } - current, exists := bestPerSlot[def.EquipSlot] + current, exists := bestPerSlot[def.EquipSlot()] val := def.Value - if def.EquipSlot == item.SlotAmmo && def.Stackable { + if def.EquipSlot() == item.SlotAmmo && def.Stackable { val = def.Value * slot.Quantity } if !exists || val > current.value { - bestPerSlot[def.EquipSlot] = struct { + bestPerSlot[def.EquipSlot()] = struct { itemID string value int invSlot int diff --git a/internal/game/combat_attack.go b/internal/game/combat_attack.go index bae210b..ddc3b8f 100644 --- a/internal/game/combat_attack.go +++ b/internal/game/combat_attack.go @@ -59,7 +59,7 @@ func (g *Game) doAttack(sess *net.Session, input string) { } if itemID, ok := p.Equipment[item.SlotMainHand]; ok { - if def, err := g.ItemStore.Load(itemID); err == nil && def.WeaponType == item.WeaponRanged { + if def, err := g.ItemStore.Load(itemID); err == nil && def.EquipmentType() == item.EquipRangedWeapon { if _, hasAmmo := p.Equipment[item.SlotAmmo]; !hasAmmo || p.AmmoQty <= 0 { sess.WriteLine("You don't have any ammo equipped.") return @@ -289,23 +289,23 @@ func (g *Game) playerAttack(sess *net.Session, p *player.Player, mob *world.MobI } } -func (g *Game) calculatePlayerAttackRoll(p *player.Player, mob *world.MobInstance) (attackType string, weaponType item.WeaponType, attRoll int, defRoll int, maxHit int) { +func (g *Game) calculatePlayerAttackRoll(p *player.Player, mob *world.MobInstance) (attackType string, weaponType item.EquipmentType, attRoll int, defRoll int, maxHit int) { attackType = "crush" if itemID, ok := p.Equipment[item.SlotMainHand]; ok { if def, err := g.ItemStore.Load(itemID); err == nil { - if def.AttackType != "" { - attackType = def.AttackType - } else if def.WeaponType == item.WeaponRanged { + if def.AttackType() != "" { + attackType = def.AttackType() + } else if def.EquipmentType() == item.EquipRangedWeapon { attackType = "ranged" - } else if def.WeaponType == item.WeaponScience { + } else if def.EquipmentType() == item.EquipScienceWeapon { attackType = "science" } - weaponType = def.WeaponType + weaponType = def.EquipmentType() } } totals := g.playerEquipBonuses(p) - isRanged := weaponType == item.WeaponRanged + isRanged := weaponType == item.EquipRangedWeapon if isRanged { rangedBonus, _ := combat.RangedStyleBonus(string(p.AttackStyle)) @@ -343,15 +343,15 @@ func (g *Game) playerAttackUnarmed(sess *net.Session, p *player.Player, mob *wor attackType, _, attRoll, defRoll, maxHit := g.calculateUnarmedAttackRoll(p, mob) if combat.HitCheck(attRoll, defRoll) { - g.applyPlayerHit(sess, p, mob, attackType, item.WeaponMelee, maxHit) + g.applyPlayerHit(sess, p, mob, attackType, item.EquipMeleeWeapon, maxHit) } else { - g.applyPlayerMiss(sess, p, mob, item.WeaponMelee) + g.applyPlayerMiss(sess, p, mob, item.EquipMeleeWeapon) } } -func (g *Game) calculateUnarmedAttackRoll(p *player.Player, mob *world.MobInstance) (attackType string, weaponType item.WeaponType, attRoll int, defRoll int, maxHit int) { +func (g *Game) calculateUnarmedAttackRoll(p *player.Player, mob *world.MobInstance) (attackType string, weaponType item.EquipmentType, attRoll int, defRoll int, maxHit int) { attackType = "crush" - weaponType = item.WeaponMelee + weaponType = item.EquipMeleeWeapon attBonus, strBonus, _ := combat.AttackStyleBonus(string(p.AttackStyle)) effectiveAccuracy := p.Level(player.Accuracy) + g.techLevelBonus(p, "accuracy") + g.buffLevelBonus(p, "accuracy") @@ -365,7 +365,7 @@ func (g *Game) calculateUnarmedAttackRoll(p *player.Player, mob *world.MobInstan return } -func (g *Game) applyPlayerHit(sess *net.Session, p *player.Player, mob *world.MobInstance, attackType string, weaponType item.WeaponType, maxHit int) { +func (g *Game) applyPlayerHit(sess *net.Session, p *player.Player, mob *world.MobInstance, attackType string, weaponType item.EquipmentType, maxHit int) { dmg := combat.RollDamage(maxHit) mob.HP -= dmg @@ -390,7 +390,7 @@ func (g *Game) applyPlayerHit(sess *net.Session, p *player.Player, mob *world.Mo mobDisplayName(mob, false), fbName))) } - isRanged := weaponType == item.WeaponRanged + isRanged := weaponType == item.EquipRangedWeapon gains := g.awardCombatXP(sess, p, dmg, isRanged) if isRanged { @@ -425,10 +425,10 @@ func (g *Game) applyPlayerHit(sess *net.Session, p *player.Player, mob *world.Mo } } -func (g *Game) applyPlayerMiss(sess *net.Session, p *player.Player, mob *world.MobInstance, weaponType item.WeaponType) { +func (g *Game) applyPlayerMiss(sess *net.Session, p *player.Player, mob *world.MobInstance, weaponType item.EquipmentType) { sess.WriteLine(g.colorize(sess, "miss", fmt.Sprintf("You miss %s.", mobDisplayName(mob, true)))) - if weaponType == item.WeaponRanged { + if weaponType == item.EquipRangedWeapon { g.consumeAmmo(sess, p) if p.AmmoQty <= 0 { sess.WriteLine("You've run out of ammo!") diff --git a/internal/game/core_equip.go b/internal/game/core_equip.go index cc8016d..a297466 100644 --- a/internal/game/core_equip.go +++ b/internal/game/core_equip.go @@ -12,20 +12,20 @@ func (g *Game) playerEquipBonuses(p *player.Player) item.ItemStats { if err != nil { continue } - totals.StabAttack += def.Stats.StabAttack - totals.SlashAttack += def.Stats.SlashAttack - totals.CrushAttack += def.Stats.CrushAttack - totals.ScienceAttack += def.Stats.ScienceAttack - totals.RangedAttack += def.Stats.RangedAttack - totals.StabDefense += def.Stats.StabDefense - totals.SlashDefense += def.Stats.SlashDefense - totals.CrushDefense += def.Stats.CrushDefense - totals.ScienceDefense += def.Stats.ScienceDefense - totals.RangedDefense += def.Stats.RangedDefense - totals.StrengthBonus += def.Stats.StrengthBonus - totals.RangedStrength += def.Stats.RangedStrength - totals.ScienceDamage += def.Stats.ScienceDamage - totals.TechnologyBonus += def.Stats.TechnologyBonus + totals.StabAttack += def.Stats().StabAttack + totals.SlashAttack += def.Stats().SlashAttack + totals.CrushAttack += def.Stats().CrushAttack + totals.ScienceAttack += def.Stats().ScienceAttack + totals.RangedAttack += def.Stats().RangedAttack + totals.StabDefense += def.Stats().StabDefense + totals.SlashDefense += def.Stats().SlashDefense + totals.CrushDefense += def.Stats().CrushDefense + totals.ScienceDefense += def.Stats().ScienceDefense + totals.RangedDefense += def.Stats().RangedDefense + totals.StrengthBonus += def.Stats().StrengthBonus + totals.RangedStrength += def.Stats().RangedStrength + totals.ScienceDamage += def.Stats().ScienceDamage + totals.TechnologyBonus += def.Stats().TechnologyBonus } return totals } @@ -33,8 +33,8 @@ func (g *Game) playerEquipBonuses(p *player.Player) item.ItemStats { func (g *Game) playerWeaponSpeed(p *player.Player) float64 { if itemID, ok := p.Equipment[item.SlotMainHand]; ok { def, err := g.ItemStore.Load(itemID) - if err == nil && def.Speed > 0 { - return def.Speed + if err == nil && def.Speed()> 0 { + return def.Speed() } } return 5.0 diff --git a/internal/game/core_production.go b/internal/game/core_production.go index 8a38f36..da9466f 100644 --- a/internal/game/core_production.go +++ b/internal/game/core_production.go @@ -11,8 +11,8 @@ func (g *Game) findTool(p *player.Player, toolTypes []string) (toolSpeed float64 if itemID, ok := p.Equipment[item.SlotMainHand]; ok { if def, err := g.ItemStore.Load(itemID); err == nil { for _, t := range toolTypes { - if def.ToolType == t { - return def.ToolSpeed, def.Name, true + if def.ToolType() == t { + return def.ToolSpeed(), def.Name, true } } } @@ -27,8 +27,8 @@ func (g *Game) findTool(p *player.Player, toolTypes []string) (toolSpeed float64 continue } for _, t := range toolTypes { - if def.ToolType == t { - return def.ToolSpeed, def.Name, true + if def.ToolType() == t { + return def.ToolSpeed(), def.Name, true } } } @@ -58,7 +58,7 @@ var productionTypes = map[string]productionTypeInfo{ EndMessage: "You've finished cooking.", FailMessage: "You accidentally burn the %i1.", }, - "smelting": { + "smelt": { ActionType: behavior.TypeSmelt, DisplayVerb: "smelting", StartMessage: "You place the %i1 into the furnace.", diff --git a/internal/game/look_target.go b/internal/game/look_target.go index 915e4a7..a93d969 100644 --- a/internal/game/look_target.go +++ b/internal/game/look_target.go @@ -311,7 +311,7 @@ func showPlayerInfo(g *Game, sess *net.Session, p *player.Player) { } func (g *Game) showItemStats(sess *net.Session, def *item.ItemDef) { - s := def.Stats + s := def.Stats() hasAttack := s.StabAttack != 0 || s.SlashAttack != 0 || s.CrushAttack != 0 || s.ScienceAttack != 0 || s.RangedAttack != 0 hasDefense := s.StabDefense != 0 || s.SlashDefense != 0 || s.CrushDefense != 0 || @@ -348,11 +348,11 @@ func (g *Game) showItemStats(sess *net.Session, def *item.ItemDef) { sess.WriteLine(fmt.Sprintf(" Technology: %+d", s.TechnologyBonus)) } } - if def.AttackType != "" { - sess.WriteLine(fmt.Sprintf("Attack type: %s", def.AttackType)) + if def.AttackType() != "" { + sess.WriteLine(fmt.Sprintf("Attack type: %s", def.AttackType())) } - if def.Speed > 0 { - sess.WriteLine(fmt.Sprintf("Speed: %.0f", def.Speed)) + if def.Speed()> 0 { + sess.WriteLine(fmt.Sprintf("Speed: %.0f", def.Speed())) } if len(def.Requirements) > 0 { sess.WriteLine("") diff --git a/internal/game/production_engine.go b/internal/game/production_engine.go index c30e7bb..048e152 100644 --- a/internal/game/production_engine.go +++ b/internal/game/production_engine.go @@ -25,7 +25,7 @@ func (g *Game) resolveCraftVar(sess *net.Session, varSpec string, craft *item.Cr } varSpec = strings.ReplaceAll(varSpec, "%n", outputName) - for i, e := range craft.Consume { + for i, e := range craft.Ingredients { key := fmt.Sprintf("%%i%d", i+1) if !strings.Contains(varSpec, key) { continue @@ -134,14 +134,19 @@ func (g *Game) startProductionFromItem(sess *net.Session, p *player.Player, item stationName = "inventory" } - info, ok := productionTypes[craft.Type] + cKey := craft.Subtype + if cKey == "" { + cKey = craft.Type + } + + info, ok := productionTypes[cKey] if !ok { info = productionTypeInfo{ - ActionType: behavior.ActionType(craft.Type), - DisplayVerb: craft.Type, - StartMessage: "You start " + craft.Type + " %i1.", + ActionType: behavior.ActionType(cKey), + DisplayVerb: cKey, + StartMessage: "You start " + cKey + " %i1.", SuccessMessage: "You produce %n.", - EndMessage: "You've finished " + craft.Type + ".", + EndMessage: "You've finished " + cKey + ".", } } @@ -215,7 +220,12 @@ func (g *Game) advanceProduction(sess *net.Session, p *player.Player) bool { chance = behavior.SuccessChance(behavior.SuccessFormula(*craft.Success), skillLevel, craft.Level) } - info, _ := productionTypes[craft.Type] + cKey := craft.Subtype + if cKey == "" { + cKey = craft.Type + } + + info, _ := productionTypes[cKey] if rand.Float64() < chance { outputQty := craft.OutputQty @@ -231,7 +241,7 @@ func (g *Game) advanceProduction(sess *net.Session, p *player.Player) bool { for i := 0; i < 28; i++ { slot := p.InvSlot(i) if slot != nil && slot.ItemID == item.ID { - craftConsumeAll(craft, p.HasItem, p.RemoveItem) + consumeIngredients(craft, p.HasItem, p.RemoveItem) slot.Quantity += outputQty placed = true break @@ -239,7 +249,7 @@ func (g *Game) advanceProduction(sess *net.Session, p *player.Player) bool { } } if !placed { - craftConsumeAll(craft, p.HasItem, p.RemoveItem) + consumeIngredients(craft, p.HasItem, p.RemoveItem) freeSlot := p.FirstFreeSlot() if freeSlot == -1 { sess.WriteLine("Your inventory is too full!") @@ -274,7 +284,7 @@ func (g *Game) advanceProduction(sess *net.Session, p *player.Player) bool { } sess.WriteLine(msg) } else { - craftConsumeAll(craft, p.HasItem, p.RemoveItem) + consumeIngredients(craft, p.HasItem, p.RemoveItem) if craft.Fail != "" { freeSlot := p.FirstFreeSlot() @@ -320,7 +330,7 @@ func (g *Game) collectByproducts(p *player.Player, item *item.ItemDef) []string return nil } var byproducts []string - for _, e := range craft.Consume { + for _, e := range craft.Ingredients { if len(e.Byproducts) == 0 { continue } diff --git a/internal/game/production_index.go b/internal/game/production_index.go index 648ccc8..77fc08a 100644 --- a/internal/game/production_index.go +++ b/internal/game/production_index.go @@ -9,6 +9,7 @@ import ( type CraftIndex struct { mu sync.RWMutex byType map[string][]*item.ItemDef + bySubtype map[string][]*item.ItemDef byInput map[string][]*item.ItemDef byStation map[string][]*item.ItemDef } @@ -16,6 +17,7 @@ type CraftIndex struct { func NewCraftIndex() *CraftIndex { return &CraftIndex{ byType: make(map[string][]*item.ItemDef), + bySubtype: make(map[string][]*item.ItemDef), byInput: make(map[string][]*item.ItemDef), byStation: make(map[string][]*item.ItemDef), } @@ -26,6 +28,7 @@ func (idx *CraftIndex) Build(items []*item.ItemDef) { defer idx.mu.Unlock() idx.byType = make(map[string][]*item.ItemDef) + idx.bySubtype = make(map[string][]*item.ItemDef) idx.byInput = make(map[string][]*item.ItemDef) idx.byStation = make(map[string][]*item.ItemDef) @@ -41,7 +44,11 @@ func (idx *CraftIndex) Build(items []*item.ItemDef) { } idx.byType[t] = appendUnique(idx.byType[t], def) - for _, e := range craft.Consume { + if craft.Subtype != "" { + idx.bySubtype[craft.Subtype] = appendUnique(idx.bySubtype[craft.Subtype], def) + } + + for _, e := range craft.Ingredients { for _, id := range e.Items { idx.byInput[id] = appendUnique(idx.byInput[id], def) } @@ -72,6 +79,15 @@ func (idx *CraftIndex) ByType(craftType string) []*item.ItemDef { return out } +func (idx *CraftIndex) BySubtype(subtype string) []*item.ItemDef { + idx.mu.RLock() + defer idx.mu.RUnlock() + items := idx.bySubtype[subtype] + out := make([]*item.ItemDef, len(items)) + copy(out, items) + return out +} + func (idx *CraftIndex) ByStation(stationDefID string) []*item.ItemDef { idx.mu.RLock() defer idx.mu.RUnlock() @@ -147,7 +163,7 @@ func craftEntryFor(def *item.ItemDef, itemID string) int { } func craftEntry(craft item.CraftDef, itemID string) int { - for ei, e := range craft.Consume { + for ei, e := range craft.Ingredients { for _, id := range e.Items { if id == itemID { return ei @@ -161,7 +177,7 @@ func craftMatchesEntry(c *item.CraftDef, itemID string) bool { if c == nil { return false } - for _, e := range c.Consume { + for _, e := range c.Ingredients { for _, id := range e.Items { if id == itemID { return true @@ -175,7 +191,7 @@ func craftHasAllItems(c *item.CraftDef, hasItem func(string) bool) bool { if c == nil { return false } - for _, e := range c.Consume { + for _, e := range c.Ingredients { found := false for _, id := range e.Items { if hasItem(id) { @@ -194,7 +210,7 @@ func craftHasAllItemsQty(c *item.CraftDef, countItem func(string) int) bool { if c == nil { return false } - for _, e := range c.Consume { + for _, e := range c.Ingredients { found := false for _, id := range e.Items { qty := e.Quantity @@ -213,11 +229,11 @@ func craftHasAllItemsQty(c *item.CraftDef, countItem func(string) int) bool { return true } -func craftConsumeAll(c *item.CraftDef, hasItem func(string) bool, removeItem func(string, int) bool) bool { +func consumeIngredients(c *item.CraftDef, hasItem func(string) bool, removeItem func(string, int) bool) bool { if c == nil { return false } - for _, e := range c.Consume { + for _, e := range c.Ingredients { found := false for _, id := range e.Items { if hasItem(id) { diff --git a/internal/game/production_menu.go b/internal/game/production_menu.go index bc2fccc..ff9fc51 100644 --- a/internal/game/production_menu.go +++ b/internal/game/production_menu.go @@ -106,7 +106,7 @@ func (g *Game) formatMaterials(sess *net.Session, item *item.ItemDef) string { return "" } var parts []string - for _, e := range craft.Consume { + for _, e := range craft.Ingredients { itemName := e.Items[0] if def, err := g.ItemStore.Load(e.Items[0]); err == nil { itemName = g.itemColorize(sess, def, def.Name) diff --git a/internal/game/sys_science.go b/internal/game/sys_science.go index b04072f..bded8c4 100644 --- a/internal/game/sys_science.go +++ b/internal/game/sys_science.go @@ -182,7 +182,7 @@ func (g *Game) hasDeckEquipped(p *player.Player) bool { if err != nil { return false } - return def.WeaponType == item.WeaponScience + return def.EquipmentType() == item.EquipScienceWeapon } func (g *Game) providesJunk(p *player.Player) string { @@ -194,7 +194,7 @@ func (g *Game) providesJunk(p *player.Player) string { if err != nil { return "" } - return def.ProvidesJunk + return def.ProvidesJunk() } func (g *Game) effectiveJunkCost(p *player.Player, mod *ModDef) map[string]int { @@ -296,7 +296,7 @@ func (g *Game) totalScienceAttack(p *player.Player) int { for _, itemID := range p.Equipment { def, err := g.ItemStore.Load(itemID) if err == nil { - total += def.Stats.ScienceAttack + total += def.Stats().ScienceAttack } } return total diff --git a/internal/game/sys_technology.go b/internal/game/sys_technology.go index 7df68d4..9e6a635 100644 --- a/internal/game/sys_technology.go +++ b/internal/game/sys_technology.go @@ -128,7 +128,7 @@ func (g *Game) totalTechBonus(p *player.Player) int { for _, itemID := range p.Equipment { def, err := g.ItemStore.Load(itemID) if err == nil { - total += def.Stats.TechnologyBonus + total += def.Stats().TechnologyBonus } } return total diff --git a/internal/item/item.go b/internal/item/item.go index 890fa8d..0e63156 100644 --- a/internal/item/item.go +++ b/internal/item/item.go @@ -24,54 +24,195 @@ const ( SlotRing EquipSlot = "ring" ) -type WeaponType string +type EquipmentType string const ( - WeaponMelee WeaponType = "melee" - WeaponRanged WeaponType = "ranged" - WeaponScience WeaponType = "science" + EquipMeleeWeapon EquipmentType = "melee_weapon" + EquipRangedWeapon EquipmentType = "ranged_weapon" + EquipScienceWeapon EquipmentType = "tech_weapon" + EquipArmor EquipmentType = "armor" + EquipTool EquipmentType = "tool" + EquipAmmo EquipmentType = "ammo" ) +func (et EquipmentType) IsWeapon() bool { + return et == EquipMeleeWeapon || et == EquipRangedWeapon || et == EquipScienceWeapon +} + +type AttackBonuses struct { + Stab int `yaml:"stab,omitempty"` + Slash int `yaml:"slash,omitempty"` + Crush int `yaml:"crush,omitempty"` + Ranged int `yaml:"ranged,omitempty"` + Science int `yaml:"science,omitempty"` +} + +type DefenseBonuses struct { + Stab int `yaml:"stab,omitempty"` + Slash int `yaml:"slash,omitempty"` + Crush int `yaml:"crush,omitempty"` + Ranged int `yaml:"ranged,omitempty"` + Science int `yaml:"science,omitempty"` +} + +type OtherBonuses struct { + Strength int `yaml:"strength,omitempty"` + Ranged int `yaml:"ranged,omitempty"` + Science int `yaml:"science,omitempty"` + Technology int `yaml:"technology,omitempty"` +} + +type EquipmentDef struct { + Type EquipmentType `yaml:"type"` + Slot EquipSlot `yaml:"slot,omitempty"` + AttackType string `yaml:"attack_type,omitempty"` + Speed float64 `yaml:"speed,omitempty"` + Junk string `yaml:"junk,omitempty"` + Attack *AttackBonuses `yaml:"attack,omitempty"` + Defense *DefenseBonuses `yaml:"defense,omitempty"` + Other *OtherBonuses `yaml:"other,omitempty"` +} + +type ToolDef struct { + Type string `yaml:"type"` + Speed float64 `yaml:"speed,omitempty"` +} + type ItemDef struct { - ID string `yaml:"id"` - Name string `yaml:"name"` - Color string `yaml:"color"` - Description string `yaml:"description"` - Value int `yaml:"value"` - Stackable bool `yaml:"stackable"` - EquipSlot EquipSlot `yaml:"equip_slot"` - WeaponType WeaponType `yaml:"weapon_type"` - AttackType string `yaml:"attack_type"` - Stats ItemStats `yaml:"stats"` - Speed float64 `yaml:"speed"` - Requirements map[string]int `yaml:"requirements,omitempty"` - ToolType string `yaml:"tool_type"` - ToolSpeed float64 `yaml:"tool_speed"` - BurnTicks float64 `yaml:"burn_ticks"` - FireLevel int `yaml:"fire_level"` - FireXP int `yaml:"fire_xp"` - Quality int `yaml:"quality"` - MaxQuality int `yaml:"max_quality"` - SearchTable string `yaml:"search_table"` - SearchMiscTable string `yaml:"search_misc_table"` - SearchTicks float64 `yaml:"search_ticks"` - SearchMessage string `yaml:"search_message"` - HealValue int `yaml:"heal_value"` - EatMessage string `yaml:"eat_message"` - Craft CraftList `yaml:"craft,omitempty"` - ProvidesJunk string `yaml:"provides_junk,omitempty"` - FarmPatchType string `yaml:"farm_patch_type"` - FarmLevel int `yaml:"farm_level"` - FarmPlantXP int `yaml:"farm_plant_xp"` - FarmHarvestXP int `yaml:"farm_harvest_xp"` - FarmStages int `yaml:"farm_stages"` - FarmProduct string `yaml:"farm_product"` - FarmMinYield int `yaml:"farm_min_yield"` - FarmMaxYield int `yaml:"farm_max_yield"` - PotionEffect string `yaml:"potion_effect"` - PotionBonus int `yaml:"potion_bonus"` - PotionDuration float64 `yaml:"potion_duration"` - Recoverable bool `yaml:"recoverable"` + ID string `yaml:"id"` + Name string `yaml:"name"` + Color string `yaml:"color"` + Description string `yaml:"description"` + Value int `yaml:"value"` + Stackable bool `yaml:"stackable"` + Recoverable bool `yaml:"recoverable"` + + Equipment *EquipmentDef `yaml:"equipment,omitempty"` + Tool *ToolDef `yaml:"tool,omitempty"` + Requirements map[string]int `yaml:"requirements,omitempty"` + + Quality int `yaml:"quality"` + MaxQuality int `yaml:"max_quality"` + Craft CraftList `yaml:"craft,omitempty"` + + SearchTable string `yaml:"search_table"` + SearchTicks float64 `yaml:"search_ticks"` + SearchMessage string `yaml:"search_message"` + + HealValue int `yaml:"heal_value"` + EatMessage string `yaml:"eat_message"` + + FarmPatchType string `yaml:"farm_patch_type"` + FarmLevel int `yaml:"farm_level"` + FarmPlantXP int `yaml:"farm_plant_xp"` + FarmHarvestXP int `yaml:"farm_harvest_xp"` + FarmStages int `yaml:"farm_stages"` + FarmProduct string `yaml:"farm_product"` + FarmMinYield int `yaml:"farm_min_yield"` + FarmMaxYield int `yaml:"farm_max_yield"` + + PotionEffect string `yaml:"potion_effect"` + PotionBonus int `yaml:"potion_bonus"` + PotionDuration float64 `yaml:"potion_duration"` + + BurnTicks float64 `yaml:"burn_ticks"` + FireLevel int `yaml:"fire_level"` + FireXP int `yaml:"fire_xp"` +} + +func (d *ItemDef) EquipmentType() EquipmentType { + if d.Equipment != nil { + return d.Equipment.Type + } + return "" +} + +func (d *ItemDef) EquipSlot() EquipSlot { + if d.Equipment != nil { + return d.Equipment.Slot + } + return "" +} + +func (d *ItemDef) Speed() float64 { + if d.Equipment != nil { + return d.Equipment.Speed + } + return 0 +} + +func (d *ItemDef) AttackType() string { + if d.Equipment != nil { + return d.Equipment.AttackType + } + return "" +} + +func (d *ItemDef) ToolType() string { + if d.Tool != nil { + return d.Tool.Type + } + return "" +} + +func (d *ItemDef) ToolSpeed() float64 { + if d.Tool != nil { + return d.Tool.Speed + } + return 0 +} + +func (d *ItemDef) ProvidesJunk() string { + if d.Equipment != nil { + return d.Equipment.Junk + } + return "" +} + +type ItemStats struct { + StabAttack int + SlashAttack int + CrushAttack int + ScienceAttack int + RangedAttack int + + StabDefense int + SlashDefense int + CrushDefense int + ScienceDefense int + RangedDefense int + + StrengthBonus int + RangedStrength int + ScienceDamage int + TechnologyBonus int +} + +func (d *ItemDef) Stats() ItemStats { + var s ItemStats + if d.Equipment != nil { + if d.Equipment.Attack != nil { + s.StabAttack = d.Equipment.Attack.Stab + s.SlashAttack = d.Equipment.Attack.Slash + s.CrushAttack = d.Equipment.Attack.Crush + s.RangedAttack = d.Equipment.Attack.Ranged + s.ScienceAttack = d.Equipment.Attack.Science + } + if d.Equipment.Defense != nil { + s.StabDefense = d.Equipment.Defense.Stab + s.SlashDefense = d.Equipment.Defense.Slash + s.CrushDefense = d.Equipment.Defense.Crush + s.RangedDefense = d.Equipment.Defense.Ranged + s.ScienceDefense = d.Equipment.Defense.Science + } + if d.Equipment.Other != nil { + s.StrengthBonus = d.Equipment.Other.Strength + s.RangedStrength = d.Equipment.Other.Ranged + s.ScienceDamage = d.Equipment.Other.Science + s.TechnologyBonus = d.Equipment.Other.Technology + } + } + return s } type CraftList []CraftDef @@ -117,7 +258,7 @@ func (d *ItemDef) MatchingCrafts(fn func(CraftDef) bool) []*CraftDef { return result } -type ConsumeEntry struct { +type IngredientEntry struct { Items []string `yaml:"items"` Quantity int `yaml:"quantity"` Byproducts []string `yaml:"byproducts"` @@ -136,13 +277,13 @@ type SuccessFormula struct { type CraftDef struct { Type string `yaml:"type"` - Skill string `yaml:"skill"` + Subtype string `yaml:"subtype,omitempty"` Level int `yaml:"level"` XP int `yaml:"xp"` Wait float64 `yaml:"wait"` Station []string `yaml:"station"` Tool string `yaml:"tool"` - Consume []ConsumeEntry `yaml:"consume"` + Ingredients []IngredientEntry `yaml:"ingredients"` OutputQty int `yaml:"output_qty"` Fail string `yaml:"fail"` Message string `yaml:"message"` @@ -154,31 +295,9 @@ type CraftDef struct { } func (c *CraftDef) EffectiveSkill() string { - if c.Skill != "" { - return c.Skill - } return c.Type } -type ItemStats struct { - StabAttack int `yaml:"stab_attack"` - SlashAttack int `yaml:"slash_attack"` - CrushAttack int `yaml:"crush_attack"` - ScienceAttack int `yaml:"science_attack"` - RangedAttack int `yaml:"ranged_attack"` - - StabDefense int `yaml:"stab_defense"` - SlashDefense int `yaml:"slash_defense"` - CrushDefense int `yaml:"crush_defense"` - ScienceDefense int `yaml:"science_defense"` - RangedDefense int `yaml:"ranged_defense"` - - StrengthBonus int `yaml:"strength_bonus"` - RangedStrength int `yaml:"ranged_strength"` - ScienceDamage int `yaml:"science_damage"` - TechnologyBonus int `yaml:"technology_bonus"` -} - func (d *ItemDef) MatchesName(input string) bool { lower := strings.ToLower(strings.TrimSpace(input)) if lower == "" { diff --git a/internal/validate/checks.go b/internal/validate/checks.go index 50fd9a5..b35a3de 100644 --- a/internal/validate/checks.go +++ b/internal/validate/checks.go @@ -535,15 +535,6 @@ func validateItems(s Source) []Issue { }) } - if def.SearchMiscTable != "" && !dropIDs[def.SearchMiscTable] { - issues = append(issues, Issue{ - Level: "ERROR", - Type: "reference", - Message: fmt.Sprintf("Item %q: search_misc_table %q does not exist", - id, def.SearchMiscTable), - }) - } - if def.FarmProduct != "" && !itemIDs[def.FarmProduct] { issues = append(issues, Issue{ Level: "ERROR", @@ -579,14 +570,19 @@ func validateCraftBlocks(s Source) []Issue { for ci := range item.Craft { c := &item.Craft[ci] - for _, e := range c.Consume { - for _, consumeItem := range e.Items { - if consumeItem != "" && !itemIDs[consumeItem] { + craftLabel := c.Type + if c.Subtype != "" { + craftLabel = c.Type + "/" + c.Subtype + } + + for _, e := range c.Ingredients { + for _, ingredientID := range e.Items { + if ingredientID != "" && !itemIDs[ingredientID] { issues = append(issues, Issue{ Level: "ERROR", Type: "reference", Message: fmt.Sprintf("Item %q (craft: %s): consumes nonexistent item %q", - item.ID, c.Type, consumeItem), + item.ID, craftLabel, ingredientID), }) } } @@ -597,7 +593,7 @@ func validateCraftBlocks(s Source) []Issue { Level: "ERROR", Type: "reference", Message: fmt.Sprintf("Item %q (craft: %s): fail product %q does not exist", - item.ID, c.Type, c.Fail), + item.ID, craftLabel, c.Fail), }) } @@ -607,7 +603,7 @@ func validateCraftBlocks(s Source) []Issue { Level: "ERROR", Type: "reference", Message: fmt.Sprintf("Item %q (craft: %s): station object %q does not exist", - item.ID, c.Type, sid), + item.ID, craftLabel, sid), }) } } |
