Skip to content

Architecture

Daniel Nylander edited this page Aug 1, 2026 · 1 revision

Architecture

Developer onboarding guide for the Firestaff codebase.

Overview

Firestaff is a pure C application (no C++) that reimplements five Dungeon Master game engines with source-level fidelity to the originals. It builds with CMake and Ninja, renders via SDL3, and runs on macOS, Windows, Linux, and Steam Deck.

Codebase scale: 1,190,000+ lines of C across 2,425 source files, 2,379 headers, and 2,919 test files containing 3,673 tests.

Layer Architecture: M10 / M11 / M12

Firestaff is organized into three major layers:

M10 -- Game Logic Layer

M10 owns all game state and mechanics. It is the engine core shared across presentation modes:

  • Party state (champions, inventory, stats, position).
  • Dungeon state (maps, things, doors, actuators, sensors).
  • Combat resolution and damage calculation.
  • Creature AI and movement.
  • Projectile tracking.
  • Item interactions and thing-list management.
  • Save/load serialization.

M10 is game-specific: DM1/CSB share one M10 path (from ReDMCSB), DM2 has its own (from skproject), and Nexus/Theron have independent M10 implementations.

M11 -- Original Presentation Layer

M11 is the Original (faithful) rendering path. It reproduces the exact visual output of the original game:

  • m11_game_view.c (~50,000 lines): the monolithic game view that drives viewport rendering, HUD drawing, menu display, and input dispatch.
  • M11_GameViewState: the central state struct (~1,570 lines in include/m11_game_view.h) containing world state, party, dungeon, audio, viewport, HUD, DM2, and presentation state.
  • Viewport rendering follows the original draw order and clipping rules.
  • Wall ornaments, floor ornaments, creatures, and items are drawn at original pixel positions.

M12 -- Custom Presentation Layer

M12 adds modern rendering features on top of the proven M11/M10 engine:

  • Camera system with smooth movement and rotation.
  • Resolution-independent scaling.
  • Fullscreen and windowed modes.
  • Enhanced lighting (DM2).
  • Controller and touch input mapping.

M12 consumes M10 state but does not modify game logic. The Original engine must be proven correct before Custom features are built on top.

Source Directory Map

src/
  engine/      M11 game view (m11_game_view.c and supporting modules)
  csb/         CSB-specific: viewport, boot, runtime, DSA
  dm1/         DM1-specific: viewport 3D, music, movement, ornaments
  dm1v2/       DM1 Custom presentation (camera, modern rendering)
  dm2/         DM2 runtime (boot, CCM, combat, GDAT, champions)
  shared/      Cross-game: audio (SDL3), rendering, main entry point
  memory/      Dungeon data decoding, save/load, combat serialization
  frontend/    UI frontend, dialog, text rendering
  audio/       Audio decoding (SND, SONG.DAT, HMP)

include/       All public headers (~2,379 files)
tests/         Test sources (~2,919 files)
parity-evidence/  Source-lock evidence documents (960+ files)

Build System

Firestaff uses CMake with Ninja as the preferred generator:

cmake -S . -B build -DCMAKE_C_COMPILER=cc -G Ninja
ninja -C build

Key build system details:

  • Single CMakeLists.txt with the project version at line ~3505.
  • Pure C with LANGUAGES C enforced -- no C++ compilation.
  • Compiler: system cc (Clang on macOS, GCC on Linux). Do not use gcc.
  • SDL3 is the only external dependency.
  • Tests are registered with CTest and can be run in parallel.

How to Add a Test

  1. Create a test source file in tests/:

    tests/test_{module_name}.c
    
  2. Write the test using the project's test patterns. Tests are standalone C programs that return 0 on success and nonzero on failure.

  3. Register the test in CMakeLists.txt using add_test(). Follow the existing patterns near where similar tests are registered.

  4. Build and run:

    ninja -C build
    ctest --test-dir build -R "test_{module_name}" --output-on-failure

How to Run Probes

Probes are targeted test programs that verify specific engine behaviors against known-good outputs. They are registered as CTest tests with descriptive names:

# Run all probes for a specific game
ctest --test-dir build -R "dm1" -j4 --output-on-failure

# Run a specific probe
ctest --test-dir build -R "viewport_wall_ornament" --output-on-failure

Some probes require original game data files to be present under ~/.firestaff/data/. Probes that need game data will fail or time out without it.

Parity Evidence

Parity evidence is the project's verification system. Each piece of evidence documents that a specific Firestaff behavior matches the original game:

  • Evidence files live in parity-evidence/ with names like pass{NNN}_{description}.md.
  • Each document records what was tested, how it was verified, and what the expected behavior is.
  • There are 960+ parity-evidence documents covering DM1, CSB, DM2, Nexus, and Theron's Quest.
  • Evidence is cumulative: once a behavior is source-locked, it stays locked and regression tests prevent it from breaking.

A feature is considered "source-locked" when it has both:

  1. A passing test that verifies the behavior.
  2. A parity-evidence document that records the verification.

Naming Conventions

Pattern Example Use
dm1_v1_{feature}_pc34_compat.h dm1_v1_random_ornament_pc34_compat.h DM1 PC 3.4 headers
dm1_v1_{feature}_pc34_compat.c dm1_v1_random_ornament_pc34_compat.c DM1 PC 3.4 sources
csb_v1_{feature}_pc34_compat.{h,c} csb_v1_viewport_pc34_compat.c CSB modules
dm2_v1_{feature}.c dm2_v1_boot.c DM2 modules
F0NNN_Name_Compat() F0170_Random_Ornament_Compat() ReDMCSB function names
test_{module}.c test_dm1_viewport.c Test files
pass{NNN}_{desc}.md pass216_nexus_saturn_hardware_evidence.md Evidence docs

Reference Sources

Game Reference Identifier style
DM1 ReDMCSB F0NNN_Name, ReDMCSB FILENAME.C:LINE
CSB ReDMCSB Same as DM1
DM2 skproject skproject function/variable names
Nexus None Firestaff-native identifiers
Theron None Firestaff-native identifiers

See Also

Clone this wiki locally