mud/.claude/CLAUDE.md
Jared Miller 6344c09275
Restructure combat moves: single-word commands with variant args
The DREAMBOOK always described "punch right/left [target]" as one command
with a direction argument, but the implementation had separate TOML files
and multi-word command names that the dispatcher couldn't reach (it only
matches the first word). Aliases like "pr" also couldn't pass targets
because the shared handler tried to re-derive the move from args.

Changes:
- Merge punch_left/right, dodge_left/right, parry_high/low into single
  TOML files with [variants] sections
- Add command/variant fields to CombatMove for tracking move families
- load_move() now returns list[CombatMove], expanding variants
- Handlers bound to moves via closures at registration time:
  variant handler for base commands (punch → parses direction from args),
  direct handler for aliases and simple moves (pr → move already known)
- Core logic in do_attack/do_defend takes a resolved move
- Combat doc rewritten as rst with architecture details
- Simplify mud.tin aliases (pr/pl/etc are built-in MUD commands now)
2026-02-08 00:20:52 -05:00

2.8 KiB

mudlib

Telnet MUD engine built on telnetlib3. Python 3.12+, managed with uv.

Commands

  • just check - lint (ruff --fix + format), typecheck (ty), test (pytest)
  • just lint / just typecheck / just test - individual steps
  • just run - start the server (python -m mudlib)
  • just debug - start with debug logging
  • just render - generate full world map HTML in build/

Project Layout

  • src/mudlib/ - the engine (commands, world, combat, render, store)
  • tests/ - pytest tests
  • content/ - content definitions (commands, combat moves) loaded at runtime
  • worlds/ - world definition files (yaml/toml, version controlled)
  • docs/ - project knowledge (see below)
  • DREAMBOOK.md - the vision, philosophy, wild ideas. not a spec
  • scripts/ - standalone tools (map renderer, etc)
  • build/ - generated output (gitignored)
  • repos/ - symlinked reference repos (telnetlib3, miniboa). gitignored, not our code

Docs

Three categories in docs/. Plain text or rst, not markdown.

  • docs/how/ - how things work. write one when you build something non-obvious. terrain generation, command system, etc. aimed at someone reading the code who wants the "why did we do it this way" context.
  • docs/why/ - design philosophy. telnet-first, text worlds, etc. the reasoning behind big decisions. doesn't change often.
  • docs/lessons/ - things we learned the hard way. write one when you hit a real bug or gotcha that cost time. charset-vs-mtts, etc. include the fix so we don't repeat it.

Update docs when:

  • you build a new system (add a how/)
  • you make a design decision worth explaining (add a why/)
  • you debug something painful (add a lessons/)
  • existing docs become wrong (update them)

Architecture

  • telnetlib3 is a dependency, not vendored. contribute fixes upstream
  • telnetlib3 gives us: GMCP, MSDP, NAWS, async server, reader/writer streams
  • game loop is tick-based (async task alongside telnet server)
  • world is toroidal (wraps in both axes). terrain noise tiles seamlessly
  • world definitions live in data files, runtime state lives in memory
  • SQLite for persistence (player accounts, progress)
  • session mode stack filters what events reach the player (normal/combat/editor)
  • combat system: state machine with TOML-defined moves (attacks, defends, counters). see docs/how/combat.rst
    • moves with directional variants (punch left/right) use a single TOML with [variants] sections
    • commands are always single words; direction is an argument, not part of the command name
  • content loading: TOML definitions for commands and combat moves, loaded at startup
  • entity model: Entity base class, Player and Mob subclasses sharing common interface
  • editor mode: in-world text editor with syntax highlighting and search/replace

Style

  • simple > clever
  • no mock implementations
  • match existing patterns in each file