The Caesar II savegame format
A Caesar II save is the plainest format in the whole series once you have the source: the recovered savegame() function writes about 430 registered fields in order, then appends a sibling file whole. Nothing is inferred from a hex dump — every offset below follows directly from the recovered table.
Used by Caesar II
savegame() and loadgame() in the recovered source read and write two things, in sequence. First, a 500-slot table of registered game-state blocks — some a single byte, most a 4-byte counter, a handful multi-kilobyte arrays — terminated by the first zero-size entry, which the write loop treats as the end. Second, the complete contents of a sibling history.dat file, exactly 4,000 bytes, copied in with one read() and one write() and never touched by the entry table at all.
Of the 500 declared slots, 432 carry real data; the rest are zero-size padding the loop never reaches. Those 432 add up to exactly 221,745 bytes. Add the 4,000-byte history tail and every Caesar II save is 225,745 bytes — confirmed by the port's own round-trip tests against the real engine, not measured off a sample of files.
The largest blocks, in file order
Offsets are cumulative, exactly as the registration table declares them. Scalars in between are omitted here — roughly 380 of them, mostly 4-byte counters and rates named for what they track (denarii, population, ind_tax_rate…) — the full list is in loadsave.c, linked above.
| Offset | Size | Type | Field | Description |
|---|---|---|---|---|
| 0 | 16 | — | view state | Map mode, overlay mode, zoom level (written twice), map scroll direction and position. |
| 16 | 4550 | army_rec[] | army_list | Every field army. |
| 4566 | 11658 | citizen_rec[] | citizen_list | Every citizen record. |
| 16224 | 3978 | unit_rec[] | unit_list | Military units. |
| 20202 | 17688 | figure_rec[] | figure_list | Every animated figure on the map — walkers, soldiers, wildlife. The most heavily annotated struct in the reconstruction: every field is cross-referenced against the functions that read it. |
| 37890 | 9045 | arrow_rec[] | arrow_list | Projectiles and thrown weapons in flight. |
| 46935 | 3460 | army_route_rec[] | army_routes | Pathing state for field armies. |
| 50395 | 128000 | uint8[] | city_map | 80×80 tiles, 20 bytes each. Independently confirmed: entities.h's CITY_W × CITY_H × CITY_CELL_BYTES macros multiply to exactly this figure. |
| 178395 | 28800 | uint8[] | region_map | 60×60 tiles, 8 bytes each. Same cross-check as city_map. |
| 208338 | 10816 | uint8[] | battle_map | 52×52 tiles, 4 bytes each. Same cross-check again. |
| 219792 | 768 | industry_rec[] | industry | Per-province industry state. |
| 221205 | 200 | — | empire_won | Province conquest flags. |
| 221745 | 4000 | — | history.dat tail | The complete contents of the separate history.dat file, copied in unmodified — not part of the registered entry table, and always exactly 4,000 bytes. |