⚓ Seaworth Games

VCMI · Heroes of Might & Magic III engine

Systems Map

A top-level survey of how the engine is built: one shared library, a server that alone may change game state, a client and a set of AIs that read a local copy of it. Use this to pick where to dig in next.

The one rule the whole engine is built on

Everything above — UI, AI planning, replay, the map editor — is downstream of a single asymmetry: state has exactly one writer.

CLIENT · AI same interfaces serve both local cached state client & AI read here read via Callback · no network hop SERVER sole writer of state CGameState written only here validated before every write request · network pack result · broadcast pack
Game state has one writer. Client and AI act by sending a request across this boundary; the server validates it and broadcasts the result. Everything else — rendering, AI planning, the UI — reads a local cache that the broadcast keeps in sync, without touching the network. What's actually inside those two arrows is its own document: the wire protocol →

The regions

Five areas, each built and shipped differently: one static core, three consumers of it, and a belt of standalone tools.

Core Library — lib/

vcmiMain — game rules and data structures, no rendering or transport code of its own

bonuses/28The bonus system — every stat, resistance and immunity flows through two DAGs of nodes with propagators, limiters, and updaters — dig in →
battle/46core combat rules, damage calculation, unit state — dig in →
gameState/26CGameState itself — the authoritative snapshot — dig in →
callback/34read-only interfaces AI & client query instead of touching state directly — dig in →
entities/36heroes, creatures, artifacts, spells, buildings — dig in →
mapObjects/48+ mapObjectConstructors/ (24) — towns, dwellings, mines and the rest of the adventure map — dig in →
rewardable/10the requirement/grant pair behind every reward object — dig in →
rmg/78random map generator — the largest single subsystem in lib — dig in →
spells/52spell definitions and casting logic — dig in →
mapping/38map load / save — dig in →
serializer/29save-game and network serialization framework — dig in →
networkPacks/20the packet vocabulary client and server speak to each other — dig in →
modding/21mod and content loading — dig in →
filesystem/, json/, texts/68archive loading, config parsing, localization
pathfinder/, campaign/28hero pathfinding — dig in →; campaign progression — dig in →
Server — server/

vcmiservercommon — the only process allowed to mutate CGameState

CGameHandler the hub — validates every incoming request, is the single write path — dig in →
battles/ server-side combat flow processing — dig in →
queries/ player decision prompts (e.g. “choose a reward”) — dig in →
processors/ turn, hero and economy processing — dig in →
Client — client/

SDL2-based — renders and reads the local cache, never writes state directly

adventureMap/ + battle/ — mode-specific UI and logic — dig in → (or the battle screen)
gui/ the CIntObject widget framework everything else builds on — dig in →
render/ + renderSDL/ — rendering abstraction over SDL2
eventsSDL/ keyboard, mouse, touch and gamepad input — dig in →
mapView/ adventure map rendering — dig in →
globalLobby/ vs. lobby/ — online matchmaking UI vs. local game setup — dig in →
AI — AI/

statically linked, chosen by name through AIFactory — no dynamic loading

Nullkiller2 modern adventure-map AI — default — dig in →
BattleAI default combat AI — dig in →
StupidAI minimal combat AI for neutral / passive players
MMAI experimental, machine-learning-based combat AI
EmptyAI no-op stub, used for testing
Tooling & Apps

standalone executables and Qt tools built alongside the engine

launcher/ Qt-based game launcher — dig in →
mapeditor/ Qt-based map editor — dig in →
lobby/ standalone SQLite-backed global lobby server (distinct from client/globalLobby/) — dig in →
luascript/ Lua scripting host (vcmiLua) for ERM/Lua mods — dig in →
libFacade/ links vcmiMain + vcmiLua + every AI into the shipped libvcmi — dig in →
serverapp/, clientapp/ the actual executable entry points

Threading model

Four lanes running alongside each other inside the same process pair.

Main GUI

input processing and rendering

runNetwork

processes incoming packets, runs combat AI reactions

runServer

processes requests, applies game state updates

AI tasks

TBB-based parallel tasks for adventure-map AI

Index

Every deep dive published from this map so far, in the order they were dug.

First pass — lib/
⚔️
how a fight starts, the turn loop, and a Lua-scripted damage calculator with no C++ fallback
🎲
zone placement, then a dependency-scheduled modifier graph — not a fixed generation order
🔮
one CSpell definition, two unrelated runtimes depending on where it's cast
📜
a loaded map, a generated map, and a saved map all converge on one CMap
🕷️
two DAGs, not one — inheritance is lazy, propagation is eager
📡
the double-dispatch visitor underneath this map's own “one rule” diagram
Second pass
🧠
Nullkiller's depth-first goal decomposer, and the deterministic shadow battle BattleAI fights first
🫝
the parent-child tree and the input dispatch lists are two independent structures
🧰
one shipped library, four programs, and the Lua script registry finally explained
Third pass
💾
the one CGameState::apply() that the server and every client run independently against their own state
🌅
where the NewTurn pack is built, and why simultaneous turns are decided by an actual pathfinder
🔢
how a byte stream remembers its real type, and where the canonical serialization doc has drifted from the code
👁️
the read side of this atlas — layered query interfaces, where a request pack is actually built, and a randomizer that remembers your bad luck
🥱
one template instantiated six times, a mod loader that resolves names it doesn't have yet, and a save that remembers exactly which mods wrote it
🧙
a Dijkstra search over layered path nodes, gated by a fixed five-rule chain the player, the turn-order check, and the AI each configure differently
🏰
a two-tier class/subtype factory behind every town and treasure, and a hero visit that can pause on a network round trip before it finishes
🎛️
the real pack-dispatch entry point every other doc cited, and the one mechanic — a hero's single step — it never delegates to a specialist
🖼️
a map renderer that never branches on what it's drawing, and the wait that pauses pack processing until a hero's walk finishes on screen
🎮
the screen's own mode switch flipping alongside the map view's, and a shortcut table that rebuilds its enabled flags from that state every time it's read
🎁
two near-mirror-image structs for what a reward needs and what it gives, and a second, differently-shaped solution to a problem the Bonus System already solved once
🥳
a campaign as a container of embedded, ordinary .h3m files, and the one hero-carrying serialization path this atlas's binary framework was never meant to cover