Keyboard shortcuts

Press ← or → to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

Architecture

The game is five layers deep. Each calls only the ones beneath it, and the port replaces the bottom two.

 ┌──────────────────────────────────────────────────────────────────────┐
 │ The game      scenes (puzzles, map, camps), Zoombinis, dialogs, save │  decomp/<scene>.cpp, snoids,
 │               files, input groups, views and scripts                 │  features, view, focus, ...
 ├──────────────────────────────────────────────────────────────────────┤
 │ e2 layer      the game's own wrappers over the engine: handles,      │  e2memory, loading, graphics,
 │               resources, shapes, sounds, fonts, fade, errors         │  sound, anim
 ├──────────────────────────────────────────────────────────────────────┤
 │ Mohawk engine QuickDraw-style ports and regions; Mac-style memory    │  0x4764bc-0x494000: baseport,
 │               and resource managers; audio objects, WaveMix; async   │  newhandle, resourcefile, ...
 │               files; INI reader; timers                              │
 ├──────────────────────────────────────────────────────────────────────┤
 │ Mohawk OS     reference counts, local memory, deferred calls,        │  os_*.cpp  (0x46d754-0x46f7a4)
 │ layer         cooperative threads on fibers, timers, window hooks    │
 ├──────────────────────────────────────────────────────────────────────┤
 │ Win32 / C RTL KERNEL32, USER32, GDI32, WINMM, DSOUND (by name),      │  Borland CW32.LIB, the Windows
 │ QuickTime     QuickTime for Windows 2.x (by name, via SDK glue)      │  DLLs; miniwin + SDL2 in the port
 └──────────────────────────────────────────────────────────────────────┘

Why it looks like a Mac game

Logical Journey of the Zoombinis was a Mac title first, and Broderbund's Mohawk engine imitates the Mac Toolbox so that game code could move across. The evidence is everywhere: handles and purgeable memory, a resource manager with typed IDs, regions and Rect/Point, GrafPort-style ports, transfer modes, 'CURS'/'tBMP'/'tMID' resource types, Mac message strings, 16-bit-style short arithmetic, and big-endian resources byte-swapped on load. The Windows layer below it is thin. This is also why the port is cheap: it implements Win32 for the engine, and the game never notices.

What each layer owns

LayerOwnsKey objectsRead
Gamethe rules of every puzzle; the journey; saved gamesScene, View, Snoid, gameState, input GroupsGame layer, Entities
e2loading and lifetime of game resourcesresource handles, ImageBank, SoundEntryGame layer
Engine: graphicsdrawingbasePort and subclasses, DIB, regions, Palette, ColorGraphics
Engine: memory/resourcesstorage and Mohawk archiveshandles, 'BM' blocks, 'RMap' mapsMemory and resources
Engine: audiosoundaudioObj, wavebuf, wmxMixerOS layer, timers, audio
Engine: files, INIthe file systemfileSpec, asyncAPI, INI readerOS layer, timers, audio
OS layerpseudo-threads, timers, deferred callsthread, sync, DeferLockOS layer, timers, audio

C++ classes

Only the engine and OS layer are polymorphic (46 classes with RTTI); the game's own logic is plain functions and structs, which is why most game structs carry a /* +0x.. */ comment and no vtable. See Classes.

Control flow in one picture

 WinMain
   └─ loop:  mainLoopUpdate()           enterNextScene if pendingScene != -1; handle an event or the mouse
             mainLoopEvents()           handleWaitingMessage (the Win32 queue → mainWindowProc → events)
                └─ frameHook = gameFrame   scenes[currentScene]->frame()   ← each scene's logic runs here

See Startup and The main loop.