Skip to content

Repository files navigation

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.

status engine tests determinism honours license

title screen

"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.


Table of Contents


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).
  • A run that has an arc. Milestones teach you: break the blood-seal and your hands get quicker, read his cipher and you get sharper. Skills were pinned at zero for the entire game before this — every check was a naked d20 for a day-one apprentice and a day-six veteran alike.
  • Fights you read instead of grind. Every enemy telegraphs its next move a turn ahead, affinity is shown beside the health bar, and the apex is a duel of four announced intents each blunted by a different one of your five actions — guess right and he loses half of what he meant to take.
  • The Chronicle. Every finished run is remembered — bloodline, fate, day, seed — behind an eight-cell ending gallery. Herb-lore you paid reagents to learn is kept for good, honours pay the next apprentice forward (capped, so a full board never trivialises the cottage), and the vessel who failed last leaves behind something specific to how they failed.
  • People in the wood. Sylas the Seeker, Gorn the Bridge-Warden, the Lady of the Well and Elara come to your fire — each with three priced offers and a memory of how you have treated their faction. Wrong enough of them and nobody visits at all.
  • 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, per-bloodline painted apprentice sheets, named-NPC portraits, 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
phase 1 phase 2
A Wild Encounter Choose Your Bloodline
combat lineage
A Night Visitor The Ritual Apex
camp phase 3
The Honours Board The Chronicle
honours chronicle

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)
Alchemy panel 16 brew a recipe · click two reagents · Enter combine · T the workings (tag-pair grimoire) · Esc close
Title ↑/↓ choose · Enter confirm · New Run → difficulty, D toggles the Daily Trial seed
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

python tools/okf_validate.py            # G-OKF-CONFORM data gate
./build/bin/ms_tests                    # unit tests (core, world, AI, apex, content, actions)
./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 and CI (tools/github-workflows/ci.yml). 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. Manual smoke: docs/PLAYTEST_CHECKLIST.md.


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_hash is provably unchanged. Floats are stored as per-mille integers (1.25 → 1250) because std::stod isn'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 against data/strings/ — the game can be re-skinned or translated without touching a line of C++.
  • A conformance gate. python tools/okf_validate.py enforces the record grammar, unique ids, and the integer-only rule for core-consumed tables; python tools/gen_okf_index.py maintains an index.md + log.md per 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.


Documentation

Document For
docs/GAMEPLAY.md Player's guide — phases, resources, mechanics, endings
docs/GAME_DESIGN.md Design document — pillars, systems, balance philosophy
design/okf/ Full design bundle (OKF) — lineages, magic, AI, world, factions, lore
docs/ARCHITECTURE.md Technical architecture — layers, determinism, modules
docs/API.md Integration API — agent protocol, ContentDB schema, engine actions
docs/MODDING.md Authoring data-driven content
docs/BUILDING.md Building from source, toolchains, packaging
CHANGELOG.md Version history
CREDITS.md Attributions and third-party licenses

Tech Stack

  • Engine: C++17 + raylib (fetched via CMake FetchContent), MinGW-w64 / MSVC, statically linked.
  • Testing: doctest; a headless ms_headless runner 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).

License

MIT License. Copyright © 2026 Ray Daniels. See LICENSE for the full text. Third-party components (raylib, doctest, fonts, ElevenLabs-generated audio) remain under their own licenses.

About

A narrative-driven gothic roguelike where the villain is a real AI agent bound by the same rules as you. C++17 + raylib.

Resources

Stars

1 star

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages