Sid Meier's Colonization (DOS, VICEROY.EXE v3.0) running as C# on a virtual x86 CPU, in the style of OpenCivOne.
The game code comes from the Disassembler
(colonization branch), which turns
every function of VICEROY.EXE and its 31 overlays into C# calls on IRB.VirtualCPU.VCPU.
This repository is the host: the CPU, DOS/BIOS services, a mode 13h VGA, and an Avalonia window.
src/VirtualCPU- the CPU, memory and DOS/BIOS interrupts, taken from OpenCivOne (MIT, seeLICENSE.OpenCivOne)src/VirtualCPU/VCPUVGA.cs- A000:0000 framebuffer and DAC palette, read by the UIsrc/Game/OpenColoGame.cs- root object the generated segment classes hang off; loads VICEROY.EXE, sets up the PSP and environment, and stands in for the game's timer interrupt and the mouse driver's event callssrc/Game/SoundDriver.cs- the#SOUND.COLdrivers: RSOUND.COL on an MT-32, a stand-in for the otherssrc/Audio- OpenAL output, the MT-32 (munt) and the MPU-401 in front of itsrc/Generated- the Disassembler'scolonization-runnableoutput (not in git, see below): VICEROY.EXE and RSOUND.COLsrc/UI- Avalonia window, BIOS key mappingdocs/startup.md- how the original starts: OPENING/VICEROY/CLOSING chain,main(), CONFIG.COL, command-line switchesdocs/timer.md- the game's own INT 8 handler, PIT rate, tick counters, water color cyclingdocs/memory.md- VICEROY.EXE file and overlay layout, address conventions, known DGROUP variablesdocs/madspack.md- MADSPACK containers (.PIK/.SS/.FF), FAB decompression, the codec tabledocs/sound.md- loading the#SOUND.COLdriver, the1059call interface, running without soundtools/fab_check.py- reference FAB decoder; checks every MADSPACK file in a game directory (python3 tools/fab_check.py $OPENCOLO_PATH)
The game code is generated, not kept here. Generate it with the
Disassembler from your own copy
of the game and copy it into src/Generated. The Disassembler reads the game from
GameSRC/COLONIZE and must be run from its repository root:
git clone -b colonization https://github.com/nan0desu/Disassembler.git
cd Disassembler
mkdir -p GameSRC && cp -r <game directory> GameSRC/COLONIZE
dotnet build src/Disassembler.csproj
dotnet src/bin/Debug/net9.0/Disassembler.dll colonization-runnable
cp src/bin/Debug/net9.0/Output/ColonizationRunnable/*.cs <OpenColo>/src/Generated/Or point the build at the output directory with -p:GeneratedCodePath=<dir>. Then:
mise exec -- dotnet build src/OpenColo.csproj
OPENCOLO_PATH=~/dos/COLONIZE mise exec -- dotnet run --project src/OpenColo.csprojOPENCOLO_PATHis the directory with the original DOS game files; without it the executable's own directory is used.OPENCOLO_ARGSis the VICEROY command line, empty by default (see docs/startup.md).-c:Nturns the sound driver off. Don't add-owithout OPENING: the start menu then takes its background from the screen OPENING left behind.- The sound device is the one in the game's
CONFIG.COL, as set up by its INSTALL. The digitized effects fromCOLDIG.BINplay through OpenAL with any device. For Roland (R), the original driver plays the music and the MIDI part of the effects on an emulated MT-32 or CM-32L. That needs munt's libmt32emu (themt32emupackage on Fedora) and the ROMs:OPENCOLO_MT32_ROMSis the directory with the ROM files,~/.config/dosbox/mt32-romsby default, the same as DOSBox Staging's. Halves of a ROM are merged.OPENCOLO_MT32picks the machine by its munt ID (cm32l_1_02,mt32_2_07, ...). By default it is the first of CM-32L 1.02, CM-32L 1.00, then the MT-32s from the newest that has a complete set of ROMs. Without munt or the ROMs, and for the other devices, there is no music yet.
COLONIZE, if set, is passed into the game's environment (COLONIZE=MULTI).OPENCOLO_LOG=1writesLog.txtnext to the executable.- F12 in the window writes
Dump.bin(conventional memory),Dump.txt(registers and the functions being executed) andDump.png(the 320x200 screen) next to the executable; so does a non-zero exit, andDump.vga(the 64K at A000:0000, then the 768 byte DAC palette). Existing dumps are kept, the next ones areDump1,Dump2, ...OPENCOLO_CHECKS=1turns on the debug checks inOpenColoGame.AddDebugChecks, which dump when a function is entered with arguments known to be bad.
The host starts VICEROY.EXE at the C runtime's Start, skipping the overlay manager. It
doesn't emulate the timer interrupt or the mouse driver; it runs their effect on the game
thread between memory accesses (VCPU.DoEvents): the BIOS tick count, or once the game has
installed its INT 8 handler, a C# copy of that handler that calls the game's own color cycling
callback and the sound driver; and the game's INT 33h event handler when the mouse moves. The PIT counter and the
VGA retrace bit follow real time, which is what the game's VGA timing calibration measures.
This port wouldn't exist without Rajko Horvat. His OpenCivOne brought Sid Meier's Civilization back to life by turning the original executable into readable, runnable C#. It showed that the same could be done for Colonization, and it is what started this project. Rajko also wrote the first version of the Disassembler, which generates all of the game code here, and the virtual CPU this host is built on. Thank you, Rajko, for the work and for sharing it.
OpenColo is licensed under the GNU General Public License v3.0, see LICENSE.
src/VirtualCPU and src/IRB are based on OpenCivOne by Rajko Horvat and remain under the
MIT License, see LICENSE.OpenCivOne. Changes made to them here are under GPLv3.
The license covers this repository only. The code generated from VICEROY.EXE in
src/Generated is a translation of the original game. It isn't part of OpenColo and isn't
covered by this license.
Sid Meier's Colonization, MicroProse and all other trademarks are the property of their respective owners. This project is not affiliated with or endorsed by MicroProse or any current rights holder. It is an unofficial fan port.
This repository contains no files from the original game: no executables, graphics,
sounds, music or text. To play, you need your own copy of the DOS version of Colonization.
Point OPENCOLO_PATH at its directory.