A C++/SFML game engine aiming to deliver a fully playable remake of Might and Magic Book One: The Secret of the Inner Sanctum, using the assets from the original MS-DOS release.
  • C++ 99%
  • C 0.7%
  • CMake 0.3%
Find a file
Repository files (latest commit first)
Filename Latest commit message Latest commit date
2026-09-14 17:10:57 +03:00
core The character sheet's own keys, as 0x6E40 reads them 2026-09-14 17:10:57 +03:00
docs The character sheet's own keys, as 0x6E40 reads them 2026-09-14 17:10:57 +03:00
gui The world the overlay runs in, and the screen it comes out on 2026-09-10 01:14:12 +03:00
media Print messages and read walls the way the original does 2026-09-09 20:57:03 +03:00
model The character sheet's own keys, as 0x6E40 reads them 2026-09-14 17:10:57 +03:00
render Wandering monsters 2026-09-09 22:21:02 +03:00
states The character sheet's own keys, as 0x6E40 reads them 2026-09-14 17:10:57 +03:00
tests The character sheet's own keys, as 0x6E40 reads them 2026-09-14 17:10:57 +03:00
.gitignore Dump every string in the data segment, not only the named ones 2026-09-09 00:18:43 +03:00
CHANGELOG.txt The character sheet's own keys, as 0x6E40 reads them 2026-09-14 17:10:57 +03:00
CMakeLists.txt Initial commit: VARN Engine 2026-09-08 17:15:43 +03:00
Definitions.h Classic mode: the original's screen, colours and field of view 2026-09-09 12:45:05 +03:00
LICENSE Initial commit: VARN Engine 2026-09-08 17:15:43 +03:00
main.cpp Load the EXE's strings in one pass and print the game's own labels 2026-09-09 00:48:10 +03:00
README.md The speaker, four commands from the maze, and the sheets on the right grid 2026-09-11 05:01:56 +03:00
ResourceIdentifiers.h Initial commit: VARN Engine 2026-09-08 17:15:43 +03:00
THIRD-PARTY-NOTICES.md Initial commit: VARN Engine 2026-09-08 17:15:43 +03:00

VARN Engine

A C++/SFML game engine aiming to deliver a fully playable remake of Might and Magic Book One: The Secret of the Inner Sanctum, using the assets from the original MS-DOS release.

Forked from filasfilas/F-MM1.


Goal

Produce a complete, playable game that loads and uses the data files from the original MM1 DOS release (wall textures, map data, sprites, music). No asset recreation — original files are loaded at runtime.

Status

  • Raycasting renderer with DDA, boundary walls, fog of war minimap
  • 5 towns (Sorpigal, Dusk, etc.) and full outdoor world grid navigable
  • Party system: view characters, manage inventory, equip/remove items
  • Map scripts partially implemented (town events, encounters)
  • Wandering monsters: the region's own encounter constants, the original's group builder, and the monster picture out of MONPIX.DTA. The fight itself is not written yet, so the party can simply walk away
  • Town services: blacksmith, market, temple, training hall and tavern, all priced and stocked out of MM.EXE; the inn is a stub
  • Combat and spells — in progress

What's changed from F-MM1

F-MM1 was abandoned; VARN Engine picks it up, but little of it is untouched. The two projects differ in kind, not just in features.

Nothing from the original game is in the repository

This is the change everything else is arranged around. F-MM1 committed data extracted from the game (data/items.dat, data/monsters.dat), art traced from or lifted out of it (media/images/walls/wall01–18.png, the ten intro/screen* frames, MM1-book.png, MM1-map.png), the original soundtrack as media/music/MM1-main.ogg, and even a save/ROSTER.DTA. Might and Magic is Ubisoft's; none of that is redistributable.

VARN Engine ships none of it and reads everything from the copy of the game you already own, at startup:

  • MM.EXE — spell tables, the 255-entry item table, the 195-entry monster table, class/race/alignment/condition names, wall strings, and the CGA bitmap font, which is decoded into an in-memory BDF so SFML can use it as a font
  • WALLPIX.DTA — wall textures, RLE- and CGA-decoded at runtime
  • MONPIX.DTA — the 76 monster pictures, decoded the same way, with their colours read out of MM.EXE
  • MAZEDATA.DTA and the *.OVR overlays — maze layouts, per-region constants and scripts
  • Manual.pdf and Might and Magic - Cluebook.pdf — the spell and region names, which the game never stored in a data file (see "Asset setup")

