The Master’s Shadow
A narrative-driven gothic roguelike of apprenticeship, escape, and ritual inversion — where the villain is a real AI agent bound by the same brutal rules as you.
“He needs you young. He needs you skilled. He needs you alive… until the final moment.”
You are an apprentice bound to the ancient wizard Master Malacor through a partial sympathetic ritual. When the moon comes full he means to pour his mind into your young body and let what remains of you go dark. Serve. Steal. Learn forbidden magic. Sabotage the rite. Slip the wood before the clock strikes — and survive the reckoning at the Heart of the Ritual.
The Master is not a scripted villain. He is an autonomous agent adjudicated by the same deterministic engine that governs you — he forages, tires, loses the trail, lays traps, and can fail. And he can be driven by any brain: the built-in reproducible ACO pathfinder, or a local/frontier LLM you plug in at runtime.
Highlights
- A villain that plays like a player. The Master issues the same legal actions you can, validated by one authoritative
RulesEngine. He cannot cheat the simulation, and a Monte-Carlo sweep proves he is a real but beatable threat (~22% catch against an optimal fugitive). - Pluggable AI antagonist. Hand the Master to a local LM Studio model or a frontier API with one environment variable. Decisions run asynchronously so the game never stalls, and any illegal or slow reply falls back to the deterministic brain.
- Three distinct games in one arc. A KQ3-style stealth cottage, a Curious Expedition–style survival hex-crawl, and a turn-based ritual duel — each with its own loop, UI, and failure states.
- Six bloodlines that genuinely play differently. Each has a decision-changing signature across the forest and the apex — a scent-poisoning decoy, a damage-to-mana siphon, a foresight that reads the Master’s intent, and more.
- A learnable spellbook and a usable satchel. Twenty-two data-defined spells (White/Grey/Black, including a full Grey information-war kit — Memory Fog, Invisibility, Haste, Sleep) you learn, cast in combat, and work in the field; a real inventory of items — all driven from the
data/bundle, so a new spell or item is a few lines of markdown, no code. - A day that costs something. Phase 1 runs on a visible segment budget — chores, snooping and study all spend it, exhaustion ends your options, and only your bed ends the day while the ritual clock grinds on. Two difficulties (Normal / Hardcore), both hard; Hardcore is a shorter fuse in a sharper house — and it never saves. One life, one shot.
- Puzzles that feed your escape. The cottage is a web: the Master’s chest yields a cipher scrap, the hidden library’s desk breaks it, and suddenly you know where the ritual knife sleeps — the reckless escape becomes a plan. Every bloodline finds one door that opens easier for it, and every failed pry teaches the House how you work (retry-hardening DCs).
- Fifteen Honours. An achievements board of dark medallions — escape clean, break the rite, win a Hardcore heart, keep your hands white — three of them hidden, all persistent across runs, with day-boundary Continue checkpoints on Normal.
- An information war. Brew emergent concoctions from tagged reagents, fog the Master’s memory of your trail, and weather his six counter-workings — potion corruption, alchemical backlash, memory anchors — while his Architect self seeds the wood with seven kinds of trap.
- Deep, systemic mechanics. A ritual doom-clock, sympathetic bond clash, corrupting Trace Parasite and Echo Bleed, crowd-simulated faction wars over the wood, weather, alchemy, and eight endings with per-lineage epilogues.
- Fully deterministic core.
(seed, lineage, action-journal) → identical state hash, enforced by the engine and verified in tests. Replays, headless AI-vs-AI sims, and balance sweeps all reproduce exactly. - Self-contained & regenerable. All pixel art (Python + Pillow) and audio (ElevenLabs) are generated by scripts and bundled — the shipped build needs no keys, no network, no external runtime.
The Three Phases
Phase 1 — The Apprentice’s Cage
A story-first stealth/puzzle loop in one open cottage of physical, furnished rooms. Read the chore board, do your tasks in plain sight, and learn magic or sabotage the rite only while the Master is away — his absences are announced per-destination with a consistent, learnable length and a live “~N turns till he returns” countdown. A rising Suspicion meter triggers escalating searches. Dice appear only when an action needs a check. Discover what you are, find the way out, and choose one of four escapes.
Phase 2 — The Forest Pursuit
A procedural hex-crawl on a Curious Expedition day/move budget. Manage Food / Water / Energy / Mana, make camp to survive, and forage at authored nodes — springs, fae rings, goblin markets, shrines, contested ley-nexuses — each with its own interaction. Sense the Master’s strategy through your blood, weather the rain and storms that wash or betray your trail, brew alchemy from harvested reagents, and evade a bounded pursuer (Bloodhound direct-run vs Architect interception) while faction warbands contest the wood in a live crowd simulation you can incite, exploit, or avoid. Proc-gen encounters drop you into a biome-tinted combat sub-screen.
Phase 3 — The Ritual Apex
A turn-based sympathetic bond clash at the Heart of the Ritual, amid nine chaos events that warp the field. Press the bond, foul it with Grey static, ward yourself, sever the rite, or — with enough disruption sigils — invert it and turn the Master’s own working against him. Every bloodline breaks the rite its own way. It resolves to one of eight endings, each with a written, lineage-flavored epilogue.
The Six Bloodlines
Each bloodline reshapes how you learn, flee, and face the ritual — and each has a signature mechanic that changes your decisions, not just a stat.
| Bloodline | Identity | Phase 2 signature | Phase 3 signature |
|---|---|---|---|
| Veyra — The Vessels | Bond, at the cost of self | Echo-foresight reads the Master’s next intent (closing vs. flanking), paid in Echo Bleed | Bond-hijack skims his clash contribution |
| Nyxari — The Veiled | Misdirection | Lays a false trail that poisons the Master AI’s scent map | Calms the chaos storm |
| Thalor — The Wardens | Defensive stability | Ley-line footing ignores distortion & traps on Water and Path | Ward-wall inversion |
| Dravenblood — The Binders | Black magic & inversion | Black-siphon turns damage taken into mana | Inversion charge; the parasite that hurts others feeds them |
| Sylvara — The Fae-Touched | Nature & resistance | Wild-forage and a beast-pact that makes the wild’s own stand aside | Domination-resistant; the wood surges to their aid |
| Auralis — The Echoes | Memory & information | Copies the Master’s last tactic → a free step, a laid trap, or a cleansed trace | Rides the Echo Storm |
Screenshots
Every scene is a hand-directed painted backdrop walked inside by a depth-scaled, animated character — with soft firelight, foreground occlusion, particle motes, bloodline-tinted sprites, HD flat-top hex tiles, and a gothic UI-Kit HUD. It renders at a fixed 1280×720 and scales crisply to any window or DPI.
| The Apprentice’s Cage | The Forest Pursuit |
|---|---|
![]() |
![]() |
| Night Camp — Cook, Brew, Rest | A Wild Encounter |
![]() |
![]() |
| The Ritual Apex | Choose Your Bloodline |
![]() |
![]() |
| The Honours Board | |
![]() |
Build & Run
Requirements: CMake ≥ 3.16, a C++17 compiler (MinGW-w64 g++ or MSVC), Git, and an internet connection on the first configure (raylib is fetched automatically via FetchContent). No other runtime dependencies — executables are statically linked and self-contained.
# from the repository root
cmake -S . -B build -G Ninja -DCMAKE_BUILD_TYPE=Release \
-DCMAKE_C_COMPILER=gcc -DCMAKE_CXX_COMPILER=g++ # MinGW; omit the compiler flags for MSVC
cmake --build build
# play
./build/bin/masters_shadow # Windows: build\bin\masters_shadow.exe
Handy flags: --start=title|lineage|phase1|phase2|phase3 boots straight to a screen; --smoke --shot=out.png renders a few frames, saves a screenshot, and exits (used by CI and this README).
Ship a standalone build: bash tools/package.sh produces a self-contained dist/the_masters_shadow/ (exe + assets + data + docs) that runs with no toolchain installed.
See docs/BUILDING.md for the full toolchain guide, MSVC preset, and troubleshooting.
Controls
| Where | Keys |
|---|---|
| Menus | ←/→ choose · Enter confirm · mouse click |
| Phase 1 (cottage) | WASD walk · E interact · Space wait (costs a segment!) · G spellbook · I satchel · L codex |
| Phase 2 (forest) | click a hex to move · E node · Space wait · C camp · X brew/combine · T disarm trap · G spellbook · I satchel · L codex · F the war · B aid · D false trail (Nyxari) · R echo (Auralis) |
| Phase 3 (apex) | 1 Press the Bond · 2 Grey Disruption · 3 Sever the Rite · 4 Invert · 5 Ward · G spellbook · I satchel |
| Anywhere in play | Esc pause |
The game renders at a fixed 1280×720 virtual resolution and scales crisply to any window or DPI (letterboxed, point-filtered pixels).
Plugging in an AI Master
By default the Master runs on the built-in, deterministic ACO brain (offline, reproducible). To hand him to a model instead:
export MS_MASTER_AGENT=llm # route decisions through the LM Studio bridge
export MS_LLM_MODEL="your-fast-instruct-model"
./build/bin/masters_shadow
Each Master decision is serialized to an honest, bounded observation plus the legal moves and sent through agent_engine/run.py to a local LM Studio server (http://127.0.0.1:1234/v1). The model returns a structured, validated choice via /no_think + OpenAI-style tool calling (one act(action, index, say) tool) — typically in well under a second even on a small local model — and its choice is re-validated against the current legal set. Any illegal, timed-out, or unavailable response falls back to the deterministic bloodhound heuristic, so the Master always acts and can never cheat.
Async by design: the LLM decision runs on a background thread while the ACO brain plays instantly, so the game never freezes regardless of model speed. The bridge uses only a model LM Studio already has resident (it never force-loads → no memory blow-ups). A raw frontier endpoint works with MS_MASTER_AGENT=openai + MS_LLM_URL.
Auth: newer LM Studio builds require an API token — set MS_LLM_KEY or drop the token in lmstudio-api-key.txt at the repo root; every C++ and Python path sends it as a Bearer header automatically.
Full protocol, observation/action schemas, and env knobs are in docs/API.md.
Testing & Balance
./build/bin/ms_tests # 51 unit tests (core, world, AI, apex, content)
./build/bin/ms_headless --selftest # replay determinism check (identical state hashes)
./build/bin/ms_headless --balance 500 # Monte-Carlo Phase-2 pursuit sweep (win/loss rates)
./build/bin/ms_headless --apex 600 # per-lineage Phase-3 clash balance sweep
The determinism guarantee — (seed, lineage, action-journal) → identical state hash — is enforced by the RulesEngine and verified in tests. The pursuit sweep confirms the Master is a real but beatable threat (~22% catch against an optimal fugitive); the apex sweep confirms every bloodline can win and lose the ritual — tuned FTL-flagship hard, a tight 47–67% band under a naive policy with real preparation making the difference. One command runs everything: bash tools/verify.sh.
Architecture
Three layers plus data — the deterministic simulation is completely decoupled from raylib so it can be unit-tested and self-played headlessly.
ms_core (deterministic, no raylib) masters_shadow (raylib presentation)
├─ core/ RNG, hex math, skill checks, ├─ render/ 2.5D scene, sprites, lighting
│ RulesEngine + replay journal, ├─ ui/ HUD, ritual dial, panels
│ ContentDB ├─ audio/ layered music, SFX, ambience
├─ world/ hex map, flow fields, A*, └─ game/ screen flow: Title → Lineage
│ procedural forest, faction war → Phase1 → Phase2 → Phase3 → End
├─ ai/ Master brain (ACO), pursuit sim
├─ magic/ lineages, ritual apex, endings agent_engine/ standalone Python bridge to
├─ agent/ IAgent + ACO / LLM adapters LM Studio (SSE + REST tools)
└─ save/ serialize state + journal data/ git-native ContentDB records
Full module map, data flow, and the determinism model are in docs/ARCHITECTURE.md.
Data-Driven by Design (OKF)
As little as possible is hardcoded. Following an Open-Knowledge-Format (OKF) convention, the game’s rules tables, tuning numbers, and every user-facing word live in a git-native data/ bundle of plain-markdown records. The branching logic stays in ms_core; the values and text it runs on are externalized, inspectable, and hot-swappable.
- Determinism-safe injection. Core tables — enemy stats, the six lineages, chaos weights, terrain costs, tuning knobs — are parsed in the app layer and handed to the raylib-free core as frozen integer POD structs before the first turn, so the simulation stays I/O-free and its
state_hashis provably unchanged. Floats are stored as per-mille integers (1.25 → 1250) becausestd::stodisn’t byte-stable across libc, and a float leak would break the hash. - All text is data. ~364 UI and narrative strings resolve through a
tr(id, fallback)lookup againstdata/strings/— the game can be re-skinned or translated without touching a line of C++. - A conformance gate.
python tools/okf_validate.pyenforces the record grammar, unique ids, and the integer-only rule for core-consumed tables;python tools/gen_okf_index.pymaintains anindex.md+log.mdper bundle. - A condensed design corpus. The full design — concept, systems, the AI antagonist, the world, the arc — is itself a cross-linked OKF bundle: design/okf/.
Authoring guide: docs/MODDING.md.
Tech Stack
- Engine: C++17 + raylib (fetched via CMake
FetchContent), MinGW-w64 / MSVC, statically linked. - Testing: doctest; a headless
ms_headlessrunner for determinism and Monte-Carlo balance. - Art: procedural pixel art in Python + Pillow (
tools/gen_*.py,tools/msart.py). - Audio: generated via the ElevenLabs API (voice, music, SFX, ambience), cached by content hash, bundled at ship.
- AI Master: deterministic ACO pathfinder + a pluggable LLM bridge (
agent_engine/) to LM Studio / OpenAI-compatible endpoints. - Fonts: Orbitron, IM Fell English, Share Tech Mono (SIL OFL).







