Civilization II: Multiplayer Gold Edition (Win32 retail)

Registry id civ2_mge, tree test/binaries/candidates/civilization-2-mge-win32/ (gitignored): cd/ is the disc, installed/ the game install.

Movies are Indeo 4, and Indeo is a separate install

The advisor, wonder and council movies are cd/Civ2/VIDEO/*.AVI, all IV41 (Indeo 4). Civ2 MGE reaches them through AVIFIL32 + ICLocate/ICDecompress and MCIWndCreateA. It bundles no decoder: the disc has Intel's installer under cd/Win_95nt Indeo/IVI_95NT.EXE, which puts ir41_32.dll (plus ir41_qc.dll, ir41_qcx.dll, ir32_32.dll, iyvu9_32.dll) in c:\windows\system and registers them in SYSTEM.INI:

[drivers32]
VIDC.IV41=ir41_32.dll
VIDC.IV32=ir32_32.dll
VIDC.IV31=ir32_32.dll
VIDC.YVU9=iyvu9_32.dll

Without that install, ICLocate returns 0 and the game skips the movie, just as Windows does on a machine without Indeo. With it, the emulator loads the driver and runs its DriverProc as guest x86 (see "Installable codec drivers" in docs/video-support-design.md). Intel's DLLs are never committed. Take them from the disc by running the installer.

Watch out: the installed files differ in size. ir41_32.dll is 739,328 bytes and ir32_32.dll is 199,168. Swap them and VIDC.IV41 loads the Indeo 3 driver, which opens, accepts the stream and then decodes black frames. Nothing crashes. Check the size first.

Headless Indeo install (2026-09-28)

S = a scratch directory. Three stages, each an ordinary test/run.js run.

  1. Self-extractor. IVI_95NT.EXE unpacks an InstallShield 3 setup into c:\windows\temp:

    node test/run.js --exe="test/binaries/candidates/civilization-2-mge-win32/cd/Win_95nt Indeo/IVI_95NT.EXE" \
      --overlay-dir=$S/ivi-ov --screen=800x600 --no-build --quiet-api --no-close \
      --max-batches=3000 --max-seconds=90
    

    Copy the overlay's files out under their real names (setup.exe, setup.ins, setup.pkg, _setup.lib, data.z, _inst32i.ex_, …) into $S/ivi-tmp (the overlay format is index.json + blobs/).

  2. setup.exe -sms. It unpacks the real engine and ShellExecutes it. Capture that launch:

    node test/run.js --exe=$S/ivi-tmp/setup.exe --args=-sms --vfs-include='*' \
      --capture-launch=$S/ivi-cap --screen=800x600 --no-build --quiet-api --no-close \
      --batch-size=100000 --max-batches=3000
    

    $S/ivi-cap then holds the VFS tree, including windows/temp/_ins0432._mp, the 32-bit IS3 engine.

  3. The engine, with the arguments setup passed it, clicking Next through the wizard:

    node test/run.js --exe=$S/ivi-cap/windows/temp/_ins0432._mp --vfs-tree=$S/ivi-cap \
      '--args=-sms -fC:\SETUP.INS  -z1 -cx -xC:\WINDOWS\TEMP\' '--cwd=C:\' \
      --overlay-dir=$S/ivi-ov-s3 --screen=800x600 --no-build --no-close --max-seconds=100 \
      --input=1400:dlg-cmd:1,1700:mousedown:493:454,1705:mouseup:493:454,2100:mousedown:493:454,2105:mouseup:493:454,2500:mousedown:396:337,2505:mouseup:396:337,2900:mousedown:493:454,2905:mouseup:493:454,3300:mousedown:493:454,3305:mouseup:493:454,3700:mousedown:493:454,3705:mouseup:493:454,4100:mousedown:493:454,4105:mouseup:493:454,4500:mousedown:493:454,4505:mouseup:493:454
    

    (493,454 is Next/Finish on an 800x600 screen. 396,337 is the licence "Yes".) $S/ivi-ov-s3 ends up holding the five DLLs, indeo.hlp, the new SYSTEM.INI and uninst.exe. That overlay, or just SYSTEM.INI plus ir41_32.dll, is the Indeo machine.

Registry quirk. The IS script writes its ICM registration to HKCR\System\CurrentControlSet\control\MediaResources\icm\vidc.IV41. The guest really passes hKey = 0x80000000, so that is the script's own doing and not an emulator bug. It means no Windows finds the codec through the registry, and SYSTEM.INI [drivers32] is the lookup that matters on Win9x.

Proving the decode without Civ2's own route

The simplest player that exercises the path is Half-Life: Uplink's intro, which plays media\intro.avi with MCI play sierravideo wait into a 320x240 window at (160,120) of 640x480. Give it Civ2's ANARCHY0.AVI (480x120, 15 fps, 111 frames) as c:\media\intro.avi in the overlay:

Getting there took two emulator fixes (details in the design doc):

ir41_32 also calls LocalHandle as the stream ends.

The game's own movies (2026-09-28)

--app=civ2_mge plays opening.avi with nothing extra: no overlay and no --media-mount. test/test-civ2-mge-movie.js pins this. The same route works in the browser with the guest in a Worker. It took three fixes:

Headless recipe: --batch-size=100000 --tick-ms-per-batch=20. The Diplomatic Heralds prompt (first launch) appears around batch 500. Its OK button is at 403,387 (mousedown at batch 1210, mouseup at 1230). The movie follows; after it comes the main menu with its animated IV41 map.

Not yet done

The Win16 build plays its movies through the disc's 16-bit Indeo (2026-09-28)

The Win16 disc (civ2_win16) ships Video for Windows 1.1 setup media in VFW_INST\. Its IR41.DL_ is Intel's **16-bit** Indeo 4 driver, KWAJ method 3 compressed and with no stored length. SETUP.INF gives the size:

node tools/kwaj.js "…/cd/VFW_INST/IR41.DL_" …/civilization-2-win16/vfw/ir41.dll --size=774960

(sha256 88f156f5…d99721; test/test-kwaj-expand.js checks it.) lib/apps.js mounts it as c:\windows\system\ir41.dll and writes VIDC.IV41=ir41.dll into system.ini [drivers]. The game calls Win16 MSVIDEO ICLocate/ICSendMessage/ ICMessage in src/09e-win16-api.wat. Those load the NE driver and run its DriverProc as a far call.

What the driver needs from the emulator, in the order it hit them:

Where to look when a frame fails: seg10:0x969a maps the codec's internal status (0..0x16) to an ICERR. The 32-bit decode is seg10:0x16a0 → 0x17f2. Segment bases in these runs: seg2 0x021a0000 … seg10 0x02220000, DGROUP (seg19) 0x022b0000.

Headless recipe: node test/run.js --app=civ2_win16 --quiet-api --no-close --batch-size=100000 --tick-ms-per-batch=20 --input=400:mousemove:209:280, 410:mousedown:209:280,430:mouseup:209:280,700:mousemove:322:327, 710:mousedown:322:327,730:mouseup:322:327,950:png:a.png,1200:png:b.png. The intro's starfield, title and galaxy burst decode frame by frame. test/test-win16-use32-stack.js pins the ESP semantics.

Gameplay (city screen, naming)

Route to the first city, controlled: node test/run.js --app=civ2_win16 --no-close --control=PORT --frozen --batch-size=100000 --tick-ms-per-batch=20, then drive it with tools/ctl.js (Enter through setup, then cmd keypress:98 for b on the tutorial's "good site for a city"). ctl key sends keydown/keyup only, so letter commands need cmd keypress:<ascii>.

Civilopedia (Win16, 2026-09-29)

The Civilopedia menu does not show a dialog. Civ2 WinExecs PEDIA\GET_INFO.EXE, an 11 MB Authorware 2 runtime (its image is ~750 KB; the rest is an overlay it reads from its own file). The two talk through FindWindow("Get_Info") and ShowWindow, plus a get_info.txt Civ2 writes with the topic. GET_INFO loads PEDIA\CIVJUMP.DLL, a small NE, by full path. It runs as a second Win16 task: see docs/win16-multitask-design.md.

Controlled route: from the setup screens, Enter ×16 (with step 250 between) reaches the map. cmd post-cmd:386 then opens the Civilopedia's Civilization Advances list; the menu item ids are the WM_COMMAND the bar sends. After about 240 batches the list is up. A click on a name (for example 102,117 for Alphabet) opens its page. EXIT on a topic page is at 497,461, and on the list at 425,432.