The media/ tree that remains is original work under its own licences, listed in THIRD-PARTY-NOTICES.md.

Hardcoded data replaced by runtime extraction

F-MM1 hardcoded what it could not load. Roughly 2500 lines of it are gone: model/maps/maze00.cpp–maze25.cpp and mazelist.h, one hand-written subclass per maze, are replaced by data-driven map loading plus OVR script classification; string tables scattered through the sources are consolidated behind ExeLoader; the spell system is driven off the EXE's own tables.

F-MM1's two remaining hand-entered map tables are gone as well. The outdoor adjacency grid now comes from each region's own OVR exit triples, and a region's three wall sprites from the wall ids in its maze constants, looked up in the 20-word table MM.EXE keeps for that purpose. model/hardcoded.h no longer exists.

Dead code removed

states/shops/Market.*, model/shops/market.* and states/TitleState.* were non-functional stubs and are gone — shops will be written against the real data rather than grown out of them. So are the stale duplicates render/MapSprite.h, render/MapSprite (копия).h and render/oldVer/, and a set of character.h members that were declared but never defined. The engine is about 6.5k lines to F-MM1's 7.8k while doing considerably more.

Ported to SFML 3 and C++17

F-MM1 targets SFML 2. The port covers the event system (pollEvent returning std::optional, getIf<>/is<> instead of the union), sf::Sprite and sf::Text no longer being default-constructible, the sf::Vector2-based geometry API, and scoped enums throughout.

Renderer and performance

Wall quads are batched into three sf::VertexArray by texture instead of one draw call per column, the finished frame is cached in an sf::RenderTexture and only redrawn when the view changes, the DDA loop is bounded at 32 steps rather than 100, and the frame rate is capped at 60.

Memory safety

The virtual destructor State never had — every state change was deleting a derived object through a base pointer and handing operator delete the wrong size — plus out-of-range roster and inventory indices, unchecked optional access and the crash on leaving the menu. tests/state_smoke.cpp now drives every state through its full lifecycle under AddressSanitizer and UBSan as a CTest target; it found the destructor bug on its first run.

New in VARN

  • Fog-of-war minimap
  • Widescreen support: F11 fullscreen and a maze that widens its field of view rather than stretching (see "Display")
  • A graphicRework toggle switching between the original CGA look and higher-resolution art with character portraits
  • Spell system, and OVR scripts read straight out of the region overlays: portal prompts, message/sign handlers — including signs that read differently depending on which way the party faces — and Sorpigal's statues, whose handlers carry only a number and leave the plaque to MM.EXE's own tables
  • Every string the game files hold is addressed, not numbered: MM.EXE's data segment and each overlay's data section are kept as images and read by the same addresses the original code uses, so a translation file can override any of them one at a time and fall back to the original for the rest (see media/localization/README.md)
  • One translation file for every string the game can show, the interface's own text included (see "Localization"); F-MM1's Russian strings were dropped rather than left to rot half-translated

Requirements

  • SFML 3.x
  • zlib (PDF content streams in the manual and cluebook are Flate-compressed)
  • CMake 3.10+
  • C++17 compiler
  • Original MM1 DOS game files placed under assets/mm1/ (see "Asset setup")

Build

cmake -S . -B build -DCMAKE_BUILD_TYPE=Release
cmake --build build -j$(nproc)
./build/VARN-Engine

Tests

state-smoke drives every state through init/update/draw plus a full key sweep, then exercises the state stack, the widescreen layout maths and window recreation, all under AddressSanitizer and UBSan. It runs against the game files in assets/mm1/ and skips itself if they (or a display) are missing.

cmake -S . -B build -DVARN_BUILD_TESTS=ON
cmake --build build -j$(nproc)
ctest --test-dir build --output-on-failure

Display

The game is laid out in a 1024x768 (4:3) space, but the maze is raycast, so a widescreen window widens the horizontal field of view instead of stretching or letterboxing the picture: walls keep their size and you see more of the corridor at the sides. The minimap and party portraits follow the new edges. Aspects narrower than 4:3, or wider than 2.4:1, letterbox the remainder.

