aboutsummaryrefslogtreecommitdiff
path: root/worldbuilding_guide
diff options
context:
space:
mode:
authorhistoria <[not public]>2026-06-24 20:58:25 -0400
committerhistoria <[not public]>2026-06-24 20:58:25 -0400
commit9d4b799db4868bcab291b83599ff088763cd4ed6 (patch)
tree252f0fcc779acf35243983d643d6399ee2e0cd0b /worldbuilding_guide
parentd25638d98fe63efdeab570ef77e6a6a97f2d7a60 (diff)
downloadthehouseoficarus-9d4b799db4868bcab291b83599ff088763cd4ed6.tar.gz
feat: new type of non-violent 'combat': work
Diffstat (limited to 'worldbuilding_guide')
-rw-r--r--worldbuilding_guide/bank.md68
-rw-r--r--worldbuilding_guide/behaviors.md402
-rw-r--r--worldbuilding_guide/conditions.md70
-rw-r--r--worldbuilding_guide/construction.md223
-rw-r--r--worldbuilding_guide/courses.md119
-rw-r--r--worldbuilding_guide/doors.md97
-rw-r--r--worldbuilding_guide/drops.md52
-rw-r--r--worldbuilding_guide/hacking.md49
-rw-r--r--worldbuilding_guide/hidden_objects.md40
-rw-r--r--worldbuilding_guide/index.md17
-rw-r--r--worldbuilding_guide/items.md190
-rw-r--r--worldbuilding_guide/mobs.md179
-rw-r--r--worldbuilding_guide/objects.md392
-rw-r--r--worldbuilding_guide/quests.md103
-rw-r--r--worldbuilding_guide/recipes.md277
-rw-r--r--worldbuilding_guide/rooms.md134
-rw-r--r--worldbuilding_guide/search.md15
-rw-r--r--worldbuilding_guide/state.md8
-rw-r--r--worldbuilding_guide/tips.md21
-rw-r--r--worldbuilding_guide/wandering_mobs.md20
-rw-r--r--worldbuilding_guide/wandering_objects.md39
21 files changed, 0 insertions, 2515 deletions
diff --git a/worldbuilding_guide/bank.md b/worldbuilding_guide/bank.md
deleted file mode 100644
index 0a5ec88..0000000
--- a/worldbuilding_guide/bank.md
+++ /dev/null
@@ -1,68 +0,0 @@
-# Bank System
-
-The bank system allows players to store items permanently, freeing up inventory space.
-
-## Objects
-
-### bank_booth
-
-A bank terminal that players can interact with. Has no special behavior — the `bank` command checks for any `bank_booth` object in the room.
-
-```yaml
-id: bank_booth
-name: bank booth
-color: "226"
-description: "..."
-inroom_description: "A bank booth is set into the wall."
-```
-
-To place a bank booth in a room, add it to the room's `objects:` list:
-
-```yaml
-objects:
- - id: bank_booth
-```
-
-## Commands
-
-| Command | Description |
-|---------|-------------|
-| `bank` | Opens bank interface (requires bank booth in room) |
-| `use bank` | Same as `bank` |
-
-### Bank Interface Commands
-
-| Command | Description |
-|---------|-------------|
-| `deposit <item>` | Move item from inventory to bank |
-| `deposit all` | Deposit entire inventory |
-| `withdraw <item>` | Move item from bank to inventory |
-| `browse` / `list` | Show bank contents |
-| `leave` | Exit bank interface |
-
-## Implementation
-
-### Session State
-
-`StateBank` (defined in `internal/net/server.go`) is the session state for the bank interface. Input is routed through `handleBankInput` in `internal/game/cmd_bank.go`.
-
-### Player Storage
-
-Bank items are stored in the `Player.Bank` field (`map[int]*InventorySlot`), saved in character YAML. Bank slots are sequential and reuse freed slots. There is no slot limit.
-
-### Command Dispatch
-
-- `bank` is classified as `ClassActive` in `classifyCommand()`
-- `bank` case in `executeCommand()` calls `doBank(sess)`
-- `doUse()` checks for `"bank"` or `"bank booth"` targets and routes to `doBank()`
-- `doBank()` checks for a `bank_booth` object in the current room
-- `handleBankInput()` dispatches deposit/withdraw/browse/leave commands
-
-### Data Files
-
-| File | Purpose |
-|------|---------|
-| `data/objects/bank_booth.yaml` | Bank booth object definition |
-| `data/help/bank.yaml` | Help topic for the bank system |
-
-Default bank booth locations: Town Square (room 1), Forge (room 12).
diff --git a/worldbuilding_guide/behaviors.md b/worldbuilding_guide/behaviors.md
deleted file mode 100644
index 22e97fe..0000000
--- a/worldbuilding_guide/behaviors.md
+++ /dev/null
@@ -1,402 +0,0 @@
-## Behaviors
-
-Behaviors are **inline configs** placed directly inside object YAML (`gather:`, `talk:`,
-`use:`, `safespot:`) or mob YAML (`talk:`). Each section below shows the keys you can use under each behavior type.
-
-### Gather (mining, fishing, woodcutting)
-
-Mining — per-drop depletion on a rock object:
-```yaml
-id: copper_rock
-name: copper rock
-color: "178"
-gather:
- skill: mining
- level: 1
- xp: 17 # XP awarded per successful gather
- base_wait: 8 # ticks between attempts
- tools: # requires item with matching tool_type
- - pickaxe
- success:
- base: 0.40 # 40% base chance
- per_level: 0.01 # +1% per level above requirement
- cap: 0.95 # 95% max
- gather_message: "You swing your pickaxe at the rock..."
- fail_message: "You chip away but get nothing useful."
- drops:
- - item_id: copper_ore
- weight: 90 # 90% chance when roll succeeds
- depletes: true # rock becomes depleted after this drop
- message: "You manage to mine some {178}copper ore{/}."
- - table: gem_table # reference a shared drop table
- weight: 10
- depletes: false # gem drops don't deplete the rock
- message: "You spot a glint of something valuable!"
- respawn_timer: 50 # ticks until rock respawns
- respawn_broadcast: "A glint of copper catches your eye from some {name}."
-```
-
-Drop messages support inline color tags: `{<0-255>}text{/}`. Use the item's color
-index to match its display color. Gradients also work: `{g:196,82}text{/}`.
-
-Non-depleting gather (fishing on a fishing spot object):
-```yaml
-id: bait_fishing_spot
-name: fishing spot
-gather:
- skill: fishing
- level: 1
- xp: 10
- base_wait: 4
- tools:
- - fishing_rod
- bait: fishing_bait
- success:
- base: 0.30
- per_level: 0.01
- cap: 0.90
- gather_message: "You cast your line into the water..."
- fail_message: "Nothing seems to bite."
- drops:
- - item_id: raw_trout
- weight: 100
- depletes: false # never depletes
- message: "You catch a {69}raw trout{/}!"
-```
-
-Woodcutting with shared depletion and bird's nests:
-```yaml
-id: oak_tree
-name: oak tree
-color: "113"
-gather:
- skill: woodcutting
- level: 15
- xp: 37
- base_wait: 6
- tools:
- - axe
- success:
- base: 0.40
- per_level: 0.01
- cap: 0.90
- gather_message: "You swing your axe at the oak tree..."
- fail_message: "You swing but get no logs."
- drops:
- - item_id: oak_logs
- weight: 100
- depletes: false # depletion is timer-based (deplete_timer)
- message: "You get some {113}oak logs{/}."
- respawn_timer: 14 # ticks until tree respawns after being cut down
- deplete_timer: 45 # max ticks before next gather depletes (counts down while chopping)
- nest_chance: 256 # 1/256 chance for a bird's nest on each successful gather
- respawn_broadcast: "An {name} grows back."
-```
-
-Regular tree — always depletes on first gather, no shared timer, no nests:
-```yaml
-id: tree
-name: tree
-gather:
- skill: woodcutting
- level: 1
- xp: 25
- base_wait: 4
- tools:
- - axe
- success:
- base: 0.50
- per_level: 0.01
- cap: 0.95
- gather_message: "You swing your axe at the tree..."
- fail_message: "You swing but get no logs."
- drops:
- - item_id: logs
- weight: 100
- depletes: true # regular tree depletes on first successful gather
- message: "You get some {107}logs{/}."
- respawn_timer: 80
- respawn_broadcast: "A {name} grows back."
-```
-
-#### GatherConfig Fields
-
-| Field | Type | Description |
-|---|---|---|
-| `skill` | string | Skill name for level check |
-| `level` | int | Required level to gather |
-| `xp` | int | XP per successful gather |
-| `base_wait` | float64 | Base ticks per action cycle |
-| `tools` | []string | Required tool_type list (e.g. `[pickaxe]`) |
-| `bait` | string | Required bait item (for fishing) |
-| `success` | SuccessFormula | Base + per_level, capped |
-| `gather_message` | string | Custom "You gather..." message |
-| `depleted_message` | string | Custom "The rock is depleted" message |
-| `exhausted_message` | string | Custom "The tree falls" message |
-| `fail_message` | string | Custom failure message |
-| `drops` | []DropEntry | Weighted drop entries |
-| `respawn_timer` | float64 | Ticks until depleted object respawns |
-| `respawn_broadcast` | string | Broadcast message when object respawns |
-| `deplete_timer` | float64 | Ticks for shared depletion (trees) |
-| `nest_chance` | int | 1/N chance for bird's nest alongside normal drop |
-
-#### SuccessFormula
-
-| Field | Type | Description |
-|---|---|---|
-| `base` | float64 | Base success chance (0.0-1.0) |
-| `per_level` | float64 | Chance increase per level above requirement |
-| `cap` | float64 | Maximum success chance |
-
-#### DropEntry
-
-| Field | Type | Description |
-|---|---|---|
-| `item_id` | string | Item ID to drop |
-| `table` | string | Reference to a shared drop table in `data/drops/` |
-| `weight` | int | Relative drop weight |
-| `depletes` | bool | Resource depletes on this drop |
-| `quantity` | int | Amount to drop (1-3 for random) |
-| `message` | string | Player message on drop |
-| `level` | int | Skill level required for this drop |
-| `xp` | int | Bonus XP on this drop |
-
-#### Shared depletion explained
-
-When `deplete_timer > 0`, the tree has a shared despawn timer:
-- The timer starts at `deplete_timer` max when the first player begins chopping.
-- Each tick, if anyone is chopping, the timer counts down.
-- When the timer reaches 0, the NEXT successful gather depletes the tree.
-- If no one is chopping and the tree isn't depleted, the timer ticks back UP.
-- All players chopping the same tree are interrupted when it depletes.
-
-Use `deplete_timer` for trees. Use `depletes: true` on individual drops for rocks.
-
-#### Bird's nests
-
-When `nest_chance > 0`, each successful gather has a 1/N independent chance to also drop
-a bird's nest. The nest goes to inventory (or to the ground if inventory is full).
-Use the `search` command to open nests — they roll on the `birds_nest_drop` table.
-
-#### XP drops
-
-When `xp > 0`, the gather awards XP on each successful drop. If the player's `xpdrops`
-toggle is on, the output includes the XP gain: `(+37xp wct)`.
-
-### Talk (dialog trees)
-
-Talk configs go under the `talk:` key on objects or mobs. Full conversation with
-conditions, actions, and player flag tracking:
-
-```yaml
-id: guard
-name: Guard
-talk:
- nodes:
- start:
- message: "\"Halt! This area is restricted.\""
- options:
- - text: "\"What's behind that gate?\""
- goto: about_gate
- - text: "\"I have copper ore.\""
- goto: trade_ore
- condition:
- has_item: copper_ore
- - text: "\"I have a pass.\""
- goto: has_pass
- condition:
- player_flag: got_pass
- value: true
- - text: "\"Goodbye.\""
- end: true
-
- about_gate:
- message: "\"Bring me some copper ore and I'll stamp you a pass.\""
- action:
- set_player_flags:
- talked_to_guard: true
- options:
- - text: "\"I'll be back.\""
- end: true
- - text: "\"I have some right here.\""
- goto: trade_ore
- condition:
- has_item: copper_ore
-
- trade_ore:
- message: "\"Good quality ore.\" He stamps a pass and hands it to you."
- action:
- take_item: copper_ore
- give_item: pass_stub
- set_player_flags:
- got_pass: true
- options:
- - text: "\"Thanks.\""
- end: true
-
- has_pass:
- message: "\"Alright, I'll open the gate for you.\""
- action:
- set_flags:
- gate_open: true
- options:
- - text: "\"Thanks.\""
- end: true
-```
-
-#### Node action reference
-
-| Field | Effect |
-|---|---|
-| `set_flags` | Sets world flags (global, shared by all players) |
-| `set_player_flags` | Sets player-local flags (per-character, quest progress) |
-| `give_item` | Gives an item to the player's inventory |
-| `take_item` | Removes an item from the player's inventory |
-| `teleport` | Moves the player to a room ID |
-| `heal` | Restores that many hitpoints |
-| `cost` | Credits charged for the action |
-| `shop` | Opens a buy/sell shop interface (see Shop section below) |
-| `assign_task` | Assigns a random assassin task to the player based on their assassin level |
-| `skip_task` | Cancels current assassin task, costs 30 reputation, resets streak |
-| `extend_task` | Adds 50% more kills to current task, costs 30 reputation |
-| `reputation_cost` | Deducts reputation from the player's `assassin_reputation` flag (fails node if insufficient) |
-| `sawmill` | Opens sawmill plank conversion interface |
-
-All fields in a single action are processed together — you can give an item, take an item,
-set flags, and heal all in one node.
-
-Example — quest completion:
-```yaml
-action:
- take_item: dragon_head
- give_item: dragon_slayer_medal
- set_player_flags:
- dragon_quest: complete
- dragon_slain: true
- heal: 99
- teleport: 1
-```
-
-#### Shop (buy/sell interface)
-
-The `shop` node action opens a dedicated buy/sell interface. The player can browse
-items, buy with credits, and sell items back. Define a shop on a talk node:
-
-```yaml
-action:
- shop:
- message: "What would you like to buy or sell?"
- items:
- - item_id: fishing_rod
- buy_price: 10
- sell_price: 2
- - item_id: fishing_bait
- buy_price: 2
- sell_price: 0
-```
-
-| Field | Description |
-|---|---|
-| `shop.message` | Greeting shown when entering the shop |
-| `shop.items` | List of items for sale |
-| `item_id` | Item definition ID |
-| `buy_price` | Credits to buy from shop |
-| `sell_price` | Credits shop pays (0 = won't buy) |
-
-Typical shop flow: a talk node with a "Browse" option leads to a `shop` node.
-When the player leaves the shop, they return to the talk node's options.
-
-Full example — General Store:
-```yaml
-id: general_store_clerk
-name: General Store Clerk
-talk:
- nodes:
- start:
- message: "\"Welcome to the General Store!\""
- options:
- - text: "\"I'd like to browse.\""
- goto: shop
- - text: "\"Goodbye.\""
- end: true
- shop:
- message: "\"Take your time.\""
- action:
- shop:
- message: "What would you like to buy or sell?"
- items:
- - item_id: fishing_rod
- buy_price: 10
- sell_price: 2
- - item_id: hammer
- buy_price: 20
- sell_price: 5
- options:
- - text: "\"I'm done.\""
- goto: start
-```
-
-Node options on the shop node are shown when the player leaves the shop.
-Use `goto: start` to loop back to the main greeting.
-
-### Object Interactions (levers, switches, gates)
-
-Interaction configs go under the `use_interactions:` key on objects.
-Entries with no `item` field are bare interactions triggered by "use"
-or "push"/"pull":
-
-```yaml
-id: iron_gate
-name: iron gate
-hidden: true
-description: "A heavy iron gate set into the north wall."
-use_interactions:
- - condition:
- flag: gate_open
- value: true
- not: true
- message: "You push the heavy iron gate open."
- action:
- set_flags:
- gate_open: true
-```
-
-Item-specific interaction:
-```yaml
-id: bookshelf
-name: bookshelf
-use_interactions:
- - item: dusty_tome
- message: "The bookshelf slides aside, revealing a secret passage!"
- action:
- set_flags:
- secret_passage_open: true
-```
-
-### Use (crafting stations)
-
-Use configs go under the `use:` key on objects (e.g. furnaces, ranges):
-
-```yaml
-id: furnace
-name: furnace
-color: "208"
-use:
- message: "You place the ore in the furnace..."
- wait: 4
- consume:
- copper_ore: 1
- reward:
- item_id: copper_bar
- quantity: 1
- fail_message: "The ore crumbles to dust."
- success:
- base: 0.60
- per_level: 0.01
- cap: 0.95
- skill: smithing
- level: 1
- xp: 15
-```
-
----
diff --git a/worldbuilding_guide/conditions.md b/worldbuilding_guide/conditions.md
deleted file mode 100644
index 972dadc..0000000
--- a/worldbuilding_guide/conditions.md
+++ /dev/null
@@ -1,70 +0,0 @@
-## Conditions Reference
-
-Conditions are used in talk options, exit gates, on-enter scripts, and use_interactions checks.
-
-### Simple conditions
-
-```yaml
-# Check a world flag
-condition:
- flag: gate_open
- value: true
-
-# Check a world flag is NOT set
-condition:
- flag: gate_open
- not: true
-
-# Check a player flag
-condition:
- player_flag: finished_tutorial
- value: true
-
-# Check if player has an item
-condition:
- has_item: bronze_key
-
-# Check if player does NOT have an item
-condition:
- has_item: bronze_key
- not: true
-
-# Check if player has enough credits
-condition:
- min_credits: 50
-```
-
-### Compound conditions
-
-All must pass:
-```yaml
-condition:
- all_of:
- - flag: gate_open
- value: true
- - has_item: pass_stub
-```
-
-Any one must pass:
-```yaml
-condition:
- any_of:
- - has_item: bronze_key
- - has_item: iron_key
- - player_flag: master_of_unlocking
- value: true
-```
-
-Nested compounds:
-```yaml
-condition:
- all_of:
- - player_flag: quest_started
- value: true
- - any_of:
- - has_item: wolf_pelt
- - has_item: bear_pelt
-```
-
----
-
diff --git a/worldbuilding_guide/construction.md b/worldbuilding_guide/construction.md
deleted file mode 100644
index 2c4b7ce..0000000
--- a/worldbuilding_guide/construction.md
+++ /dev/null
@@ -1,223 +0,0 @@
-# Construction Skill
-
-The Construction skill allows players to process logs into planks and assemble planks into furniture at a workbench. Higher-tier logs produce more valuable planks and furniture.
-
-## Skill
-
-- Skill name: `construction`
-- Abbreviation: `con`
-- Level range: 1-99
-- XP table: RSC standard
-
-## Commands
-
-| Command | Description |
-|---------|-------------|
-| `construct` / `make` | Open construction menu at a workbench |
-| `construct <item>` | Build a specific item |
-| `construct <qty> <item>` | Build multiple of an item |
-
-## Objects
-
-### workbench
-
-The primary construction station. Placed in rooms to enable construction.
-
-```yaml
-id: workbench
-name: workbench
-color: "172"
-description: "A sturdy wooden workbench..."
-inroom_description: "A workbench stands against the wall..."
-```
-
-### estate_directory
-
-A terminal that shows registered homeowners and lets them enter their house. Handled entirely in Go code (`internal/game/cmd_estate_directory.go`), not via YAML behaviors.
-
-```yaml
-id: estate_directory
-name: Estate Directory
-color: "39"
-description: "A holographic terminal displaying property records..."
-inroom_description: "An estate directory terminal..."
-```
-
-When a player looks at the directory, it scans `data/players/characters/*.yaml` for the `owns_house_local_neighborhood` player flag and lists all homeowners. When a player uses or talks to the directory and owns a house, they can teleport to their house entrance room.
-
-## Tools
-
-### saw
-
-Required tool for cutting logs into planks at the workbench.
-
-```yaml
-id: saw
-name: saw
-tool_type: saw
-value: 30
-```
-
-## Items
-
-### Planks (4 tiers)
-
-| Item ID | Name | Level | Value | Made From |
-|---------|------|-------|-------|-----------|
-| `planks` | planks | 1 | 20 | logs |
-| `oak_planks` | oak planks | 15 | 40 | oak_logs |
-| `teak_planks` | teak planks | 35 | 80 | teak_logs |
-| `mahogany_planks` | mahogany planks | 50 | 120 | mahogany_logs |
-
-### Furniture (sellables)
-
-| Item ID | Level | Planks Required |
-|---------|-------|-----------------|
-| `wooden_shelf` | 4 | 2 planks |
-| `wooden_table` | 6 | 3 planks |
-| `wooden_chair` | 8 | 2 planks |
-| `oak_shelf` | 18 | 2 oak planks |
-| `oak_table` | 20 | 3 oak planks |
-| `teak_table` | 38 | 3 teak planks |
-| `mahogany_table` | 52 | 3 mahogany planks |
-
-## Recipes
-
-All recipes use `type: construction` and `station: [workbench]`. Log-to-plank recipes additionally require `tool: saw`.
-
-Example plank recipe:
-```yaml
-id: construct_oak_planks
-type: construction
-level: 15
-xp: 10
-wait: 20
-station: [workbench]
-tool: saw
-consume:
- - items: [oak_logs]
- quantity: 1
-output: oak_planks
-message: "You saw the oak logs into sturdy oak planks."
-```
-
-Example furniture recipe:
-```yaml
-id: construct_wooden_table
-type: construction
-level: 6
-xp: 25
-wait: 6
-station: [workbench]
-consume:
- - items: [planks]
- quantity: 3
-output: wooden_table
-message: "You build a sturdy wooden table."
-```
-
-## NPCs
-
-### estate_broker
-
-Located in room 16 (Construction Site). Talk behavior sells a house plot for 10 credits via `cost` + `set_player_flags`. Sets `owns_house_local_neighborhood: "local_neighborhood"` on purchase.
-
-```yaml
-id: estate_broker
-name: estate broker
-talk:
- nodes:
- start:
- message: "\"Interested in a house?\""
- options:
- - text: "\"How much?\""
- goto: offer
- - text: "\"No thanks.\""
- end: true
- offer:
- message: "\"10 credits for a plot.\""
- action:
- cost: 10
- set_player_flags:
- owns_house_local_neighborhood: "local_neighborhood"
- options:
- - text: "\"Deal!\""
- end: true
-unique: true
-```
-
-### sawmill_operator
-
-Located in room 171 (Lumberyard). Talk behavior processes all logs in inventory into planks for a credit fee. Uses the `sawmill: true` node action which triggers `processSawmill()` in `internal/game/action_talk.go`.
-
-Fees: regular (5cr), oak (10cr), teak (20cr), mahogany (40cr).
-
-## Science Mod: Plank Make
-
-Level 86 Science utility mod that converts logs to planks at 70% of sawmill cost. Uses naturejunk, solarjunk, and scrap.
-
-```go
-{ID: "plank_make", Name: "Plank Make", Level: 86, BaseXP: 90.0,
- JunkCost: map[string]int{"naturejunk": 5, "solarjunk": 1, "scrap": 1},
- Category: ModUtility, TargetType: "inventory"},
-```
-
-Usage: `trigger plank make` (all logs) or `trigger plank make <log type>` (specific).
-
-## Player Houses
-
-Player houses are real YAML rooms stored in `data/rooms/player_housing/`. Each house area (e.g. Local Neighborhood) has entrance + workshop rooms with unique room IDs in the 200+ range.
-
-House room files follow the same format as world rooms:
-```yaml
-id: 200
-name: "Player House: Entrance Hall"
-description: "..."
-exits:
- south: 170
- north: 201
-objects:
- - id: charging_station
-```
-
-The room loader (`World.LoadRoom`) checks `data/rooms/<id>.yaml` first, then falls back to `data/rooms/player_housing/<id>.yaml`.
-
-Ownership is tracked via player flags (e.g. `owns_house_local_neighborhood: "local_neighborhood"`). The Estate Directory scans character YAML files for these flags.
-
-## Implementation
-
-### Production Integration
-
-Construction is added to `productionTypes` in `action_production.go`:
-```go
-"construction": {"construct", "constructing"},
-```
-
-This enables automatic support through the unified production system (`advanceProduction`, `startProductionFromRecipe`, etc.).
-
-### Command
-
-`cmd_construct.go` follows the same pattern as `cmd_craft.go`, using per-recipe `Station` and `Tool` checks. Station: `workbench`, Tool: `saw` (for plank recipes only).
-
-### Option
-
-`construct_all` (OptBool, default false): Auto-start construction when only one product is available.
-
-## Data File Summary
-
-| Path | Purpose |
-|------|---------|
-| `data/objects/workbench.yaml` | Workbench station object |
-| `data/objects/estate_directory.yaml` | Directory terminal object |
-| `data/items/saw.yaml` | Saw tool |
-| `data/items/planks.yaml` - `mahogany_planks.yaml` | Plank items (4 tiers) |
-| `data/items/wooden_shelf.yaml` - `mahogany_table.yaml` | Furniture items (7 items) |
-| Item YAMLs with `craft:` blocks (planks, furniture) | Construction recipes — inline on output item YAML |
-| `data/mobs/estate_broker.yaml` | Estate broker mob (talk inline) |
-| `data/mobs/sawmill_operator.yaml` | Sawmill operator mob (talk inline) |
-| `data/rooms/16.yaml` | Construction Site (updated) |
-| `data/rooms/170.yaml` | Local Neighborhood |
-| `data/rooms/171.yaml` | Lumberyard |
-| `data/rooms/player_housing/200.yaml` | Player house entrance |
-| `data/rooms/player_housing/201.yaml` | Player house workshop |
-| `data/help/construct.yaml` | Help topic |
diff --git a/worldbuilding_guide/courses.md b/worldbuilding_guide/courses.md
deleted file mode 100644
index 491e2bd..0000000
--- a/worldbuilding_guide/courses.md
+++ /dev/null
@@ -1,119 +0,0 @@
-## Agility Courses
-
-Agility courses are defined in `data/courses/<id>.yaml`. Each course defines a sequence of obstacle rooms, each with a specific verb the player must type to advance. Obstacle rooms themselves are standard room YAML files (typically in `data/rooms/agility/`).
-
-### Course YAML
-
-```yaml
-id: "vent_shaft"
-name: "Ventilation Shaft Course"
-required_level: 1
-start_room: 200
-completion_xp: 40
-obstacles:
- - room_id: 201
- verb: scramble
- ticks_per_phase: 2
- xp: 8
- fail_damage: [1, 2]
- messages:
- - "You approach the corroded ventilation wall..."
- - "You find footholds in the rusted panels and begin to climb..."
- - "You scramble up the wall and haul yourself onto the ledge!"
- - room_id: 202
- verb: balance
- ticks_per_phase: 2
- xp: 8
- fail_damage: [1, 2]
- messages:
- - "You step onto the narrow coolant pipe..."
- - "Arms outstretched, you carefully place one foot in front of the other..."
- - "You reach the other side of the pipe and step onto solid ground!"
-```
-
-### CourseConfig Fields
-
-| Field | Type | Description |
-| ---------------- | ------------- | ---------------------------------------------------- |
-| `id` | string | Unique course identifier |
-| `name` | string | Display name shown to players |
-| `required_level` | int | Minimum Agility level to attempt the course |
-| `start_room` | int | Hub room — teleported here on fail or lap completion |
-| `completion_xp` | int | Bonus XP awarded when a full lap is completed |
-| `obstacles` | []ObstacleDef | Ordered list of obstacles |
-
-### ObstacleDef Fields
-
-| Field | Type | Description |
-| ----------------- | -------- | --------------------------------------------------------------------------- |
-| `room_id` | int | Room ID for this obstacle |
-| `verb` | string | Command the player types to attempt it (e.g. `scramble`, `jump`, `climb`) |
-| `ticks_per_phase` | float64 | Ticks between each phase message (supports fractional via `engine.ToTicks`) |
-| `xp` | int | XP awarded for successfully completing this single obstacle |
-| `fail_damage` | [2]int | `[min, max]` damage on failure (HP clamped to minimum 1 — cannot kill) |
-| `messages` | []string | Exactly 3 strings for the 3-phase advancement system |
-
-### 3-Phase Message System
-
-Each obstacle advances through 3 phases, printing one message per phase:
-
-```
-Phase 0 (start): messages[0] printed immediately
-Phase 1 (middle): messages[1] printed — FAILURE CHECK happens here
-Phase 2 (end): messages[2] printed — XP awarded, teleport to next room
-```
-
-Failure only occurs at phase 1. Success chance is based on Agility level:
-- At required level: 70% success (30% fail)
-- Each level above reduces fail chance by 1% (down to minimum 5%)
-- Fail chance capped at 60%
-
-On failure, the player takes random damage in `[fail_damage[0], fail_damage[1]]`, is teleported back to `start_room`, and must restart the course.
-
-### Lap Counting
-
-Completing all obstacles in a course increments a lap counter stored as a player flag (`agility_laps_<course_id>`). The `completion_xp` bonus is awarded on the final obstacle only.
-
-### Obstacle Room YAML
-
-Each obstacle room should have an `on_enter` message telling the player which verb to use, and a `down` exit back to the course hub:
-
-```yaml
-id: 201
-name: "Ventilation Shaft - Corroded Wall"
-description: "A towering wall of corroded ventilation panels..."
-on_enter:
- - message: "Type 'scramble' to climb the wall."
-exits:
- down:
- room: 200
- blocked_message: ""
-```
-
-The hub room (e.g. room 200) links to the first obstacle of each course:
-
-```yaml
-id: 200
-name: "Agility Training Grounds"
-exits:
- south: 17
- north: 201 # Vent Shaft (level 1)
- east: 210 # Rooftop (level 20)
- west: 220 # Reactor (level 50)
-```
-
-### Supported Obstacle Verbs
-
-| Verb | Gerund (display) |
-| ---------- | ---------------- |
-| `scramble` | scrambling |
-| `jump` | jumping |
-| `swing` | swinging |
-| `balance` | balancing |
-| `climb` | climbing |
-| `crawl` | crawling |
-| `vault` | vaulting |
-| `leap` | leaping |
-| `slide` | sliding |
-
-Obstacle verbs are auto-registered at startup from all course YAML files. No changes to `cmd_registry.go` needed when adding new courses — any verb in a `data/courses/` file will work.
diff --git a/worldbuilding_guide/doors.md b/worldbuilding_guide/doors.md
deleted file mode 100644
index 1e9fb7a..0000000
--- a/worldbuilding_guide/doors.md
+++ /dev/null
@@ -1,97 +0,0 @@
-## Global vs Player State: Door Examples
-
-### Example A: Door with a button in another room (GLOBAL)
-
-A button in room 3 opens a door in room 7. Anyone can press it. Once pressed, the door is open for everyone.
-
-**Button object** (`data/objects/door_button.yaml`):
-```yaml
-id: door_button
-name: stone button
-hidden: true
-use_interactions:
- - condition:
- flag: secret_door_open
- not: true
- message: "You press the stone button. You hear grinding stone in the distance."
- action:
- set_flags:
- secret_door_open: true
-```
-
-**Room 3** — contains the button:
-```yaml
-id: 3
-name: "Button Chamber"
-description: "A small stone chamber. A button protrudes from the east wall."
-exits:
- south: 1
-objects:
- - id: door_button
-```
-
-**Room 7** — contains the door:
-```yaml
-id: 7
-name: "Hidden Passage"
-description: "A dusty corridor. A heavy stone door blocks the way north."
-exits:
- south: 2
- north:
- room: 8
- condition:
- flag: secret_door_open # checks WORLD flag
- value: true
- blocked_message: "A heavy stone door blocks the way."
-objects:
- - id: stone_door
- hidden: true
-```
-
-### Example B: Key-locked door (PLAYER-LOCAL)
-
-A locked door that only opens for a player carrying the key. Each player must find their own key.
-
-**Key item** (`data/items/rusty_key.yaml`):
-```yaml
-id: rusty_key
-name: rusty key
-description: "An old iron key, still functional."
-value: 0
-stackable: false
-```
-
-**Room 5** — locked door:
-```yaml
-id: 5
-name: "Locked Storage"
-description: "A small storage room. The way east is blocked by a locked iron door."
-exits:
- west: 2
- east:
- room: 6
- condition:
- has_item: rusty_key # checks PLAYER inventory
- blocked_message: "The iron door is locked. You need a key."
-objects:
- - id: iron_door
- hidden: true
-```
-
-**Room 6** — the other side (no key needed to exit):
-```yaml
-id: 6
-name: "Storage Closet"
-description: "Shelves of dusty crates."
-exits:
- west: 5 # exit back — no condition
-spawns:
- - item_id: uncut_ruby
- quantity: 1
- respawn_ticks: 500
-```
-
-Key difference: the button door uses `flag` (shared state — one player presses, everyone benefits), the key door uses `has_item` (per-player inventory check — each player needs their own key).
-
----
-
diff --git a/worldbuilding_guide/drops.md b/worldbuilding_guide/drops.md
deleted file mode 100644
index e5a17ff..0000000
--- a/worldbuilding_guide/drops.md
+++ /dev/null
@@ -1,52 +0,0 @@
-## Drop Tables
-
-Shared drop tables can be referenced by multiple behaviors:
-```yaml
-# data/drops/gem_table.yaml
-id: gem_table
-drops:
- - item_id: uncut_sapphire
- weight: 47
- - item_id: uncut_emerald
- weight: 16
- - item_id: uncut_ruby
- weight: 4
- - item_id: uncut_diamond
- weight: 1
-```
-
-Bird's nest drop table:
-```yaml
-# data/drops/birds_nest_drop.yaml
-id: birds_nest_drop
-drops:
- - item_id: credits
- weight: 50
- quantity: 200
- - item_id: credits
- weight: 30
- quantity: 500
- - item_id: credits
- weight: 15
- quantity: 1000
- - item_id: credits
- weight: 4
- quantity: 3000
- - item_id: credits
- weight: 1
- quantity: 10000
-```
-
-Referenced from a gather behavior:
-```yaml
-drops:
- - item_id: copper_ore
- weight: 90
- depletes: true
- - table: gem_table # pulls from data/drops/gem_table.yaml
- weight: 10
- depletes: false
-```
-
----
-
diff --git a/worldbuilding_guide/hacking.md b/worldbuilding_guide/hacking.md
deleted file mode 100644
index 8927b3e..0000000
--- a/worldbuilding_guide/hacking.md
+++ /dev/null
@@ -1,49 +0,0 @@
-## Hacking
-
-Hacking minigames are played by jacking into terminal objects. Terminals are YAML objects that are registered in Go's `terminalDefs` map.
-
-### Terminal Object YAML
-
-```yaml
-id: terminal_basic
-name: basic terminal
-color: "40"
-description: "A battered terminal with a cracked screen. {40}[Level 1 Hacking]{/}"
-inroom_description: "A {40}basic terminal{/} hums quietly against the wall."
-```
-
-- `id` must match a key in `terminalDefs` (Go code in `internal/game/hacking.go`)
-- `name` is used for matching in the `jack` command
-- `color` controls the display color
-- `description` is shown when examining the terminal
-- `inroom_description` is shown in room listings
-- No `behavior` field — terminals are registered in Go, not YAML behaviors
-
-### Adding a New Terminal
-
-1. Create an object YAML file in `data/objects/terminal_<name>.yaml`
-2. Add an entry to `terminalDefs` in `internal/game/hacking.go`
-3. Optionally create a new minigame implementation in `internal/game/hacking_<name>.go`
-4. Place the terminal object in a room's `objects:` list
-
-### Adding a New Minigame
-
-New minigames implement the `HackingMinigame` interface:
-
-```go
-type HackingMinigame interface {
- Init(level int) string
- HandleInput(input string) (output string, done bool, won bool)
- Name() string
-}
-```
-
-Optionally implement `XPBonuser` for bonus XP:
-
-```go
-type XPBonuser interface {
- BonusXP() int
-}
-```
-
-
diff --git a/worldbuilding_guide/hidden_objects.md b/worldbuilding_guide/hidden_objects.md
deleted file mode 100644
index 24fd6bc..0000000
--- a/worldbuilding_guide/hidden_objects.md
+++ /dev/null
@@ -1,40 +0,0 @@
-## Hidden Objects
-
-Objects with `hidden: true` don't appear in the room's object listing. Players discover them by reading room descriptions or trying commands. The object is still fully interactable — `push gate`, `look gate`, etc.
-
-```yaml
-# data/objects/secret_lever.yaml
-id: secret_lever
-name: stone lever
-hidden: true
-description: "A cleverly concealed lever behind a loose stone."
-use_interactions:
- - condition:
- flag: secret_passage_open
- value: true
- not: true
- message: "You pull the lever. A grinding sound echoes from the east."
- action:
- set_flags:
- secret_passage_open: true
-```
-
-Room description hints at it:
-```yaml
-description: "A dusty corridor. One of the wall stones looks slightly out of place."
-```
-
-### Safespot Objects
-
-Safespot objects should always be `hidden: true`. They only become visible in `look` when the player's effective safespot tier meets the object's `safespot.tier` requirement. This creates a natural discovery mechanic: completing quests and achievements reveals new coverage opportunities.
-
-Players can discover safespots by:
-- Reading room descriptions for hints
-- Trying `hide <object_name>` (name matching works even for hidden objects)
-- Using `look <object>` once they know the name
-- Gaining tier through progression, which reveals safespots in `look`
-
-See [Safespots](objects.md#safespots) for the full YAML format.
-
----
-
diff --git a/worldbuilding_guide/index.md b/worldbuilding_guide/index.md
deleted file mode 100644
index e79ee1b..0000000
--- a/worldbuilding_guide/index.md
+++ /dev/null
@@ -1,17 +0,0 @@
-## Quick Reference
-
-| What you want | Where to put it |
-|---|---|
-| A room | `data/rooms/<id>.yaml` |
-| An item (sword, ore, key) | `data/items/<id>.yaml` |
-| A mob (NPC, monster) | `data/mobs/<id>.yaml` |
-| An interactive object (rock, lever, door) | `data/objects/<id>.yaml` |
-| A shared drop table | `data/drops/<id>.yaml` |
-| A crafting recipe | In the output item's YAML under a `craft:` block |
-| A help topic | `data/help/<id>.yaml` |
-| A science module | `data/modules/<id>.yaml` |
-| An agility course | `data/courses/<id>.yaml` |
-| A player house | `data/rooms/player_housing/<id>.yaml` |
-
-Behaviors (gather, talk, use) are defined **inline** in object and mob YAML
-under `gather:`, `talk:`, or `use:` keys. There is no separate behavior directory.
diff --git a/worldbuilding_guide/items.md b/worldbuilding_guide/items.md
deleted file mode 100644
index 2e36349..0000000
--- a/worldbuilding_guide/items.md
+++ /dev/null
@@ -1,190 +0,0 @@
-## Items
-
-```yaml
-id: bronze_pickaxe
-name: bronze pickaxe
-color: "178" # xterm-256 color index (0-255)
-aliases: ["pick", "pickaxe"]
-description: "A sturdy bronze pickaxe."
-value: 10
-stackable: false
-equip_slot: main_hand # optional — where it equips
-weapon_type: melee # optional — melee, ranged, or science
-attack_type: stab # stab/slash/crush/ranged/science — determines accuracy type
-stats: # optional — per-type combat bonuses
- stab_attack: 4
- slash_attack: -2
- crush_attack: 2
- strength_bonus: 3
-speed: 5 # ticks between attacks
-tool_type: pickaxe # used by gather behaviors that require "tool: pickaxe"
-tool_speed: 2 # reduces gather wait time
-requirements: # optional — skill levels needed to equip
- attack: 1
-```
-
-### Equipment Stats (ItemStats)
-
-Weapons have per-type **attack bonuses** — these determine accuracy based on the weapon's `attack_type`:
-
-| Field | Description |
-|---|---|
-| `stab_attack` | Accuracy bonus for stab attacks |
-| `slash_attack` | Accuracy bonus for slash attacks |
-| `crush_attack` | Accuracy bonus for crush attacks |
-| `science_attack` | Accuracy bonus for science attacks |
-| `ranged_attack` | Accuracy bonus for ranged attacks |
-
-Armor has per-type **defense bonuses** — the mob's `attack_type` determines which defense is used:
-
-| Field | Description |
-|---|---|
-| `stab_defense` | Defense vs stab attacks |
-| `slash_defense` | Defense vs slash attacks |
-| `crush_defense` | Defense vs crush attacks |
-| `science_defense` | Defense vs science attacks (negative on metal armor) |
-| `ranged_defense` | Defense vs ranged attacks |
-
-Other damage/utility bonuses:
-
-| Field | Description |
-|---|---|
-| `strength_bonus` | Melee max hit bonus |
-| `ranged_strength` | Ranged max hit bonus (on ammo) |
-| `science_damage` | Science max hit bonus |
-| `technology_bonus` | Reduces tech battery drain rate |
-
-### Attack Type
-
-Weapons should always set `attack_type`. Common mappings:
-
-| Category | attack_type |
-|---|---|
-| Swords | slash |
-| Daggers | stab |
-| Axes | slash |
-| Pickaxes | stab |
-| Bows | ranged |
-| Unarmed | crush (default) |
-
-### Equipment Requirements
-
-Higher-tier equipment requires skill levels to equip:
-
-```yaml
-requirements:
- attack: 20 # melee weapons
- defense: 20 # armor
- ranged: 30 # ranged weapons/armor
-```
-
-Standard tiers: bronze/iron (none), steel (5), black (10), mithril (20), adamant (30), rune (40), dragon (60).
-
-### Ranged Ammo
-
-Arrows and bolts use `ranged_strength` for damage. Accuracy comes from the bow:
-
-```yaml
-id: iron_arrow
-name: iron arrow
-stackable: true
-equip_slot: ammo
-stats:
- ranged_strength: 10
-```
-
-### Color
-
-The `color` field accepts xterm-256 palette indices (0-255) with optional modifiers:
-
-```yaml
-color: "178" # bronze/gold
-color: "75 bold" # bold steel blue
-color: "g:196,208,226" # gradient red → orange → gold
-```
-
-In ANSI mode, extended colors (16-255) automatically downgrade to the nearest ANSI color. Use `colortable` in-game to see all 256 colors.
-
-Key item (quest token, not equippable):
-```yaml
-id: pass_stub
-name: pass stub
-description: "A crumpled slip of paper stamped with the guard's seal."
-value: 0
-stackable: false
-```
-
----
-
-## Firemaking
-
-```yaml
-id: logs
-name: logs
-fire_level: 1 # firemaking level required
-fire_xp: 40 # XP for burning/stoking
-burn_ticks: 24 # how long the fire burns
-```
-
-## Food / Healing
-
-```yaml
-id: bread
-name: bread
-color: "222"
-description: "A fresh loaf of bread, still warm from the oven."
-value: 5
-heal_value: 5 # positive = heal, negative = damage
-eat_message: "You eat the bread. Warm and satisfying."
-```
-
-## MadeFrom — Item Combinations
-
-Define what items combine to make this item. Used by the `use` command. Combinations run through the production system — players are prompted "How many?" and the action loops with a timer.
-
-```yaml
-id: bread_dough
-name: bread dough
-color: "222"
-ticks: 2
-made_from:
- - items: [pot_of_flour]
- quantity: 1
- byproducts: [empty_pot]
- - items: [bucket_of_water, pitcher_of_water]
- quantity: 1
- byproducts: [empty_bucket, empty_pitcher]
-```
-
-Each entry is an ingredient slot. Multiple `items` means any of them works. The first matching item found in inventory is consumed.
-
-`ticks` controls how many game ticks each production cycle takes (default 2).
-
-### Byproducts
-
-`byproducts` is a list matching the `items` list by index. When `bucket_of_water` (items[0]) is consumed, `empty_bucket` (byproducts[0]) is returned to inventory. When `pitcher_of_water` (items[1]) is consumed, `empty_pitcher` (byproducts[1]) is returned instead.
-
-Use `""` for items that produce no byproduct:
-
-```yaml
-made_from:
- - items: [pot_of_flour, loose_flour]
- quantity: 1
- byproducts: [empty_pot, ""] # pot returns empty_pot, loose flour returns nothing
- - items: [bucket_of_water]
- quantity: 1
- byproducts: [empty_bucket]
-```
-
-Omit `byproducts` entirely if no items in that slot produce a byproduct:
-
-```yaml
-made_from:
- - items: [pot_of_flour]
- quantity: 1
- byproducts: [empty_pot] # returns empty_pot
- - items: [salt]
- quantity: 1 # no byproducts field — salt is consumed entirely
-```
-
-See also `recipes.md` for station-based recipes.
diff --git a/worldbuilding_guide/mobs.md b/worldbuilding_guide/mobs.md
deleted file mode 100644
index c19efff..0000000
--- a/worldbuilding_guide/mobs.md
+++ /dev/null
@@ -1,179 +0,0 @@
-## Mobs
-
-Basic combat mob with per-type defense bonuses:
-```yaml
-id: "man"
-name: "man"
-description: "A shabby-looking man."
-attack: 1
-strength: 1
-defense: 1
-hp: 7
-speed: 5
-aggressive: false
-respawn_ticks: 30
-attack_type: crush # stab/slash/crush/ranged/science (default: crush)
-stab_defense: 0 # per-type defense bonuses
-slash_defense: 0
-crush_defense: 0
-science_defense: 0
-ranged_defense: 0
-drops:
- remains: "bones" # always dropped on death
- loot:
- - item_id: "credits"
- weight: 98
- quantity: 10
- - item_id: "credits"
- weight: 2
- quantity: 150
-idle_descriptions:
- - "scribbles something in a small notebook"
- - "gazes skyward at the clouds"
-combat_descriptions:
- - "is engaged in a fight to the death with %s"
-```
-
-### Aggressive Mobs
-
-Mobs with `aggressive: true` auto-attack players entering their room (1-tick delay). Only aggros if the player's combat level is at most double the mob's combat level. Checked on room enter and login.
-
-```yaml
-id: goblin
-name: goblin
-aggressive: true # attacks players on sight
-attack: 1
-strength: 3
-defense: 3
-hp: 12
-attack_type: slash
-attack_bonus: 3 # equipment-equivalent attack bonus for mob's attack roll
-strength_bonus: 2 # equipment-equivalent strength bonus for mob's max hit
-stab_defense: 4
-slash_defense: 3
-crush_defense: -2 # weak to crush — negative defense is valid
-science_defense: 0
-ranged_defense: 3
-```
-
-### Mob Attack/Defense Fields
-
-| Field | Description |
-|---|---|
-| `attack` | Attack level (base accuracy) |
-| `strength` | Strength level (base max hit) |
-| `defense` | Defense level (base defense) |
-| `hp` | Hit points |
-| `ranged` | Ranged level (for ranged/science mobs) |
-| `science` | Science level |
-| `attack_bonus` | Equipment-equivalent attack bonus (added to attack roll) |
-| `strength_bonus` | Equipment-equivalent strength bonus (added to max hit) |
-| `attack_type` | Determines which player defense is used against this mob |
-| `stab_defense` through `ranged_defense` | Per-type defense bonuses |
-| `weakness` | Elemental weakness (solar/hydro/eco/bio) — for future Science combat |
-| `size` | Mob size for safespot blocking: small/medium/large/massive (default: medium) |
-
-### Protected/Unique Mobs
-
-Mob with talk behavior — can be talked to via `talk:` inline config:
-```yaml
-id: "guard"
-name: "Guard"
-talk: # inline talk config (no separate behavior file)
- nodes:
- start:
- message: "\"Halt! Who goes there?\""
- options:
- - text: "\"Just passing through.\""
- end: true
-unique: true # displays as "Guard" not "a guard"
-protected: true # cannot be attacked
-attack: 5
-strength: 5
-defense: 5
-hp: 30
-speed: 5
-aggressive: false
-respawn_ticks: 60
-attack_type: slash
-attack_bonus: 8
-strength_bonus: 6
-stab_defense: 12
-slash_defense: 15
-crush_defense: 10
-science_defense: -5
-ranged_defense: 12
-idle_descriptions:
- - "scans the area with a watchful eye"
- - "adjusts the grip on his weapon"
-```
-
-Note: `wander_rooms` and `wander_interval` are NOT set on the mob definition. Wander config
-is per-instance in the room YAML (see Rooms > Mobs section above).
-
-### Stealable Mobs
-
-Mobs can be stealable via the `steal` command. On failure, the mob turns hostile and attacks.
-
-```yaml
-id: farmer
-name: Farmer
-steal_table: farmer_steal # Drop table for steal loot
-steal_level: 10 # Required thieving level
-steal_xp: 15 # XP per successful steal
-steal_speed: 4 # Ticks per steal attempt
-```
-
-| Field | Description |
-|---|---|
-| `steal_table` | Drop table ID for loot when stealing |
-| `steal_level` | Required thieving level |
-| `steal_xp` | XP awarded per successful steal |
-| `steal_speed` | Ticks per steal attempt (base wait) |
-
-### Assassin Mobs
-
-Assassin (Slayer) mobs restrict combat by assassin level and introduce finishing blows and protective equipment:
-
-```yaml
-id: slug
-name: slug
-assassin_level: 1 # required assassin level to attack
-finishing_blow: salt # item required to kill (mob stays at 1 HP otherwise)
-attack: 3
-strength: 3
-defense: 1
-hp: 15
-speed: 6
-drops:
- remains: slug_mucus
- loot:
- - item_id: credits
- weight: 100
- quantity: 15
-```
-
-Damage-without mobs deal 1.5x damage unless the player has the specified item equipped:
-```yaml
-id: drone
-name: drone
-assassin_level: 15
-damage_without: insulated_gloves # 1.5x damage without this item equipped
-attack: 15
-strength: 14
-defense: 12
-hp: 45
-speed: 4
-aggressive: true
-```
-
-| Field | Description |
-|---|---|
-| `assassin_level` | Required assassin skill level to attack this mob |
-| `finishing_blow` | Item ID required to kill this mob (mob stays at 1 HP until used via `use <item> on <target>`) |
-| `damage_without` | Item ID for protection — mob deals 1.5x damage if player doesn't have it equipped |
-
-Mobs without these fields work normally (assassin_level defaults to 0, finishing_blow and damage_without default to empty).
-
----
-
diff --git a/worldbuilding_guide/objects.md b/worldbuilding_guide/objects.md
deleted file mode 100644
index 427968a..0000000
--- a/worldbuilding_guide/objects.md
+++ /dev/null
@@ -1,392 +0,0 @@
-## Objects
-
-Objects interact with the world through **inline behavior configs** under
-`gather:`, `talk:`, or `use:` keys. There is no separate behavior
-directory — everything goes directly in the object's YAML.
-
-Gathering object (mining):
-```yaml
-id: copper_rock
-name: copper rock
-color: "178" # xterm-256 color index (0-255)
-gather:
- skill: mining
- level: 1
- xp: 17
- base_wait: 8
- tools:
- - pickaxe
- success:
- base: 0.40
- per_level: 0.01
- cap: 0.95
- gather_message: "You swing your pickaxe at the rock..."
- fail_message: "You chip away but get nothing useful."
- drops:
- - item_id: copper_ore
- weight: 90
- depletes: true
- message: "You manage to mine some {178}copper ore{/}."
- - table: gem_table
- weight: 10
- depletes: false
- message: "You spot a glint of something valuable!"
- respawn_timer: 50
- respawn_broadcast: "A glint of copper catches your eye from some {name}."
-```
-
-Tree object (woodcutting with shared depletion):
-```yaml
-id: oak_tree
-name: oak tree
-color: "113"
-gather:
- skill: woodcutting
- level: 15
- xp: 37
- base_wait: 6
- tools:
- - axe
- success:
- base: 0.40
- per_level: 0.01
- cap: 0.90
- gather_message: "You swing your axe at the oak tree..."
- fail_message: "You swing but get no logs."
- drops:
- - item_id: oak_logs
- weight: 100
- depletes: false
- message: "You get some {113}oak logs{/}."
- respawn_timer: 14
- deplete_timer: 45
- nest_chance: 256
- respawn_broadcast: "An {name} grows back."
-```
-
-Color accepts xterm-256 indices with optional modifiers (`bold`, `dim`, `underline`)
-and gradients (`g:196,82`). In ANSI mode, extended colors downgrade to the nearest
-ANSI color.
-
-Object interaction (gate, lever — uses `use_interactions:` key):
-```yaml
-id: iron_gate
-name: iron gate
-hidden: true
-description: "A heavy iron gate set into the north wall."
-use_interactions:
- - condition:
- flag: gate_open
- value: true
- not: true
- message: "You push the heavy iron gate open."
- action:
- set_flags:
- gate_open: true
-```
-
-Decorative object (no behavior keys — just a name/description):
-```yaml
-id: lumby_fountain
-name: town fountain
-description: "Clear water sparkles in the sunlight."
-```
-
-Talk object (NPC conversations — uses `talk:` key):
-```yaml
-id: tool_shed
-name: Tool Shed
-description: "A small shed with an open window."
-talk:
- nodes:
- start:
- message: "\"Welcome to the tool shed!\""
- options:
- - text: "\"What do you have?\""
- goto: shop
- - text: "\"Goodbye.\""
- end: true
-```
-
-See the [Talk section of behaviors](behaviors.md#talk-dialog-trees) for the full
-dialog tree format. See [Stealable Objects](#stealable-objects) for theft mechanics.
-
----
-
-## Use Interactions
-
-Objects can define `use_interactions` to handle when a player uses a specific item on the object. Each interaction can check conditions, show a message, and execute actions — using the same condition and action primitives as the talk system.
-
-Entries are checked top-to-bottom; the first match with a passing condition wins.
-
-Simple message (no action):
-```yaml
-id: anvil
-name: anvil
-use_interactions:
- - item_id: silver_bar
- message: "You should use this with a mold at a furnace."
- - item_id: gold_bar
- message: "You should use this with a mold at a furnace."
-```
-
-Puzzle interaction (take item, set flag):
-```yaml
-id: crystal_slot
-name: crystal slot
-use_interactions:
- - item_id: crystal_key
- condition:
- flag: crystal_inserted
- message: "The crystal key is already in the slot."
- - item_id: crystal_key
- message: "You insert the crystal key into the slot. It clicks into place."
- action:
- take_item: crystal_key
- set_flags:
- crystal_inserted: true
-```
-
-Quest item exchange:
-```yaml
-use_interactions:
- - item_id: ancient_scroll
- condition:
- player_flag: quest_started
- message: "You place the scroll on the pedestal. The door rumbles open!"
- action:
- take_item: ancient_scroll
- set_player_flags:
- quest_complete: true
- set_flags:
- temple_door_open: true
-```
-
-### UseInteraction Fields
-
-| Field | Type | Description |
-| ----------- | ---------- | ------------------------------------------------ |
-| `item_id` | string | Item ID that triggers this interaction |
-| `condition` | Condition | Optional condition (same as exits/talk/use_interactions) |
-| `message` | string | Message shown to the player |
-| `action` | NodeAction | Optional actions (same as talk node actions) |
-
-### Available Actions (same as talk)
-
-| Field | Type | Description |
-| ------------------ | -------------- | ---------------------------------- |
-| `set_flags` | map[string]any | Set world flags (shared) |
-| `set_player_flags` | map[string]any | Set player flags (per-character) |
-| `give_item` | string | Give an item to inventory |
-| `take_item` | string | Remove an item from inventory |
-| `teleport` | int | Move player to a room ID |
-| `heal` | int | Restore hitpoints |
-
-### Available Conditions (same as exits/talk)
-
-| Field | Description |
-| ------------- | -------------------------------- |
-| `flag` | World flag check |
-| `player_flag` | Per-character flag check |
-| `has_item` | Inventory item check |
-| `value` | Expected value for flag checks |
-| `not` | Invert the condition |
-| `all_of` | All sub-conditions must pass |
-| `any_of` | Any sub-condition must pass |
-
----
-
-## Stealable Objects
-
-Objects can be stealable via the `steal` command. These use the same drop table system as mobs and searches.
-
-```yaml
-id: market_stall
-name: Market Stall
-description: "A wooden stall piled with food and sundries."
-steal_table: market_stall_steal
-steal_level: 5
-steal_xp: 12
-steal_speed: 5
-guard_mob: guard
-```
-
-| Field | Description |
-| ------------- | ------------------------------------------------ |
-| `steal_table` | Drop table ID for loot when stealing |
-| `steal_level` | Required thieving level |
-| `steal_xp` | XP awarded per successful steal |
-| `steal_speed` | Ticks per steal attempt (base wait) |
-| `guard_mob` | Mob def ID that guards this object (watches it) |
-
-When `guard_mob` is set, a mob with that def ID in the same room watches the object
-on a tick-based cycle (8 ticks watching, 4 ticks looking away). While the guard is
-watching, steal success chance is halved and failures trigger a confrontation dialog.
-
-Use the `sneak` command to see guard watch state changes in real time.
-
----
-
-## Safespots
-
-Safespot objects provide cover that blocks melee attacks. Players use `hide <object>` to
-crouch behind them and attack with ranged or science weapons. Melee attacks force the player
-out of cover.
-
-```yaml
-id: rock_outcrop
-name: rock outcrop
-color: "248"
-hidden: true
-inroom_description: "A jagged rock outcrop juts from the floor."
-description: "A large, jagged rock formation providing natural cover."
-safespot:
- tier: 2
- max_block_size: large
- max_occupants: 3
- unsafe_chance: 0.008
- decay_ticks: 500
- decay_chance: 0.01
- respawn_on_hide: false
- respawn_ticks: 300
- levels:
- - message: "The rock formation stands solid."
- degrade_message: "The rock structure begins crumbling!"
- - message: "The rock outcrop is cracked and worn."
- degrade_message: "A few jagged bits are all that's left of the rock outcrop!"
- - message: "Only a few jagged rocks remain."
- degrade_message: "The rock outcrop crumbles to nothing!"
-```
-
-Safespot objects should be `hidden: true`. They never appear in room descriptions — players
-discover them through quest guidance, `inroom_description` text in the room's YAML, or by
-examining objects directly with `look <name>`.
-
-### SafespotConfig Fields
-
-| Field | Type | Default | Description |
-|---|---|---|---|
-| `tier` | int | 0 | Required safespot tier to use this object |
-| `max_block_size` | string | `""` (all) | Largest mob size blocked: small/medium/large/massive |
-| `max_occupants` | int | 0 | Max players that can hide behind this object (0 = unlimited) |
-| `unsafe_chance` | float64 | 0 | Per-tick chance (0.0-1.0) to be forced out of cover |
-| `decay_ticks` | float64 | 0 | Guaranteed ticks before object degrades one level |
-| `decay_chance` | float64 | 0 | Per-tick random chance (0.0-1.0) to degrade one level |
-| `respawn_on_hide` | bool | false | If true, hiding behind an empty safespot resets it to max level. Only triggers when no occupants are present. |
-| `respawn_ticks` | float64 | 0 | Ticks until a destroyed safespot respawns (0 = never respawns — object is deleted from the room) |
-| `levels` | []SafespotLevel | required | At least one level entry |
-
-### SafespotLevel Fields
-
-| Field | Type | Description |
-|---|---|---|
-| `message` | string | Shown to the player when the safespot is at this level |
-| `degrade_message` | string | Broadcast to the room when the safespot degrades FROM this level |
-
-Levels are ordered from highest to lowest. The first entry is the safespot's best state;
-the last entry is its weakest state before destruction. When the last level degrades,
-the safespot is destroyed.
-
-### Three Safespot Patterns
-
-The combination of `respawn_on_hide` and `respawn_ticks` creates three distinct use cases:
-
-**1. Standard Safespot (always available)**
-
-```yaml
-safespot:
- respawn_on_hide: true
- respawn_ticks: 0
- levels:
- - message: "You crouch behind the rock formation, using it as cover."
-```
-
-The safespot starts at full health each time a player hides behind it (first occupant only —
-subsequent players don't reset the level). Ideal for skilling areas and general exploration.
-Since `respawn_ticks: 0`, a destroyed safespot would be deleted, but with a single level and
-no decay, it never degrades. Simple and permanent.
-
-**2. Regenerating Safespot (timer-based respawn)**
-
-```yaml
-safespot:
- respawn_on_hide: false
- respawn_ticks: 300
- levels:
- - message: "The rock formation stands solid."
- degrade_message: "The rock structure begins crumbling!"
- - message: "The rock outcrop is cracked and worn."
- degrade_message: "A few jagged bits are all that's left!"
- - message: "Only a few jagged rocks remain."
- degrade_message: "The rock outcrop crumbles to nothing!"
-```
-
-Degradation persists between hides — a player who leaves and re-hides finds the
-safespot at its previous level. After total destruction, a timer (`respawn_ticks`)
-counts down, then the safespot reforms at full health. Suits areas with heavy use
-where a temporary respite is valuable.
-
-**3. Disposable Safespot (boss fight cover)**
-
-```yaml
-safespot:
- respawn_on_hide: false
- respawn_ticks: 0
- levels:
- - message: "The barricade offers solid cover."
- degrade_message: "The barricade splinters under the assault!"
- - message: "The barricade is splintering badly."
- degrade_message: "The barricade shatters completely!"
-```
-
-Degradation persists between hides. When the last level degrades, the safespot is
-**deleted from the room entirely** — it does not respawn. Perfect for boss encounters
-where a room script places temporary cover that the party consumes during the fight.
-Once destroyed, it's gone for good (until the boss room re-instantiates it).
-
-### Mob Size
-
-Mobs must have a `size` field for safespot blocking to work:
-
-```yaml
-# data/mobs/cow.yaml
-size: small
-
-# data/mobs/moss_giant.yaml
-size: large
-```
-
-Size ordering: `small` < `medium` < `large` < `massive`. Defaults to `medium` when absent.
-A safespot with `max_block_size: large` blocks mobs of size small, medium, and large,
-but not massive.
-
-### Progression
-
-Players gain safespot tier by completing quests and combat achievements, which set
-player flags via talk node actions:
-
-| Flag | Source | Tier bonus |
-|---|---|---|
-| `quest_animal_magnetism` | Quest completion | +1 |
-| `quest_dragon_slayer` | Quest completion | +1 |
-| `achieve_medium_combat` | Combat achievement | +1 |
-| `achieve_hard_combat` | Combat achievement | +2 |
-
-### Combat Integration
-
-- Melee mobs (attack_type: stab/slash/crush) cannot initiate aggro or land hits on
- safespotted players if the mob's size is within the safespot's `max_block_size`.
-- Ranged and science mobs (attack_type: ranged/science) ignore safespots entirely.
-- If a safespotted player attacks with melee, they automatically leave cover.
-- Hiding in combat takes 4 ticks; if the mob hits during this time, the hide fails.
-- Hiding out of combat takes 1 tick.
-
-### Option: safespot_alert
-
-Players can customize the message shown when forced out of a safespot:
-
- option safespot_alert "{196 bold}** DANGER **{/} Cover blown!"
-Default: `"{196 bold}** Your safespot has been compromised! **{/}"`
-
----
-
diff --git a/worldbuilding_guide/quests.md b/worldbuilding_guide/quests.md
deleted file mode 100644
index b5f18fa..0000000
--- a/worldbuilding_guide/quests.md
+++ /dev/null
@@ -1,103 +0,0 @@
-## Complete Quest Example: "Clear the Rats"
-
-### 1. Quest giver mob (`data/mobs/quest_giver.yaml`)
-```yaml
-id: "quest_giver"
-name: "Elder"
-unique: true
-protected: true
-talk:
- nodes:
- start:
- message: "\"Rats! Rats everywhere in the cellar. Clear them out and I'll reward you.\""
- options:
- - text: "\"I'll handle it.\""
- goto: accept_quest
- condition:
- player_flag: rat_quest
- not: true
- - text: "\"I killed the rats.\""
- goto: turn_in
- condition:
- player_flag: rat_quest
- value: started
- - text: "\"Goodbye.\""
- end: true
-
- accept_quest:
- message: "\"Good lad. The cellar is west of here. Come back when they're dead.\""
- action:
- set_player_flags:
- rat_quest: started
- options:
- - text: "\"On my way.\""
- end: true
-
- turn_in:
- message: "\"You did it! The village owes you a debt. Here — take this.\""
- action:
- give_item: rusty_sword
- set_player_flags:
- rat_quest: complete
- heal: 10
- options:
- - text: "\"Thanks!\""
- end: true
-attack: 1
-strength: 1
-defense: 1
-hp: 20
-speed: 5
-aggressive: false
-idle_descriptions:
- - "mutters about the rat infestation"
-```
-
-Talk configs are inline on the mob under the `talk:` key. No separate behavior file needed.
-
-### 2. Rat mobs (`data/mobs/rat.yaml`)
-```yaml
-id: "rat"
-name: "giant rat"
-attack: 2
-strength: 1
-defense: 1
-hp: 3
-speed: 4
-aggressive: true
-respawn_ticks: 60
-drops:
- remains: "rat bones"
-```
-
-### 3. Cellar room (`data/rooms/20.yaml`)
-```yaml
-id: 20
-name: "Cellar"
-description: "A damp, dark cellar. The floor scuttles with movement."
-exits:
- east: 1
-mobs:
- - "rat"
- - "rat"
- - "rat"
- - "rat"
- - "rat"
-```
-
-### 4. Room 1 with quest giver (`data/rooms/1.yaml`)
-```yaml
-id: 1
-name: "Town Square"
-description: "Cobblestone paths lead in all directions. The Elder stands near the fountain."
-exits:
- west: 20
- north: 2
-mobs:
- - "quest_giver"
-objects:
- - id: lumby_fountain
-```
-
----
-
diff --git a/worldbuilding_guide/recipes.md b/worldbuilding_guide/recipes.md
deleted file mode 100644
index 450ded9..0000000
--- a/worldbuilding_guide/recipes.md
+++ /dev/null
@@ -1,277 +0,0 @@
-# The House of Icarus - World Building Guide
-
-## Crafting
-
-Crafting information lives on the **output item's YAML file** via the `craft:` block. There is no separate recipe directory. To find out how to make `bronze_dagger`, open `data/items/equipment/bronze_dagger.yaml` and look for the `craft:` block.
-
-### 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) |
-| `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) |
-| `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) |
-| `fail_message` | string | Failure message (optional, empty = silent fail) |
-| `start_message`| string | Message when action begins (optional, see message defaults) |
-| `end_message` | string | Message when action completes (optional, see message defaults) |
-| `steps` | []CraftStep | Multi-step messages at tick intervals (optional)|
-| `success` | SuccessFormula | Optional skill check formula (see Behaviors) |
-
-The output is the item itself — no `output` field needed. The item ID IS the craft ID.
-
-### Message Variables
-
-All message fields (`message`, `fail_message`, `start_message`, `end_message`, and `steps[].message`) support variables that expand to colorized item names:
-
-| Variable | Expands to |
-| -------- | ----------------------------------------------- |
-| `%n` | Output item name (colored, e.g. "stim potion") |
-| `%i1` | 1st consume entry's matched item (colored) |
-| `%i2` | 2nd consume 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.
-
-Variables work alongside inline color tags (`{196}text{/}`) which are expanded after variable substitution.
-
-### Message Defaults
-
-If a message field is omitted from the YAML, the game uses a skill-level default based on the craft `type`:
-
-| Type | Default `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."` |
-| `smithing` | `"You smith a %n."` | `"You begin smithing %i1."` |
-| `crafting` | `"You craft a %n."` | `"You begin crafting %i1."` |
-| `fletching` | `"You fletch a %n."` | `"You begin fletching %i1."` |
-| `pharmacy` | `"You mix a %n."` | `"You start mixing %i1."` |
-| `construction` | `"You construct a %n."` | `"You begin constructing %i1."` |
-| `clean` | `"You clean the %i1."` | `"You begin cleaning herbs."` |
-| (unset) | `"You produce %n."` | `"You start <verb> %i1."` |
-
-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.
-
-### CraftStep — Multi-Step Messages
-
-Optional interim messages fired at specific tick offsets during the craft cycle. The `tick` is the number of ticks elapsed since the start of the cycle.
-
-```yaml
-craft:
- type: ""
- wait: 6
- consume:
- - items: [map_piece_1]
- quantity: 1
- - items: [map_piece_2]
- quantity: 1
- - items: [map_piece_3]
- quantity: 1
- steps:
- - tick: 1
- message: "You try to puzzle how the pieces fit together."
- - tick: 3
- message: "Aha, this edge lines up here!"
- message: "You assemble the map!"
-```
-
-### ConsumeEntry — Multi-Item Ingredient Slots
-
-Each consume entry defines an ingredient slot with multiple valid items. The first matching item found in the player's inventory is consumed.
-
-```yaml
-consume:
- - items: [item_id, alternative_id, ...]
- quantity: 1
- byproducts: [byproduct_for_item, byproduct_for_alt, ...]
-```
-
-`byproducts` is optional. When present, it matches the `items` list by index — consuming `items[0]` returns `byproducts[0]` to inventory. Use `""` for items with no byproduct:
-
-```yaml
-consume:
- - items: [bucket_of_water, vial_of_water]
- quantity: 1
- byproducts: [empty_bucket, ""] # bucket returns empty, vial is consumed entirely
- - items: [herb]
- quantity: 1 # no byproducts — herb is consumed entirely
-```
-
-### Skill-Based Production
-
-```yaml
-# data/items/consumables/stim_potion.yaml
-craft:
- type: pharmacy
- skill: pharmacy
- level: 3
- xp: 25
- wait: 4
- consume:
- - items: [guam_potion_unf]
- quantity: 1
- - items: [eye_of_newt]
- quantity: 1
- message: "You mix a %n." # %n expands to "stim potion" colored
-```
-
-### Station-Based Production
-
-```yaml
-# data/items/materials/bronze_bar.yaml
-craft:
- type: smelting
- skill: smithing
- level: 1
- xp: 6
- wait: 4
- station: [furnace]
- consume:
- - items: [copper_ore]
- quantity: 1
- - items: [tin_ore]
- quantity: 1
- message: "You smelt a %n." # default is "You remove a white hot %n!"
- # overridden here for simpler flavor
-```
-
-```yaml
-# data/items/equipment/bronze_dagger.yaml
-craft:
- type: smithing
- skill: smithing
- level: 1
- xp: 12
- wait: 4
- station: [anvil]
- consume:
- - items: [bronze_bar]
- quantity: 1
- # message omitted — uses default "You smith a %n."
-```
-
-For stackable outputs, use `output_qty`:
-
-```yaml
-# data/items/ammo/bronze_nails.yaml
-craft:
- type: smithing
- skill: smithing
- level: 4
- xp: 12
- wait: 4
- station: [anvil]
- consume:
- - items: [bronze_bar]
- quantity: 1
- output_qty: 15
- # message omitted — uses default "You smith a %n."
-```
-
-### Tool-Based Production
-
-```yaml
-# data/items/ammo/arrow_shafts.yaml
-craft:
- type: fletching
- level: 1
- xp: 5
- wait: 3
- tool: knife
- consume:
- - items: [logs, oak_logs, willow_logs]
- quantity: 1
- output_qty: 15
-```
-
-The `tool` field requires the player to have an item with that `tool_type` equipped or in inventory. The tool is NOT consumed.
-
-### Skill-Less Combinations (Item-on-Item)
-
-Omit `type` (or leave it empty) for combinations with no skill check, no XP, and 100% success:
-
-```yaml
-# data/items/consumables/bucket_of_water.yaml
-craft:
- wait: 0
- consume:
- - items: [vial_of_water, jug_of_water]
- quantity: 1
- byproducts: [empty_vial, empty_jug]
- - items: [empty_bucket]
- quantity: 1
- message: "You pour the %i1 into the %i2." # %i1 = water source, %i2 = bucket
-```
-
-### Multi-Piece Assembly (3+ items → 1)
-
-```yaml
-# data/items/quest/ancient_map.yaml
-craft:
- wait: 0
- consume:
- - items: [torn_page_1]
- quantity: 1
- - items: [torn_page_2]
- quantity: 1
- - items: [torn_page_3]
- quantity: 1
- steps:
- - tick: 1
- message: "You try to puzzle how the pieces fit together."
- - tick: 3
- message: "Aha, this edge lines up here!"
- message: "You assemble the %n."
-```
-
-### Clean Recipes
-
-Clean herb recipes use `type: 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
- level: 3
- xp: 3
- wait: 2
- consume:
- - items: [grimy_guam]
- quantity: 1
- # message omitted — uses default "You clean the %i1."
- # %i1 expands to the grimy herb name with its color
-```
-
-### Food/Healing Items
-
-Items with `heal_value` and `eat_message` can be consumed via the `eat` command.
-
-```yaml
-id: bread
-name: bread
-color: "222"
-description: "A fresh loaf of bread, still warm from the oven."
-value: 5
-heal_value: 5
-eat_message: "You eat the bread. Warm and satisfying."
-```
-
-### Architecture
-
-The `CraftIndex` (`internal/game/craft_index.go`) is built once at startup from all item YAMLs that have a `craft:` block. It provides `O(1)` lookups by type, input item, and station. All crafting commands query the CraftIndex — no runtime file scanning.
-
-**Indexes:**
-- `byType["pharmacy"]` → all pharmacy-craftable items (used by `mix`)
-- `byInput["guam"]` → all items that consume guam (used by `use` to find combinations)
-- `byStation["anvil"]` → all items craftable at an anvil (used by `use bar on anvil`)
-- `FindByTwoInputs(a, b)` → items consuming both inputs in different consume entries
diff --git a/worldbuilding_guide/rooms.md b/worldbuilding_guide/rooms.md
deleted file mode 100644
index 3d6db7d..0000000
--- a/worldbuilding_guide/rooms.md
+++ /dev/null
@@ -1,134 +0,0 @@
-## Rooms
-
-Minimal room:
-```yaml
-id: 1
-name: "Town Square"
-description: "Cobblestone paths lead in all directions. A fountain gurgles peacefully."
-exits:
- north: 2
- west: 7
- east: 3
-```
-
-### Inline Color Tags
-
-Room descriptions support inline color tags using `{spec}text{/}` syntax. Untagged text uses the `room_desc` color.
-
-```yaml
-description: "On the table lies a {182 bold}mysterious vase{/} with a rose in it."
-```
-
-Tag spec format: `{<0-255> [bold] [dim] [underline]}text{/}`
-
-Gradients: `{g:196,82}gradient text{/}`. Multi-stop: `{g:45,39,59}three stops{/}`.
-
-### Exits — simple vs conditional
-
-Simple exit — always passable:
-```yaml
-exits:
- north: 2
-```
-
-Conditional exit — blocked until a world flag is set:
-```yaml
-exits:
- north:
- room: 11
- condition:
- flag: gate_open
- value: true
- blocked_message: "A heavy iron gate blocks the way north."
-```
-
-Conditional exit — blocked unless the PLAYER has a flag (key, permission, quest state):
-```yaml
-exits:
- east:
- room: 12
- condition:
- player_flag: has_vault_key
- value: true
- blocked_message: "The vault door is locked. You need a key."
-```
-
-Conditional exit with compound condition — requires both a world flag AND a player flag:
-```yaml
-exits:
- north:
- room: 20
- condition:
- all_of:
- - flag: bridge_repaired
- value: true
- - player_flag: paid_toll
- value: true
- blocked_message: "The bridge is out, and the toll collector blocks the path."
-```
-
-### Item Spawns — ground items that respawn
-
-```yaml
-item_spawns:
- - id: bronze_pickaxe
- quantity: 1
- respawn_ticks: 30 # reappears 30 ticks (18 seconds) after being picked up
- - id: copper_ore
- quantity: 3
- respawn_ticks: 50
-```
-
-### Mobs — NPCs placed in the room
-
-Simple string (no wandering):
-```yaml
-mobs:
- - "newbie_trainer"
- - "man"
-```
-
-With wander config per-instance:
-```yaml
-mobs:
- - id: man
- wander_interval: 10 # attempts to wander every 10 ticks
- - id: man
- wander_interval: 15
- wander_rooms: [1, 4, 5] # optional — only exit to these rooms
-```
-
-Mob wander config lives in the room YAML, not in the mob definition. This keeps mobs generic
-so the same `man` can wander differently depending on where it's placed. Mobs wander through
-legal (unconditioned) room exits. If no legal exits exist, the mob stays still. Mobs with
-no `wander_interval` never wander.
-
-### Objects — interactive fixtures
-
-```yaml
-objects:
- - id: copper_rock # simple placement
- - id: copper_rock # second instance
- - id: fishing_spot
- wander_rooms: [7, 8, 9] # teleports between these rooms
- wander_interval: 12 # every 12 ticks
- - id: iron_gate # hidden object (see below)
-```
-
-### On-enter scripts — messages when a player arrives
-
-```yaml
-on_enter:
- - message: "The guard barks: \"State your business!\""
- condition:
- player_flag: talked_to_guard
- not: true # only first visit
-
- - message: "The guard nods. \"Back again?\""
- condition:
- player_flag: talked_to_guard
- value: true # subsequent visits
-```
-
----
-
diff --git a/worldbuilding_guide/search.md b/worldbuilding_guide/search.md
deleted file mode 100644
index e6e2a14..0000000
--- a/worldbuilding_guide/search.md
+++ /dev/null
@@ -1,15 +0,0 @@
-## The `search` Command
-
-Used to open searchable items in your inventory (bird's nests, etc.):
-```
-Usage: search <item>
-
-Example: search nest
- search birds nest
-```
-
-Searches your inventory for the named item. If found, removes it and rolls on a drop table.
-Currently only bird's nests are searchable.
-
----
-
diff --git a/worldbuilding_guide/state.md b/worldbuilding_guide/state.md
deleted file mode 100644
index 2eefcc4..0000000
--- a/worldbuilding_guide/state.md
+++ /dev/null
@@ -1,8 +0,0 @@
-## State: World vs Player
-
-**World flags** (`set_flags`, checked with `flag`) are shared by every player on the server. A door opened by one player is open for everyone. A lever pulled once changes the world for all.
-
-**Player flags** (`set_player_flags`, checked with `player_flag`) are per-character. Quest progress, "has read the sign," "paid the toll" — these are different for each player. Saved to the character YAML and persist across logins.
-
----
-
diff --git a/worldbuilding_guide/tips.md b/worldbuilding_guide/tips.md
deleted file mode 100644
index 307ea1e..0000000
--- a/worldbuilding_guide/tips.md
+++ /dev/null
@@ -1,21 +0,0 @@
-## Tips
-
-1. **Use player flags for quest progress, world flags for environmental state.** If a bridge is repaired, that's world state. If a player has read a sign, that's player state.
-
-2. **Conditions on enter scripts** make rooms feel alive. A guard who only barks the first time, a room that changes after a quest completes.
-
-3. **Hidden objects** keep room descriptions clean. Mention them in the room's description text instead of auto-listing them.
-
-4. **Drop tables** are shareable. The `gem_table` is used by copper rocks AND mob loot. Define once, reference everywhere.
-
-5. **Objects are for fixtures, mobs are for living things.** If it has HP and can die, it's a mob. If it's a rock, lever, door, or crafting station, it's an object. Both can have behaviors.
-
-6. **The `talk` field on mobs** lets you talk to them directly — `talk guard` finds the guard mob, no duplicate object entry needed.
-
-7. **Exits accept both `int` and `map` formats.** `north: 2` is shorthand for `north: {room: 2}`. Add `condition` and `blocked_message` only when needed. Mob room entries accept both `"man"` and `{id: man, ...}`.
-
-8. **Live editing works.** Room, item, mob, object, and behavior YAML files are read from disk on each access. Change a room description or dialog and it takes effect immediately — no restart needed.
-
-9. **Shared depletion vs per-drop depletion.** Use `deplete_timer` for trees — the timer counts down while being chopped and regens when left alone. Use `depletes: true` on individual drops for rocks — they deplete on first successful gather.
-
-10. **Mob wander config goes in the room YAML**, not the mob definition. This lets the same `man` wander differently in different rooms.
diff --git a/worldbuilding_guide/wandering_mobs.md b/worldbuilding_guide/wandering_mobs.md
deleted file mode 100644
index 8d49ed9..0000000
--- a/worldbuilding_guide/wandering_mobs.md
+++ /dev/null
@@ -1,20 +0,0 @@
-## Wandering Mobs
-
-Mob wandering is configured per-instance in the room YAML, not on the mob definition:
-```yaml
-# In a room:
-mobs:
- - id: man
- wander_interval: 10 # attempt to wander every 10 ticks
- - id: man
- wander_interval: 15
- wander_rooms: [5, 6, 7] # optional — restrict which rooms via exits
-```
-
-Mobs wander through legal (unconditioned) room exits. When the wander interval expires,
-the mob picks a random exit with no conditions and moves through it. If `wander_rooms`
-is set, only exits leading to those room IDs are legal. Mobs without `wander_interval`
-never wander. Mobs stop wandering while in combat. Dead mobs respawn at their home room.
-
----
-
diff --git a/worldbuilding_guide/wandering_objects.md b/worldbuilding_guide/wandering_objects.md
deleted file mode 100644
index f1f91c5..0000000
--- a/worldbuilding_guide/wandering_objects.md
+++ /dev/null
@@ -1,39 +0,0 @@
-## Wandering Objects
-
-Fishing spots that move between rooms:
-```yaml
-# data/objects/fishing_spot.yaml
-id: fishing_spot
-name: fishing spot
-gather:
- skill: fishing
- level: 1
- xp: 10
- base_wait: 4
- tools:
- - fishing_rod
- bait: fishing_bait
- success:
- base: 0.30
- per_level: 0.01
- cap: 0.90
- gather_message: "You cast your line into the water..."
- drops:
- - item_id: raw_trout
- weight: 100
- message: "You catch a raw trout!"
-```
-
-```yaml
-# In a room:
-objects:
- - id: fishing_spot
- wander_rooms: [7, 8, 9]
- wander_interval: 12
-```
-
-Objects teleport between rooms in their `wander_rooms` list. Players gathering from a
-wandering object are silently interrupted when it moves.
-
----
-