Files
mudserver/TESTING.md
AI Agent 005c4faf08 Flexible race system with slot-based equipment and dragon race
- Expand race TOML schema: 7 stats, body shape (size/weight/custom slots),
  natural armor and attacks with damage types, resistances, traits/disadvantages,
  regen multipliers, vision types, XP rate, guild compatibility
- Replace equipped_weapon/equipped_armor with slot-based HashMap<String, Object>
- Each race defines available equipment slots; default humanoid slots as fallback
- Combat uses natural weapons/armor from race when no gear equipped
- DB migration from old weapon/armor columns to equipped_json
- Add Dragon race: huge body, custom slots (forelegs/wings/tail), fire breath,
  natural armor 8, fire immune, slow XP rate for balance
- Update all existing races with expanded fields (traits, resistances, vision, regen)
- Objects gain optional slot field; kind=weapon/armor still works as fallback
- Update chargen to display race traits, size, natural attacks, vision
- Update stats display to show equipment and natural bonuses separately
- Update TESTING.md and AGENTS.md with race/slot system documentation

Made-with: Cursor
2026-03-14 15:37:20 -06:00

9.8 KiB

Pre-Commit Test Checklist

Run through these checks before every commit to ensure consistent feature coverage.

Build

  • cargo build succeeds with no errors
  • cargo build --bin mudtool succeeds

Server Startup

  • Server starts: RUST_LOG=info ./target/debug/mudserver
  • World loads all rooms, NPCs, objects, races, classes (check log output)
  • Database opens (or creates) successfully
  • Tick engine starts and logs tick rate

Character Creation

  • New player SSH → gets chargen flow (race + class selection)
  • Chargen accepts both number and name input
  • All races display with expanded info (size, traits, natural attacks, vision)
  • Dragon race shows custom body slots, natural armor, fire breath, vision types
  • After chargen, player appears in spawn room with correct stats
  • Stats reflect race modifiers (STR, DEX, CON, INT, WIS, PER, CHA)
  • Player saved to DB after creation

Player Persistence

  • Reconnecting player skips chargen, sees "Welcome back!"
  • Room, stats, inventory, equipment all restored from DB
  • Status effects persist across logout/login (stored in DB)
  • Status effects continue ticking while player is offline
  • On reconnect, expired effects are gone; active effects resume
  • Verify with: sqlite3 mudserver.db "SELECT * FROM players;"

Movement & Navigation

  • go north, n, south, s, etc. all work
  • Invalid direction shows error
  • Room view shows: NPCs (colored by attitude), objects, exits, other players
  • Cannot move while in combat (combat lockout)

NPC Interaction

  • examine <npc> shows description, stats, attitude label
  • talk <friendly> shows greeting dialogue
  • talk <hostile> shows snarl message
  • Dead NPCs don't appear in room view

Combat - Tick-Based

  • attack <npc> enters combat state with any NPC that has combat stats
  • Attacking friendly/neutral NPCs is allowed but incurs attitude penalties
  • Attacking non-hostile NPC: attitude shift -30 individual, -15 faction
  • "The locals look on in horror" message when attacking non-hostile
  • Combat rounds resolve automatically on server ticks (not on command)
  • Player receives tick-by-tick combat output (damage dealt, damage taken)
  • Default combat action is "attack" if no other action queued
  • defend / def sets defensive stance (reduced incoming damage next tick)
  • NPC death: awards XP, shifts attitude -10, shifts faction -5
  • Player death: respawns at spawn room with full HP, combat cleared, effects cleared
  • NPCs respawn after configured time
  • Combat lockout: can only attack/defend/flee/look/stats/inv/use/quit during combat
  • flee queues escape attempt — may fail based on stats
  • use <item> in combat queues item use for next tick
  • Multiple ticks of combat resolve correctly without player input
  • Combat ends when NPC dies (player exits combat state)
  • Combat ends when player flees successfully
  • NPCs without explicit [combat] section get default stats (20 HP, 4 ATK, 2 DEF, 5 XP)

Combat - NPC AI

  • Hostile NPCs auto-engage players who enter their room
  • Aggressive NPCs do NOT auto-engage (only attackable, not initiating)
  • NPC attacks resolve on tick alongside player attacks
  • NPCs in combat continue attacking even if player sends no commands

Combat - RNG

  • Damage varies between hits (not identical each time)
  • Multiple rapid attacks produce different damage values

Items & Equipment Slots

  • take <item> picks up takeable objects
  • drop <item> places item in room
  • equip <weapon> equips to main_hand slot (backwards-compat via kind)
  • equip <armor> equips to appropriate slot (obj slot field or fallback)
  • Equipping to an occupied slot returns old item to inventory
  • equip fails if race doesn't have the required slot
  • Objects with explicit slot field use that slot
  • use <consumable> heals and removes item (immediate out of combat)
  • use <consumable> in combat queues for next tick
  • inventory shows equipped items by slot name + bag items
  • stats shows equipment bonuses and natural bonuses separately

Status Effects

  • Poison deals damage each tick, shows message to player
  • Regeneration heals each tick, shows message to player
  • Status effects expire after their duration (in ticks)
  • stats command shows active status effects and remaining duration
  • Multiple status effects can be active simultaneously
  • Negative status effects cleared on player death/respawn
  • Status effects on offline players resolve by wall-clock time on next login

