From c55d0e4150b23f2c5c9f96bbc3d4dc2fc6dbaa36 Mon Sep 17 00:00:00 2001 From: historia <[not public]> Date: Thu, 25 Jun 2026 19:37:20 -0400 Subject: feat: yaml conversation trees more robust --- building_guide/behaviors.md | 170 +++++++++++++++------ building_guide/construction.md | 2 - building_guide/mobs.md | 39 ++++- building_guide/objects.md | 15 +- building_guide/quests.md | 3 - data/mobs/ancient_construct.yaml | 47 ------ data/mobs/bandit.yaml | 38 ----- data/mobs/bioengineer.yaml | 44 ------ data/mobs/client.yaml | 219 ---------------------------- data/mobs/corrupted_scientist.yaml | 43 ------ data/mobs/cow.yaml | 28 ---- data/mobs/crawler.yaml | 32 ---- data/mobs/drone.yaml | 32 ---- data/mobs/elite_synth.yaml | 43 ------ data/mobs/enforcer_bot.yaml | 42 ------ data/mobs/estate_broker.yaml | 54 ------- data/mobs/examples/ancient_construct.yaml | 47 ++++++ data/mobs/examples/bandit.yaml | 38 +++++ data/mobs/examples/bioengineer.yaml | 44 ++++++ data/mobs/examples/client.yaml | 214 +++++++++++++++++++++++++++ data/mobs/examples/corrupted_scientist.yaml | 43 ++++++ data/mobs/examples/cow.yaml | 28 ++++ data/mobs/examples/crawler.yaml | 32 ++++ data/mobs/examples/drone.yaml | 32 ++++ data/mobs/examples/elite_synth.yaml | 43 ++++++ data/mobs/examples/enforcer_bot.yaml | 42 ++++++ data/mobs/examples/estate_broker.yaml | 55 +++++++ data/mobs/examples/farmer.yaml | 44 ++++++ data/mobs/examples/feral_cyborg.yaml | 38 +++++ data/mobs/examples/general_store_clerk.yaml | 70 +++++++++ data/mobs/examples/ghoul.yaml | 38 +++++ data/mobs/examples/goblin.yaml | 32 ++++ data/mobs/examples/greater_drone.yaml | 33 +++++ data/mobs/examples/guard.yaml | 71 +++++++++ data/mobs/examples/heavy_mech.yaml | 42 ++++++ data/mobs/examples/iron_sentinel.yaml | 31 ++++ data/mobs/examples/lesser_drone.yaml | 32 ++++ data/mobs/examples/man.yaml | 48 ++++++ data/mobs/examples/molten_elemental.yaml | 42 ++++++ data/mobs/examples/moss_giant.yaml | 32 ++++ data/mobs/examples/mutant_rat.yaml | 39 +++++ data/mobs/examples/newbie_trainer.yaml | 25 ++++ data/mobs/examples/phantom.yaml | 32 ++++ data/mobs/examples/plasma_wraith.yaml | 43 ++++++ data/mobs/examples/psionic_entity.yaml | 46 ++++++ data/mobs/examples/rat.yaml | 22 +++ data/mobs/examples/sawmill_operator.yaml | 50 +++++++ data/mobs/examples/scrap_bot.yaml | 39 +++++ data/mobs/examples/security_turret.yaml | 41 ++++++ data/mobs/examples/skeleton.yaml | 31 ++++ data/mobs/examples/slug.yaml | 27 ++++ data/mobs/examples/solar_panel_frame.yaml | 33 +++++ data/mobs/examples/tanner.yaml | 65 +++++++++ data/mobs/examples/titan_sentinel.yaml | 41 ++++++ data/mobs/examples/veteran_merc.yaml | 42 ++++++ data/mobs/examples/void_reaper.yaml | 52 +++++++ data/mobs/examples/war_drone.yaml | 42 ++++++ data/mobs/examples/weapons_smith.yaml | 64 ++++++++ data/mobs/examples/zombie.yaml | 33 +++++ data/mobs/farmer.yaml | 44 ------ data/mobs/feral_cyborg.yaml | 38 ----- data/mobs/flight_attendant.yaml | 32 ++++ data/mobs/general_store_clerk.yaml | 71 --------- data/mobs/ghoul.yaml | 38 ----- data/mobs/goblin.yaml | 32 ---- data/mobs/greater_drone.yaml | 33 ----- data/mobs/guard.yaml | 76 ---------- data/mobs/heavy_mech.yaml | 42 ------ data/mobs/iron_sentinel.yaml | 31 ---- data/mobs/lesser_drone.yaml | 32 ---- data/mobs/man.yaml | 48 ------ data/mobs/molten_elemental.yaml | 42 ------ data/mobs/moss_giant.yaml | 32 ---- data/mobs/mutant_rat.yaml | 39 ----- data/mobs/newbie_trainer.yaml | 25 ---- data/mobs/phantom.yaml | 32 ---- data/mobs/plasma_wraith.yaml | 43 ------ data/mobs/psionic_entity.yaml | 46 ------ data/mobs/rat.yaml | 22 --- data/mobs/sawmill_operator.yaml | 49 ------- data/mobs/scrap_bot.yaml | 39 ----- data/mobs/security_turret.yaml | 41 ------ data/mobs/skeleton.yaml | 31 ---- data/mobs/slug.yaml | 27 ---- data/mobs/solar_panel_frame.yaml | 33 ----- data/mobs/tanner.yaml | 68 --------- data/mobs/titan_sentinel.yaml | 41 ------ data/mobs/veteran_merc.yaml | 42 ------ data/mobs/void_reaper.yaml | 52 ------- data/mobs/war_drone.yaml | 42 ------ data/mobs/weapons_smith.yaml | 65 --------- data/mobs/zombie.yaml | 33 ----- data/objects/netrunner.yaml | 18 +-- data/objects/tool_shed.yaml | 3 +- data/objects/unique/1001_sign.yaml | 6 +- data/rooms/intro/1001.yaml | 11 +- internal/behavior/behavior.go | 5 +- internal/behavior/types.go | 28 +++- internal/game/act_steal.go | 14 +- internal/game/act_talk.go | 119 ++++++++++----- internal/game/cmd_shop.go | 42 +++--- internal/game/look_entities.go | 11 +- internal/game/look_target.go | 49 ++++--- internal/object/object.go | 1 + internal/validate/checks.go | 27 ++++ internal/world/mob.go | 10 +- 106 files changed, 2386 insertions(+), 2108 deletions(-) delete mode 100644 data/mobs/ancient_construct.yaml delete mode 100644 data/mobs/bandit.yaml delete mode 100644 data/mobs/bioengineer.yaml delete mode 100644 data/mobs/client.yaml delete mode 100644 data/mobs/corrupted_scientist.yaml delete mode 100644 data/mobs/cow.yaml delete mode 100644 data/mobs/crawler.yaml delete mode 100644 data/mobs/drone.yaml delete mode 100644 data/mobs/elite_synth.yaml delete mode 100644 data/mobs/enforcer_bot.yaml delete mode 100644 data/mobs/estate_broker.yaml create mode 100644 data/mobs/examples/ancient_construct.yaml create mode 100644 data/mobs/examples/bandit.yaml create mode 100644 data/mobs/examples/bioengineer.yaml create mode 100644 data/mobs/examples/client.yaml create mode 100644 data/mobs/examples/corrupted_scientist.yaml create mode 100644 data/mobs/examples/cow.yaml create mode 100644 data/mobs/examples/crawler.yaml create mode 100644 data/mobs/examples/drone.yaml create mode 100644 data/mobs/examples/elite_synth.yaml create mode 100644 data/mobs/examples/enforcer_bot.yaml create mode 100644 data/mobs/examples/estate_broker.yaml create mode 100644 data/mobs/examples/farmer.yaml create mode 100644 data/mobs/examples/feral_cyborg.yaml create mode 100644 data/mobs/examples/general_store_clerk.yaml create mode 100644 data/mobs/examples/ghoul.yaml create mode 100644 data/mobs/examples/goblin.yaml create mode 100644 data/mobs/examples/greater_drone.yaml create mode 100644 data/mobs/examples/guard.yaml create mode 100644 data/mobs/examples/heavy_mech.yaml create mode 100644 data/mobs/examples/iron_sentinel.yaml create mode 100644 data/mobs/examples/lesser_drone.yaml create mode 100644 data/mobs/examples/man.yaml create mode 100644 data/mobs/examples/molten_elemental.yaml create mode 100644 data/mobs/examples/moss_giant.yaml create mode 100644 data/mobs/examples/mutant_rat.yaml create mode 100644 data/mobs/examples/newbie_trainer.yaml create mode 100644 data/mobs/examples/phantom.yaml create mode 100644 data/mobs/examples/plasma_wraith.yaml create mode 100644 data/mobs/examples/psionic_entity.yaml create mode 100644 data/mobs/examples/rat.yaml create mode 100644 data/mobs/examples/sawmill_operator.yaml create mode 100644 data/mobs/examples/scrap_bot.yaml create mode 100644 data/mobs/examples/security_turret.yaml create mode 100644 data/mobs/examples/skeleton.yaml create mode 100644 data/mobs/examples/slug.yaml create mode 100644 data/mobs/examples/solar_panel_frame.yaml create mode 100644 data/mobs/examples/tanner.yaml create mode 100644 data/mobs/examples/titan_sentinel.yaml create mode 100644 data/mobs/examples/veteran_merc.yaml create mode 100644 data/mobs/examples/void_reaper.yaml create mode 100644 data/mobs/examples/war_drone.yaml create mode 100644 data/mobs/examples/weapons_smith.yaml create mode 100644 data/mobs/examples/zombie.yaml delete mode 100644 data/mobs/farmer.yaml delete mode 100644 data/mobs/feral_cyborg.yaml create mode 100644 data/mobs/flight_attendant.yaml delete mode 100644 data/mobs/general_store_clerk.yaml delete mode 100644 data/mobs/ghoul.yaml delete mode 100644 data/mobs/goblin.yaml delete mode 100644 data/mobs/greater_drone.yaml delete mode 100644 data/mobs/guard.yaml delete mode 100644 data/mobs/heavy_mech.yaml delete mode 100644 data/mobs/iron_sentinel.yaml delete mode 100644 data/mobs/lesser_drone.yaml delete mode 100644 data/mobs/man.yaml delete mode 100644 data/mobs/molten_elemental.yaml delete mode 100644 data/mobs/moss_giant.yaml delete mode 100644 data/mobs/mutant_rat.yaml delete mode 100644 data/mobs/newbie_trainer.yaml delete mode 100644 data/mobs/phantom.yaml delete mode 100644 data/mobs/plasma_wraith.yaml delete mode 100644 data/mobs/psionic_entity.yaml delete mode 100644 data/mobs/rat.yaml delete mode 100644 data/mobs/sawmill_operator.yaml delete mode 100644 data/mobs/scrap_bot.yaml delete mode 100644 data/mobs/security_turret.yaml delete mode 100644 data/mobs/skeleton.yaml delete mode 100644 data/mobs/slug.yaml delete mode 100644 data/mobs/solar_panel_frame.yaml delete mode 100644 data/mobs/tanner.yaml delete mode 100644 data/mobs/titan_sentinel.yaml delete mode 100644 data/mobs/veteran_merc.yaml delete mode 100644 data/mobs/void_reaper.yaml delete mode 100644 data/mobs/war_drone.yaml delete mode 100644 data/mobs/weapons_smith.yaml delete mode 100644 data/mobs/zombie.yaml diff --git a/building_guide/behaviors.md b/building_guide/behaviors.md index 438e859..a2c1f89 100644 --- a/building_guide/behaviors.md +++ b/building_guide/behaviors.md @@ -3,7 +3,7 @@ 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`). +The examples below are object/mob files; remember the filename is the ID for these. ### Gather (mining, fishing, woodcutting) @@ -183,15 +183,16 @@ 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: +Talk configs go under the `talk:` key on objects or mobs. A conversation is a set of named +**nodes**, each with a message, optional action, optional auto-advance target, and choices +for the player. ```yaml name: Guard talk: nodes: start: - message: "\"Halt! This area is restricted.\"" + message: "\"Halt! This area is restricted.\" The guard eyes you suspiciously." options: - text: "\"What's behind that gate?\"" goto: about_gate @@ -205,16 +206,15 @@ talk: player_flag: got_pass value: true - text: "\"Goodbye.\"" - end: true + # no goto = end conversation about_gate: - message: "\"Bring me some copper ore and I'll stamp you a pass.\"" + message: "\"Supplies. Weapons.\" He shifts his weight. \"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: @@ -229,40 +229,57 @@ talk: got_pass: true options: - text: "\"Thanks.\"" - end: true has_pass: - message: "\"Alright, I'll open the gate for you.\"" + message: "\"Alright, I'll open the gate.\"" action: set_flags: gate_open: true options: - text: "\"Thanks.\"" - end: true ``` +#### TalkNode fields + +| Field | Type | Description | +|---|---|---| +| `message` | string or list | NPC dialogue. May be a single string or a list of strings (pick one at random). | +| `action` | NodeAction | Fires when the node is entered (give items, set flags, etc). | +| `options` | []TalkOption | Player choices. If empty and `next` is set, auto-advances. | +| `next` | string | Node ID to auto-advance to when there are no visible options. | + +#### TalkOption fields + +| Field | Type | Description | +|---|---|---| +| `text` | string | Player-facing choice text. | +| `goto` | string | Node ID to navigate to if this choice is selected. Omit to end the conversation. | +| `condition` | Condition | Only show this option if the condition passes. | +| `action` | NodeAction | Fires when this option is selected, BEFORE navigating to `goto`. | + #### 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: +| `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 based on 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 `assassin_reputation` flag before other actions. | +| `sawmill` | Opens sawmill plank conversion interface. | +| `aps_node` | Marks this room's APS node as unlocked. | + +All fields in a single action are processed together — give an item, take an item, set flags, +and heal in one node. + +Example — quest completion with multiple actions: ```yaml action: take_item: dragon_head @@ -274,10 +291,85 @@ action: teleport: 1 ``` +#### Option-level actions + +Actions can be placed directly on options. The action fires when the player selects that +choice, BEFORE navigating to `goto`. This eliminates needing a separate "action node" for +simple transactions: + +```yaml +nodes: + start: + message: "Welcome! Houses are 10 credits. Interested?" + options: + - text: "Yes, I'll buy one." + action: + cost: 10 + set_player_flags: + owns_house: true + goto: purchased + condition: + player_flag: owns_house + not: true + - text: "No thanks." + purchased: + message: "Excellent! The plot is yours." + options: + - text: "Thanks!" + goto: start +``` + +If an option has both an `action` and a `goto`, the action runs first, then the player +navigates to the target node (which may also have its own action, fired on entry). + +#### Randomized messages + +`message` accepts either a plain string or a list. A list picks one entry at random each +time the node is visited: + +```yaml +nodes: + greeting: + message: + - "\"Hello, traveller.\"" + - "\"Ah, you again.\"" + - "\"A visitor! Pull up a chair.\"" + - "\"Back so soon?\"" + options: + - text: "\"Hello.\"" +``` + +#### Linear auto-advance + +When a node has no options (or all its options are hidden by conditions) and `next` is set, +the conversation automatically advances to the target node. This creates dialogue chains +without prompting the player: + +```yaml +nodes: + monologue_1: + message: "The elder clears his throat and begins..." + next: monologue_2 + monologue_2: + message: "\"Long ago, before the asteroid was settled...\"" + next: monologue_3 + monologue_3: + message: "\"...a great darkness fell upon these halls.\" He pauses." + next: choice_point + choice_point: + message: "\"Do you understand the weight of what I'm telling you?\"" + options: + - text: "\"I think so.\"" + - text: "\"Not really.\"" +``` + +If a node has both `next` and options, the options take priority — `next` is only used +when no options are visible. A node with a shop action ignores `next` entirely. + #### 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: +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: @@ -294,14 +386,11 @@ action: | 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. +| `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). | Full example — General Store: ```yaml @@ -314,7 +403,6 @@ talk: - text: "\"I'd like to browse.\"" goto: shop - text: "\"Goodbye.\"" - end: true shop: message: "\"Take your time.\"" action: @@ -332,8 +420,8 @@ talk: 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. +When the player leaves the shop, the current node's options are shown (or auto-advance +fires if no options are visible). Use `goto: start` to loop back to the main greeting. ### Object Interactions (levers, switches, gates) diff --git a/building_guide/construction.md b/building_guide/construction.md index 81e4249..40e4b9f 100644 --- a/building_guide/construction.md +++ b/building_guide/construction.md @@ -129,7 +129,6 @@ talk: - text: "\"How much?\"" goto: offer - text: "\"No thanks.\"" - end: true offer: message: "\"10 credits for a plot.\"" action: @@ -138,7 +137,6 @@ talk: owns_house_local_neighborhood: "local_neighborhood" options: - text: "\"Deal!\"" - end: true unique: true ``` diff --git a/building_guide/mobs.md b/building_guide/mobs.md index d10f685..32ee408 100644 --- a/building_guide/mobs.md +++ b/building_guide/mobs.md @@ -77,18 +77,46 @@ ranged_defense: 3 ### Protected/Unique Mobs -Mob with talk behavior — can be talked to via `talk:` inline config: +Protected mobs cannot be attacked. All combat and stat fields (`attack`, `strength`, +`defense`, `hp`, `speed`, `attack_type`, `attack_bonus`, `strength_bonus`, +`*_defense`, `weakness`, `size`, `drops`, `aggressive`, `respawn_ticks`) are +**optional for protected mobs** — omit them entirely. Protected mobs don't show +a combat level in room listings or when examined. + +Minimal protected mob (shopkeeper, quest giver, NPC): +```yaml +name: flight attendant +description: A smiling flight attendant in a crisp uniform. +unique: true # displays as "Flight attendant" not "a flight attendant" +protected: true # cannot be attacked, combat stats are optional +idle_descriptions: + - adjusts her name badge + - smiles politely at passengers +talk: # inline talk config + nodes: + start: + message: "\"Welcome aboard!\"" + options: + - text: "\"What should I do?\"" + goto: check_sign + - text: "\"Goodbye.\"" + check_sign: + message: "\"Review the safety information.\"" + options: + - text: "\"Will do.\"" +``` + +Protected mob with combat stats (for internal testing or debug purposes): ```yaml name: "Guard" -talk: # inline talk config (no separate behavior file) +unique: true +protected: true +talk: 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 @@ -106,7 +134,6 @@ 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 diff --git a/building_guide/objects.md b/building_guide/objects.md index 110eb56..87b9710 100644 --- a/building_guide/objects.md +++ b/building_guide/objects.md @@ -120,9 +120,22 @@ talk: - text: "\"What do you have?\"" goto: shop - text: "\"Goodbye.\"" - end: true ``` +On-look action (runs when a player examines an object with `look `): +```yaml +name: sign +aliases: [notice, board] +description: "A wooden signpost with faded writing." +on_look: + set_player_flags: + read_sign: true +``` +`on_look` fires the action AFTER showing the object's description. It uses the same +`NodeAction` type as talk nodes — supports `set_player_flags`, `set_flags`, +`give_item`, `take_item`, `teleport`, `heal`, `cost`, and everything else in the +[node action reference](behaviors.md#node-action-reference). + 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. diff --git a/building_guide/quests.md b/building_guide/quests.md index a764f8e..b9556dc 100644 --- a/building_guide/quests.md +++ b/building_guide/quests.md @@ -23,7 +23,6 @@ talk: 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.\"" @@ -32,7 +31,6 @@ talk: 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.\"" @@ -43,7 +41,6 @@ talk: heal: 10 options: - text: "\"Thanks!\"" - end: true attack: 1 strength: 1 defense: 1 diff --git a/data/mobs/ancient_construct.yaml b/data/mobs/ancient_construct.yaml deleted file mode 100644 index 190e8c2..0000000 --- a/data/mobs/ancient_construct.yaml +++ /dev/null @@ -1,47 +0,0 @@ -name: ancient construct -description: "An impossibly old machine from before the regression, still operational. Its design is alien even by modern standards, covered in glowing runes that predate recorded history." -attack: 58 -strength: 62 -defense: 66 -hp: 152 -speed: 4 -aggressive: true -respawn_ticks: 150 -attack_type: slash -attack_bonus: 55 -strength_bonus: 55 -stab_defense: 95 -slash_defense: 100 -crush_defense: 85 -science_defense: -40 -ranged_defense: 70 -weakness: chaos -idle_descriptions: - - "etches glowing symbols into the air" - - "reconfigures its form with clicking sounds" - - "projects a holographic star map" - - "emits a resonant chime that shakes the walls" -combat_descriptions: - - "slices at %s with a blade of pure light" - - "unleashes a cascade of ancient energy at %s" - - "teleports behind %s and strikes" -size: massive -drops: - remains: scrap - loot: - - item_id: credits - weight: 40 - quantity: 10000 - - item_id: bloodjunk - weight: 20 - quantity: 8 - - item_id: deathjunk - weight: 15 - quantity: 8 - - table: gem_table - weight: 10 - - item_id: uncut_diamond - weight: 5 - quantity: 3 - - table: herb_table_high - weight: 10 diff --git a/data/mobs/bandit.yaml b/data/mobs/bandit.yaml deleted file mode 100644 index 51e4b8e..0000000 --- a/data/mobs/bandit.yaml +++ /dev/null @@ -1,38 +0,0 @@ -name: bandit -description: "A scrappy outlaw with a cybernetic arm and patched armor. He eyes you with predatory intent." -attack: 10 -strength: 12 -defense: 12 -hp: 28 -speed: 5 -aggressive: true -respawn_ticks: 30 -attack_type: slash -attack_bonus: 5 -strength_bonus: 5 -stab_defense: 10 -slash_defense: 15 -crush_defense: 8 -science_defense: -5 -ranged_defense: 12 -idle_descriptions: - - "scans the horizon for targets" - - "wipes a blade on his sleeve" - - "spits on the ground" - - "adjusts a cybernetic knuckle" -combat_descriptions: - - "slashes at %s with a serrated blade" - - "delivers a crushing punch with a cybernetic fist" - - "lunges at %s with a battle cry" -size: medium -drops: - remains: bones - loot: - - item_id: credits - weight: 70 - quantity: 30 - - item_id: credits - weight: 20 - quantity: 80 - - table: herb_table_low - weight: 10 diff --git a/data/mobs/bioengineer.yaml b/data/mobs/bioengineer.yaml deleted file mode 100644 index 4761991..0000000 --- a/data/mobs/bioengineer.yaml +++ /dev/null @@ -1,44 +0,0 @@ -name: Bioengineer -description: "A lab-coated scientist carrying a satchel of genetically modified seeds. Her pockets are stuffed with rare specimens." -combat_descriptions: - - "jabs a syringe at %s" - - "is being overpowered by %s" - - "fights desperately against %s" -idle_descriptions: - - "scribbles notes on a clipboard" - - "carefully inspects a vial of green liquid" - - "adjusts her safety goggles" - - "mutters about gene splicing yields" -attack: 6 -strength: 4 -defense: 5 -hp: 25 -speed: 5 -aggressive: false -respawn_ticks: 50 -attack_type: crush -stab_defense: 0 -slash_defense: 0 -crush_defense: 0 -science_defense: 0 -ranged_defense: 0 -steal_table: bioengineer_steal -steal_level: 38 -steal_xp: 45 -steal_speed: 4 -size: small -drops: - remains: "bones" - loot: - - item_id: "sweetcorn_seed" - weight: 30 - quantity: 2 - - item_id: "strawberry_seed" - weight: 25 - quantity: 1 - - item_id: "watermelon_seed" - weight: 15 - quantity: 1 - - item_id: "ranarr_seed" - weight: 5 - quantity: 1 \ No newline at end of file diff --git a/data/mobs/client.yaml b/data/mobs/client.yaml deleted file mode 100644 index 678ba41..0000000 --- a/data/mobs/client.yaml +++ /dev/null @@ -1,219 +0,0 @@ -aggressive: false -attack: 1 -defense: 1 -description: A shadowy figure in a dark coat. They speak in clipped, measured tones and seem to know everything about every creature in the sector. -hp: 100 -idle_descriptions: - - reviews a holographic dossier - - marks a location on a worn star chart - - flips a credit chit between their fingers - - mutters coordinates under their breath - - glances at you appraisingly - - taps a data pad with a stylus -name: The Client -protected: true -respawn_ticks: 30 -speed: 5 -strength: 1 -talk: - nodes: - assign_task: - action: - assign_task: true - message: '"Let me check what''s available..." The Client scrolls through their data pad.' - options: - - end: true - text: '"Understood."' - - goto: start - text: '"What else do you have?"' - buy_acid: - action: - cost: 10 - give_item: acid_vial - message: '"Handle with care." The Client passes you a vial of corrosive acid.' - options: - - condition: - min_credits: 10 - goto: buy_acid - text: '"Buy more."' - - goto: supplies - text: '"Thanks."' - buy_auto_acid: - action: - reputation_cost: 200 - set_player_flags: - assassin_unlocked_auto_acid_vial: true - message: '"Auto-acid purchased. Acid vials will no longer be consumed."' - options: - - goto: rep_shop - text: '"Thanks."' - buy_auto_salt: - action: - reputation_cost: 200 - set_player_flags: - assassin_unlocked_auto_salt: true - message: '"Auto-salt purchased. You''ll no longer consume salt on finishing blows."' - options: - - goto: rep_shop - text: '"Thanks."' - buy_extend_unlock: - action: - reputation_cost: 100 - set_player_flags: - assassin_unlocked_extend: true - message: '"You can now extend tasks via our conversation."' - options: - - goto: rep_shop - text: '"Thanks."' - buy_gloves: - action: - cost: 50 - give_item: insulated_gloves - message: '"These''ll keep the current from frying your hands." The Client tosses you a pair of thick rubber gloves.' - options: - - goto: supplies - text: '"Thanks."' - buy_salt: - action: - cost: 5 - give_item: salt - message: '"Here you go." The Client slides a packet of salt across the table.' - options: - - condition: - min_credits: 5 - goto: buy_salt - text: '"Buy more."' - - goto: supplies - text: '"Thanks."' - buy_superiors: - action: - reputation_cost: 300 - set_player_flags: - assassin_unlocked_superiors: true - message: '"Superior encounters unlocked. Watch yourself out there."' - options: - - goto: rep_shop - text: '"Thanks."' - buy_visor: - action: - cost: 75 - give_item: spectral_visor - message: '"Spectral frequency filter. Makes the invisible visible — and keeps their attacks from scrambling your brain."' - options: - - goto: supplies - text: '"Thanks."' - current_task: - message: '"Let me check your file." The Client pulls up your record.' - options: - - end: true - text: '"Okay."' - extend_confirm: - message: '"Extending your task costs 30 Reputation and adds more kills. Want to proceed?"' - options: - - goto: extend_done - text: '"Yes, extend it."' - - goto: start - text: '"Never mind."' - extend_done: - action: - extend_task: true - message: '"Done. I''ve added more targets to your contract."' - options: - - end: true - text: '"Thanks."' - rep_shop: - message: '"Here''s what I''ve got. All purchases are permanent."' - options: - - condition: - not: true - player_flag: assassin_unlocked_auto_salt - goto: buy_auto_salt - text: '"Auto-finish: Salt (200 Rep) - Never consume salt on finishing blows."' - - condition: - not: true - player_flag: assassin_unlocked_auto_acid_vial - goto: buy_auto_acid - text: '"Auto-finish: Acid Vial (200 Rep) - Never consume acid vials on finishing blows."' - - condition: - not: true - player_flag: assassin_unlocked_superiors - goto: buy_superiors - text: '"Unlock Superior Mobs (300 Rep) - Rare superior variants may spawn."' - - condition: - not: true - player_flag: assassin_unlocked_extend - goto: buy_extend_unlock - text: '"Unlock Extended Tasks (100 Rep) - Allows extending tasks."' - - goto: start - text: '"Back."' - skip_confirm: - message: '"Skipping a task costs 30 Reputation and resets your streak. Are you sure?"' - options: - - goto: skip_done - text: '"Yes, skip it."' - - goto: start - text: '"Never mind."' - skip_done: - action: - skip_task: true - message: '"Task cancelled. Your streak has been reset."' - options: - - goto: assign_task - text: '"Give me a new one."' - - end: true - text: '"Goodbye."' - start: - message: The Client looks up from their data pad. "What do you need?" - options: - - condition: - not: true - player_flag: assassin_task_mob - goto: assign_task - text: '"I need a job."' - - condition: - not: false - player_flag: assassin_task_mob - goto: current_task - text: '"What''s my current task?"' - - condition: - not: false - player_flag: assassin_task_mob - goto: skip_confirm - text: '"I want to skip my task."' - - condition: - all_of: - - not: false - player_flag: assassin_task_mob - - player_flag: assassin_unlocked_extend - value: true - goto: extend_confirm - text: '"I want to extend my task."' - - goto: rep_shop - text: '"I''d like to browse the Reputation Shop."' - - goto: supplies - text: '"I need supplies."' - - end: true - text: '"Goodbye."' - supplies: - message: '"I stock everything you need for the job. Cheap, too."' - options: - - condition: - min_credits: 5 - goto: buy_salt - text: '"Buy salt (5 credits each)."' - - condition: - min_credits: 10 - goto: buy_acid - text: '"Buy acid vial (10 credits each)."' - - condition: - min_credits: 50 - goto: buy_gloves - text: '"Buy insulated gloves (50 credits)."' - - condition: - min_credits: 75 - goto: buy_visor - text: '"Buy spectral visor (75 credits)."' - - goto: start - text: '"Back."' -unique: true -size: small diff --git a/data/mobs/corrupted_scientist.yaml b/data/mobs/corrupted_scientist.yaml deleted file mode 100644 index 2083c03..0000000 --- a/data/mobs/corrupted_scientist.yaml +++ /dev/null @@ -1,43 +0,0 @@ -name: corrupted scientist -description: "A researcher whose mind was consumed by their own experiments. Energy crackles around their fingertips and their lab coat is singed and tattered." -attack: 1 -strength: 1 -defense: 18 -hp: 40 -science: 50 -speed: 5 -aggressive: true -respawn_ticks: 45 -attack_type: science -attack_bonus: 0 -strength_bonus: 0 -stab_defense: 25 -slash_defense: 25 -crush_defense: 20 -science_defense: 35 -ranged_defense: -5 -weakness: eco -idle_descriptions: - - "mutters incomprehensible formulas" - - "energy arcs between their fingers" - - "scribbles equations on the wall in soot" - - "stares at their own hands in horror" -combat_descriptions: - - "blasts %s with a burst of unstable energy" - - "unleashes a wave of chaotic force at %s" - - "channels raw power through their hands at %s" -size: medium -drops: - remains: bones - loot: - - item_id: credits - weight: 50 - quantity: 150 - - item_id: solarjunk - weight: 20 - quantity: 2 - - item_id: hydrojunk - weight: 15 - quantity: 2 - - table: herb_table_mid - weight: 15 diff --git a/data/mobs/cow.yaml b/data/mobs/cow.yaml deleted file mode 100644 index 7f1ee3c..0000000 --- a/data/mobs/cow.yaml +++ /dev/null @@ -1,28 +0,0 @@ -name: cow -description: "A placid dairy cow, chewing cud." -attack: 1 -strength: 1 -defense: 1 -hp: 8 -speed: 5 -aggressive: false -respawn_ticks: 30 -attack_type: crush -stab_defense: 1 -slash_defense: 1 -crush_defense: 1 -science_defense: 0 -ranged_defense: 0 -idle_descriptions: - - "moos softly" - - "chews on some grass" - - "swishes its tail lazily" - - "stares at you with big brown eyes" -size: large -drops: - remains: bones - loot: - - item_id: cowhide - weight: 100 - - item_id: raw_beef - weight: 100 diff --git a/data/mobs/crawler.yaml b/data/mobs/crawler.yaml deleted file mode 100644 index 9021c51..0000000 --- a/data/mobs/crawler.yaml +++ /dev/null @@ -1,32 +0,0 @@ -name: crawler -description: "A heavily armored bio-mechanical creature with a chitinous exoskeleton. Its regenerative biology prevents death unless dissolved with acid." -assassin_level: 30 -finishing_blow: acid_vial -attack: 25 -strength: 22 -defense: 30 -hp: 80 -speed: 5 -aggressive: false -respawn_ticks: 45 -idle_descriptions: - - "scrapes its mandibles together menacingly" - - "clicks and chitters in an alien rhythm" - - "tests the air with feathered antennae" - - "coils its segmented body defensively" -combat_descriptions: - - "snaps its mandibles at %s" - - "lashes out with a barbed tail at %s" - - "charges headlong into %s" -size: large -drops: - remains: chitin_plate - loot: - - item_id: credits - weight: 70 - quantity: 250 - - item_id: acid_vial - weight: 10 - - item_id: credits - weight: 20 - quantity: 500 diff --git a/data/mobs/drone.yaml b/data/mobs/drone.yaml deleted file mode 100644 index 5ac6552..0000000 --- a/data/mobs/drone.yaml +++ /dev/null @@ -1,32 +0,0 @@ -name: drone -description: "A malfunctioning security drone crackling with electrical discharge. Its attacks are especially dangerous to anyone not wearing insulated gloves." -assassin_level: 15 -damage_without: insulated_gloves -attack: 15 -strength: 14 -defense: 12 -hp: 45 -speed: 4 -aggressive: true -respawn_ticks: 35 -idle_descriptions: - - "hovers erratically, sparking" - - "emits a high-pitched whine" - - "scans the area with a flickering red beam" - - "rotates its weapon array with a mechanical click" -combat_descriptions: - - "fires an electrical bolt at %s" - - "charges its capacitors and zaps %s" - - "swoops down on %s with crackling energy" -size: small -drops: - remains: circuit_board - loot: - - item_id: credits - weight: 80 - quantity: 75 - - item_id: insulated_gloves - weight: 5 - - item_id: credits - weight: 15 - quantity: 200 diff --git a/data/mobs/elite_synth.yaml b/data/mobs/elite_synth.yaml deleted file mode 100644 index b095716..0000000 --- a/data/mobs/elite_synth.yaml +++ /dev/null @@ -1,43 +0,0 @@ -name: elite synth -description: "A sleek combat android with glowing blue optics and a compact energy weapon. Its chassis is polished alloy and its movements are disturbingly fluid." -attack: 1 -strength: 1 -defense: 38 -hp: 104 -science: 65 -speed: 4 -aggressive: true -respawn_ticks: 75 -attack_type: science -attack_bonus: 0 -strength_bonus: 0 -stab_defense: 45 -slash_defense: 45 -crush_defense: 40 -science_defense: 55 -ranged_defense: -15 -weakness: chaos -idle_descriptions: - - "calibrates targeting sensors with a soft chime" - - "projects a holographic tactical display" - - "emits a binary chirp" - - "reconfigures its weapon array silently" -combat_descriptions: - - "unleashes a coherent energy beam at %s" - - "fires a pulse of disruptor energy at %s" - - "overloads its emitters and blasts %s" -size: medium -drops: - remains: circuit_board - loot: - - item_id: credits - weight: 50 - quantity: 1500 - - item_id: biojunk - weight: 20 - quantity: 3 - - item_id: naturejunk - weight: 15 - quantity: 3 - - table: gem_table - weight: 15 diff --git a/data/mobs/enforcer_bot.yaml b/data/mobs/enforcer_bot.yaml deleted file mode 100644 index 78150c3..0000000 --- a/data/mobs/enforcer_bot.yaml +++ /dev/null @@ -1,42 +0,0 @@ -name: enforcer bot -description: "A heavy riot control automaton with impact shields and a shock baton. It moves with deliberate, crushing steps." -attack: 30 -strength: 35 -defense: 32 -hp: 70 -speed: 5 -aggressive: true -respawn_ticks: 55 -attack_type: crush -attack_bonus: 25 -strength_bonus: 25 -stab_defense: 40 -slash_defense: 40 -crush_defense: 50 -science_defense: -15 -ranged_defense: 30 -weakness: solar -idle_descriptions: - - "patrols the area with heavy footsteps" - - "deploys its riot shield with a hiss" - - "announces a warning in garbled speech" - - "tests its shock baton against a wall" -combat_descriptions: - - "smashes %s with a shock baton" - - "slams its riot shield into %s" - - "delivers a stunning blow to %s" -size: large -drops: - remains: scrap - loot: - - item_id: credits - weight: 60 - quantity: 350 - - item_id: scrap - weight: 20 - quantity: 5 - - item_id: credits - weight: 15 - quantity: 800 - - table: gem_table - weight: 5 diff --git a/data/mobs/estate_broker.yaml b/data/mobs/estate_broker.yaml deleted file mode 100644 index 3196012..0000000 --- a/data/mobs/estate_broker.yaml +++ /dev/null @@ -1,54 +0,0 @@ -color: "227" -description: A sharply-dressed real estate agent with a datapad and a practiced smile. -idle: The estate broker flashes a professional smile. -name: estate broker -talk: - nodes: - already_own: - message: Yes, you're already a proud homeowner here! Your house is waiting for you. Use the Estate Directory to enter it, or expand your workshop. - options: - - next: start - text: Good to know. - goodbye: - message: Come back when you're ready to invest in your future! - info: - message: Each house comes with an entrance hall and a workshop equipped with a workbench. You can use the workbench with a saw to turn logs into planks, or assemble planks into furniture. Furniture can be sold for a profit or displayed in your home. Future developments will allow adding more rooms to your house. - options: - - action: - cost: 10 - set_player_flags: - owns_house_local_neighborhood: local_neighborhood - condition: - not: true - player_flag: owns_house_local_neighborhood - next: purchased - text: Sounds great! I'll buy one. - - next: goodbye - text: Maybe later. - purchased: - message: Excellent! The plot is yours. You'll find your new home in the Local Neighborhood just north of here. Use the Estate Directory terminal to enter your house. The home comes with a workshop — perfect for construction projects. - options: - - next: start - text: Thanks! - start: - message: Welcome to the Local Neighborhood development! I'm selling premium housing plots for only 10 credits. Interested in buying a house? - options: - - action: - cost: 10 - set_player_flags: - owns_house_local_neighborhood: local_neighborhood - condition: - not: true - player_flag: owns_house_local_neighborhood - next: purchased - text: Yes, I'd like to buy a house. - - condition: - player_flag: owns_house_local_neighborhood - next: already_own - text: I already own a house here. - - next: goodbye - text: No thanks. - - next: info - text: What do I get with a house? -unique: true -size: small diff --git a/data/mobs/examples/ancient_construct.yaml b/data/mobs/examples/ancient_construct.yaml new file mode 100644 index 0000000..190e8c2 --- /dev/null +++ b/data/mobs/examples/ancient_construct.yaml @@ -0,0 +1,47 @@ +name: ancient construct +description: "An impossibly old machine from before the regression, still operational. Its design is alien even by modern standards, covered in glowing runes that predate recorded history." +attack: 58 +strength: 62 +defense: 66 +hp: 152 +speed: 4 +aggressive: true +respawn_ticks: 150 +attack_type: slash +attack_bonus: 55 +strength_bonus: 55 +stab_defense: 95 +slash_defense: 100 +crush_defense: 85 +science_defense: -40 +ranged_defense: 70 +weakness: chaos +idle_descriptions: + - "etches glowing symbols into the air" + - "reconfigures its form with clicking sounds" + - "projects a holographic star map" + - "emits a resonant chime that shakes the walls" +combat_descriptions: + - "slices at %s with a blade of pure light" + - "unleashes a cascade of ancient energy at %s" + - "teleports behind %s and strikes" +size: massive +drops: + remains: scrap + loot: + - item_id: credits + weight: 40 + quantity: 10000 + - item_id: bloodjunk + weight: 20 + quantity: 8 + - item_id: deathjunk + weight: 15 + quantity: 8 + - table: gem_table + weight: 10 + - item_id: uncut_diamond + weight: 5 + quantity: 3 + - table: herb_table_high + weight: 10 diff --git a/data/mobs/examples/bandit.yaml b/data/mobs/examples/bandit.yaml new file mode 100644 index 0000000..51e4b8e --- /dev/null +++ b/data/mobs/examples/bandit.yaml @@ -0,0 +1,38 @@ +name: bandit +description: "A scrappy outlaw with a cybernetic arm and patched armor. He eyes you with predatory intent." +attack: 10 +strength: 12 +defense: 12 +hp: 28 +speed: 5 +aggressive: true +respawn_ticks: 30 +attack_type: slash +attack_bonus: 5 +strength_bonus: 5 +stab_defense: 10 +slash_defense: 15 +crush_defense: 8 +science_defense: -5 +ranged_defense: 12 +idle_descriptions: + - "scans the horizon for targets" + - "wipes a blade on his sleeve" + - "spits on the ground" + - "adjusts a cybernetic knuckle" +combat_descriptions: + - "slashes at %s with a serrated blade" + - "delivers a crushing punch with a cybernetic fist" + - "lunges at %s with a battle cry" +size: medium +drops: + remains: bones + loot: + - item_id: credits + weight: 70 + quantity: 30 + - item_id: credits + weight: 20 + quantity: 80 + - table: herb_table_low + weight: 10 diff --git a/data/mobs/examples/bioengineer.yaml b/data/mobs/examples/bioengineer.yaml new file mode 100644 index 0000000..4761991 --- /dev/null +++ b/data/mobs/examples/bioengineer.yaml @@ -0,0 +1,44 @@ +name: Bioengineer +description: "A lab-coated scientist carrying a satchel of genetically modified seeds. Her pockets are stuffed with rare specimens." +combat_descriptions: + - "jabs a syringe at %s" + - "is being overpowered by %s" + - "fights desperately against %s" +idle_descriptions: + - "scribbles notes on a clipboard" + - "carefully inspects a vial of green liquid" + - "adjusts her safety goggles" + - "mutters about gene splicing yields" +attack: 6 +strength: 4 +defense: 5 +hp: 25 +speed: 5 +aggressive: false +respawn_ticks: 50 +attack_type: crush +stab_defense: 0 +slash_defense: 0 +crush_defense: 0 +science_defense: 0 +ranged_defense: 0 +steal_table: bioengineer_steal +steal_level: 38 +steal_xp: 45 +steal_speed: 4 +size: small +drops: + remains: "bones" + loot: + - item_id: "sweetcorn_seed" + weight: 30 + quantity: 2 + - item_id: "strawberry_seed" + weight: 25 + quantity: 1 + - item_id: "watermelon_seed" + weight: 15 + quantity: 1 + - item_id: "ranarr_seed" + weight: 5 + quantity: 1 \ No newline at end of file diff --git a/data/mobs/examples/client.yaml b/data/mobs/examples/client.yaml new file mode 100644 index 0000000..91b6802 --- /dev/null +++ b/data/mobs/examples/client.yaml @@ -0,0 +1,214 @@ +aggressive: false +attack: 1 +defense: 1 +description: A shadowy figure in a dark coat. They speak in clipped, measured tones and seem to know everything about every creature in the sector. +hp: 100 +idle_descriptions: + - reviews a holographic dossier + - marks a location on a worn star chart + - flips a credit chit between their fingers + - mutters coordinates under their breath + - glances at you appraisingly + - taps a data pad with a stylus +name: The Client +protected: true +respawn_ticks: 30 +speed: 5 +strength: 1 +talk: + nodes: + assign_task: + action: + assign_task: true + message: '"Let me check what''s available..." The Client scrolls through their data pad.' + options: + - text: '"Understood."' + - goto: start + text: '"What else do you have?"' + buy_acid: + action: + cost: 10 + give_item: acid_vial + message: '"Handle with care." The Client passes you a vial of corrosive acid.' + options: + - condition: + min_credits: 10 + goto: buy_acid + text: '"Buy more."' + - goto: supplies + text: '"Thanks."' + buy_auto_acid: + action: + reputation_cost: 200 + set_player_flags: + assassin_unlocked_auto_acid_vial: true + message: '"Auto-acid purchased. Acid vials will no longer be consumed."' + options: + - goto: rep_shop + text: '"Thanks."' + buy_auto_salt: + action: + reputation_cost: 200 + set_player_flags: + assassin_unlocked_auto_salt: true + message: '"Auto-salt purchased. You''ll no longer consume salt on finishing blows."' + options: + - goto: rep_shop + text: '"Thanks."' + buy_extend_unlock: + action: + reputation_cost: 100 + set_player_flags: + assassin_unlocked_extend: true + message: '"You can now extend tasks via our conversation."' + options: + - goto: rep_shop + text: '"Thanks."' + buy_gloves: + action: + cost: 50 + give_item: insulated_gloves + message: '"These''ll keep the current from frying your hands." The Client tosses you a pair of thick rubber gloves.' + options: + - goto: supplies + text: '"Thanks."' + buy_salt: + action: + cost: 5 + give_item: salt + message: '"Here you go." The Client slides a packet of salt across the table.' + options: + - condition: + min_credits: 5 + goto: buy_salt + text: '"Buy more."' + - goto: supplies + text: '"Thanks."' + buy_superiors: + action: + reputation_cost: 300 + set_player_flags: + assassin_unlocked_superiors: true + message: '"Superior encounters unlocked. Watch yourself out there."' + options: + - goto: rep_shop + text: '"Thanks."' + buy_visor: + action: + cost: 75 + give_item: spectral_visor + message: '"Spectral frequency filter. Makes the invisible visible — and keeps their attacks from scrambling your brain."' + options: + - goto: supplies + text: '"Thanks."' + current_task: + message: '"Let me check your file." The Client pulls up your record.' + options: + - text: '"Okay."' + extend_confirm: + message: '"Extending your task costs 30 Reputation and adds more kills. Want to proceed?"' + options: + - goto: extend_done + text: '"Yes, extend it."' + - goto: start + text: '"Never mind."' + extend_done: + action: + extend_task: true + message: '"Done. I''ve added more targets to your contract."' + options: + - text: '"Thanks."' + rep_shop: + message: '"Here''s what I''ve got. All purchases are permanent."' + options: + - condition: + not: true + player_flag: assassin_unlocked_auto_salt + goto: buy_auto_salt + text: '"Auto-finish: Salt (200 Rep) - Never consume salt on finishing blows."' + - condition: + not: true + player_flag: assassin_unlocked_auto_acid_vial + goto: buy_auto_acid + text: '"Auto-finish: Acid Vial (200 Rep) - Never consume acid vials on finishing blows."' + - condition: + not: true + player_flag: assassin_unlocked_superiors + goto: buy_superiors + text: '"Unlock Superior Mobs (300 Rep) - Rare superior variants may spawn."' + - condition: + not: true + player_flag: assassin_unlocked_extend + goto: buy_extend_unlock + text: '"Unlock Extended Tasks (100 Rep) - Allows extending tasks."' + - goto: start + text: '"Back."' + skip_confirm: + message: '"Skipping a task costs 30 Reputation and resets your streak. Are you sure?"' + options: + - goto: skip_done + text: '"Yes, skip it."' + - goto: start + text: '"Never mind."' + skip_done: + action: + skip_task: true + message: '"Task cancelled. Your streak has been reset."' + options: + - goto: assign_task + text: '"Give me a new one."' + - text: '"Goodbye."' + start: + message: The Client looks up from their data pad. "What do you need?" + options: + - condition: + not: true + player_flag: assassin_task_mob + goto: assign_task + text: '"I need a job."' + - condition: + not: false + player_flag: assassin_task_mob + goto: current_task + text: '"What''s my current task?"' + - condition: + not: false + player_flag: assassin_task_mob + goto: skip_confirm + text: '"I want to skip my task."' + - condition: + all_of: + - not: false + player_flag: assassin_task_mob + - player_flag: assassin_unlocked_extend + value: true + goto: extend_confirm + text: '"I want to extend my task."' + - goto: rep_shop + text: '"I''d like to browse the Reputation Shop."' + - goto: supplies + text: '"I need supplies."' + - text: '"Goodbye."' + supplies: + message: '"I stock everything you need for the job. Cheap, too."' + options: + - condition: + min_credits: 5 + goto: buy_salt + text: '"Buy salt (5 credits each)."' + - condition: + min_credits: 10 + goto: buy_acid + text: '"Buy acid vial (10 credits each)."' + - condition: + min_credits: 50 + goto: buy_gloves + text: '"Buy insulated gloves (50 credits)."' + - condition: + min_credits: 75 + goto: buy_visor + text: '"Buy spectral visor (75 credits)."' + - goto: start + text: '"Back."' +unique: true +size: small diff --git a/data/mobs/examples/corrupted_scientist.yaml b/data/mobs/examples/corrupted_scientist.yaml new file mode 100644 index 0000000..2083c03 --- /dev/null +++ b/data/mobs/examples/corrupted_scientist.yaml @@ -0,0 +1,43 @@ +name: corrupted scientist +description: "A researcher whose mind was consumed by their own experiments. Energy crackles around their fingertips and their lab coat is singed and tattered." +attack: 1 +strength: 1 +defense: 18 +hp: 40 +science: 50 +speed: 5 +aggressive: true +respawn_ticks: 45 +attack_type: science +attack_bonus: 0 +strength_bonus: 0 +stab_defense: 25 +slash_defense: 25 +crush_defense: 20 +science_defense: 35 +ranged_defense: -5 +weakness: eco +idle_descriptions: + - "mutters incomprehensible formulas" + - "energy arcs between their fingers" + - "scribbles equations on the wall in soot" + - "stares at their own hands in horror" +combat_descriptions: + - "blasts %s with a burst of unstable energy" + - "unleashes a wave of chaotic force at %s" + - "channels raw power through their hands at %s" +size: medium +drops: + remains: bones + loot: + - item_id: credits + weight: 50 + quantity: 150 + - item_id: solarjunk + weight: 20 + quantity: 2 + - item_id: hydrojunk + weight: 15 + quantity: 2 + - table: herb_table_mid + weight: 15 diff --git a/data/mobs/examples/cow.yaml b/data/mobs/examples/cow.yaml new file mode 100644 index 0000000..7f1ee3c --- /dev/null +++ b/data/mobs/examples/cow.yaml @@ -0,0 +1,28 @@ +name: cow +description: "A placid dairy cow, chewing cud." +attack: 1 +strength: 1 +defense: 1 +hp: 8 +speed: 5 +aggressive: false +respawn_ticks: 30 +attack_type: crush +stab_defense: 1 +slash_defense: 1 +crush_defense: 1 +science_defense: 0 +ranged_defense: 0 +idle_descriptions: + - "moos softly" + - "chews on some grass" + - "swishes its tail lazily" + - "stares at you with big brown eyes" +size: large +drops: + remains: bones + loot: + - item_id: cowhide + weight: 100 + - item_id: raw_beef + weight: 100 diff --git a/data/mobs/examples/crawler.yaml b/data/mobs/examples/crawler.yaml new file mode 100644 index 0000000..9021c51 --- /dev/null +++ b/data/mobs/examples/crawler.yaml @@ -0,0 +1,32 @@ +name: crawler +description: "A heavily armored bio-mechanical creature with a chitinous exoskeleton. Its regenerative biology prevents death unless dissolved with acid." +assassin_level: 30 +finishing_blow: acid_vial +attack: 25 +strength: 22 +defense: 30 +hp: 80 +speed: 5 +aggressive: false +respawn_ticks: 45 +idle_descriptions: + - "scrapes its mandibles together menacingly" + - "clicks and chitters in an alien rhythm" + - "tests the air with feathered antennae" + - "coils its segmented body defensively" +combat_descriptions: + - "snaps its mandibles at %s" + - "lashes out with a barbed tail at %s" + - "charges headlong into %s" +size: large +drops: + remains: chitin_plate + loot: + - item_id: credits + weight: 70 + quantity: 250 + - item_id: acid_vial + weight: 10 + - item_id: credits + weight: 20 + quantity: 500 diff --git a/data/mobs/examples/drone.yaml b/data/mobs/examples/drone.yaml new file mode 100644 index 0000000..5ac6552 --- /dev/null +++ b/data/mobs/examples/drone.yaml @@ -0,0 +1,32 @@ +name: drone +description: "A malfunctioning security drone crackling with electrical discharge. Its attacks are especially dangerous to anyone not wearing insulated gloves." +assassin_level: 15 +damage_without: insulated_gloves +attack: 15 +strength: 14 +defense: 12 +hp: 45 +speed: 4 +aggressive: true +respawn_ticks: 35 +idle_descriptions: + - "hovers erratically, sparking" + - "emits a high-pitched whine" + - "scans the area with a flickering red beam" + - "rotates its weapon array with a mechanical click" +combat_descriptions: + - "fires an electrical bolt at %s" + - "charges its capacitors and zaps %s" + - "swoops down on %s with crackling energy" +size: small +drops: + remains: circuit_board + loot: + - item_id: credits + weight: 80 + quantity: 75 + - item_id: insulated_gloves + weight: 5 + - item_id: credits + weight: 15 + quantity: 200 diff --git a/data/mobs/examples/elite_synth.yaml b/data/mobs/examples/elite_synth.yaml new file mode 100644 index 0000000..b095716 --- /dev/null +++ b/data/mobs/examples/elite_synth.yaml @@ -0,0 +1,43 @@ +name: elite synth +description: "A sleek combat android with glowing blue optics and a compact energy weapon. Its chassis is polished alloy and its movements are disturbingly fluid." +attack: 1 +strength: 1 +defense: 38 +hp: 104 +science: 65 +speed: 4 +aggressive: true +respawn_ticks: 75 +attack_type: science +attack_bonus: 0 +strength_bonus: 0 +stab_defense: 45 +slash_defense: 45 +crush_defense: 40 +science_defense: 55 +ranged_defense: -15 +weakness: chaos +idle_descriptions: + - "calibrates targeting sensors with a soft chime" + - "projects a holographic tactical display" + - "emits a binary chirp" + - "reconfigures its weapon array silently" +combat_descriptions: + - "unleashes a coherent energy beam at %s" + - "fires a pulse of disruptor energy at %s" + - "overloads its emitters and blasts %s" +size: medium +drops: + remains: circuit_board + loot: + - item_id: credits + weight: 50 + quantity: 1500 + - item_id: biojunk + weight: 20 + quantity: 3 + - item_id: naturejunk + weight: 15 + quantity: 3 + - table: gem_table + weight: 15 diff --git a/data/mobs/examples/enforcer_bot.yaml b/data/mobs/examples/enforcer_bot.yaml new file mode 100644 index 0000000..78150c3 --- /dev/null +++ b/data/mobs/examples/enforcer_bot.yaml @@ -0,0 +1,42 @@ +name: enforcer bot +description: "A heavy riot control automaton with impact shields and a shock baton. It moves with deliberate, crushing steps." +attack: 30 +strength: 35 +defense: 32 +hp: 70 +speed: 5 +aggressive: true +respawn_ticks: 55 +attack_type: crush +attack_bonus: 25 +strength_bonus: 25 +stab_defense: 40 +slash_defense: 40 +crush_defense: 50 +science_defense: -15 +ranged_defense: 30 +weakness: solar +idle_descriptions: + - "patrols the area with heavy footsteps" + - "deploys its riot shield with a hiss" + - "announces a warning in garbled speech" + - "tests its shock baton against a wall" +combat_descriptions: + - "smashes %s with a shock baton" + - "slams its riot shield into %s" + - "delivers a stunning blow to %s" +size: large +drops: + remains: scrap + loot: + - item_id: credits + weight: 60 + quantity: 350 + - item_id: scrap + weight: 20 + quantity: 5 + - item_id: credits + weight: 15 + quantity: 800 + - table: gem_table + weight: 5 diff --git a/data/mobs/examples/estate_broker.yaml b/data/mobs/examples/estate_broker.yaml new file mode 100644 index 0000000..a156e83 --- /dev/null +++ b/data/mobs/examples/estate_broker.yaml @@ -0,0 +1,55 @@ +color: "227" +description: A sharply-dressed real estate agent with a datapad and a practiced smile. +idle: The estate broker flashes a professional smile. +name: estate broker +protected: true +talk: + nodes: + already_own: + message: Yes, you're already a proud homeowner here! Your house is waiting for you. Use the Estate Directory to enter it, or expand your workshop. + options: + - goto: start + text: Good to know. + goodbye: + message: Come back when you're ready to invest in your future! + info: + message: Each house comes with an entrance hall and a workshop equipped with a workbench. You can use the workbench with a saw to turn logs into planks, or assemble planks into furniture. Furniture can be sold for a profit or displayed in your home. Future developments will allow adding more rooms to your house. + options: + - action: + cost: 10 + set_player_flags: + owns_house_local_neighborhood: local_neighborhood + condition: + not: true + player_flag: owns_house_local_neighborhood + goto: purchased + text: Sounds great! I'll buy one. + - goto: goodbye + text: Maybe later. + purchased: + message: Excellent! The plot is yours. You'll find your new home in the Local Neighborhood just north of here. Use the Estate Directory terminal to enter your house. The home comes with a workshop — perfect for construction projects. + options: + - goto: start + text: Thanks! + start: + message: Welcome to the Local Neighborhood development! I'm selling premium housing plots for only 10 credits. Interested in buying a house? + options: + - action: + cost: 10 + set_player_flags: + owns_house_local_neighborhood: local_neighborhood + condition: + not: true + player_flag: owns_house_local_neighborhood + goto: purchased + text: Yes, I'd like to buy a house. + - condition: + player_flag: owns_house_local_neighborhood + goto: already_own + text: I already own a house here. + - goto: goodbye + text: No thanks. + - goto: info + text: What do I get with a house? +unique: true +size: small diff --git a/data/mobs/examples/farmer.yaml b/data/mobs/examples/farmer.yaml new file mode 100644 index 0000000..591f1a3 --- /dev/null +++ b/data/mobs/examples/farmer.yaml @@ -0,0 +1,44 @@ +name: Farmer +description: "A weathered farmer in muddy overalls, pockets bulging with seeds." +combat_descriptions: + - "swings a shovel at %s" + - "is getting beaten by %s" + - "grapples with %s" +idle_descriptions: + - "examines a handful of seeds" + - "wipes dirt from his hands" + - "mutters about the growing season" + - "adjusts his wide-brimmed hat" +attack: 3 +strength: 3 +defense: 3 +hp: 15 +speed: 5 +aggressive: false +respawn_ticks: 40 +attack_type: crush +stab_defense: 0 +slash_defense: 0 +crush_defense: 0 +science_defense: 0 +ranged_defense: 0 +steal_table: farmer_steal +steal_level: 10 +steal_xp: 15 +steal_speed: 4 +size: small +drops: + remains: "bones" + loot: + - item_id: "potato_seed" + weight: 40 + quantity: 3 + - item_id: "onion_seed" + weight: 30 + quantity: 2 + - item_id: "cabbage_seed" + weight: 20 + quantity: 2 + - item_id: "tomato_seed" + weight: 10 + quantity: 1 \ No newline at end of file diff --git a/data/mobs/examples/feral_cyborg.yaml b/data/mobs/examples/feral_cyborg.yaml new file mode 100644 index 0000000..8b30cc3 --- /dev/null +++ b/data/mobs/examples/feral_cyborg.yaml @@ -0,0 +1,38 @@ +name: feral cyborg +description: "A heavily augmented human whose implants have driven them to madness. Razor-sharp blades extend from their forearms and their optical implant glows red." +attack: 34 +strength: 36 +defense: 32 +hp: 82 +speed: 4 +aggressive: true +respawn_ticks: 50 +attack_type: slash +attack_bonus: 30 +strength_bonus: 28 +stab_defense: 35 +slash_defense: 45 +crush_defense: 30 +science_defense: -10 +ranged_defense: 35 +idle_descriptions: + - "paces back and forth, muttering" + - "retracts and extends forearm blades" + - "emits a distorted laugh" + - "scratches at their own cybernetics" +combat_descriptions: + - "slashes %s with forearm blades" + - "delivers a powered kick to %s" + - "grapples %s with augmented strength" +size: medium +drops: + remains: bones + loot: + - item_id: credits + weight: 60 + quantity: 300 + - item_id: scrap + weight: 25 + quantity: 3 + - table: herb_table_mid + weight: 15 diff --git a/data/mobs/examples/general_store_clerk.yaml b/data/mobs/examples/general_store_clerk.yaml new file mode 100644 index 0000000..8a07191 --- /dev/null +++ b/data/mobs/examples/general_store_clerk.yaml @@ -0,0 +1,70 @@ +aggressive: false +attack: 1 +attack_type: crush +crush_defense: 0 +defense: 1 +description: A friendly merchant with a tidy apron, standing behind a well-stocked counter. +hp: 50 +idle_descriptions: + - arranges items on the shelves + - polishes the counter + - counts credits in the register + - greets a passerby with a nod +name: Shopkeeper +protected: true +ranged_defense: 0 +respawn_ticks: 30 +science_defense: 0 +slash_defense: 0 +speed: 5 +stab_defense: 0 +strength: 1 +talk: + nodes: + shop: + action: + shop: + items: + - buy_price: 10 + item_id: fishing_rod + sell_price: 2 + - buy_price: 2 + item_id: fishing_bait + sell_price: 0 + - buy_price: 10 + item_id: matches + sell_price: 2 + - buy_price: 40 + item_id: firesteel + sell_price: 10 + - buy_price: 30 + item_id: lighter + sell_price: 7 + - buy_price: 20 + item_id: hammer + sell_price: 5 + - buy_price: 10 + item_id: knife + sell_price: 2 + - buy_price: 10 + item_id: chisel + sell_price: 2 + - buy_price: 10 + item_id: bread + sell_price: 2 + - buy_price: 20 + item_id: bowstring + sell_price: 5 + message: What would you like to buy or sell? + message: '"Take your time. What can I get you?"' + options: + - goto: start + text: '"I''m done."' + start: + message: '"Welcome to the General Store! Need any supplies?"' + options: + - goto: shop + text: '"I''d like to browse."' + - text: '"Goodbye."' +unique: true +size: small diff --git a/data/mobs/examples/ghoul.yaml b/data/mobs/examples/ghoul.yaml new file mode 100644 index 0000000..ae8fed6 --- /dev/null +++ b/data/mobs/examples/ghoul.yaml @@ -0,0 +1,38 @@ +name: ghoul +description: "A radiation-scarred crew member, barely recognizable as human. Its flesh glows faintly and its eyes are hollow sockets." +attack: 22 +strength: 22 +defense: 20 +hp: 54 +speed: 4 +aggressive: true +respawn_ticks: 35 +attack_type: crush +attack_bonus: 15 +strength_bonus: 12 +stab_defense: 20 +slash_defense: 25 +crush_defense: 15 +science_defense: -5 +ranged_defense: 20 +weakness: hydro +idle_descriptions: + - "shambles aimlessly and moans" + - "scratches at the walls leaving glowing marks" + - "stares blankly into the darkness" + - "emits a low, rattling groan" +combat_descriptions: + - "claws at %s with irradiated hands" + - "lunges at %s with a gurgling shriek" + - "bites %s with decaying teeth" +size: medium +drops: + remains: bones + loot: + - item_id: credits + weight: 60 + quantity: 80 + - item_id: scrap + weight: 25 + - table: herb_table_low + weight: 15 diff --git a/data/mobs/examples/goblin.yaml b/data/mobs/examples/goblin.yaml new file mode 100644 index 0000000..a02c112 --- /dev/null +++ b/data/mobs/examples/goblin.yaml @@ -0,0 +1,32 @@ +name: goblin +description: "A small green-skinned goblin with a rusty blade." +attack: 1 +strength: 3 +defense: 3 +hp: 12 +speed: 5 +aggressive: true +respawn_ticks: 25 +attack_type: slash +attack_bonus: 3 +strength_bonus: 2 +stab_defense: 4 +slash_defense: 3 +crush_defense: -2 +science_defense: 0 +ranged_defense: 3 +idle_descriptions: + - "mutters something unintelligible" + - "waves a rusty blade around" + - "picks its nose" + - "kicks a pebble" +size: small +drops: + remains: bones + loot: + - item_id: credits + weight: 80 + quantity: 5 + - item_id: credits + weight: 20 + quantity: 25 diff --git a/data/mobs/examples/greater_drone.yaml b/data/mobs/examples/greater_drone.yaml new file mode 100644 index 0000000..11cf8e2 --- /dev/null +++ b/data/mobs/examples/greater_drone.yaml @@ -0,0 +1,33 @@ +name: greater drone +description: "A large, heavily armored drone with multiple energy emitters. Red warning lights pulse along its hull." +attack: 1 +strength: 1 +defense: 30 +hp: 120 +ranged: 0 +science: 40 +speed: 4 +aggressive: true +respawn_ticks: 80 +attack_type: science +attack_bonus: 0 +strength_bonus: 0 +stab_defense: 55 +slash_defense: 55 +crush_defense: 50 +science_defense: 40 +ranged_defense: -20 +idle_descriptions: + - "projects a defensive energy shield" + - "recalibrates its targeting array" + - "emits a warning klaxon" + - "deploys sensor probes" +size: medium +drops: + loot: + - item_id: scrap + weight: 40 + quantity: 3 + - item_id: credits + weight: 60 + quantity: 1500 diff --git a/data/mobs/examples/guard.yaml b/data/mobs/examples/guard.yaml new file mode 100644 index 0000000..7bd7d19 --- /dev/null +++ b/data/mobs/examples/guard.yaml @@ -0,0 +1,71 @@ +aggressive: false +attack: 5 +attack_bonus: 8 +attack_type: slash +crush_defense: 10 +defense: 5 +description: A stern-looking guard in weathered armor. +hp: 30 +idle_descriptions: + - scans the area with a watchful eye + - adjusts the grip on his weapon + - nods curtly at passersby + - leans against the gate, arms folded +name: Guard +protected: true +ranged_defense: 12 +respawn_ticks: 60 +science_defense: -5 +slash_defense: 15 +speed: 5 +stab_defense: 12 +strength: 5 +strength_bonus: 6 +talk: + nodes: + about_gate: + action: + set_player_flags: + talked_to_guard: true + message: '"Supplies. Weapons. Things you don''t need to worry about." He shifts his weight. "Tell you what — bring me some copper ore and I''ll stamp you a pass."' + options: + - text: '"I''ll be back."' + - condition: + has_item: copper_ore + goto: trade_ore + text: '"I have some right here."' + - text: '"Goodbye."' + has_pass: + action: + set_flags: + gate_open: true + message: '"Let me see that..." He examines your pass and nods. "Alright, I''ll open the gate for you."' + options: + - text: '"Thanks."' + start: + message: '"Halt! This area is restricted." The guard eyes you suspiciously.' + options: + - goto: about_gate + text: '"What''s behind that gate?"' + - condition: + has_item: copper_ore + goto: trade_ore + text: '"I have copper ore."' + - condition: + player_flag: got_pass + value: true + goto: has_pass + text: '"I have a pass."' + - text: '"Goodbye."' + trade_ore: + action: + give_item: pass_stub + set_player_flags: + got_pass: true + talked_to_guard: true + take_item: copper_ore + message: '"Good quality ore. This''ll do." He stamps a slip of paper and hands it to you. "That''s your pass. Don''t lose it."' + options: + - text: '"Thanks."' +unique: true +size: medium diff --git a/data/mobs/examples/heavy_mech.yaml b/data/mobs/examples/heavy_mech.yaml new file mode 100644 index 0000000..e2f5f5a --- /dev/null +++ b/data/mobs/examples/heavy_mech.yaml @@ -0,0 +1,42 @@ +name: heavy mech +description: "A lumbering assault mech with layered armor plating and a rotary cannon arm. Steam vents from its exhaust ports with each step." +attack: 40 +strength: 44 +defense: 44 +hp: 94 +speed: 5 +aggressive: true +respawn_ticks: 70 +attack_type: crush +attack_bonus: 35 +strength_bonus: 35 +stab_defense: 55 +slash_defense: 55 +crush_defense: 65 +science_defense: -25 +ranged_defense: 40 +weakness: solar +idle_descriptions: + - "scans the room with a blue optical beam" + - "vents a cloud of steam" + - "rotates its cannon with a mechanical whine" + - "announces a threat level assessment" +combat_descriptions: + - "fires its rotary cannon at %s" + - "smashes %s with a hydraulic fist" + - "unleashes a missile salvo at %s" +size: massive +drops: + remains: scrap + loot: + - item_id: credits + weight: 55 + quantity: 1000 + - item_id: scrap + weight: 25 + quantity: 8 + - table: gem_table + weight: 10 + - item_id: lawjunk + weight: 10 + quantity: 2 diff --git a/data/mobs/examples/iron_sentinel.yaml b/data/mobs/examples/iron_sentinel.yaml new file mode 100644 index 0000000..bf8b9b5 --- /dev/null +++ b/data/mobs/examples/iron_sentinel.yaml @@ -0,0 +1,31 @@ +name: iron sentinel +description: "A massive bipedal automaton forged from pre-regression alloys. Its joints grind with each deliberate step." +attack: 25 +strength: 30 +defense: 45 +hp: 180 +speed: 6 +aggressive: true +respawn_ticks: 100 +attack_type: crush +attack_bonus: 40 +strength_bonus: 35 +stab_defense: 80 +slash_defense: 80 +crush_defense: 70 +science_defense: -30 +ranged_defense: 50 +idle_descriptions: + - "stands motionless, servos whining softly" + - "turns its armored head with a mechanical grind" + - "vents steam from exhaust ports" + - "scans the area with a red optical sensor" +size: large +drops: + loot: + - item_id: scrap + weight: 30 + quantity: 5 + - item_id: credits + weight: 60 + quantity: 5000 diff --git a/data/mobs/examples/lesser_drone.yaml b/data/mobs/examples/lesser_drone.yaml new file mode 100644 index 0000000..c9e50a5 --- /dev/null +++ b/data/mobs/examples/lesser_drone.yaml @@ -0,0 +1,32 @@ +name: lesser drone +description: "A floating metallic drone with a pulsing energy core. Its surface crackles with electric discharge." +attack: 1 +strength: 1 +defense: 18 +hp: 55 +ranged: 0 +science: 20 +speed: 4 +aggressive: true +respawn_ticks: 50 +attack_type: science +attack_bonus: 0 +strength_bonus: 0 +stab_defense: 35 +slash_defense: 35 +crush_defense: 30 +science_defense: 20 +ranged_defense: -10 +idle_descriptions: + - "hovers silently, scanning the area" + - "emits a low electronic hum" + - "projects a thin beam of light across the floor" + - "rotates slowly in place" +size: small +drops: + loot: + - item_id: scrap + weight: 60 + - item_id: credits + weight: 40 + quantity: 300 diff --git a/data/mobs/examples/man.yaml b/data/mobs/examples/man.yaml new file mode 100644 index 0000000..8478f41 --- /dev/null +++ b/data/mobs/examples/man.yaml @@ -0,0 +1,48 @@ +name: man +description: "A shabby-looking man loitering in the town square." +combat_descriptions: + - "is engaged in a fight to the death with %s" + - "is getting pummelled by %s" + - "is locked in combat with %s" + - "trades blows with %s" + - "circles warily around %s" +idle_descriptions: + - "scribbles something in a small notebook" + - "gazes skyward at the clouds" + - "leans against a wall, looking bored" + - "scratches his head thoughtfully" + - "stares off into the distance" + - "adjusts his tunic and stretches" +attack: 1 +strength: 1 +defense: 1 +hp: 7 +speed: 5 +aggressive: false +respawn_ticks: 30 +steal_table: man_steal +steal_level: 1 +steal_xp: 8 +steal_speed: 4 +attack_type: crush +stab_defense: 0 +slash_defense: 0 +crush_defense: 0 +science_defense: 0 +ranged_defense: 0 +size: small +drops: + remains: "bones" + loot: + - item_id: "credits" + weight: 98 + quantity: 10 + - item_id: "credits" + weight: 2 + quantity: 150 + - item_id: "grimy_guam" + weight: 8 + - item_id: "grimy_marrentill" + weight: 4 + - item_id: "grimy_tarromin" + weight: 2 diff --git a/data/mobs/examples/molten_elemental.yaml b/data/mobs/examples/molten_elemental.yaml new file mode 100644 index 0000000..9c46ccb --- /dev/null +++ b/data/mobs/examples/molten_elemental.yaml @@ -0,0 +1,42 @@ +name: molten elemental +description: "A flowing mass of liquid metal and superheated slag, roughly humanoid. The air around it shimmers with heat and droplets of molten alloy drip to the floor." +attack: 48 +strength: 52 +defense: 52 +hp: 115 +speed: 5 +aggressive: true +respawn_ticks: 80 +attack_type: crush +attack_bonus: 40 +strength_bonus: 42 +stab_defense: 60 +slash_defense: 60 +crush_defense: 70 +science_defense: -30 +ranged_defense: 45 +weakness: hydro +idle_descriptions: + - "bubbles and churns, throwing off sparks" + - "melts a nearby chunk of metal absent-mindedly" + - "pulses with an inner orange glow" + - "drips glowing droplets onto the floor" +combat_descriptions: + - "hurls a glob of molten metal at %s" + - "engulfs %s in a wave of liquid fire" + - "smashes %s with a superheated limb" +size: large +drops: + remains: scrap + loot: + - item_id: credits + weight: 50 + quantity: 2000 + - item_id: biojunk + weight: 20 + quantity: 3 + - item_id: bloodjunk + weight: 15 + quantity: 2 + - table: herb_table_high + weight: 15 diff --git a/data/mobs/examples/moss_giant.yaml b/data/mobs/examples/moss_giant.yaml new file mode 100644 index 0000000..f19f0a3 --- /dev/null +++ b/data/mobs/examples/moss_giant.yaml @@ -0,0 +1,32 @@ +name: moss giant +description: "A towering creature covered in moss and vines, its rocky skin dripping with moisture." +attack: 12 +strength: 14 +defense: 10 +hp: 60 +speed: 7 +aggressive: true +respawn_ticks: 45 +attack_type: crush +attack_bonus: 10 +strength_bonus: 12 +stab_defense: 15 +slash_defense: 12 +crush_defense: 18 +science_defense: -5 +ranged_defense: 15 +idle_descriptions: + - "surveys its territory with dull eyes" + - "pulls a vine from its shoulder" + - "stamps the ground, sending tremors" + - "scratches its mossy hide" +size: massive +drops: + remains: bones + loot: + - item_id: credits + weight: 50 + quantity: 120 + - item_id: credits + weight: 50 + quantity: 500 diff --git a/data/mobs/examples/mutant_rat.yaml b/data/mobs/examples/mutant_rat.yaml new file mode 100644 index 0000000..7836ef9 --- /dev/null +++ b/data/mobs/examples/mutant_rat.yaml @@ -0,0 +1,39 @@ +name: mutant rat +description: "A bloated rodent with glowing green eyes and exposed muscle tissue. Bio-engineering runoff has made it unnaturally aggressive." +attack: 13 +strength: 13 +defense: 12 +hp: 32 +speed: 4 +aggressive: true +respawn_ticks: 25 +attack_type: crush +attack_bonus: 8 +strength_bonus: 6 +stab_defense: 15 +slash_defense: 15 +crush_defense: 10 +science_defense: -10 +ranged_defense: 5 +weakness: bio +idle_descriptions: + - "scurries frantically in circles" + - "gnaws on a rusted pipe" + - "emits a gurgling screech" + - "twitches unnaturally" +combat_descriptions: + - "bites %s with glowing teeth" + - "slashes %s with mutated claws" + - "lunges at %s with unnatural speed" +size: small +drops: + remains: bones + loot: + - item_id: credits + weight: 60 + quantity: 20 + - item_id: scrap + weight: 30 + - item_id: credits + weight: 10 + quantity: 60 diff --git a/data/mobs/examples/newbie_trainer.yaml b/data/mobs/examples/newbie_trainer.yaml new file mode 100644 index 0000000..3897dba --- /dev/null +++ b/data/mobs/examples/newbie_trainer.yaml @@ -0,0 +1,25 @@ +name: Newbie Trainer +description: "A friendly-looking instructor ready to help new adventurers." +unique: true +protected: true +attack: 1 +strength: 1 +defense: 1 +hp: 50 +speed: 5 +aggressive: false +respawn_ticks: 30 +attack_type: crush +stab_defense: 0 +slash_defense: 0 +crush_defense: 0 +science_defense: 0 +ranged_defense: 0 +idle_descriptions: + - "reviews a training manual" + - "adjusts a practice dummy" + - "demonstrates a sword stance to no one in particular" + - "offers a friendly nod to passersby" + - "polishes a wooden shield" + - "checks a stopwatch and jots something down" +size: small diff --git a/data/mobs/examples/phantom.yaml b/data/mobs/examples/phantom.yaml new file mode 100644 index 0000000..d871b76 --- /dev/null +++ b/data/mobs/examples/phantom.yaml @@ -0,0 +1,32 @@ +name: phantom +description: "A semi-transparent entity that phases in and out of visible light. Its psychic attacks are devastating to anyone without a spectral visor." +assassin_level: 45 +damage_without: spectral_visor +attack: 35 +strength: 30 +defense: 25 +hp: 100 +speed: 3 +aggressive: true +respawn_ticks: 50 +idle_descriptions: + - "flickers between visible and invisible" + - "emits a low, resonant hum" + - "drifts through a wall and back again" + - "stares at you with hollow, glowing eyes" +combat_descriptions: + - "blasts %s with a psychic wave" + - "phases through %s's defenses" + - "unleashes a spectral shriek at %s" +size: medium +drops: + remains: ectoplasm + loot: + - item_id: credits + weight: 60 + quantity: 500 + - item_id: spectral_visor + weight: 3 + - item_id: credits + weight: 37 + quantity: 1000 diff --git a/data/mobs/examples/plasma_wraith.yaml b/data/mobs/examples/plasma_wraith.yaml new file mode 100644 index 0000000..c4ced2b --- /dev/null +++ b/data/mobs/examples/plasma_wraith.yaml @@ -0,0 +1,43 @@ +name: plasma wraith +description: "A shimmering entity of contained plasma, vaguely humanoid in shape. It radiates intense heat and hums with barely contained energy." +attack: 1 +strength: 1 +defense: 22 +hp: 56 +science: 65 +speed: 4 +aggressive: true +respawn_ticks: 60 +attack_type: science +attack_bonus: 0 +strength_bonus: 0 +stab_defense: 30 +slash_defense: 30 +crush_defense: 25 +science_defense: 45 +ranged_defense: -10 +weakness: hydro +idle_descriptions: + - "drifts silently, leaving heat shimmer in its wake" + - "pulses with internal light" + - "phases partially through a wall" + - "emits a low frequency hum" +combat_descriptions: + - "lashes %s with a whip of plasma" + - "engulfs %s in a superheated cloud" + - "discharges a concentrated beam at %s" +size: medium +drops: + remains: ectoplasm + loot: + - item_id: credits + weight: 50 + quantity: 400 + - item_id: chaosjunk + weight: 20 + quantity: 2 + - item_id: cosmicjunk + weight: 15 + quantity: 2 + - table: gem_table + weight: 15 diff --git a/data/mobs/examples/psionic_entity.yaml b/data/mobs/examples/psionic_entity.yaml new file mode 100644 index 0000000..1c518bf --- /dev/null +++ b/data/mobs/examples/psionic_entity.yaml @@ -0,0 +1,46 @@ +name: psionic entity +description: "A barely visible distortion in the air, only detectable by the pressure it exerts on your mind. When it focuses, you see a shimmering outline of something vast and ancient." +attack: 1 +strength: 1 +defense: 42 +hp: 128 +science: 97 +speed: 4 +aggressive: true +respawn_ticks: 100 +attack_type: science +attack_bonus: 0 +strength_bonus: 0 +stab_defense: 50 +slash_defense: 50 +crush_defense: 45 +science_defense: 70 +ranged_defense: -20 +idle_descriptions: + - "probes the edges of your consciousness" + - "flickers between visible and invisible states" + - "emits a subsonic pulse you feel in your teeth" + - "momentarily shows you visions of another dimension" +combat_descriptions: + - "assaults %s's mind with psionic force" + - "tears at %s's perception of reality" + - "unleashes a devastating mental blast at %s" +size: large +drops: + remains: ectoplasm + loot: + - item_id: credits + weight: 40 + quantity: 5000 + - item_id: lawjunk + weight: 20 + quantity: 5 + - item_id: cosmicjunk + weight: 15 + quantity: 5 + - table: gem_table + weight: 15 + - item_id: spectral_visor + weight: 5 + - table: herb_table_high + weight: 5 diff --git a/data/mobs/examples/rat.yaml b/data/mobs/examples/rat.yaml new file mode 100644 index 0000000..4265674 --- /dev/null +++ b/data/mobs/examples/rat.yaml @@ -0,0 +1,22 @@ +name: rat +description: "A large, mangy rat with beady red eyes." +attack: 1 +strength: 1 +defense: 1 +hp: 2 +speed: 4 +aggressive: false +respawn_ticks: 20 +attack_type: crush +stab_defense: 0 +slash_defense: 0 +crush_defense: 0 +science_defense: 0 +ranged_defense: 0 +idle_descriptions: + - "sniffs around the ground" + - "nibbles on something" + - "scurries in circles" +size: small +drops: + remains: bones diff --git a/data/mobs/examples/sawmill_operator.yaml b/data/mobs/examples/sawmill_operator.yaml new file mode 100644 index 0000000..b70362f --- /dev/null +++ b/data/mobs/examples/sawmill_operator.yaml @@ -0,0 +1,50 @@ +color: "186" +description: A burly worker in a thick apron, covered in sawdust. He operates the industrial sawmill. +idle: The sawmill operator wipes sawdust from his goggles. +name: sawmill operator +protected: true +talk: + nodes: + goodbye: + message: Come back anytime you need more planks! + prices: + message: |- + Here's what I charge per log: + Regular logs: 5 credits + Oak logs: 10 credits + Teak logs: 20 credits + Mahogany logs: 40 credits + + Want me to process your logs? + options: + - condition: + any_of: + - has_item: logs + - has_item: oak_logs + - has_item: teak_logs + - has_item: mahogany_logs + goto: process + text: Yes, process all my logs. + - goto: goodbye + text: No thanks. + process: + action: + sawmill: true + message: "" + start: + message: Welcome to the lumberyard! I can turn your logs into planks — for a small fee, of course. What can I do for ya? + options: + - condition: + any_of: + - has_item: logs + - has_item: oak_logs + - has_item: teak_logs + - has_item: mahogany_logs + goto: prices + text: Turn all my logs into planks. + - goto: prices + text: What are your prices? + - goto: goodbye + text: Nothing for now. +unique: true +size: small diff --git a/data/mobs/examples/scrap_bot.yaml b/data/mobs/examples/scrap_bot.yaml new file mode 100644 index 0000000..a8b34d8 --- /dev/null +++ b/data/mobs/examples/scrap_bot.yaml @@ -0,0 +1,39 @@ +name: scrap bot +description: "A malfunctioning maintenance robot that has gone rogue. Its chassis is covered in dents and rust, and one optical sensor flickers erratically." +attack: 15 +strength: 15 +defense: 14 +hp: 30 +speed: 5 +aggressive: true +respawn_ticks: 30 +attack_type: crush +attack_bonus: 10 +strength_bonus: 8 +stab_defense: 20 +slash_defense: 15 +crush_defense: 25 +science_defense: -5 +ranged_defense: 10 +idle_descriptions: + - "beeps erratically and twitches" + - "bumps into a wall and reverses" + - "emits a burst of static" + - "scans the floor with a flickering beam" +combat_descriptions: + - "rams %s with its chassis" + - "swings a broken manipulator arm at %s" + - "discharges a spark at %s" +size: medium +drops: + remains: scrap + loot: + - item_id: credits + weight: 60 + quantity: 40 + - item_id: scrap + weight: 30 + quantity: 2 + - item_id: credits + weight: 10 + quantity: 100 diff --git a/data/mobs/examples/security_turret.yaml b/data/mobs/examples/security_turret.yaml new file mode 100644 index 0000000..9929106 --- /dev/null +++ b/data/mobs/examples/security_turret.yaml @@ -0,0 +1,41 @@ +name: security turret +description: "A ceiling-mounted auto-turret with twin barrels and a red targeting laser. It tracks you with mechanical precision." +attack: 1 +strength: 1 +defense: 16 +hp: 44 +ranged: 34 +speed: 5 +aggressive: true +respawn_ticks: 40 +attack_type: ranged +attack_bonus: 0 +strength_bonus: 0 +stab_defense: 30 +slash_defense: 20 +crush_defense: 40 +science_defense: -20 +ranged_defense: 15 +weakness: solar +idle_descriptions: + - "pans the room with a targeting laser" + - "emits a rhythmic clicking sound" + - "calibrates its targeting sensors" + - "beeps a warning tone" +combat_descriptions: + - "fires twin bolts at %s" + - "unleashes a burst of rounds at %s" + - "locks onto %s and opens fire" +size: small +drops: + remains: scrap + loot: + - item_id: credits + weight: 70 + quantity: 100 + - item_id: scrap + weight: 20 + quantity: 3 + - item_id: credits + weight: 10 + quantity: 250 diff --git a/data/mobs/examples/skeleton.yaml b/data/mobs/examples/skeleton.yaml new file mode 100644 index 0000000..ba82afc --- /dev/null +++ b/data/mobs/examples/skeleton.yaml @@ -0,0 +1,31 @@ +name: skeleton +description: "An animated pile of bones, held together by dark energy." +attack: 8 +strength: 6 +defense: 8 +hp: 22 +speed: 5 +aggressive: true +respawn_ticks: 30 +attack_type: stab +attack_bonus: 6 +strength_bonus: 4 +stab_defense: 10 +slash_defense: 18 +crush_defense: -5 +science_defense: -8 +ranged_defense: 10 +idle_descriptions: + - "rattles ominously" + - "clicks its jaw open and shut" + - "stares with empty eye sockets" +size: medium +drops: + remains: bones + loot: + - item_id: credits + weight: 70 + quantity: 30 + - item_id: credits + weight: 30 + quantity: 100 diff --git a/data/mobs/examples/slug.yaml b/data/mobs/examples/slug.yaml new file mode 100644 index 0000000..64082ec --- /dev/null +++ b/data/mobs/examples/slug.yaml @@ -0,0 +1,27 @@ +name: slug +description: "A bloated, translucent slug the size of a dog. Its skin glistens with toxic mucus. It cannot be killed by conventional means — only salt can destroy it." +assassin_level: 1 +finishing_blow: salt +attack: 3 +strength: 3 +defense: 1 +hp: 15 +speed: 6 +aggressive: false +respawn_ticks: 25 +idle_descriptions: + - "oozes along the floor leaving a slimy trail" + - "contracts and expands rhythmically" + - "extends its eyestalks toward you" + - "secretes a glob of toxic mucus" +combat_descriptions: + - "lunges slimily at %s" + - "sprays mucus toward %s" + - "writhes in combat with %s" +size: small +drops: + remains: slug_mucus + loot: + - item_id: credits + weight: 100 + quantity: 15 diff --git a/data/mobs/examples/solar_panel_frame.yaml b/data/mobs/examples/solar_panel_frame.yaml new file mode 100644 index 0000000..90269f2 --- /dev/null +++ b/data/mobs/examples/solar_panel_frame.yaml @@ -0,0 +1,33 @@ +name: solar panel frame +description: "A half-assembled photovoltaic array on a steel frame. Panels, brackets and cabling are laid out, waiting to be fitted. This is work, not a fight — fix the panels into place to complete the array." +kind: task +verb: assemble +progress_noun: assembly +complete_message: "You bolt the final panel into place and the solar array hums to life!" +hp: 40 +defense: 10 +speed: 5 +aggressive: false +respawn_ticks: 40 +attack_type: crush +crush_defense: 0 +stab_defense: 40 +slash_defense: 40 +ranged_defense: 10 +science_defense: 10 +idle_descriptions: + - "stands half-assembled, panels waiting to be fitted" + - "has loose cabling dangling from an open junction box" + - "catches the light on its few mounted panels" +size: medium +drops: + loot: + - item_id: credits + weight: 70 + quantity: 40 + - item_id: credits + weight: 25 + quantity: 90 + - item_id: coal + weight: 5 + quantity: 1 diff --git a/data/mobs/examples/tanner.yaml b/data/mobs/examples/tanner.yaml new file mode 100644 index 0000000..2e5d89a --- /dev/null +++ b/data/mobs/examples/tanner.yaml @@ -0,0 +1,65 @@ +aggressive: false +attack: 1 +attack_type: crush +crush_defense: 0 +defense: 1 +description: A weathered craftsman with stained hands and a leather apron. +hp: 50 +idle_descriptions: + - scrapes at a piece of hide + - examines a stack of leathers + - sharpens a tanning knife + - wipes sweat from his brow +name: Tanner +protected: true +ranged_defense: 0 +respawn_ticks: 30 +science_defense: 0 +slash_defense: 0 +speed: 5 +stab_defense: 0 +strength: 1 +talk: + nodes: + start: + message: '"Bring me some cowhides and I''ll tan them for you. Leather is 10 credits, hard leather is 50."' + options: + - condition: + all_of: + - has_item: cowhide + - min_credits: 10 + goto: tan_leather + text: '"Tan a cowhide into leather (10 credits)."' + - condition: + all_of: + - has_item: cowhide + - min_credits: 50 + goto: tan_hard_leather + text: '"Tan a cowhide into hard leather (50 credits)."' + - text: '"Never mind."' + tan_hard_leather: + action: + cost: 50 + give_item: hard_leather + take_item: cowhide + message: The tanner takes your cowhide and subjects it to an intense curing process. "Here's your hard leather." + options: + - condition: + has_item: cowhide + goto: start + text: '"Tan another."' + - text: '"Thanks."' + tan_leather: + action: + cost: 10 + give_item: leather + take_item: cowhide + message: The tanner takes your cowhide and works it skillfully. "Here's your leather." + options: + - condition: + has_item: cowhide + goto: start + text: '"Tan another."' + - text: '"Thanks."' +unique: true +size: small diff --git a/data/mobs/examples/titan_sentinel.yaml b/data/mobs/examples/titan_sentinel.yaml new file mode 100644 index 0000000..32ddcc2 --- /dev/null +++ b/data/mobs/examples/titan_sentinel.yaml @@ -0,0 +1,41 @@ +name: titan sentinel +description: "A colossal automaton, the bigger brother of the iron sentinel. Its armor is reinforced adamantite alloy and its optics burn with crimson fire." +attack: 50 +strength: 52 +defense: 56 +hp: 132 +speed: 5 +aggressive: true +respawn_ticks: 120 +attack_type: crush +attack_bonus: 48 +strength_bonus: 45 +stab_defense: 90 +slash_defense: 90 +crush_defense: 80 +science_defense: -35 +ranged_defense: 60 +weakness: solar +idle_descriptions: + - "stands motionless, gyros humming" + - "scans the area with a sweeping crimson beam" + - "vents superheated exhaust" + - "rotates its armored torso with a deep grinding sound" +combat_descriptions: + - "smashes %s with a titan-grade fist" + - "unleashes a devastating plasma barrage at %s" + - "drives %s into the ground with overwhelming force" +size: massive +drops: + loot: + - item_id: scrap + weight: 30 + quantity: 10 + - item_id: credits + weight: 50 + quantity: 8000 + - table: gem_table + weight: 15 + - item_id: deathjunk + weight: 5 + quantity: 5 diff --git a/data/mobs/examples/veteran_merc.yaml b/data/mobs/examples/veteran_merc.yaml new file mode 100644 index 0000000..88238b6 --- /dev/null +++ b/data/mobs/examples/veteran_merc.yaml @@ -0,0 +1,42 @@ +name: veteran merc +description: "A battle-hardened soldier with a high-powered rifle and tactical armor covered in campaign patches. Their cybernetic eye locks onto you instantly." +attack: 1 +strength: 1 +defense: 40 +hp: 93 +ranged: 79 +speed: 5 +aggressive: true +respawn_ticks: 65 +attack_type: ranged +attack_bonus: 0 +strength_bonus: 0 +stab_defense: 40 +slash_defense: 40 +crush_defense: 35 +science_defense: 20 +ranged_defense: 55 +idle_descriptions: + - "checks their rifle's ammunition counter" + - "adjusts their tactical vest" + - "scans the area through their scope" + - "spits and mutters a war story" +combat_descriptions: + - "fires a high-caliber round at %s" + - "puts %s in their crosshairs and squeezes the trigger" + - "unleashes suppressive fire at %s" +size: medium +drops: + remains: bones + loot: + - item_id: credits + weight: 55 + quantity: 1200 + - item_id: chaosjunk + weight: 15 + quantity: 2 + - item_id: deathjunk + weight: 15 + quantity: 2 + - table: herb_table_mid + weight: 15 diff --git a/data/mobs/examples/void_reaper.yaml b/data/mobs/examples/void_reaper.yaml new file mode 100644 index 0000000..e54d776 --- /dev/null +++ b/data/mobs/examples/void_reaper.yaml @@ -0,0 +1,52 @@ +name: void reaper +description: "A shadowy figure that seems to absorb light itself. Its form shifts between a hooded specter and an armored construct. A scythe of dark energy flickers in its grasp." +attack: 62 +strength: 68 +defense: 72 +hp: 170 +speed: 3 +aggressive: true +respawn_ticks: 200 +attack_type: slash +attack_bonus: 60 +strength_bonus: 60 +stab_defense: 100 +slash_defense: 110 +crush_defense: 90 +science_defense: -45 +ranged_defense: 75 +weakness: bio +assassin_level: 80 +finishing_blow: lawjunk +idle_descriptions: + - "flickers in and out of existence" + - "draws the warmth from the surrounding air" + - "whispers in a language that predates humanity" + - "reaches out with shadowy tendrils" +combat_descriptions: + - "swings its void scythe at %s" + - "drains the life force from %s" + - "envelops %s in absolute darkness" +size: massive +drops: + remains: ectoplasm + loot: + - item_id: credits + weight: 30 + quantity: 20000 + - item_id: law_identifier + weight: 5 + - item_id: death_identifier + weight: 5 + - item_id: blood_identifier + weight: 5 + - item_id: bloodjunk + weight: 20 + quantity: 10 + - table: gem_table + weight: 15 + - item_id: uncut_diamond + weight: 10 + quantity: 5 + - table: herb_table_high + weight: 10 diff --git a/data/mobs/examples/war_drone.yaml b/data/mobs/examples/war_drone.yaml new file mode 100644 index 0000000..587ad09 --- /dev/null +++ b/data/mobs/examples/war_drone.yaml @@ -0,0 +1,42 @@ +name: war drone +description: "An upgraded combat drone with reinforced plating and a heavier weapons array. Its targeting systems whir as it locks onto you." +attack: 25 +strength: 28 +defense: 25 +hp: 65 +speed: 4 +aggressive: true +respawn_ticks: 50 +attack_type: slash +attack_bonus: 20 +strength_bonus: 18 +stab_defense: 35 +slash_defense: 30 +crush_defense: 40 +science_defense: -10 +ranged_defense: 20 +weakness: solar +idle_descriptions: + - "hovers aggressively, weapons armed" + - "emits a low, threatening hum" + - "paints a targeting reticle on the wall" + - "cycles through weapon modes with a click" +combat_descriptions: + - "fires a plasma bolt at %s" + - "slashes at %s with a rotary blade" + - "launches a concussion grenade at %s" +size: medium +drops: + remains: circuit_board + loot: + - item_id: credits + weight: 60 + quantity: 200 + - item_id: scrap + weight: 20 + quantity: 4 + - item_id: credits + weight: 10 + quantity: 500 + - table: gem_table + weight: 10 diff --git a/data/mobs/examples/weapons_smith.yaml b/data/mobs/examples/weapons_smith.yaml new file mode 100644 index 0000000..0ba8237 --- /dev/null +++ b/data/mobs/examples/weapons_smith.yaml @@ -0,0 +1,64 @@ +aggressive: false +attack: 1 +attack_type: crush +crush_defense: 0 +defense: 1 +description: A burly smith with soot-stained hands and a heavy leather apron, standing proudly by the forge. +hp: 80 +idle_descriptions: + - hammers at a glowing blade on the anvil + - wipes soot from his brow + - inspects a finished sword + - tends to the furnace fire +name: Weaponsmith +protected: true +ranged_defense: 0 +respawn_ticks: 30 +science_defense: 0 +slash_defense: 0 +speed: 5 +stab_defense: 0 +strength: 1 +talk: + nodes: + shop: + action: + shop: + items: + - buy_price: 25 + item_id: bronze_sword + sell_price: 6 + - buy_price: 60 + item_id: iron_sword + sell_price: 15 + - buy_price: 20 + item_id: bronze_axe + sell_price: 5 + - buy_price: 50 + item_id: iron_axe + sell_price: 12 + - buy_price: 20 + item_id: bronze_pickaxe + sell_price: 5 + - buy_price: 50 + item_id: iron_pickaxe + sell_price: 12 + - buy_price: 16 + item_id: bronze_med_helm + sell_price: 4 + - buy_price: 40 + item_id: iron_med_helm + sell_price: 10 + message: The Smithy — buy or sell weapons and armor. + message: '"Here''s the current inventory. All quality guaranteed."' + options: + - goto: start + text: '"That''s all for now."' + start: + message: '"Welcome to the Smithy! Finest weapons and armor on the asteroid."' + options: + - goto: shop + text: '"Show me what you''ve got."' + - text: '"Nothing right now."' +unique: true +size: small diff --git a/data/mobs/examples/zombie.yaml b/data/mobs/examples/zombie.yaml new file mode 100644 index 0000000..f5989e0 --- /dev/null +++ b/data/mobs/examples/zombie.yaml @@ -0,0 +1,33 @@ +name: zombie +description: "A shambling corpse reanimated by residual asteroid radiation." +attack: 10 +strength: 8 +defense: 8 +hp: 30 +speed: 6 +aggressive: true +respawn_ticks: 35 +attack_type: crush +attack_bonus: 4 +strength_bonus: 6 +stab_defense: 8 +slash_defense: 20 +crush_defense: -8 +science_defense: -15 +ranged_defense: 8 +weakness: solar +idle_descriptions: + - "groans and shuffles forward" + - "reaches out with decaying arms" + - "stumbles and catches itself" + - "stares blankly ahead" +size: medium +drops: + remains: bones + loot: + - item_id: credits + weight: 60 + quantity: 50 + - item_id: credits + weight: 40 + quantity: 200 diff --git a/data/mobs/farmer.yaml b/data/mobs/farmer.yaml deleted file mode 100644 index 591f1a3..0000000 --- a/data/mobs/farmer.yaml +++ /dev/null @@ -1,44 +0,0 @@ -name: Farmer -description: "A weathered farmer in muddy overalls, pockets bulging with seeds." -combat_descriptions: - - "swings a shovel at %s" - - "is getting beaten by %s" - - "grapples with %s" -idle_descriptions: - - "examines a handful of seeds" - - "wipes dirt from his hands" - - "mutters about the growing season" - - "adjusts his wide-brimmed hat" -attack: 3 -strength: 3 -defense: 3 -hp: 15 -speed: 5 -aggressive: false -respawn_ticks: 40 -attack_type: crush -stab_defense: 0 -slash_defense: 0 -crush_defense: 0 -science_defense: 0 -ranged_defense: 0 -steal_table: farmer_steal -steal_level: 10 -steal_xp: 15 -steal_speed: 4 -size: small -drops: - remains: "bones" - loot: - - item_id: "potato_seed" - weight: 40 - quantity: 3 - - item_id: "onion_seed" - weight: 30 - quantity: 2 - - item_id: "cabbage_seed" - weight: 20 - quantity: 2 - - item_id: "tomato_seed" - weight: 10 - quantity: 1 \ No newline at end of file diff --git a/data/mobs/feral_cyborg.yaml b/data/mobs/feral_cyborg.yaml deleted file mode 100644 index 8b30cc3..0000000 --- a/data/mobs/feral_cyborg.yaml +++ /dev/null @@ -1,38 +0,0 @@ -name: feral cyborg -description: "A heavily augmented human whose implants have driven them to madness. Razor-sharp blades extend from their forearms and their optical implant glows red." -attack: 34 -strength: 36 -defense: 32 -hp: 82 -speed: 4 -aggressive: true -respawn_ticks: 50 -attack_type: slash -attack_bonus: 30 -strength_bonus: 28 -stab_defense: 35 -slash_defense: 45 -crush_defense: 30 -science_defense: -10 -ranged_defense: 35 -idle_descriptions: - - "paces back and forth, muttering" - - "retracts and extends forearm blades" - - "emits a distorted laugh" - - "scratches at their own cybernetics" -combat_descriptions: - - "slashes %s with forearm blades" - - "delivers a powered kick to %s" - - "grapples %s with augmented strength" -size: medium -drops: - remains: bones - loot: - - item_id: credits - weight: 60 - quantity: 300 - - item_id: scrap - weight: 25 - quantity: 3 - - table: herb_table_mid - weight: 15 diff --git a/data/mobs/flight_attendant.yaml b/data/mobs/flight_attendant.yaml new file mode 100644 index 0000000..81bc3bf --- /dev/null +++ b/data/mobs/flight_attendant.yaml @@ -0,0 +1,32 @@ +name: Flight attendant +description: A smiling flight attendant in a crisp uniform, ready to assist passengers. +unique: false +protected: true +idle_descriptions: + - straightens a seat cushion + - checks the cabin for loose items + - adjusts her name badge + - smiles politely at passengers +talk: + nodes: + start: + message: '"Welcome aboard! Is there anything I can help you with?"' + options: + - text: '"I''m ready to disembark."' + goto: disembark + condition: + player_flag: 1001_look_sign + - text: '"What should I do?"' + goto: check_sign + condition: + player_flag: 1001_look_sign + not: true + - text: '"Goodbye."' + disembark: + message: '"Of course! Please proceed down the stairs when you''re ready. Have a wonderful stay."' + options: + - text: '"Thanks!"' + check_sign: + message: '"Before we land, please review the safety information posted on the wall. Just type {11 bold}look sign{/} to see it."' + options: + - text: '"Okay, I''ll take a look."' diff --git a/data/mobs/general_store_clerk.yaml b/data/mobs/general_store_clerk.yaml deleted file mode 100644 index 351b4c0..0000000 --- a/data/mobs/general_store_clerk.yaml +++ /dev/null @@ -1,71 +0,0 @@ -aggressive: false -attack: 1 -attack_type: crush -crush_defense: 0 -defense: 1 -description: A friendly merchant with a tidy apron, standing behind a well-stocked counter. -hp: 50 -idle_descriptions: - - arranges items on the shelves - - polishes the counter - - counts credits in the register - - greets a passerby with a nod -name: Shopkeeper -protected: true -ranged_defense: 0 -respawn_ticks: 30 -science_defense: 0 -slash_defense: 0 -speed: 5 -stab_defense: 0 -strength: 1 -talk: - nodes: - shop: - action: - shop: - items: - - buy_price: 10 - item_id: fishing_rod - sell_price: 2 - - buy_price: 2 - item_id: fishing_bait - sell_price: 0 - - buy_price: 10 - item_id: matches - sell_price: 2 - - buy_price: 40 - item_id: firesteel - sell_price: 10 - - buy_price: 30 - item_id: lighter - sell_price: 7 - - buy_price: 20 - item_id: hammer - sell_price: 5 - - buy_price: 10 - item_id: knife - sell_price: 2 - - buy_price: 10 - item_id: chisel - sell_price: 2 - - buy_price: 10 - item_id: bread - sell_price: 2 - - buy_price: 20 - item_id: bowstring - sell_price: 5 - message: What would you like to buy or sell? - message: '"Take your time. What can I get you?"' - options: - - goto: start - text: '"I''m done."' - start: - message: '"Welcome to the General Store! Need any supplies?"' - options: - - goto: shop - text: '"I''d like to browse."' - - end: true - text: '"Goodbye."' -unique: true -size: small diff --git a/data/mobs/ghoul.yaml b/data/mobs/ghoul.yaml deleted file mode 100644 index ae8fed6..0000000 --- a/data/mobs/ghoul.yaml +++ /dev/null @@ -1,38 +0,0 @@ -name: ghoul -description: "A radiation-scarred crew member, barely recognizable as human. Its flesh glows faintly and its eyes are hollow sockets." -attack: 22 -strength: 22 -defense: 20 -hp: 54 -speed: 4 -aggressive: true -respawn_ticks: 35 -attack_type: crush -attack_bonus: 15 -strength_bonus: 12 -stab_defense: 20 -slash_defense: 25 -crush_defense: 15 -science_defense: -5 -ranged_defense: 20 -weakness: hydro -idle_descriptions: - - "shambles aimlessly and moans" - - "scratches at the walls leaving glowing marks" - - "stares blankly into the darkness" - - "emits a low, rattling groan" -combat_descriptions: - - "claws at %s with irradiated hands" - - "lunges at %s with a gurgling shriek" - - "bites %s with decaying teeth" -size: medium -drops: - remains: bones - loot: - - item_id: credits - weight: 60 - quantity: 80 - - item_id: scrap - weight: 25 - - table: herb_table_low - weight: 15 diff --git a/data/mobs/goblin.yaml b/data/mobs/goblin.yaml deleted file mode 100644 index a02c112..0000000 --- a/data/mobs/goblin.yaml +++ /dev/null @@ -1,32 +0,0 @@ -name: goblin -description: "A small green-skinned goblin with a rusty blade." -attack: 1 -strength: 3 -defense: 3 -hp: 12 -speed: 5 -aggressive: true -respawn_ticks: 25 -attack_type: slash -attack_bonus: 3 -strength_bonus: 2 -stab_defense: 4 -slash_defense: 3 -crush_defense: -2 -science_defense: 0 -ranged_defense: 3 -idle_descriptions: - - "mutters something unintelligible" - - "waves a rusty blade around" - - "picks its nose" - - "kicks a pebble" -size: small -drops: - remains: bones - loot: - - item_id: credits - weight: 80 - quantity: 5 - - item_id: credits - weight: 20 - quantity: 25 diff --git a/data/mobs/greater_drone.yaml b/data/mobs/greater_drone.yaml deleted file mode 100644 index 11cf8e2..0000000 --- a/data/mobs/greater_drone.yaml +++ /dev/null @@ -1,33 +0,0 @@ -name: greater drone -description: "A large, heavily armored drone with multiple energy emitters. Red warning lights pulse along its hull." -attack: 1 -strength: 1 -defense: 30 -hp: 120 -ranged: 0 -science: 40 -speed: 4 -aggressive: true -respawn_ticks: 80 -attack_type: science -attack_bonus: 0 -strength_bonus: 0 -stab_defense: 55 -slash_defense: 55 -crush_defense: 50 -science_defense: 40 -ranged_defense: -20 -idle_descriptions: - - "projects a defensive energy shield" - - "recalibrates its targeting array" - - "emits a warning klaxon" - - "deploys sensor probes" -size: medium -drops: - loot: - - item_id: scrap - weight: 40 - quantity: 3 - - item_id: credits - weight: 60 - quantity: 1500 diff --git a/data/mobs/guard.yaml b/data/mobs/guard.yaml deleted file mode 100644 index 46c235c..0000000 --- a/data/mobs/guard.yaml +++ /dev/null @@ -1,76 +0,0 @@ -aggressive: false -attack: 5 -attack_bonus: 8 -attack_type: slash -crush_defense: 10 -defense: 5 -description: A stern-looking guard in weathered armor. -hp: 30 -idle_descriptions: - - scans the area with a watchful eye - - adjusts the grip on his weapon - - nods curtly at passersby - - leans against the gate, arms folded -name: Guard -protected: true -ranged_defense: 12 -respawn_ticks: 60 -science_defense: -5 -slash_defense: 15 -speed: 5 -stab_defense: 12 -strength: 5 -strength_bonus: 6 -talk: - nodes: - about_gate: - action: - set_player_flags: - talked_to_guard: true - message: '"Supplies. Weapons. Things you don''t need to worry about." He shifts his weight. "Tell you what — bring me some copper ore and I''ll stamp you a pass."' - options: - - end: true - text: '"I''ll be back."' - - condition: - has_item: copper_ore - goto: trade_ore - text: '"I have some right here."' - - end: true - text: '"Goodbye."' - has_pass: - action: - set_flags: - gate_open: true - message: '"Let me see that..." He examines your pass and nods. "Alright, I''ll open the gate for you."' - options: - - end: true - text: '"Thanks."' - start: - message: '"Halt! This area is restricted." The guard eyes you suspiciously.' - options: - - goto: about_gate - text: '"What''s behind that gate?"' - - condition: - has_item: copper_ore - goto: trade_ore - text: '"I have copper ore."' - - condition: - player_flag: got_pass - value: true - goto: has_pass - text: '"I have a pass."' - - end: true - text: '"Goodbye."' - trade_ore: - action: - give_item: pass_stub - set_player_flags: - got_pass: true - talked_to_guard: true - take_item: copper_ore - message: '"Good quality ore. This''ll do." He stamps a slip of paper and hands it to you. "That''s your pass. Don''t lose it."' - options: - - end: true - text: '"Thanks."' -unique: true -size: medium diff --git a/data/mobs/heavy_mech.yaml b/data/mobs/heavy_mech.yaml deleted file mode 100644 index e2f5f5a..0000000 --- a/data/mobs/heavy_mech.yaml +++ /dev/null @@ -1,42 +0,0 @@ -name: heavy mech -description: "A lumbering assault mech with layered armor plating and a rotary cannon arm. Steam vents from its exhaust ports with each step." -attack: 40 -strength: 44 -defense: 44 -hp: 94 -speed: 5 -aggressive: true -respawn_ticks: 70 -attack_type: crush -attack_bonus: 35 -strength_bonus: 35 -stab_defense: 55 -slash_defense: 55 -crush_defense: 65 -science_defense: -25 -ranged_defense: 40 -weakness: solar -idle_descriptions: - - "scans the room with a blue optical beam" - - "vents a cloud of steam" - - "rotates its cannon with a mechanical whine" - - "announces a threat level assessment" -combat_descriptions: - - "fires its rotary cannon at %s" - - "smashes %s with a hydraulic fist" - - "unleashes a missile salvo at %s" -size: massive -drops: - remains: scrap - loot: - - item_id: credits - weight: 55 - quantity: 1000 - - item_id: scrap - weight: 25 - quantity: 8 - - table: gem_table - weight: 10 - - item_id: lawjunk - weight: 10 - quantity: 2 diff --git a/data/mobs/iron_sentinel.yaml b/data/mobs/iron_sentinel.yaml deleted file mode 100644 index bf8b9b5..0000000 --- a/data/mobs/iron_sentinel.yaml +++ /dev/null @@ -1,31 +0,0 @@ -name: iron sentinel -description: "A massive bipedal automaton forged from pre-regression alloys. Its joints grind with each deliberate step." -attack: 25 -strength: 30 -defense: 45 -hp: 180 -speed: 6 -aggressive: true -respawn_ticks: 100 -attack_type: crush -attack_bonus: 40 -strength_bonus: 35 -stab_defense: 80 -slash_defense: 80 -crush_defense: 70 -science_defense: -30 -ranged_defense: 50 -idle_descriptions: - - "stands motionless, servos whining softly" - - "turns its armored head with a mechanical grind" - - "vents steam from exhaust ports" - - "scans the area with a red optical sensor" -size: large -drops: - loot: - - item_id: scrap - weight: 30 - quantity: 5 - - item_id: credits - weight: 60 - quantity: 5000 diff --git a/data/mobs/lesser_drone.yaml b/data/mobs/lesser_drone.yaml deleted file mode 100644 index c9e50a5..0000000 --- a/data/mobs/lesser_drone.yaml +++ /dev/null @@ -1,32 +0,0 @@ -name: lesser drone -description: "A floating metallic drone with a pulsing energy core. Its surface crackles with electric discharge." -attack: 1 -strength: 1 -defense: 18 -hp: 55 -ranged: 0 -science: 20 -speed: 4 -aggressive: true -respawn_ticks: 50 -attack_type: science -attack_bonus: 0 -strength_bonus: 0 -stab_defense: 35 -slash_defense: 35 -crush_defense: 30 -science_defense: 20 -ranged_defense: -10 -idle_descriptions: - - "hovers silently, scanning the area" - - "emits a low electronic hum" - - "projects a thin beam of light across the floor" - - "rotates slowly in place" -size: small -drops: - loot: - - item_id: scrap - weight: 60 - - item_id: credits - weight: 40 - quantity: 300 diff --git a/data/mobs/man.yaml b/data/mobs/man.yaml deleted file mode 100644 index 8478f41..0000000 --- a/data/mobs/man.yaml +++ /dev/null @@ -1,48 +0,0 @@ -name: man -description: "A shabby-looking man loitering in the town square." -combat_descriptions: - - "is engaged in a fight to the death with %s" - - "is getting pummelled by %s" - - "is locked in combat with %s" - - "trades blows with %s" - - "circles warily around %s" -idle_descriptions: - - "scribbles something in a small notebook" - - "gazes skyward at the clouds" - - "leans against a wall, looking bored" - - "scratches his head thoughtfully" - - "stares off into the distance" - - "adjusts his tunic and stretches" -attack: 1 -strength: 1 -defense: 1 -hp: 7 -speed: 5 -aggressive: false -respawn_ticks: 30 -steal_table: man_steal -steal_level: 1 -steal_xp: 8 -steal_speed: 4 -attack_type: crush -stab_defense: 0 -slash_defense: 0 -crush_defense: 0 -science_defense: 0 -ranged_defense: 0 -size: small -drops: - remains: "bones" - loot: - - item_id: "credits" - weight: 98 - quantity: 10 - - item_id: "credits" - weight: 2 - quantity: 150 - - item_id: "grimy_guam" - weight: 8 - - item_id: "grimy_marrentill" - weight: 4 - - item_id: "grimy_tarromin" - weight: 2 diff --git a/data/mobs/molten_elemental.yaml b/data/mobs/molten_elemental.yaml deleted file mode 100644 index 9c46ccb..0000000 --- a/data/mobs/molten_elemental.yaml +++ /dev/null @@ -1,42 +0,0 @@ -name: molten elemental -description: "A flowing mass of liquid metal and superheated slag, roughly humanoid. The air around it shimmers with heat and droplets of molten alloy drip to the floor." -attack: 48 -strength: 52 -defense: 52 -hp: 115 -speed: 5 -aggressive: true -respawn_ticks: 80 -attack_type: crush -attack_bonus: 40 -strength_bonus: 42 -stab_defense: 60 -slash_defense: 60 -crush_defense: 70 -science_defense: -30 -ranged_defense: 45 -weakness: hydro -idle_descriptions: - - "bubbles and churns, throwing off sparks" - - "melts a nearby chunk of metal absent-mindedly" - - "pulses with an inner orange glow" - - "drips glowing droplets onto the floor" -combat_descriptions: - - "hurls a glob of molten metal at %s" - - "engulfs %s in a wave of liquid fire" - - "smashes %s with a superheated limb" -size: large -drops: - remains: scrap - loot: - - item_id: credits - weight: 50 - quantity: 2000 - - item_id: biojunk - weight: 20 - quantity: 3 - - item_id: bloodjunk - weight: 15 - quantity: 2 - - table: herb_table_high - weight: 15 diff --git a/data/mobs/moss_giant.yaml b/data/mobs/moss_giant.yaml deleted file mode 100644 index f19f0a3..0000000 --- a/data/mobs/moss_giant.yaml +++ /dev/null @@ -1,32 +0,0 @@ -name: moss giant -description: "A towering creature covered in moss and vines, its rocky skin dripping with moisture." -attack: 12 -strength: 14 -defense: 10 -hp: 60 -speed: 7 -aggressive: true -respawn_ticks: 45 -attack_type: crush -attack_bonus: 10 -strength_bonus: 12 -stab_defense: 15 -slash_defense: 12 -crush_defense: 18 -science_defense: -5 -ranged_defense: 15 -idle_descriptions: - - "surveys its territory with dull eyes" - - "pulls a vine from its shoulder" - - "stamps the ground, sending tremors" - - "scratches its mossy hide" -size: massive -drops: - remains: bones - loot: - - item_id: credits - weight: 50 - quantity: 120 - - item_id: credits - weight: 50 - quantity: 500 diff --git a/data/mobs/mutant_rat.yaml b/data/mobs/mutant_rat.yaml deleted file mode 100644 index 7836ef9..0000000 --- a/data/mobs/mutant_rat.yaml +++ /dev/null @@ -1,39 +0,0 @@ -name: mutant rat -description: "A bloated rodent with glowing green eyes and exposed muscle tissue. Bio-engineering runoff has made it unnaturally aggressive." -attack: 13 -strength: 13 -defense: 12 -hp: 32 -speed: 4 -aggressive: true -respawn_ticks: 25 -attack_type: crush -attack_bonus: 8 -strength_bonus: 6 -stab_defense: 15 -slash_defense: 15 -crush_defense: 10 -science_defense: -10 -ranged_defense: 5 -weakness: bio -idle_descriptions: - - "scurries frantically in circles" - - "gnaws on a rusted pipe" - - "emits a gurgling screech" - - "twitches unnaturally" -combat_descriptions: - - "bites %s with glowing teeth" - - "slashes %s with mutated claws" - - "lunges at %s with unnatural speed" -size: small -drops: - remains: bones - loot: - - item_id: credits - weight: 60 - quantity: 20 - - item_id: scrap - weight: 30 - - item_id: credits - weight: 10 - quantity: 60 diff --git a/data/mobs/newbie_trainer.yaml b/data/mobs/newbie_trainer.yaml deleted file mode 100644 index 3897dba..0000000 --- a/data/mobs/newbie_trainer.yaml +++ /dev/null @@ -1,25 +0,0 @@ -name: Newbie Trainer -description: "A friendly-looking instructor ready to help new adventurers." -unique: true -protected: true -attack: 1 -strength: 1 -defense: 1 -hp: 50 -speed: 5 -aggressive: false -respawn_ticks: 30 -attack_type: crush -stab_defense: 0 -slash_defense: 0 -crush_defense: 0 -science_defense: 0 -ranged_defense: 0 -idle_descriptions: - - "reviews a training manual" - - "adjusts a practice dummy" - - "demonstrates a sword stance to no one in particular" - - "offers a friendly nod to passersby" - - "polishes a wooden shield" - - "checks a stopwatch and jots something down" -size: small diff --git a/data/mobs/phantom.yaml b/data/mobs/phantom.yaml deleted file mode 100644 index d871b76..0000000 --- a/data/mobs/phantom.yaml +++ /dev/null @@ -1,32 +0,0 @@ -name: phantom -description: "A semi-transparent entity that phases in and out of visible light. Its psychic attacks are devastating to anyone without a spectral visor." -assassin_level: 45 -damage_without: spectral_visor -attack: 35 -strength: 30 -defense: 25 -hp: 100 -speed: 3 -aggressive: true -respawn_ticks: 50 -idle_descriptions: - - "flickers between visible and invisible" - - "emits a low, resonant hum" - - "drifts through a wall and back again" - - "stares at you with hollow, glowing eyes" -combat_descriptions: - - "blasts %s with a psychic wave" - - "phases through %s's defenses" - - "unleashes a spectral shriek at %s" -size: medium -drops: - remains: ectoplasm - loot: - - item_id: credits - weight: 60 - quantity: 500 - - item_id: spectral_visor - weight: 3 - - item_id: credits - weight: 37 - quantity: 1000 diff --git a/data/mobs/plasma_wraith.yaml b/data/mobs/plasma_wraith.yaml deleted file mode 100644 index c4ced2b..0000000 --- a/data/mobs/plasma_wraith.yaml +++ /dev/null @@ -1,43 +0,0 @@ -name: plasma wraith -description: "A shimmering entity of contained plasma, vaguely humanoid in shape. It radiates intense heat and hums with barely contained energy." -attack: 1 -strength: 1 -defense: 22 -hp: 56 -science: 65 -speed: 4 -aggressive: true -respawn_ticks: 60 -attack_type: science -attack_bonus: 0 -strength_bonus: 0 -stab_defense: 30 -slash_defense: 30 -crush_defense: 25 -science_defense: 45 -ranged_defense: -10 -weakness: hydro -idle_descriptions: - - "drifts silently, leaving heat shimmer in its wake" - - "pulses with internal light" - - "phases partially through a wall" - - "emits a low frequency hum" -combat_descriptions: - - "lashes %s with a whip of plasma" - - "engulfs %s in a superheated cloud" - - "discharges a concentrated beam at %s" -size: medium -drops: - remains: ectoplasm - loot: - - item_id: credits - weight: 50 - quantity: 400 - - item_id: chaosjunk - weight: 20 - quantity: 2 - - item_id: cosmicjunk - weight: 15 - quantity: 2 - - table: gem_table - weight: 15 diff --git a/data/mobs/psionic_entity.yaml b/data/mobs/psionic_entity.yaml deleted file mode 100644 index 1c518bf..0000000 --- a/data/mobs/psionic_entity.yaml +++ /dev/null @@ -1,46 +0,0 @@ -name: psionic entity -description: "A barely visible distortion in the air, only detectable by the pressure it exerts on your mind. When it focuses, you see a shimmering outline of something vast and ancient." -attack: 1 -strength: 1 -defense: 42 -hp: 128 -science: 97 -speed: 4 -aggressive: true -respawn_ticks: 100 -attack_type: science -attack_bonus: 0 -strength_bonus: 0 -stab_defense: 50 -slash_defense: 50 -crush_defense: 45 -science_defense: 70 -ranged_defense: -20 -idle_descriptions: - - "probes the edges of your consciousness" - - "flickers between visible and invisible states" - - "emits a subsonic pulse you feel in your teeth" - - "momentarily shows you visions of another dimension" -combat_descriptions: - - "assaults %s's mind with psionic force" - - "tears at %s's perception of reality" - - "unleashes a devastating mental blast at %s" -size: large -drops: - remains: ectoplasm - loot: - - item_id: credits - weight: 40 - quantity: 5000 - - item_id: lawjunk - weight: 20 - quantity: 5 - - item_id: cosmicjunk - weight: 15 - quantity: 5 - - table: gem_table - weight: 15 - - item_id: spectral_visor - weight: 5 - - table: herb_table_high - weight: 5 diff --git a/data/mobs/rat.yaml b/data/mobs/rat.yaml deleted file mode 100644 index 4265674..0000000 --- a/data/mobs/rat.yaml +++ /dev/null @@ -1,22 +0,0 @@ -name: rat -description: "A large, mangy rat with beady red eyes." -attack: 1 -strength: 1 -defense: 1 -hp: 2 -speed: 4 -aggressive: false -respawn_ticks: 20 -attack_type: crush -stab_defense: 0 -slash_defense: 0 -crush_defense: 0 -science_defense: 0 -ranged_defense: 0 -idle_descriptions: - - "sniffs around the ground" - - "nibbles on something" - - "scurries in circles" -size: small -drops: - remains: bones diff --git a/data/mobs/sawmill_operator.yaml b/data/mobs/sawmill_operator.yaml deleted file mode 100644 index 81521bd..0000000 --- a/data/mobs/sawmill_operator.yaml +++ /dev/null @@ -1,49 +0,0 @@ -color: "186" -description: A burly worker in a thick apron, covered in sawdust. He operates the industrial sawmill. -idle: The sawmill operator wipes sawdust from his goggles. -name: sawmill operator -talk: - nodes: - goodbye: - message: Come back anytime you need more planks! - prices: - message: |- - Here's what I charge per log: - Regular logs: 5 credits - Oak logs: 10 credits - Teak logs: 20 credits - Mahogany logs: 40 credits - - Want me to process your logs? - options: - - condition: - any_of: - - has_item: logs - - has_item: oak_logs - - has_item: teak_logs - - has_item: mahogany_logs - next: process - text: Yes, process all my logs. - - next: goodbye - text: No thanks. - process: - action: - sawmill: true - message: "" - start: - message: Welcome to the lumberyard! I can turn your logs into planks — for a small fee, of course. What can I do for ya? - options: - - condition: - any_of: - - has_item: logs - - has_item: oak_logs - - has_item: teak_logs - - has_item: mahogany_logs - next: prices - text: Turn all my logs into planks. - - next: prices - text: What are your prices? - - next: goodbye - text: Nothing for now. -unique: true -size: small diff --git a/data/mobs/scrap_bot.yaml b/data/mobs/scrap_bot.yaml deleted file mode 100644 index a8b34d8..0000000 --- a/data/mobs/scrap_bot.yaml +++ /dev/null @@ -1,39 +0,0 @@ -name: scrap bot -description: "A malfunctioning maintenance robot that has gone rogue. Its chassis is covered in dents and rust, and one optical sensor flickers erratically." -attack: 15 -strength: 15 -defense: 14 -hp: 30 -speed: 5 -aggressive: true -respawn_ticks: 30 -attack_type: crush -attack_bonus: 10 -strength_bonus: 8 -stab_defense: 20 -slash_defense: 15 -crush_defense: 25 -science_defense: -5 -ranged_defense: 10 -idle_descriptions: - - "beeps erratically and twitches" - - "bumps into a wall and reverses" - - "emits a burst of static" - - "scans the floor with a flickering beam" -combat_descriptions: - - "rams %s with its chassis" - - "swings a broken manipulator arm at %s" - - "discharges a spark at %s" -size: medium -drops: - remains: scrap - loot: - - item_id: credits - weight: 60 - quantity: 40 - - item_id: scrap - weight: 30 - quantity: 2 - - item_id: credits - weight: 10 - quantity: 100 diff --git a/data/mobs/security_turret.yaml b/data/mobs/security_turret.yaml deleted file mode 100644 index 9929106..0000000 --- a/data/mobs/security_turret.yaml +++ /dev/null @@ -1,41 +0,0 @@ -name: security turret -description: "A ceiling-mounted auto-turret with twin barrels and a red targeting laser. It tracks you with mechanical precision." -attack: 1 -strength: 1 -defense: 16 -hp: 44 -ranged: 34 -speed: 5 -aggressive: true -respawn_ticks: 40 -attack_type: ranged -attack_bonus: 0 -strength_bonus: 0 -stab_defense: 30 -slash_defense: 20 -crush_defense: 40 -science_defense: -20 -ranged_defense: 15 -weakness: solar -idle_descriptions: - - "pans the room with a targeting laser" - - "emits a rhythmic clicking sound" - - "calibrates its targeting sensors" - - "beeps a warning tone" -combat_descriptions: - - "fires twin bolts at %s" - - "unleashes a burst of rounds at %s" - - "locks onto %s and opens fire" -size: small -drops: - remains: scrap - loot: - - item_id: credits - weight: 70 - quantity: 100 - - item_id: scrap - weight: 20 - quantity: 3 - - item_id: credits - weight: 10 - quantity: 250 diff --git a/data/mobs/skeleton.yaml b/data/mobs/skeleton.yaml deleted file mode 100644 index ba82afc..0000000 --- a/data/mobs/skeleton.yaml +++ /dev/null @@ -1,31 +0,0 @@ -name: skeleton -description: "An animated pile of bones, held together by dark energy." -attack: 8 -strength: 6 -defense: 8 -hp: 22 -speed: 5 -aggressive: true -respawn_ticks: 30 -attack_type: stab -attack_bonus: 6 -strength_bonus: 4 -stab_defense: 10 -slash_defense: 18 -crush_defense: -5 -science_defense: -8 -ranged_defense: 10 -idle_descriptions: - - "rattles ominously" - - "clicks its jaw open and shut" - - "stares with empty eye sockets" -size: medium -drops: - remains: bones - loot: - - item_id: credits - weight: 70 - quantity: 30 - - item_id: credits - weight: 30 - quantity: 100 diff --git a/data/mobs/slug.yaml b/data/mobs/slug.yaml deleted file mode 100644 index 64082ec..0000000 --- a/data/mobs/slug.yaml +++ /dev/null @@ -1,27 +0,0 @@ -name: slug -description: "A bloated, translucent slug the size of a dog. Its skin glistens with toxic mucus. It cannot be killed by conventional means — only salt can destroy it." -assassin_level: 1 -finishing_blow: salt -attack: 3 -strength: 3 -defense: 1 -hp: 15 -speed: 6 -aggressive: false -respawn_ticks: 25 -idle_descriptions: - - "oozes along the floor leaving a slimy trail" - - "contracts and expands rhythmically" - - "extends its eyestalks toward you" - - "secretes a glob of toxic mucus" -combat_descriptions: - - "lunges slimily at %s" - - "sprays mucus toward %s" - - "writhes in combat with %s" -size: small -drops: - remains: slug_mucus - loot: - - item_id: credits - weight: 100 - quantity: 15 diff --git a/data/mobs/solar_panel_frame.yaml b/data/mobs/solar_panel_frame.yaml deleted file mode 100644 index 90269f2..0000000 --- a/data/mobs/solar_panel_frame.yaml +++ /dev/null @@ -1,33 +0,0 @@ -name: solar panel frame -description: "A half-assembled photovoltaic array on a steel frame. Panels, brackets and cabling are laid out, waiting to be fitted. This is work, not a fight — fix the panels into place to complete the array." -kind: task -verb: assemble -progress_noun: assembly -complete_message: "You bolt the final panel into place and the solar array hums to life!" -hp: 40 -defense: 10 -speed: 5 -aggressive: false -respawn_ticks: 40 -attack_type: crush -crush_defense: 0 -stab_defense: 40 -slash_defense: 40 -ranged_defense: 10 -science_defense: 10 -idle_descriptions: - - "stands half-assembled, panels waiting to be fitted" - - "has loose cabling dangling from an open junction box" - - "catches the light on its few mounted panels" -size: medium -drops: - loot: - - item_id: credits - weight: 70 - quantity: 40 - - item_id: credits - weight: 25 - quantity: 90 - - item_id: coal - weight: 5 - quantity: 1 diff --git a/data/mobs/tanner.yaml b/data/mobs/tanner.yaml deleted file mode 100644 index 1325468..0000000 --- a/data/mobs/tanner.yaml +++ /dev/null @@ -1,68 +0,0 @@ -aggressive: false -attack: 1 -attack_type: crush -crush_defense: 0 -defense: 1 -description: A weathered craftsman with stained hands and a leather apron. -hp: 50 -idle_descriptions: - - scrapes at a piece of hide - - examines a stack of leathers - - sharpens a tanning knife - - wipes sweat from his brow -name: Tanner -protected: true -ranged_defense: 0 -respawn_ticks: 30 -science_defense: 0 -slash_defense: 0 -speed: 5 -stab_defense: 0 -strength: 1 -talk: - nodes: - start: - message: '"Bring me some cowhides and I''ll tan them for you. Leather is 10 credits, hard leather is 50."' - options: - - condition: - all_of: - - has_item: cowhide - - min_credits: 10 - goto: tan_leather - text: '"Tan a cowhide into leather (10 credits)."' - - condition: - all_of: - - has_item: cowhide - - min_credits: 50 - goto: tan_hard_leather - text: '"Tan a cowhide into hard leather (50 credits)."' - - end: true - text: '"Never mind."' - tan_hard_leather: - action: - cost: 50 - give_item: hard_leather - take_item: cowhide - message: The tanner takes your cowhide and subjects it to an intense curing process. "Here's your hard leather." - options: - - condition: - has_item: cowhide - goto: start - text: '"Tan another."' - - end: true - text: '"Thanks."' - tan_leather: - action: - cost: 10 - give_item: leather - take_item: cowhide - message: The tanner takes your cowhide and works it skillfully. "Here's your leather." - options: - - condition: - has_item: cowhide - goto: start - text: '"Tan another."' - - end: true - text: '"Thanks."' -unique: true -size: small diff --git a/data/mobs/titan_sentinel.yaml b/data/mobs/titan_sentinel.yaml deleted file mode 100644 index 32ddcc2..0000000 --- a/data/mobs/titan_sentinel.yaml +++ /dev/null @@ -1,41 +0,0 @@ -name: titan sentinel -description: "A colossal automaton, the bigger brother of the iron sentinel. Its armor is reinforced adamantite alloy and its optics burn with crimson fire." -attack: 50 -strength: 52 -defense: 56 -hp: 132 -speed: 5 -aggressive: true -respawn_ticks: 120 -attack_type: crush -attack_bonus: 48 -strength_bonus: 45 -stab_defense: 90 -slash_defense: 90 -crush_defense: 80 -science_defense: -35 -ranged_defense: 60 -weakness: solar -idle_descriptions: - - "stands motionless, gyros humming" - - "scans the area with a sweeping crimson beam" - - "vents superheated exhaust" - - "rotates its armored torso with a deep grinding sound" -combat_descriptions: - - "smashes %s with a titan-grade fist" - - "unleashes a devastating plasma barrage at %s" - - "drives %s into the ground with overwhelming force" -size: massive -drops: - loot: - - item_id: scrap - weight: 30 - quantity: 10 - - item_id: credits - weight: 50 - quantity: 8000 - - table: gem_table - weight: 15 - - item_id: deathjunk - weight: 5 - quantity: 5 diff --git a/data/mobs/veteran_merc.yaml b/data/mobs/veteran_merc.yaml deleted file mode 100644 index 88238b6..0000000 --- a/data/mobs/veteran_merc.yaml +++ /dev/null @@ -1,42 +0,0 @@ -name: veteran merc -description: "A battle-hardened soldier with a high-powered rifle and tactical armor covered in campaign patches. Their cybernetic eye locks onto you instantly." -attack: 1 -strength: 1 -defense: 40 -hp: 93 -ranged: 79 -speed: 5 -aggressive: true -respawn_ticks: 65 -attack_type: ranged -attack_bonus: 0 -strength_bonus: 0 -stab_defense: 40 -slash_defense: 40 -crush_defense: 35 -science_defense: 20 -ranged_defense: 55 -idle_descriptions: - - "checks their rifle's ammunition counter" - - "adjusts their tactical vest" - - "scans the area through their scope" - - "spits and mutters a war story" -combat_descriptions: - - "fires a high-caliber round at %s" - - "puts %s in their crosshairs and squeezes the trigger" - - "unleashes suppressive fire at %s" -size: medium -drops: - remains: bones - loot: - - item_id: credits - weight: 55 - quantity: 1200 - - item_id: chaosjunk - weight: 15 - quantity: 2 - - item_id: deathjunk - weight: 15 - quantity: 2 - - table: herb_table_mid - weight: 15 diff --git a/data/mobs/void_reaper.yaml b/data/mobs/void_reaper.yaml deleted file mode 100644 index e54d776..0000000 --- a/data/mobs/void_reaper.yaml +++ /dev/null @@ -1,52 +0,0 @@ -name: void reaper -description: "A shadowy figure that seems to absorb light itself. Its form shifts between a hooded specter and an armored construct. A scythe of dark energy flickers in its grasp." -attack: 62 -strength: 68 -defense: 72 -hp: 170 -speed: 3 -aggressive: true -respawn_ticks: 200 -attack_type: slash -attack_bonus: 60 -strength_bonus: 60 -stab_defense: 100 -slash_defense: 110 -crush_defense: 90 -science_defense: -45 -ranged_defense: 75 -weakness: bio -assassin_level: 80 -finishing_blow: lawjunk -idle_descriptions: - - "flickers in and out of existence" - - "draws the warmth from the surrounding air" - - "whispers in a language that predates humanity" - - "reaches out with shadowy tendrils" -combat_descriptions: - - "swings its void scythe at %s" - - "drains the life force from %s" - - "envelops %s in absolute darkness" -size: massive -drops: - remains: ectoplasm - loot: - - item_id: credits - weight: 30 - quantity: 20000 - - item_id: law_identifier - weight: 5 - - item_id: death_identifier - weight: 5 - - item_id: blood_identifier - weight: 5 - - item_id: bloodjunk - weight: 20 - quantity: 10 - - table: gem_table - weight: 15 - - item_id: uncut_diamond - weight: 10 - quantity: 5 - - table: herb_table_high - weight: 10 diff --git a/data/mobs/war_drone.yaml b/data/mobs/war_drone.yaml deleted file mode 100644 index 587ad09..0000000 --- a/data/mobs/war_drone.yaml +++ /dev/null @@ -1,42 +0,0 @@ -name: war drone -description: "An upgraded combat drone with reinforced plating and a heavier weapons array. Its targeting systems whir as it locks onto you." -attack: 25 -strength: 28 -defense: 25 -hp: 65 -speed: 4 -aggressive: true -respawn_ticks: 50 -attack_type: slash -attack_bonus: 20 -strength_bonus: 18 -stab_defense: 35 -slash_defense: 30 -crush_defense: 40 -science_defense: -10 -ranged_defense: 20 -weakness: solar -idle_descriptions: - - "hovers aggressively, weapons armed" - - "emits a low, threatening hum" - - "paints a targeting reticle on the wall" - - "cycles through weapon modes with a click" -combat_descriptions: - - "fires a plasma bolt at %s" - - "slashes at %s with a rotary blade" - - "launches a concussion grenade at %s" -size: medium -drops: - remains: circuit_board - loot: - - item_id: credits - weight: 60 - quantity: 200 - - item_id: scrap - weight: 20 - quantity: 4 - - item_id: credits - weight: 10 - quantity: 500 - - table: gem_table - weight: 10 diff --git a/data/mobs/weapons_smith.yaml b/data/mobs/weapons_smith.yaml deleted file mode 100644 index 2af6299..0000000 --- a/data/mobs/weapons_smith.yaml +++ /dev/null @@ -1,65 +0,0 @@ -aggressive: false -attack: 1 -attack_type: crush -crush_defense: 0 -defense: 1 -description: A burly smith with soot-stained hands and a heavy leather apron, standing proudly by the forge. -hp: 80 -idle_descriptions: - - hammers at a glowing blade on the anvil - - wipes soot from his brow - - inspects a finished sword - - tends to the furnace fire -name: Weaponsmith -protected: true -ranged_defense: 0 -respawn_ticks: 30 -science_defense: 0 -slash_defense: 0 -speed: 5 -stab_defense: 0 -strength: 1 -talk: - nodes: - shop: - action: - shop: - items: - - buy_price: 25 - item_id: bronze_sword - sell_price: 6 - - buy_price: 60 - item_id: iron_sword - sell_price: 15 - - buy_price: 20 - item_id: bronze_axe - sell_price: 5 - - buy_price: 50 - item_id: iron_axe - sell_price: 12 - - buy_price: 20 - item_id: bronze_pickaxe - sell_price: 5 - - buy_price: 50 - item_id: iron_pickaxe - sell_price: 12 - - buy_price: 16 - item_id: bronze_med_helm - sell_price: 4 - - buy_price: 40 - item_id: iron_med_helm - sell_price: 10 - message: The Smithy — buy or sell weapons and armor. - message: '"Here''s the current inventory. All quality guaranteed."' - options: - - goto: start - text: '"That''s all for now."' - start: - message: '"Welcome to the Smithy! Finest weapons and armor on the asteroid."' - options: - - goto: shop - text: '"Show me what you''ve got."' - - end: true - text: '"Nothing right now."' -unique: true -size: small diff --git a/data/mobs/zombie.yaml b/data/mobs/zombie.yaml deleted file mode 100644 index f5989e0..0000000 --- a/data/mobs/zombie.yaml +++ /dev/null @@ -1,33 +0,0 @@ -name: zombie -description: "A shambling corpse reanimated by residual asteroid radiation." -attack: 10 -strength: 8 -defense: 8 -hp: 30 -speed: 6 -aggressive: true -respawn_ticks: 35 -attack_type: crush -attack_bonus: 4 -strength_bonus: 6 -stab_defense: 8 -slash_defense: 20 -crush_defense: -8 -science_defense: -15 -ranged_defense: 8 -weakness: solar -idle_descriptions: - - "groans and shuffles forward" - - "reaches out with decaying arms" - - "stumbles and catches itself" - - "stares blankly ahead" -size: medium -drops: - remains: bones - loot: - - item_id: credits - weight: 60 - quantity: 50 - - item_id: credits - weight: 40 - quantity: 200 diff --git a/data/objects/netrunner.yaml b/data/objects/netrunner.yaml index 21049e9..ced3f10 100644 --- a/data/objects/netrunner.yaml +++ b/data/objects/netrunner.yaml @@ -23,15 +23,13 @@ talk: value: true goto: tips_secure text: '"Tell me about the secure terminal."' - - end: true - text: '"Goodbye."' + - text: '"Goodbye."' terminals: message: '"There''s a basic terminal right here in this lab -- good for beginners. The station down east has an advanced one if you''ve got the chops. And if you''re really good, there''s a secure terminal deep in the compound. You''ll need the skills to match though."' options: - goto: tips_basic text: '"Any tips?"' - - end: true - text: '"Thanks."' + - text: '"Thanks."' tips_advanced: action: set_player_flags: @@ -40,8 +38,7 @@ talk: options: - goto: tips_secure text: '"Tell me about the secure terminal."' - - end: true - text: '"Thanks."' + - text: '"Thanks."' tips_basic: action: set_player_flags: @@ -50,17 +47,14 @@ talk: options: - goto: tips_advanced text: '"What about the advanced terminal?"' - - end: true - text: '"Thanks."' + - text: '"Thanks."' tips_secure: message: '"Secure terminal? Signal Bluff. It''s a bluffing game -- you and the system each roll hidden dice and take turns making claims about the total. Ones are wild. Call the bluff or raise the stakes. Read the probabilities, play the odds, and don''t let it psych you out."' options: - - end: true - text: '"Thanks."' + - text: '"Thanks."' what_is: message: '"Hacking''s about jacking into terminals and running their gauntlets. Each terminal runs a different challenge -- puzzles, hunts, pattern games. Crack ''em and you get better at it. Simple as that."' options: - goto: terminals text: '"Where can I find terminals?"' - - end: true - text: '"Goodbye."' + - text: '"Goodbye."' diff --git a/data/objects/tool_shed.yaml b/data/objects/tool_shed.yaml index 583becb..87c9716 100644 --- a/data/objects/tool_shed.yaml +++ b/data/objects/tool_shed.yaml @@ -59,8 +59,7 @@ talk: player_flag: tool_shed_watering_can goto: retrieve_watering_can text: Retrieve watering can - - end: true - text: Never mind + - text: Never mind store_rake: action: set_player_flags: diff --git a/data/objects/unique/1001_sign.yaml b/data/objects/unique/1001_sign.yaml index 83b6a9c..2769563 100644 --- a/data/objects/unique/1001_sign.yaml +++ b/data/objects/unique/1001_sign.yaml @@ -1,5 +1,6 @@ name: sign -hidden: true +aliases: [safety card, safety instructions, frame] +inroom_description: A large framed sign is mounted near the cockpit door. description: |- We hope you enjoy your trip on our shuttle. Your pilot is [TYLER]. @@ -22,3 +23,6 @@ description: |- Type {12 bold}what{/} for a list of possible common actions Make sure to check the {10}help{/} pages, especially {10}help newplayer{/}! +on_look: + set_player_flags: + 1001_look_sign: true diff --git a/data/rooms/intro/1001.yaml b/data/rooms/intro/1001.yaml index 090e97c..fd7f2f3 100644 --- a/data/rooms/intro/1001.yaml +++ b/data/rooms/intro/1001.yaml @@ -2,11 +2,14 @@ name: "Inside Transport Shuttle" description: "A dim, windowless shuttle interior with a few uncomfortable rows of steel seats facing forward. A large framed sign hangs next to the closed cockpit door. A piston-powered staircase leads down out the back of the small craft with a smiling attendant ready to help disembark." objects: - id: 1001_sign +mobs: + - flight_attendant exits: - down: 1002 + down: + room: 1002 condition: player_flag: 1001_look_sign - blocked_message: "The attendant points to the sign and insists you 'look sign' before disembarking." + blocked_message: "The attendant points to the sign and insists you {10}look sign{/} before disembarking." on_enter: - condition: player_flag: 1001_welcome @@ -17,11 +20,11 @@ on_enter: player_flag: 1001_welcome not: true delay: 7 - message: "{11}Type 'look sign' to check out the sign over there and get started{/}" + message: "{11}Type{/} {10}look sign{/} {11}or{/} {10}talk attendant{/} {11}to get started{/}" set_player_flags: 1001_welcome: true - condition: player_flag: 1001_welcome not: true delay: 7 - message: "{11}Type 'help newplayer' for the new player's guide. That's it. Explore and have fun.{/}" + message: "{11}Type{/} {10}help newplayer{/} {11}for the new player's guide. That's it. Explore and have fun.{/}" diff --git a/internal/behavior/behavior.go b/internal/behavior/behavior.go index 57b2a7b..f81c73c 100644 --- a/internal/behavior/behavior.go +++ b/internal/behavior/behavior.go @@ -30,16 +30,17 @@ type TalkConfig struct { } type TalkNode struct { - Message string `yaml:"message"` + Message MessageList `yaml:"message"` Options []TalkOption `yaml:"options"` Action *NodeAction `yaml:"action"` + Next string `yaml:"next,omitempty"` } type TalkOption struct { Text string `yaml:"text"` Goto string `yaml:"goto"` - End bool `yaml:"end"` Condition *Condition `yaml:"condition"` + Action *NodeAction `yaml:"action,omitempty"` } type NodeAction struct { diff --git a/internal/behavior/types.go b/internal/behavior/types.go index 3c6e290..f8e65f7 100644 --- a/internal/behavior/types.go +++ b/internal/behavior/types.go @@ -1,6 +1,11 @@ package behavior -import "strings" +import ( + "math/rand" + "strings" + + "gopkg.in/yaml.v3" +) func WordPrefixMatch(input, name string) bool { inputWords := strings.Fields(strings.ToLower(input)) @@ -186,3 +191,24 @@ type DropEntry struct { type DropTableDef struct { Drops []DropEntry `yaml:"drops"` } + +type MessageList []string + +func (ml *MessageList) UnmarshalYAML(value *yaml.Node) error { + if value.Kind == yaml.ScalarNode { + var s string + if err := value.Decode(&s); err != nil { + return err + } + *ml = MessageList{s} + return nil + } + return value.Decode((*[]string)(ml)) +} + +func (ml MessageList) Pick() string { + if len(ml) == 0 { + return "" + } + return ml[rand.Intn(len(ml))] +} diff --git a/internal/game/act_steal.go b/internal/game/act_steal.go index 6f67944..7371782 100644 --- a/internal/game/act_steal.go +++ b/internal/game/act_steal.go @@ -28,7 +28,7 @@ func (g *Game) executeSteal(sess *net.Session, args []string, rawInput string) { var stallGuardTalk = &behavior.TalkConfig{ Nodes: map[string]behavior.TalkNode{ "start": { - Message: "Caught you red-handed! You have three options, thief.", + Message: behavior.MessageList{"Caught you red-handed! You have three options, thief."}, Options: []behavior.TalkOption{ {Text: "\"I'll pay a fine. (500 credits)\"", Goto: "bribe", Condition: &behavior.Condition{MinCredits: 500}}, {Text: "\"Take me to jail.\"", Goto: "jail"}, @@ -36,19 +36,19 @@ var stallGuardTalk = &behavior.TalkConfig{ }, }, "bribe": { - Message: "Smart choice. Hand over 500 credits and we'll forget this happened.", + Message: behavior.MessageList{"Smart choice. Hand over 500 credits and we'll forget this happened."}, Action: &behavior.NodeAction{Cost: 500}, - Options: []behavior.TalkOption{{Text: "\"Fine, take it.\"", End: true}}, + Options: []behavior.TalkOption{{Text: "\"Fine, take it.\""}}, }, "jail": { - Message: "Off to the detention cell with you!", + Message: behavior.MessageList{"Off to the detention cell with you!"}, Action: &behavior.NodeAction{Teleport: 162}, - Options: []behavior.TalkOption{{Text: "(You are dragged away)", End: true}}, + Options: []behavior.TalkOption{{Text: "(You are dragged away)"}}, }, "fight": { - Message: "Then defend yourself!", + Message: behavior.MessageList{"Then defend yourself!"}, Action: &behavior.NodeAction{SetFlags: map[string]any{"guard_hostile": true}}, - Options: []behavior.TalkOption{{Text: "(The guard attacks!)", End: true}}, + Options: []behavior.TalkOption{{Text: "(The guard attacks!)"}}, }, }, } diff --git a/internal/game/act_talk.go b/internal/game/act_talk.go index e9047b2..f54290a 100644 --- a/internal/game/act_talk.go +++ b/internal/game/act_talk.go @@ -6,6 +6,7 @@ import ( "strings" "thehouseoficarus/internal/behavior" + "thehouseoficarus/internal/color" "thehouseoficarus/internal/net" "thehouseoficarus/internal/object" "thehouseoficarus/internal/player" @@ -52,51 +53,99 @@ func (g *Game) startTalk(sess *net.Session, p *player.Player, obj *object.Object } } +func (g *Game) handleNodeAction(sess *net.Session, na *behavior.NodeAction) (intercepted bool) { + if na.Shop != nil { + g.applyNodeAction(sess, na) + g.enterShop(sess, na.Shop) + return true + } + g.applyNodeAction(sess, na) + + if v, ok := g.Flags.Get("guard_hostile"); ok && v != nil { + g.Flags.Delete("guard_hostile") + p := sess.Player + if p != nil && p.Action != nil { + if td, ok := p.Action.Data.(*behavior.TalkData); ok && td.StealGuard { + guardMob := g.findGuardInRoom(p.RoomID, "guard") + if guardMob != nil { + sess.State = net.StateGame + g.cancelAction(p) + guardMob.Protected = false + g.startCombat(sess, p, guardMob) + } + return true + } + } + } + return false +} + func (g *Game) showTalkNode(sess *net.Session, node behavior.TalkNode) { - sess.WriteLine(fmt.Sprintf("%s", g.colorize(sess, "dialog", node.Message))) + p := sess.Player + td, _ := p.Action.Data.(*behavior.TalkData) + + dialogSpec := g.resolveColor(sess, "dialog") + msg := node.Message.Pick() + if msg != "" { + sess.WriteLine(color.ExpandTagsDefault(g.colorMode(sess), dialogSpec, msg)) + } if node.Action != nil { - if node.Action.Shop != nil { - g.applyNodeAction(sess, node.Action) - g.enterShop(sess, node.Action.Shop) + if g.handleNodeAction(sess, node.Action) { + return + } + } + + cfg := td.Cfg + for { + visible := g.visibleOptions(sess, node.Options) + if len(visible) > 0 { + for i, opt := range visible { + sess.WriteLine(fmt.Sprintf(" %d. %s", i+1, opt.Text)) + } + sess.State = net.StateTalk + sess.Write("\nChoice: ") return } - g.applyNodeAction(sess, node.Action) - - if v, ok := g.Flags.Get("guard_hostile"); ok && v != nil { - g.Flags.Delete("guard_hostile") - p := sess.Player - if p != nil && p.Action != nil { - if td, ok := p.Action.Data.(*behavior.TalkData); ok && td.StealGuard { - guardMob := g.findGuardInRoom(p.RoomID, "guard") - if guardMob != nil { - sess.State = net.StateGame - g.cancelAction(p) - guardMob.Protected = false - g.startCombat(sess, p, guardMob) - } + + if node.Next != "" && cfg != nil { + next, ok := cfg.Nodes[node.Next] + if !ok { + break + } + if td != nil { + td.Node = node.Next + } + node = next + + msg := node.Message.Pick() + if msg != "" { + sess.WriteLine(color.ExpandTagsDefault(g.colorMode(sess), dialogSpec, msg)) + } + + if node.Action != nil { + if g.handleNodeAction(sess, node.Action) { return } } + } else { + break } } - if len(node.Options) == 0 { - sess.State = net.StateGame - g.writePrompt(sess) - return - } + sess.State = net.StateGame + g.writePrompt(sess) +} - visible := 0 - for _, opt := range node.Options { +func (g *Game) visibleOptions(sess *net.Session, options []behavior.TalkOption) []behavior.TalkOption { + var visible []behavior.TalkOption + for _, opt := range options { if opt.Condition != nil && !g.checkCondition(sess, opt.Condition) { continue } - visible++ - sess.WriteLine(fmt.Sprintf(" %d. %s", visible, opt.Text)) + visible = append(visible, opt) } - sess.State = net.StateTalk - sess.Write("\nChoice: ") + return visible } func (g *Game) handleTalkInput(sess *net.Session, input string) { @@ -108,6 +157,9 @@ func (g *Game) handleTalkInput(sess *net.Session, input string) { } input = strings.TrimSpace(input) + if input == "" { + input = "1" + } lower := strings.ToLower(input) if lower == "bye" || lower == "exit" || lower == "end" || lower == "quit" { g.cancelAction(p) @@ -168,11 +220,10 @@ func (g *Game) handleTalkInput(sess *net.Session, input string) { return } - if chosen.End { - g.cancelAction(p) - sess.State = net.StateGame - g.writePrompt(sess) - return + if chosen.Action != nil { + if g.handleNodeAction(sess, chosen.Action) { + return + } } if chosen.Goto != "" { diff --git a/internal/game/cmd_shop.go b/internal/game/cmd_shop.go index 51d0ab1..d1b0e9c 100644 --- a/internal/game/cmd_shop.go +++ b/internal/game/cmd_shop.go @@ -401,10 +401,8 @@ func (g *Game) leaveShop(sess *net.Session) { g.writePrompt(sess) return } - nodeKey := td.Node - cfg := td.Cfg - node, ok := cfg.Nodes[nodeKey] + node, ok := td.Cfg.Nodes[td.Node] if !ok { sess.State = net.StateGame g.cancelAction(p) @@ -412,20 +410,30 @@ func (g *Game) leaveShop(sess *net.Session) { return } - sess.State = net.StateTalk - visible := 0 - for _, opt := range node.Options { - if opt.Condition != nil && !g.checkCondition(sess, opt.Condition) { - continue + for { + visible := g.visibleOptions(sess, node.Options) + if len(visible) > 0 { + for i, opt := range visible { + sess.WriteLine(fmt.Sprintf(" %d. %s", i+1, opt.Text)) + } + sess.State = net.StateTalk + sess.Write("\nChoice: ") + return + } + + if node.Next != "" { + next, ok := td.Cfg.Nodes[node.Next] + if !ok { + break + } + td.Node = node.Next + node = next + } else { + break } - visible++ - sess.WriteLine(fmt.Sprintf(" %d. %s", visible, opt.Text)) - } - if visible == 0 { - sess.State = net.StateGame - g.cancelAction(p) - g.writePrompt(sess) - return } - sess.Write("\nChoice: ") + + sess.State = net.StateGame + g.cancelAction(p) + g.writePrompt(sess) } diff --git a/internal/game/look_entities.go b/internal/game/look_entities.go index f9412d4..915317f 100644 --- a/internal/game/look_entities.go +++ b/internal/game/look_entities.go @@ -59,9 +59,14 @@ func (g *Game) showRoomMobs(sess *net.Session, p *player.Player, room *world.Roo if m.Protected { mobColor = "protected_mob" } - mobLevel := mobCombatLevel(m) - levelStr := g.levelColorize(sess, playerLevel, mobLevel, fmt.Sprintf("(level %d)", mobLevel)) - lines = append(lines, fmt.Sprintf("%s %s%s%s", g.colorize(sess, mobColor, displayName), levelStr, hp, desc)) + var levelStr string + if m.Protected { + levelStr = "" + } else { + mobLevel := mobCombatLevel(m) + levelStr = " " + g.levelColorize(sess, playerLevel, mobLevel, fmt.Sprintf("(level %d)", mobLevel)) + } + lines = append(lines, fmt.Sprintf("%s%s%s%s", g.colorize(sess, mobColor, displayName), levelStr, hp, desc)) } return lines } diff --git a/internal/game/look_target.go b/internal/game/look_target.go index 4819411..96dc174 100644 --- a/internal/game/look_target.go +++ b/internal/game/look_target.go @@ -57,33 +57,40 @@ func (g *Game) doLookTarget(sess *net.Session, input string) { if best.Protected { mobColor = "protected_mob" } - mobLevel := mobCombatLevel(best) - levelStr := g.levelColorize(sess, p.CombatLevel(), mobLevel, fmt.Sprintf("(level %d)", mobLevel)) + var levelStr string + if best.Protected { + levelStr = color.Render(g.colorMode(sess), color.Parse("223"), "(protected)") + } else { + mobLevel := mobCombatLevel(best) + levelStr = g.levelColorize(sess, p.CombatLevel(), mobLevel, fmt.Sprintf("(level %d)", mobLevel)) + } sess.WriteLines( "", fmt.Sprintf("%s %s", g.colorize(sess, mobColor, best.Name), levelStr), ) - if best.IdleDescription != "" { - sess.WriteLine(best.IdleDescription) + if best.Description != "" { + sess.WriteLine(color.ExpandTags(g.colorMode(sess), best.Description)) } - sess.WriteLines( - "", - fmt.Sprintf("Attack: %d", best.Attack), - fmt.Sprintf("Strength: %d", best.Strength), - fmt.Sprintf("Defense: %d", best.Defense), - fmt.Sprintf("HP: %d/%d", best.HP, best.MaxHP), - ) - if best.StabDefense != 0 || best.SlashDefense != 0 || best.CrushDefense != 0 || - best.ScienceDefense != 0 || best.RangedDefense != 0 { + if !best.Protected { sess.WriteLines( "", - "Defense bonuses:", - fmt.Sprintf(" Stab: %+d Slash: %+d Crush: %+d", best.StabDefense, best.SlashDefense, best.CrushDefense), - fmt.Sprintf(" Science: %+d Ranged: %+d", best.ScienceDefense, best.RangedDefense), + fmt.Sprintf("Attack: %d", best.Attack), + fmt.Sprintf("Strength: %d", best.Strength), + fmt.Sprintf("Defense: %d", best.Defense), + fmt.Sprintf("HP: %d/%d", best.HP, best.MaxHP), ) - } - if best.Weakness != "" { - sess.WriteLine(fmt.Sprintf("Weakness: %s", best.Weakness)) + if best.StabDefense != 0 || best.SlashDefense != 0 || best.CrushDefense != 0 || + best.ScienceDefense != 0 || best.RangedDefense != 0 { + sess.WriteLines( + "", + "Defense bonuses:", + fmt.Sprintf(" Stab: %+d Slash: %+d Crush: %+d", best.StabDefense, best.SlashDefense, best.CrushDefense), + fmt.Sprintf(" Science: %+d Ranged: %+d", best.ScienceDefense, best.RangedDefense), + ) + } + if best.Weakness != "" { + sess.WriteLine(fmt.Sprintf("Weakness: %s", best.Weakness)) + } } return } @@ -142,6 +149,10 @@ func (g *Game) doLookTarget(sess *net.Session, input string) { sess.WriteLine(color.ExpandTags(g.colorMode(sess), objDescText)) } + if def.OnLook != nil { + g.applyNodeAction(sess, def.OnLook) + } + if def.Safespot != nil { realSt := g.World.GetObjState(p.RoomID, st.DefID, st.Index) if realSt != nil { diff --git a/internal/object/object.go b/internal/object/object.go index 8d1e02e..2dcc4bf 100644 --- a/internal/object/object.go +++ b/internal/object/object.go @@ -29,6 +29,7 @@ type ObjectDef struct { Talk *behavior.TalkConfig `yaml:"talk,omitempty"` Use *behavior.UseConfig `yaml:"use,omitempty"` Safespot *SafespotConfig `yaml:"safespot,omitempty"` + OnLook *behavior.NodeAction `yaml:"on_look,omitempty"` } type SafespotConfig struct { diff --git a/internal/validate/checks.go b/internal/validate/checks.go index bb7cbd9..6aa0a81 100644 --- a/internal/validate/checks.go +++ b/internal/validate/checks.go @@ -152,6 +152,14 @@ func validateMobs(s Source) []Issue { }) } + if !def.Protected && def.HP <= 0 { + issues = append(issues, Issue{ + Level: "ERROR", + Type: "reference", + Message: fmt.Sprintf("Mob %q: is not protected but has HP=%d — mobs must have hp > 0 (or set protected: true)", id, def.HP), + }) + } + if def.Kind != "" && def.Kind != "combat" && def.Kind != "task" { issues = append(issues, Issue{ Level: "ERROR", @@ -322,6 +330,10 @@ func validateObjects(s Source) []Issue { if obj.Use != nil { issues = append(issues, validateUseConfig(fmt.Sprintf("Object %q: use", id), obj.Use, itemIDs)...) } + + if obj.OnLook != nil { + issues = append(issues, validateNodeAction(fmt.Sprintf("Object %q: on_look", id), obj.OnLook, itemIDs, roomIndex)...) + } } return issues @@ -666,6 +678,21 @@ func validateTalkConfig(prefix string, cfg *behavior.TalkConfig, itemIDs map[str if node.Action != nil { issues = append(issues, validateNodeAction(nodePrefix, node.Action, itemIDs, roomIndex)...) } + if node.Next != "" { + if _, ok := cfg.Nodes[node.Next]; !ok { + issues = append(issues, Issue{ + Level: "ERROR", + Type: "reference", + Message: fmt.Sprintf("%s: next points to nonexistent node %q", nodePrefix, node.Next), + }) + } + } + for i, opt := range node.Options { + optPrefix := fmt.Sprintf("%s: option %d", nodePrefix, i+1) + if opt.Action != nil { + issues = append(issues, validateNodeAction(optPrefix, opt.Action, itemIDs, roomIndex)...) + } + } } return issues } diff --git a/internal/world/mob.go b/internal/world/mob.go index 4c6becb..f11d6fe 100644 --- a/internal/world/mob.go +++ b/internal/world/mob.go @@ -78,6 +78,7 @@ type MobInstance struct { InstanceID string DefID string Name string + Description string HP int MaxHP int Attack int @@ -133,12 +134,17 @@ func (m *MobInstance) IsTalkable() bool { return m.TalkConfig != nil } func (m *MobInstance) IsTask() bool { return m.Kind == "task" } func NewMobInstance(def *MobDef, instanceID string, roomID int, wanderRooms []int, wanderInterval float64) *MobInstance { + hp := def.HP + if def.Protected && hp <= 0 { + hp = 1 + } return &MobInstance{ InstanceID: instanceID, DefID: def.ID, Name: def.Name, - HP: def.HP, - MaxHP: def.HP, + Description: def.Description, + HP: hp, + MaxHP: hp, Attack: def.Attack, Strength: def.Strength, Defense: def.Defense, -- cgit v1.2.3