F11 toggles fullscreen; the window is also freely resizable. Set FULL_SCREEN in Definitions.h to start fullscreen.

Localization

Every string the game can show — the text in MM.EXE, the text in each region overlay, the spell and region names read out of the GOG manual and cluebook, and the interface's own lines — is reachable through one table and can be overridden from a single file, media/localization/game_<LANG>.txt. Only what the file names is replaced; everything else falls back to the game's own text, so a half-finished translation runs. --dump-strings writes a template with all 2178 of them in it. Format and workflow: media/localization/README.md.

Limitations

The engine is ready for other languages; the fonts are not. Both are ASCII-only in practice, so anything outside it — extended Latin, let alone a non-Latin script — will not render:

  • Old-school mode draws with the original CGA font lifted out of MM.EXE. That font is 65 glyphs, 0x20–0x60, and nothing else exists to draw with: lowercase is aliased to uppercase, and an accented letter has no glyph at all. Supporting more would mean drawing the extra characters by hand in the same 8x8 cell the originals use (doubled to 16x16 in the BDF the engine builds at startup) and extending that font.
  • Graphic rework mode uses Nodesto Caps Condensed, which maps 114 codepoints: 9 of them in Latin-1 Supplement, none in Latin Extended-A, none outside Latin. Anything past basic ASCII needs a different font — this one would have to be replaced, not patched.

Translating into a language that fits in ASCII works today. Anything else waits on the fonts.

Controls

Key Action
Arrow keys Move / turn
F11 Toggle fullscreen
M Toggle minimap
Q Party screen
1–6 Character detail (from party screen)
R Rest (asks first)
B Bash the barrier ahead
U Unlock the barrier ahead (picks the lock)
S Search the square
O Reorder the party
P Protections screen
F12 Cheat console

Cheat console

F12 opens a line to type into; F12 or Esc closes it again. Might and Magic never had a console — Heroes III did, and its codes were all film references, so these are too, and they share a three-letter prefix the way the originals did. A code that is not recognised answers as well, so a typo does not look like a dead key.

Code Effect
jvcbeammeup [region] The party goes to that region, or home to Sorpigal
jvcharrymudd [gold] Pays the first character, 65535 by default
jvcmirrormirror [id] Turns a character's alignment into its opposite
jvcredshirt [id] Leaves a character on one hit point
jvcgorn Switches interface without leaving the maze
jvcquadrotriticale [n] Food for the first character
jvcdilithiumcrystals [n] Gems for the first character

[id] is a party slot, 1 to 6, and the first character is meant when a code does not say. The two stores fill to the brim when no number is given, and the brim is what a character record holds — food is one byte of it and gems are two — so nothing is handed out that the roster would lose on the way to disk. mirrormirror leaves the alignment a character was made with alone, so a temple will sell it back; a neutral character has no opposite and stays as they are.

Asset setup

Place your original MM1 DOS data files under assets/mm1/. Nothing from the original game is distributed with this engine — see THIRD-PARTY-NOTICES.md.

VARN Engine is developed and tested against the GOG.com release of Might and Magic: Secret of the Inner Sanctum. Other copies of the DOS version should work — the engine only reads the original data files — but the GOG one is what everything here is verified against.

Copy the contents of the GOG installation's game directory into assets/mm1/:

  • MM.EXE — spell tables, item and monster stat tables, region overlay names and the CGA bitmap font
  • MAZEDATA.DTA, *.OVR — maze layouts and per-region scripts
  • WALLPIX.DTA — wall textures (used when the graphics rework is off)
  • MONPIX.DTA — monster pictures
  • ROSTER.DTA — character roster

Two PDFs are required as well. They carry text the game itself never stored: the original referred players to the printed documentation, so spell and region names only ever existed on paper. The engine reads them at startup rather than carrying a transcription in source.

  • Manual.pdf — the 94 spell names. Ships with the GOG release and is already in the game directory, so it comes across with everything else.
  • Might and Magic - Cluebook.pdf — the 55 region names. Not bundled with the game: download it from the extras/goodies section of the GOG product page and drop it into assets/mm1/ alongside the rest.

Without them the engine still starts, but spells and regions are nameless and it says so on stdout. Music files, by contrast, are genuinely optional — missing files are silently skipped.