From 9d4b799db4868bcab291b83599ff088763cd4ed6 Mon Sep 17 00:00:00 2001 From: historia <[not public]> Date: Wed, 24 Jun 2026 20:58:25 -0400 Subject: feat: new type of non-violent 'combat': work --- worldbuilding_guide/bank.md | 68 ------ worldbuilding_guide/behaviors.md | 402 ------------------------------- worldbuilding_guide/conditions.md | 70 ------ worldbuilding_guide/construction.md | 223 ----------------- worldbuilding_guide/courses.md | 119 --------- worldbuilding_guide/doors.md | 97 -------- worldbuilding_guide/drops.md | 52 ---- worldbuilding_guide/hacking.md | 49 ---- worldbuilding_guide/hidden_objects.md | 40 --- worldbuilding_guide/index.md | 17 -- worldbuilding_guide/items.md | 190 --------------- worldbuilding_guide/mobs.md | 179 -------------- worldbuilding_guide/objects.md | 392 ------------------------------ worldbuilding_guide/quests.md | 103 -------- worldbuilding_guide/recipes.md | 277 --------------------- worldbuilding_guide/rooms.md | 134 ----------- worldbuilding_guide/search.md | 15 -- worldbuilding_guide/state.md | 8 - worldbuilding_guide/tips.md | 21 -- worldbuilding_guide/wandering_mobs.md | 20 -- worldbuilding_guide/wandering_objects.md | 39 --- 21 files changed, 2515 deletions(-) delete mode 100644 worldbuilding_guide/bank.md delete mode 100644 worldbuilding_guide/behaviors.md delete mode 100644 worldbuilding_guide/conditions.md delete mode 100644 worldbuilding_guide/construction.md delete mode 100644 worldbuilding_guide/courses.md delete mode 100644 worldbuilding_guide/doors.md delete mode 100644 worldbuilding_guide/drops.md delete mode 100644 worldbuilding_guide/hacking.md delete mode 100644 worldbuilding_guide/hidden_objects.md delete mode 100644 worldbuilding_guide/index.md delete mode 100644 worldbuilding_guide/items.md delete mode 100644 worldbuilding_guide/mobs.md delete mode 100644 worldbuilding_guide/objects.md delete mode 100644 worldbuilding_guide/quests.md delete mode 100644 worldbuilding_guide/recipes.md delete mode 100644 worldbuilding_guide/rooms.md delete mode 100644 worldbuilding_guide/search.md delete mode 100644 worldbuilding_guide/state.md delete mode 100644 worldbuilding_guide/tips.md delete mode 100644 worldbuilding_guide/wandering_mobs.md delete mode 100644 worldbuilding_guide/wandering_objects.md (limited to 'worldbuilding_guide') 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 ` | Move item from inventory to bank | -| `deposit all` | Deposit entire inventory | -| `withdraw ` | 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 ` | Build a specific item | -| `construct ` | 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 ` (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/.yaml` first, then falls back to `data/rooms/player_housing/.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/.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_`). 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_.yaml` -2. Add an entry to `terminalDefs` in `internal/game/hacking.go` -3. Optionally create a new minigame implementation in `internal/game/hacking_.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 ` (name matching works even for hidden objects) -- Using `look ` 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/.yaml` | -| An item (sword, ore, key) | `data/items/.yaml` | -| A mob (NPC, monster) | `data/mobs/.yaml` | -| An interactive object (rock, lever, door) | `data/objects/.yaml` | -| A shared drop table | `data/drops/.yaml` | -| A crafting recipe | In the output item's YAML under a `craft:` block | -| A help topic | `data/help/.yaml` | -| A science module | `data/modules/.yaml` | -| An agility course | `data/courses/.yaml` | -| A player house | `data/rooms/player_housing/.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 on `) | -| `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 ` 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 `. - -### 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 %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 - -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. - ---- - -- cgit v1.2.3