# 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 in TOML files under `world/`. The server loads them at startup — no recompilation needed to change content. ### Directory structure ``` world/ ├── manifest.toml ├── races/ ├── classes/ ├── guilds/ ├── spells/ └── / ├── region.toml ├── rooms/ ├── npcs/ └── objects/ ``` ### Schema reference Each folder contains a reference doc listing every TOML option: | Location | Reference | |----------|-----------| | `world/` | [MANIFEST.md](world/MANIFEST.md) — world name, spawn room, layout | | `world/races/` | [RACES.md](world/races/RACES.md) — stats, body, natural attacks, resistances, etc. | | `world/classes/` | [CLASSES.md](world/classes/CLASSES.md) — base stats, growth, hidden, guild | | `world/guilds/` | [GUILDS.md](world/guilds/GUILDS.md) — spells, growth, race restrictions | | `world/spells/` | [SPELLS.md](world/spells/SPELLS.md) — damage, cost, cooldown, effects | | `world//` | [REGION.md](world/town/REGION.md) — region metadata | | `world//rooms/` | [ROOMS.md](world/town/rooms/ROOMS.md) — name, description, exits | | `world//npcs/` | [NPCS.md](world/town/npcs/NPCS.md) — attitude, race/class, combat, dialogue | | `world//objects/` | [OBJECTS.md](world/town/objects/OBJECTS.md) — slot, stats, takeable | ## 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.