## 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. The examples below are object/mob files; remember **the filename is the ID** — don't include an `id:` field (see `objects.md` / `mobs.md`). ### Gather (mining, fishing, woodcutting) Mining — per-drop depletion on a rock object: ```yaml 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 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 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 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 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 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 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 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 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 ``` ---