Passive Regeneration

  • Players out of combat slowly regenerate HP over ticks
  • Regeneration does not occur while in combat
  • HP does not exceed max_hp

Tick Engine

  • Tick runs at configured interval (~3 seconds)
  • Tick processes: NPC AI → combat rounds → status effects → respawns → regen
  • Tick output is delivered to players promptly
  • Server remains responsive to immediate commands between ticks
  • Multiple players in separate combats are processed independently per tick

Race System

  • Existing races (Human, Elf, Dwarf, Orc, Halfling) load with expanded fields
  • Dragon race loads with custom body, natural attacks, resistances, traits
  • Dragon gets custom equipment slots (forelegs, hindlegs, wings, tail)
  • Dragon's natural armor (8) shows in stats and affects defense
  • Dragon's natural attacks (fire breath 15dmg) affect effective attack
  • Items magically resize — no size restrictions on gear (dragon can use swords)
  • Races without explicit [body.slots] get default humanoid slots
  • Stat modifiers include PER (perception) and CHA (charisma)
  • Race traits and disadvantages display during chargen
  • XP rate modifier stored per race (dragon = 0.7x)
  • Regen modifiers stored per race (dragon HP regen = 1.5x)

Attitude System

  • Per-player NPC attitudes stored in DB
  • examine shows attitude label per-player
  • Killing NPC shifts attitude (individual -10, faction -5)
  • Verify: sqlite3 mudserver.db "SELECT * FROM npc_attitudes;"

Admin System

  • Non-admin can't use admin commands (gets error)
  • Set admin via mudtool: mudtool players set-admin <name> true
  • admin help shows admin command list
  • admin promote <player> grants admin (verify in DB)
  • admin demote <player> revokes admin
  • admin kick <player> disconnects target player
  • admin teleport <room_id> warps to room (shows room list on invalid)
  • admin registration off blocks new player creation
  • admin registration on re-enables it
  • admin announce <msg> broadcasts to all players
  • admin heal heals self; admin heal <player> heals target
  • admin info <player> shows detailed stats + attitudes
  • admin setattitude <player> <npc> <value> modifies attitude
  • admin list shows all players with online/offline status

Registration Gate

  • With registration open (default), new players can create characters
  • With registration off, new SSH connections get rejection message
  • Existing players can still log in when registration is closed

MUD Tool - CLI

  • mudtool players list shows all players
  • mudtool players show <name> shows details
  • mudtool players set-admin <name> true works
  • mudtool players delete <name> removes player + attitudes
  • mudtool settings list shows settings
  • mudtool settings set registration_open false works
  • mudtool attitudes list <player> shows attitudes
  • mudtool attitudes set <player> <npc> <value> works

MUD Tool - TUI

  • mudtool tui launches interactive interface
  • Tab/1/2/3 switches between Players, Settings, Attitudes tabs
  • Arrow keys navigate rows
  • 'a' toggles admin on Players tab
  • 'd' prompts delete confirmation on Players tab
  • Enter edits value on Settings and Attitudes tabs
  • ←→ switches player on Attitudes tab
  • 'q' exits TUI

Quick Smoke Test Script

# Start server in background
RUST_LOG=info ./target/debug/mudserver &
SERVER_PID=$!
sleep 2

# Test 1: New player creation + basic commands
ssh -o StrictHostKeyChecking=no -o UserKnownHostsFile=/dev/null -p 2222 smoketest@localhost <<'EOF'
1
1
look
stats
go north
talk barkeep
go south
go south
examine thief
attack thief
flee
quit
EOF

# Test 2: Persistence - reconnect
ssh -o StrictHostKeyChecking=no -o UserKnownHostsFile=/dev/null -p 2222 smoketest@localhost <<'EOF'
look
stats
quit
EOF

# Test 3: Admin via mudtool
./target/debug/mudtool players list
./target/debug/mudtool players set-admin smoketest true
./target/debug/mudtool players show smoketest
./target/debug/mudtool settings set registration_open false
./target/debug/mudtool settings list

# Test 4: Admin commands in-game
ssh -o StrictHostKeyChecking=no -o UserKnownHostsFile=/dev/null -p 2222 smoketest@localhost <<'EOF'
admin help
admin list
admin registration on
admin info smoketest
quit
EOF

# Test 5: Registration gate
./target/debug/mudtool settings set registration_open false
ssh -o StrictHostKeyChecking=no -o UserKnownHostsFile=/dev/null -p 2222 newplayer@localhost <<'EOF'
quit
EOF

# Test 6: Tick-based combat (connect and wait for ticks)
./target/debug/mudtool settings set registration_open true
./target/debug/mudtool players delete smoketest
ssh -o StrictHostKeyChecking=no -o UserKnownHostsFile=/dev/null -p 2222 smoketest@localhost <<'EOF'
1
1
go south
go south
attack thief
EOF
# Wait for several combat ticks to resolve
sleep 8
ssh -o StrictHostKeyChecking=no -o UserKnownHostsFile=/dev/null -p 2222 smoketest@localhost <<'EOF'
stats
quit
EOF
# Verify XP changed (combat happened via ticks)

# Cleanup
./target/debug/mudtool settings set registration_open true
./target/debug/mudtool players delete smoketest
kill $SERVER_PID