# MUD Server A text-based multiplayer RPG (MUD) that accepts connections over SSH. Written in Rust with a data-driven world definition system — rooms, NPCs, objects, races, and classes are all defined in TOML files and can be changed without recompiling. ## Requirements - Rust toolchain (edition 2021+) - SQLite is bundled via `rusqlite` — no system SQLite needed ## Building ```bash cargo build # builds both mudserver and mudtool cargo build --release # optimized build ``` This produces two binaries: - `mudserver` — the game server - `mudtool` — database management CLI/TUI ## Running the Server ```bash ./target/debug/mudserver ``` ### Options | Flag | Default | Description | |------|---------|-------------| | `--port`, `-p` | `2222` | SSH listen port | | `--world`, `-w` | `./world` | Path to world data directory | | `--db`, `-d` | `./mudserver.db` | Path to SQLite database file | The server generates a random SSH host key on each startup. The database is created automatically if it doesn't exist. ### Connecting Any SSH client works. The username becomes the player's character name: ```bash ssh mycharacter@localhost -p 2222 ``` Password and key auth are both accepted (no real authentication — this is a game server, not a secure shell). ### Environment Set `RUST_LOG` to control log verbosity: ```bash RUST_LOG=info ./target/release/mudserver # default RUST_LOG=debug ./target/release/mudserver # verbose ``` ## World Data The world is defined entirely in TOML files under a `world/` directory. The server reads this at startup — no recompilation needed to change content. ### Directory Structure ``` world/ ├── manifest.toml # world name and spawn room ├── races/ # playable races │ ├── dwarf.toml │ ├── elf.toml │ └── ... ├── classes/ # playable classes │ ├── warrior.toml │ ├── mage.toml │ └── ... └── / # one directory per region ├── region.toml # region metadata ├── rooms/ │ ├── town_square.toml │ └── ... ├── npcs/ │ ├── barkeep.toml │ └── ... └── objects/ ├── rusty_sword.toml └── ... ``` ### manifest.toml ```toml name = "The Shattered Realm" spawn_room = "town:town_square" ``` ### Room ```toml name = "Town Square" description = "A cobblestone square with a fountain." [exits] north = "town:tavern" south = "town:gate" east = "town:market" ``` Room IDs are `:`. ### NPC ```toml name = "Town Guard" description = "A bored guard." room = "town:gate" base_attitude = "neutral" # friendly, neutral, wary, aggressive, hostile faction = "guards" # optional — attitude shifts propagate to faction respawn_secs = 90 # optional — respawn timer after death [dialogue] greeting = "Move along." [combat] # optional — omit for weak default stats (20hp/4atk/2def/5xp) max_hp = 60 attack = 10 defense = 8 xp_reward = 25 ``` ### Object ```toml name = "Rusty Sword" description = "A battered iron blade." room = "town:cellar" kind = "weapon" # weapon, armor, consumable, treasure, or omit takeable = true [stats] damage = 5 # for weapons # armor = 4 # for armor # heal_amount = 30 # for consumables ``` ### Race ```toml name = "Dwarf" description = "Stout and unyielding." [stats] strength = 1 dexterity = -1 constitution = 2 ``` ### Class ```toml name = "Warrior" description = "Masters of arms and armor." [base_stats] max_hp = 120 attack = 14 defense = 12 [growth] hp_per_level = 15 attack_per_level = 3 defense_per_level = 2 ``` ## Game Mechanics ### Tick System The game runs on a **3-second tick cycle**. Combat actions, status effects, NPC AI, and passive regeneration all resolve on ticks rather than immediately. ### Combat Combat is tick-based. When a player enters combat (via `attack` or NPC aggro), they choose actions each tick: | Command | Effect | |---------|--------| | `attack` / `a` | Strike the enemy (default if no action queued) | | `defend` / `def` | Brace — doubles effective defense for the tick | | `flee` | Attempt to escape (success chance based on DEF stat) | | `use ` | Use a consumable during combat | Any NPC can be attacked. Attacking non-hostile NPCs carries attitude penalties (-30 individual, -15 faction) and a warning message but is not blocked. ### Attitude System Every NPC tracks a per-player attitude value from -100 to +100: | Range | Label | Behavior | |-------|-------|----------| | 50 to 100 | Friendly | Will talk | | 10 to 49 | Neutral | Will talk | | -24 to 9 | Wary | Will talk | | -25 to -74 | Aggressive | Won't talk, attackable | | -75 to -100 | Hostile | Attacks on sight | Attitudes shift from combat interactions and propagate through NPC factions. ### Status Effects Effects like poison and regeneration are stored in the database and tick down every cycle — including while the player is offline. Effects are cleared on death. ### Passive Regeneration Players out of combat regenerate 5% of max HP every 5 ticks (~15 seconds). ## Database SQLite with WAL mode. Tables: - `players` — character data (stats, inventory, equipment, room, admin flag) - `npc_attitudes` — per-player, per-NPC attitude values - `server_settings` — key-value config (e.g. `registration_open`) - `status_effects` — active effects with remaining tick counters The database is accessed through a `GameDb` trait, making backend swaps possible. ## mudtool Database management tool with both CLI and TUI modes. ### CLI ```bash mudtool --db ./mudserver.db players list mudtool --db ./mudserver.db players show hero mudtool --db ./mudserver.db players set-admin hero true mudtool --db ./mudserver.db players delete hero mudtool --db ./mudserver.db settings list mudtool --db ./mudserver.db settings set registration_open false mudtool --db ./mudserver.db attitudes list hero mudtool --db ./mudserver.db attitudes set hero town:guard 50 ``` ### TUI ```bash mudtool --db ./mudserver.db tui ``` Interactive interface with tabs for Players, Settings, and Attitudes. Navigate with arrow keys, Tab/1/2/3 to switch tabs, `a` to toggle admin, `d` to delete, Enter to edit values, `q` to quit. ## Admin System Players with the `is_admin` flag can use in-game admin commands: ``` admin promote Grant admin admin demote Revoke admin admin kick Disconnect player admin teleport Warp to room admin registration on|off Toggle new player creation admin announce Broadcast to all admin heal [player] Full heal (self or target) admin info Detailed player info admin setattitude Set attitude admin list All players (online + saved) ``` The first admin must be set via `mudtool players set-admin true`. ## Registration Gate New player creation can be toggled: ```bash mudtool settings set registration_open false # block new players mudtool settings set registration_open true # allow new players (default) ``` Or in-game: `admin registration off` / `admin registration on`. Existing players can always log in regardless of this setting.