Civilization Recomp
June 7, 2026 · View on GitHub
A static recompilation of Sid Meier's Civilization (1991) for modern Windows
"I've played a lot of Civilization in my time, I can tell you." — Literally everyone who has ever touched this game

The recompiled "Sid Meier's CIVILIZATION" title, decoded pixel-perfect and running natively on Windows 11. The full intro (logo → birth → credits, in color) plays, then New Game drives world generation, the sprite-sheet decode, and the civilization-select screen.
What Is This?
This is a fan preservation project to bring the original Sid Meier's Civilization — the game that invented an entire genre, ruined millions of sleep schedules, and taught more people about the tech tree of human progress than any history class ever could — natively to Windows 11 via static recompilation.
No emulation. No DOSBox wrapper. Just pure, native, one-more-turn glory running on modern hardware exactly as Sid intended (minus the 640K memory limit and IRQ conflicts).
This is an unauthorized fan project. We are not affiliated with Firaxis Games, Take-Two Interactive, or MicroProse. We just think this game is a masterpiece that deserves to be preserved forever, turn after turn, civilization after civilization.
A Note About Sid Meier
Sid Meier is one of the greatest game designers who has ever lived. With Civilization (1991), he and Bruce Shelley created something genuinely transcendent — a game that is simultaneously a toy, a puzzle, a strategy engine, a history lesson, and one of the most addictive pieces of software ever compiled. Meier's design philosophy of "interesting decisions" produced a game where every single turn matters and every choice echoes across millennia. The fact that we're still talking about (and playing) this game over 30 years later speaks to the brilliance of its design.
The original Civilization was a product of MicroProse Software, the legendary studio co-founded by "Wild" Bill Stealey and Sid Meier. This project exists purely out of love and respect for their work, and a desire to ensure it remains playable forever.
Why Static Recompilation?
| Approach | How It Works | Trade-offs |
|---|---|---|
| DOSBox | Emulates entire x86 CPU + DOS + hardware | Works but adds overhead, input lag, scaling artifacts |
| Source Port | Rewrite from scratch based on behavior | Massive effort, subtle differences from original |
| Static Recomp | Translate original machine code to C, run natively | Preserves exact original logic, runs at native speed |
Static recompilation gives us the best of all worlds: the exact game logic Sid wrote, compiled fresh for modern x86-64, with a thin hardware abstraction layer replacing the DOS/VGA/AdLib interfaces with SDL2.
Binary Analysis
CIV.EXE — The Main Executable
================================================================
Sid Meier's Civilization (1991) - Binary Analysis
Compiled with Microsoft C 5.x (1988 Runtime)
================================================================
File: civ.exe (305,024 bytes / 297.9 KB)
Architecture: 16-bit x86 real mode (DOS)
Compiler: Microsoft C 5.x (MSC 1988 Runtime Library)
Overlay Manager: Microsoft C INT 3Fh
Resident Code: ~174 KB (loaded at startup)
Overlay Modules: 23 modules (~124 KB demand-loaded)
Total Code: ~298 KB
Entry Point: CS:IP = 2A10:0010
Stack: SS:SP = 3217:0080
Overlay Module Map
The game uses the Microsoft C Overlay Manager to fit ~298 KB of code into DOS
memory constraints. Code is divided into a resident portion (always loaded) and 23
overlay modules that are demand-loaded via INT 3Fh when called:
Overlay File Offset Size Functions Call Sites
------- ----------- -------- --------- ----------
OVL 01 0x02B800 1.5 KB 1 1
OVL 02 0x02BE00 7.4 KB 4 4
OVL 03 0x02DC00 3.6 KB 6 8
OVL 04 0x02EC00 1.6 KB 4 18
OVL 05 0x02F400 8.3 KB 7 14
OVL 06 0x031600 10.4 KB 5 15
OVL 07 0x034000 8.2 KB 3 4
OVL 08 0x036200 7.0 KB 4 10
OVL 09 0x037E00 6.3 KB 3 5
OVL 10 0x039800 2.2 KB 2 2
OVL 11 0x03A200 4.4 KB 2 3
OVL 12 0x03B400 7.8 KB 6 9
OVL 13 0x03D400 2.9 KB 2 2
OVL 14 0x03E000 7.9 KB 8 16
OVL 15 0x040000 2.9 KB 2 2
OVL 16 0x040C00 1.8 KB 1 1
OVL 17 0x041400 4.6 KB 2 3
OVL 18 0x042800 6.7 KB 4 5
OVL 19 0x044400 8.2 KB 4 9
OVL 20 0x046600 6.0 KB 3 7
OVL 21 0x048000 1.5 KB 1 18
OVL 22 0x048800 5.3 KB 5 8
OVL 23 0x049E00 2.4 KB 4 4
-------- --------- ----------
Total: ~124 KB 83 funcs 168 calls
DOS/BIOS Interface
Interrupt Service Calls Recompilation Target
--------- ------- ----- --------------------
INT 21h DOS API 120 Win32 API / C runtime
INT 3Fh MSC Overlay 168 Direct function calls (resolved at recomp time)
INT 33h Mouse driver 7 SDL2 mouse input
INT 16h Keyboard BIOS 4 SDL2 keyboard input
INT 10h Video BIOS 3 SDL2 / D3D11 rendering
INT 09h Keyboard HW IRQ 3 SDL2 event loop
INT 08h Timer IRQ 1 SDL2 timer / QueryPerformanceCounter
Support Executables
| File | Size | Purpose |
|---|---|---|
egraphic.exe | 11,584 B | EGA (16-color) graphics driver |
mgraphic.exe | 7,142 B | MCGA/VGA (256-color) graphics driver |
tgraphic.exe | 9,990 B | Tandy (16-color) graphics driver |
misc.exe | 980 B | Utility/launcher stub |
Game Data Files
| Type | Count | Purpose |
|---|---|---|
.pic | 106 | Images (title, units, terrain, cities, diplomacy, wonders) |
.pal | 38 | VGA/EGA palettes (256 or 16 color, 6-bit RGB) |
.cvl | 4 | Sound data (AdLib/SB/Tandy/IBM speaker) |
.txt | 10 | Game text (credits, help, intro, Civilopedia entries) |
.cv | 1 | Font data |
.map | 1 | Saved map data |
.sve | 1 | Saved game state |
.dta | 1 | Hall of Fame data |
Architecture
┌─────────────────────────────────────────────────────┐
│ Recompiled Game Code │
│ (civ.exe → C, resident + 23 overlays) │
├─────────────────────────────────────────────────────┤
│ DOS Compatibility Layer │
│ INT 21h → C runtime Overlay mgr → direct call │
│ File I/O → stdio Memory → malloc/heap │
├───────────────┬───────────────┬──────────────────────┤
│ Video HAL │ Audio HAL │ Input HAL │
│ VGA 320x200 │ AdLib OPL2 │ Mouse + Keyboard │
│ 256-color │ PC Speaker │ INT 33h/16h → SDL2 │
│ → SDL2/D3D11 │ → SDL2 Audio │ │
├───────────────┴───────────────┴──────────────────────┤
│ SDL2 / Win32 │
├──────────────────────────────────────────────────────┤
│ Windows 11 x64 │
└──────────────────────────────────────────────────────┘
Project Structure
civ/
├── README.md # This file
├── CMakeLists.txt # Root build configuration (CMake 3.20+)
├── civ.syms.toml # Exported function symbol table
├── .gitignore # Excludes game files and build output
├── tools/ # Reverse engineering & analysis tools
│ ├── CMakeLists.txt
│ ├── mzparse/ # MZ header & overlay analyzer
│ ├── ovldump/ # Overlay module extractor
│ ├── picdecode/ # .PIC/.PAL image format analyzer
│ └── recomp/ # Static recompilation toolchain
│ ├── decode16.py # 16-bit x86 instruction decoder
│ ├── analyze.py # Function boundary & call graph analyzer
│ ├── lift.py # x86-16 to C code lifter
│ ├── lift_from_dump.py # EXEPACK dump lifter (decompressed code)
│ ├── recomp.py # Main recompilation driver
│ ├── map_thunks.py # Overlay thunk table decoder (EXEPACK + 7-byte entries)
│ ├── map_thunks2.py # Thunk caller analysis & cross-overlay constraint solver
│ └── parse_overlays.py # Overlay MZ header parser & function finder
├── include/ # Public headers
│ ├── recomp/
│ │ ├── cpu.h # CPU state struct (registers, flags, memory)
│ │ └── dos_compat.h # DOS API compatibility layer
│ ├── hal/
│ │ ├── video.h # VGA Mode 13h emulation
│ │ ├── input.h # Keyboard & mouse HAL
│ │ └── timer.h # PIT timer emulation
│ └── platform/
│ └── sdl_platform.h # SDL2 platform layer
├── src/
│ ├── main.c # Entry point & main game loop
│ ├── recomp/
│ │ ├── cpu.c # CPU state management
│ │ ├── dos_compat.c # Full INT 21h/10h/16h/33h implementation
│ │ └── startup.c # MSC crt0 replacement
│ ├── hal/
│ │ ├── video.c # VGA DAC palette, mode 13h, vsync
│ │ ├── input.c # Keyboard buffer, mouse state
│ │ └── timer.c # PIT timer tick emulation
│ └── platform/
│ └── sdl_platform.c # SDL2 window, rendering, input events
└── RecompiledFuncs/ # Auto-generated C output (gitignored)
├── civ_recomp.h # Master header (482 function declarations)
├── civ_recomp_000..009.c # Recompiled game code (132K lines)
├── civ_dump_lifted.c # Functions lifted from EXEPACK dump (171 funcs)
├── civ_impl.c # Hand-written implementations (tracked in git)
├── civ_stubs.c # Stub functions for unresolved symbols (auto-generated)
└── civ_aliases.c # Overlay thunk aliases (auto-generated)
Building
Prerequisites
- CMake 3.20+
- MSVC (Visual Studio 2022) or MinGW-w64
- Python 3 (for recompilation toolchain)
- SDL2 via vcpkg:
vcpkg install sdl2:x64-windows
Building
# Step 1: Run the recompiler (generates C files from CIV.EXE)
py -3 tools/recomp/recomp.py path/to/CIV.EXE RecompiledFuncs
# Step 2: Configure CMake with vcpkg
cmake -B build -G "Visual Studio 17 2022" -A x64 \
-DCMAKE_TOOLCHAIN_FILE=C:/vcpkg/scripts/buildsystems/vcpkg.cmake
# Step 3: Build
cmake --build build --config Release
Running
# Run from the game data directory
cd path/to/game/data
path/to/build/Release/civ.exe --gamedir . --scale 3
Running Analysis Tools
# Analyze the MZ executable structure
build/Release/mzparse.exe path/to/civ.exe
# Extract overlay modules
build/Release/ovldump.exe path/to/civ.exe output_dir/
# Analyze .PIC image files
build/Release/picdecode.exe path/to/logo.pic
Running the Recompiler
# Disassemble resident code
py -3 tools/recomp/decode16.py path/to/civ.exe --resident
# Disassemble overlay N
py -3 tools/recomp/decode16.py path/to/civ.exe --overlay 5
# Analyze function boundaries
py -3 tools/recomp/analyze.py path/to/civ.exe -symbols civ.syms.toml
# Full recompilation (generates C files)
py -3 tools/recomp/recomp.py path/to/civ.exe RecompiledFuncs
Progress
Phase 0 — Binary Analysis & Documentation
- MZ header parsing and structure analysis
- Microsoft C overlay manager identification (INT 3Fh)
- Overlay module enumeration (23 modules, 83 functions)
- DOS interrupt surface mapping
- String table extraction (1,807 strings)
- Support executable identification
- Game data file inventory
- .PIC image format reverse engineering
- .CVL sound format reverse engineering
- .CV font format analysis
Phase 1 — Recompilation Toolchain
- 16-bit x86 instruction decoder (full 8086/80186 opcode coverage)
- Function boundary detection (MSC 5.x prologue/epilogue patterns)
- Control flow analysis and call graph extraction
- x86-16 to C lifter (CPU state struct approach)
- MSC overlay call resolution (INT 3Fh -> direct C function calls)
- Segment:offset -> flat memory translation
- Port I/O lifting (IN/OUT -> port_in8/port_out8 dispatch)
- Batch compilation output (split across .c files)
- Symbol table export (TOML format)
- Stub generation for unresolved symbols
- EXEPACK dump lifter (
lift_from_dump.py) — lifts functions from decompressed memory dump
Recompilation Results:
Functions: 482 resident/overlay + 190 dump-lifted = 672 total
Instructions: 106,935+ (resident/overlay)
Code bytes: 280,991 (274.4 KB) resident/overlay + dump-lifted code
Output: ~150K lines of C across 10 recomp files + dump_lifted + impl + stubs
Errors: 0
Phase 2 — DOS Compatibility Layer
- INT 21h replacement (file I/O: create/open/close/read/write/seek/delete)
- INT 21h memory management (alloc/free/resize paragraphs)
- INT 21h console I/O (char in/out, print string, input status)
- INT 21h system calls (date/time, DOS version, drive/directory, interrupt vectors)
- INT 10h Video BIOS (set mode, cursor, teletype, get mode)
- INT 16h Keyboard BIOS (read key, check key, shift flags)
- INT 33h Mouse Driver (reset, show/hide, position, range, handler)
- VGA Mode 13h framebuffer (320x200, 256 colors at A000:0000)
- VGA DAC palette emulation (ports 3C7/3C8/3C9 state machine)
- VGA input status register (port 3DA, vsync toggle)
- PIT timer emulation (ports 40h/43h, 18.2 Hz tick rate)
- Port I/O dispatch (VGA, PIT, PIC, keyboard ports)
- DOS path translation (game directory mapping)
- SDL2 platform layer (window, renderer, streaming texture)
- SDL2 event handling (keyboard scancode map, mouse, fullscreen toggle)
- SDL2 VGA rendering (indexed framebuffer -> RGBA palette conversion)
- MSC crt0 startup replacement (segment register initialization + data copy)
- Main entry point with frame-driven game loop
- Full project compiles and links (zero errors, zero warnings)
Phase 3 — Stub Resolution & Call Graph
- Traced MSC crt0 startup chain:
res_02A310->ovl05_031396(C main) ->ovl21_048200(game loop) - Discovered CIV.EXE has zero MZ relocations — MSC overlay manager patches segments at runtime
- Reverse-engineered segment relocation formula:
file_off = seg*16 + off - 0x14 - Far call resolution (CALL FAR seg:off -> known function): 1081+ calls resolved
- Stubs reduced from 553 -> 352 (36% reduction)
- Stub resolver tool (
resolve_stubs.py) — maps unresolved names to existing functions - Alias file (
civ_aliases.c) — 79 wrapper functions for overlay/resident name mismatches
Phase 4 — Call Stack & Runtime Fixes
- Call stack return address simulation (NEAR: push 0 + sp+=2, FAR: push CS + push 0 + sp+=4)
- INT 10h rewrite (text mode cursor, mode get/set, character output)
- Text mode VGA rendering (0xB8000 write-through, 80x25 cell display)
- VGA mode detection (port 3DA status register emulation)
- BIOS data area setup (cursor position at 0040:0050, tick counter at 0040:006C)
Phase 5 — EXEPACK & Overlay Runtime
- EXEPACK decompression implemented (both in C runtime and Python analysis tools)
- Segment relocation applied after decompression (LOAD_SEG = 0x0100)
- DGROUP/BSS/stack initialization matching original crt0
- INT 3F inline overlay calls scanned (148 found in resident code)
- Title screen bypass (ovl02_02C200) -> "New Game" path
- Timer read (far_0000_0A40) -> BIOS tick counter from wall clock
- MSC 5.x heap allocator rewritten (correct free-list walking)
- Game reads king.txt successfully (4 fopen/fread/fclose cycles)
- Overlay thunk table structure decoded: 7-byte entries at offset 0x0761
- Thunk dual-mode design: JMP FAR (bytes 0-4) + CALL NEAR dispatcher (byte +5)
- Overlay function discovery: 155 functions across 23 modules (prologue scan + INT 3F)
- Cross-overlay caller constraint analysis for thunk mapping
- Fixed far_0000_07DF infinite recursion (corrected alias to ovl05_0307DA)
- LOMEM false alarm fixed (ovl02_02C200 returns AX=0x6000 for memory check)
- VGA mode 13h activation working
- Complete thunk-to-overlay-function mapping (64 active EA entries -> 155 overlay functions)
- Remaining stub resolution
Phase 6 — World Generation & Game Handler
- Terrain seed placement (ovl07_034D88) working
- Terrain growth scan loop working
- Jump Table 1 (terrain type assignment, 8 climate cases) reconstructed from binary
- Jump Table 2 (terrain feature placement, 14 cases) reconstructed from binary
- Continent placement (ovl07_034A5C) working — finds ocean tiles correctly
- Terrain detail pass (ovl07_034E33) working
- World generation animation skipped (ovl07_035B6E bypass)
- Game handler reached (res_0022DA) — main game loop active
- Keyboard input polling (KBHIT via SDL2)
- Timer speed multiplier (20x) for faster animation playback
Phase 7 — EXEPACK Code Lifting & CRT
- Decompressed memory dump tool (startup.c dumps civ_decompressed.bin at runtime)
- lift_from_dump.py — lifts functions from decompressed dump for EXEPACK-compressed code
- 175 functions lifted from decompressed dump (display, map, CRT, game state, rendering)
- MSC 5.x CRT functions lifted (39 functions: _open, _read, _write, _lseek, file table mgmt)
- Display subsystem lifted (far_1DDE_* — 15 rendering/GFX context functions)
- Map display functions lifted (far_1B05_* — 25 map rendering functions)
- Game state functions lifted (far_15D8_* — 12 functions including main game state)
- Blit function implemented (far_0000_07ED — 8-arg rectangle copy between GFX pages)
- Climate/temperature stub (far_205A_2AC0 returns uniform climate for now)
- File access working (game opens and checks .pic, .cv, .exe files)
- First pixels rendered (nonzero framebuffer pixels detected in game loop)
- Near function lifting support added to lift_from_dump.py (NEAR_STUBS with is_far=False)
- Near-far alias pattern for conflicting functions (same code at same offset, different calling conventions)
- Resident rendering functions lifted: res_01C813, res_01C605, res_01D221 (NEAR)
- Pipeline improvements: recomp.py excludes dump-lifted funcs from stubs without affecting recomp output
- Thunk table deep analysis: 7-byte entries, overlay manager init at 0x0B60, descriptor patching
- World gen hang fixed — 6 bugs in ovl07_034412: 4 missing gotos, 2 broken jump tables
- Near-far alias pattern for conflicting functions
Phase 8 — World Gen Fix & Thunk Resolution
- World generation completes successfully (30-60 seconds depending on random seed)
- Fixed 4 missing
gotostatements (lifter convertedjmpto comments) - Fixed 2 broken indirect jump tables (CS:0x272 and CS:0x518)
- Removed ~20 lines of garbage code (jump table data decoded as x86 instructions)
- Created
patch_worldgen.pyfor automatic post-recomp patching - Auto-inject Space key to advance past "press any key" screens
Phase 9 — Thunk Resolution & Display
- Resolved 7 thunk table entries to overlay functions
- Lifted 16+ new functions from dump (display, CRT file I/O)
- Implemented
_aFchkstk(far stack check) and buffer write subroutines - Minimap rendering with page-flip animation working (10 BLIT operations)
- DELAY timing function active — game animates between frames
Phase 10 — File I/O Pipeline
- Hand-implemented fopen/fclose with MSC FILE struct setup
- Lifted file buffer fill function (
far_1FB6_0642) - Fixed 10 UNHANDLED indirect calls in PIC decoder (
call far [DS:E84A]) - Fixed
_dos_readto handle FILE* as well as raw DOS handles - Initialized CRT _lastiob and stack limit in startup
- PIC file loading working — sp299.pic and planet2.pic read successfully (512B chunks)
- 34 file open operations, 32 close operations in a single run
- Game progresses past civilization selection into new game setup
- FILE struct corruption fixed — moved FILE state to a host-side table,
fopenreturns an opaque token (0xF200 | slot*8) instead of an in-DS FILE struct
Phase 12 — Overlay Thunk Bugs & Terrain Reveal
- Fixed the civ-select infinite recursion —
far_0000_076Fwas wrongly aliased to its own callerovl02_02CDD7(the dialog), re-entering the whole dialog 24×/cell and exhausting the stack. It's a screen-grab→sprite-handle primitive; hand-implemented. planet2.pic opens dropped 32 → 0. - Reverse-engineered the overlay thunk-binding mechanism — the
0x0761vectors are runtime-patched from per-overlay descriptors (0x0B62via DOS4B03), so the naive "overlay functions in link order" alias map is unreliable; suspect thunks must be verified by contract. - Un-stubbed
ovl07_035B6E(terrain-reveal state machine) via the project lifter — fixed an infinite spin (CPU 98% → ~8%); the game now advances past the reveal into world-gen map writes.
Phase 13 — Rendering On Screen
- Diagnosed the black-screen pipeline (mode 13h OK;
platform_rendercorrect) - Implemented the string renderer
far_0000_07F4(was mis-aliased toovl05_0307DA$) \text{as} \text{an} 8 \times 8 \text{CP437} \text{text} \text{blit} — **\text{real} \text{game} \text{text} \text{now} \text{renders} \text{on} \text{screen}** (\text{verified}: $_kills: NONEin cyan viaPrintWindow) - Capture note: GDI
BitBltshows SDL's GPU window as black; usePrintWindow(PW_RENDERFULLCONTENT)or the env-gatedCIV_RENDERDIAGfb dump - Map tile / sprite blitter
far_0000_083F(stub; reached only past the menu) - DAC palette upload (text shows via the default palette for now)
Phase 14 — Boot Flow & MSC CRT Text I/O
- Found the real boot flow (logos/title/menu) was bypassed, not missing —
un-bypassing
ovl02_02C200runs the real intro (loadslogo.pic,birth0/1.pic,credits.txt) - Implemented the MSC 5.x CRT text-stream chain (
getcres_021BC8,ungetcfar_215A_16DA, width-checkres_021C22, skip-wsres_021BEC, scanf field readerres_02178A) against the host FILE table — the 79M-call credits-parse spin is gone;credits.txtnow parses - Fixed the bad-filename pointer bug — stale
civ_dump_lifted.cdouble-pushed CS for the MSCpush cs; call near <far-func>idiom, sofar_1F67_01ADreadcsinstead of the filename;king.txtnow opens cleanly - Implemented
res_02120A(MSC_getbuf) soking.txt's 512-byte FILE buffer is allocated and thegetcchain reads — the intro completes
Phase 15 — Color Rendering Pipeline (PIC → A0000 → palette)
- PIC LZW pixel decoder un-stubbed —
far_0000_11FAdelegated decode to stubs; correct implementations existed under the overlay-lifted twin names (res_001284/0012F6/00124E/001205); wired the delegations - Fixed PIC display routing —
far_0000_07E6(row blitter) was mis-aliased toovl05_02FFC2; hand-implemented as a proper DS:src → A0000 row copy - VGA palette loaded — Civ PICs are LBM-style chunked; the
M0(0x304D) chunk is the 768-byte 6-bit RGB palette. Parse it at PIC open and upload to the DAC → the intro renders in full colour (starfield, stars, red credits) - MCGA mode 13h presents A0000 (SDL keys off
mem[0x449]==0x13) - Screen-grab sprite pair (
far_0000_076F/083Fhost sprite store; title menu save/restore works)
Phase 16 — Real Main Menu, World-Gen Completion & Game Loop
- LOMEM false alarm — real root cause fixed.
far_0000_0768(the free-memory query that gates the*LOMEMwarning inres_001A66) was mis-aliased to the title screenovl02_02C200. That hack only worked while the title was stubbed (returned AX=0x6000); with the title un-bypassed it returned a small AX → an empty*LOMEMdialog blocked startup. Fixed to report ample memory → the real main menu now builds ("Start a New Game / Load / EARTH / Customize World / View Hall of Fame") - New Game selection works — the menu string is king.txt message-DB text
(
far_1F67_01ADhash lookup →0xC936); selecting New Game sets6AC2=0 - Terrain-reveal infinite spin fixed → world-gen completes.
far_1DDE_007C(==res_01DE5C, a signedclamp(v,lo,hi)) was a wrong "delay returns arg3" stub → set the reveal timer target to0x7FFF(~30 min) soovl07_035B6E's reveal loop spun forever. Implemented the real clamp → world-gen finishes - The game's main loop runs —
begin_frame/yield/timer/input cycling, mode 13h, palette210/224. Full flow works end-to-end: intro → menu → New Game → world-gen → game loop - Map tile rendering — the in-game map is a solid fill;
far_0000_083F(tile/ sprite blitter, ~64 callers) is still a stub - A Unicorn-engine harness (
tools/recomp/uni_civ.py, modeled on the bolo recomp'suni_*tools) boots the original CIV.EXE headless — through EXEPACK, the MSC crt0, the DOS memory manager, the INT 3Fh overlay manager and graphics- driver loads — all the way to the rendered title screen, for ground-truth observation (seedocs/UNI_HARNESS.md)
Phase 17 — Sprite-Sheet Decode & Civilization Select
- sp299.pic sprite-sheet LZW decode fixed. The post-New-Game sprite sheet
corrupted
DS:0x686C(the refill file token) → aread handle 0spin. Two bugs in the core LZW byte decoder (res_0012F6), found by disassembling the original (@dump 0x12F6, capstone): the KwKwK case walked the not-yet-defined dict entry (dx) instead of the previous code ([0x688A]) → a self-referential dictionary chain whose unbounded walk overran the decode stack (base0x6A8D, grows down) into the state region and0x686C; and theprev_codesave wrotecodeinstead ofcx. Both fixed → the decode terminates cleanly - Civilization / difficulty-select screen reached. With the decode fixed, the
game grabs the 41×58 leader-portrait sprites from the sheet, loads
arch.pic(throne room) +back0a.pal/sp256.pal, and builds the*ARCHselect screen - PIC LZW decoder now pixel-perfect on large images. A third decoder bug
surfaced via the title
logo.pic(clean top, garbage lower half): the dictionary-full reset wrongly called the full re-init (0x124E, which reads a fresh stream word + reseeds the bit buffer) instead of the dict-only reset (0x1262). That consumed an extra stream word mid-decode and desynced the bitstream after the first dictionary overflow — corrupting every image large enough to fill the 0x800-entry dictionary (logo / birth / title / arch). Fixed →logo.picdecodes the full "Sid Meier's CIVILIZATION" wordmark cleanly - Deterministic New-Game repro via
CIV_KEYSCRIPT=<chars>(scripted getkey/ kbhit) —CIV_KEYSCRIPT=Nreliably drives New Game → world-gen → sprite decode - Drive the civ-select screen → the real in-game loop (
res_0023F0) - Map tile rendering (
far_0000_083F)
Phase 17.5 — Gameplay
- Title screen + main menu (New Game / Load / Earth / Custom)
- Map tile rendering
- UI chrome rendering
- City management / diplomacy / combat / tech tree / wonders
- Save/load game state
- Hall of Fame
Phase 18 — Audio & Polish
- .CVL sound data loader
- SDL2 audio output (AdLib OPL2 synthesis or PCM playback)
- Integer scaling (1x, 2x, 3x, 4x)
- Windowed / fullscreen toggle
- Modern input improvements (scroll wheel for zoom, etc.)
- Windows 11 installer / portable build
Game Data — User Supplied
You must own a legitimate copy of Civilization. Place the game files in a game/
subdirectory (gitignored). The recompiled executable loads data from this directory
at runtime.
Required files:
game/
├── civ.exe # Original executable (for reference/verification)
├── *.pic # All image files
├── *.pal # All palette files
├── *.cvl # Sound data
├── fonts.cv # Font data
├── *.txt # Game text files
├── fame.dta # Hall of Fame
└── civil0.map # Default map
Technical Notes
Why Microsoft C 5.x?
MicroProse was a Microsoft C shop in the late 80s/early 90s. The runtime signature
MS Run-Time Library - Copyright (c) 1988, Microsoft Corp confirms MSC 5.x, which
was the standard professional C compiler for DOS development at the time. This is
consistent with other MicroProse titles of the era.
The Overlay Manager
With only 640 KB of conventional memory, a ~298 KB game needed help. Microsoft C's
overlay manager uses INT 3Fh as a software interrupt to demand-load code segments
from disk. When the resident code calls an overlaid function, the overlay manager:
- Intercepts the
INT 3Fhcall - Reads the overlay number and offset from the instruction stream
- Loads the overlay module from the EXE file into memory
- Transfers control to the target function
For recompilation, this is actually a gift — every INT 3Fh call site is an explicit
inter-module function call with a known target. We resolve these statically at recomp
time into direct C function calls, eliminating the overlay manager entirely.
The Graphics Drivers
Civilization ships with separate executables for different graphics hardware:
egraphic.exe— EGA (640x350, 16 colors or 320x200, 16 colors)mgraphic.exe— MCGA/VGA (320x200, 256 colors)tgraphic.exe— Tandy 1000 (320x200, 16 colors)
The main civ.exe calls out to these as external processes for graphics initialization
and rendering. For the recomp, we implement the VGA (256-color) path directly.
Credits
Original Game
- Designed by Sid Meier with Bruce Shelley
- Programming by Sid Meier
- Computer Graphics by Larry Coones, Michael Haire, Harry Teasley, Barbara Bents, Todd Brizzi, Erroll Roberts, Chris Soares, Nicholas Rusko-Berger, Stacey Clark, Brian Martel
- Original Music by Jeffery L. Briggs
- Quality Assurance by Al Roireau, Jerry Shaffirio, Mike Corcoran, Tim Train, Michael Rea, Chris Clark, Michael Craighead, Nick Yuran, Paul Murphy
- Published by MicroProse Software (1991)
This Project
A sp00nznet fan preservation project. Built with love, respect, and far too many turns.
Legal
This is an educational and preservation project. No original game code or assets are distributed in this repository. Users must supply their own legally obtained copy of Sid Meier's Civilization.
Civilization is a trademark of Take-Two Interactive Software, Inc. / Firaxis Games. This project is not affiliated with, endorsed by, or connected to Take-Two Interactive, Firaxis Games, or the estate of MicroProse Software in any way.
"Just one more turn..."