A roguelike dungeon crawler built on the Knave TTRPG ruleset, featuring an Entity-Component-System architecture, BSP dungeon generation, and an optional LLM-driven typed gameplay mode where you describe actions in natural language and an AI Game Master interprets and narrates the results.
- ECS architecture -- dataclass components, World store, entity queries
- BSP dungeon generation -- 5 room shapes (rect, circle, octagon, cross, hybrid), cellular automata terrain (water, grass), corridor loops
- Knave combat rules -- d20 attack vs armor defense, dice pool damage, morale system, status effects
- Terminal TUI -- blessed-based with 16/256 color, shadowcasting FOV, box-drawing walls, 4-zone layout
- Web frontend -- HTML5 Canvas with Dyson Logos style SVG rendering, WebSocket communication, point-and-click interaction
- LLM Game Master -- type natural language actions, LLM interprets and narrates outcomes (Ollama, MLX, Anthropic backends)
- Multilingual -- English, Catalan, Spanish (~2000 translation lines each)
- 78 creatures -- full BEB bestiary with AI behaviors, factions, loot tables
- 193 items -- scrolls, potions, wands, rings, weapons, armor, tools
- 13 trap types -- pit, fire, poison, teleport, alarm, summoning, and more
- Identification system -- potion colors, scroll labels, ring gems, wand woods shuffled per game seed, revealed on use
- Save system -- JSON manual save/load + binary autosave (pickle+zlib)
- Docker deployment -- Caddy reverse proxy with automatic TLS via DuckDNS
- Python 3.14 or newer
- (Optional) An LLM backend for typed gameplay mode: Ollama, MLX, or an Anthropic API key
git clone https://github.com/adn770/nhc.git
cd nhc
./play -GThe ./play launcher creates a virtual environment, installs dependencies,
and starts the game. The -G flag generates a new dungeon.
./serverOpen http://localhost:5005 in your browser. The ./server launcher handles
venv setup and dependency installation automatically.
cp .env.example .env # edit with your DuckDNS token and settings
docker-compose up -dInstall the project git hooks. The pre-commit hook runs
scripts/lint_import_shadowing.py over staged files under nhc/
and rejects commits that reintroduce function-local imports
shadowing a module-level name -- the bug class behind the
teleporter-pad UnboundLocalError regression.
./scripts/install-hooks.shThe same check also runs as a regular pytest
(tests/unit/test_import_hygiene.py), so CI catches it even if a
contributor skips the hook install.
./play -G # Generate dungeon, play
./play --lang ca -G # Catalan language
./play --lang es -G # Spanish language
./play --god -G # God mode (invulnerable)
./play --mode typed --lang ca -G # Typed mode with LLM Game Master
./play --seed 12345 -G # Reproducible dungeon seed
./play --help # All options./server # Local dev, no authentication
./server --auth # Generate token, require auth
./server --host 0.0.0.0 --auth # Expose on network
./server --reset # Ignore autosave, start fresh.venv/bin/pytest # Run all tests
.venv/bin/pytest tests/unit/test_combat.py -v # Specific file
.venv/bin/pytest -k "test_name" # By name
.venv/bin/pytest -m core # By markerAvailable markers: core, dungeon, entities, rules, narrative.
The project follows an Entity-Component-System pattern with an async
game loop and event pub/sub. See the design/ directory for detailed
design documents.
ECS store with dataclass components, async turn-based game loop, event
bus for decoupled communication, and a 3-tier configuration system
(defaults, ~/.nhcrc, CLI args).
BSP algorithm with configurable room sizes and spacing. Rooms are specialized (treasure, guard, shrine) and painted with themed content. Cellular automata generates water and grass terrain. Corridors connect rooms with a main path plus extra loops. Hand-authored YAML levels are also supported.
- Terminal -- blessed TUI with 4-zone layout, shadowcasting FOV, 16/256 color themes, box-drawing wall characters
- Web -- Flask + WebSocket server, HTML5 Canvas with SVG tile rendering, inventory panel, action toolbar
- SVG -- static map export
LLM Game Master pipeline: player types intent, LLM interprets it into an action plan, actions execute, LLM narrates the outcome. Includes story compression for context window management, multilingual prompt templates, and a keyword-based fallback parser when no LLM is available.
| Category | Count |
|---|---|
| Creatures | 78 |
| Items | 193 |
| Traps | 13 |
| Languages | 3 |
| Tests | 780 |
| Key | Action | Key | Action |
|---|---|---|---|
| Arrows/hjkl | Move | g/, | Pickup |
| a | Use item | q | Quaff potion |
| e | Equip/unequip | d | Drop item |
| t | Throw potion | z | Zap wand |
| s | Search secrets | x | Look around |
| > | Descend stairs | < | Ascend stairs |
| i | Inventory | ? | Help |
| S | Save | L | Load |
| TAB | Toggle mode | Q | Quit |
The game server runs inside a Docker container managed by systemd. An interactive setup script handles the full deployment:
sudo ./deploy/setup.sh # first-time interactive setup
sudo ./deploy/setup.sh --update # rebuild image + restartThe script:
- Builds the Docker image (
nhc-web: Python 3.14-slim, gunicorn + gthread) - Creates the data directory (
/var/nhc) for persistent saves - Prompts for configuration (auth token, max sessions, optional DuckDNS)
- Installs the systemd unit (
deploy/nhc.service) - Writes secrets to a systemd override file (
override.conf, mode 600) - Enables, starts, and health-checks the service
Secrets and tunables live in the systemd override, not in .env:
/etc/systemd/system/nhc.service.d/override.conf
NHC_AUTH_TOKEN=<generated-or-provided>
NHC_MAX_SESSIONS=8
DUCKDNS_SUBDOMAIN=<optional>
DUCKDNS_TOKEN=<optional>
For internet exposure, Caddy provides TLS reverse proxy and DuckDNS handles dynamic DNS. Ports 80/443 must be forwarded to the host.
Useful commands after deployment:
journalctl -u nhc -f # follow logs
systemctl status nhc # service statusdesign/design.md-- overall system designdesign/dungeon_generator.md-- BSP dungeon generationdesign/magic_items.md-- identification and magic item systemsdesign/typed_gameplay.md-- LLM-driven typed gameplay modedesign/web_client.md-- web frontend architecture
MIT License. See LICENSE for details.