The Zeus saved-game container
A Zeus save is a table of arrays copied out of the running game. A manifest says where each array lives, how big its elements are and how many there are, and the blocks follow in order. This page comes from a third-party patcher that reads and rewrites saves and checks every rewrite by reading it back, so the container is solid. The records inside are barely mapped.
Used by Zeus
One part, or several
A save is one part. An adventure save holds one part per episode, written back to back, because the next episode needs the state of the last. Every part has the same layout: 8 bytes of version fields, then a manifest of 300 entries of 20 bytes each, then the data blocks.
The blocks begin at entry 3 and run in index order until the first entry whose element size is 0. Entries 0 to 2 have no block in the file as the patcher reads it. A reader finds later parts by looking for the same 8 version bytes again after the previous part ends.
Part header
All integers are little-endian.
| Offset | Size | Type | Field | Description |
|---|---|---|---|---|
| 0 | 8 | 2 x uint32 | versions | Two version fields. Their values are not established here; the patcher only compares them between parts. |
| 8 | 6000 | entry[300] | manifest | Three hundred entries of 20 bytes, laid out below. |
| 6008 | - | - | blocks | One block per entry from 3 up to the first entry of size 0. |
Manifest entry
Twenty bytes. The manifest mirrors the executable's own save table, a list of 139 entries of the same size at 0x63C2D0 in Zeus.exe 2.1.4.0.
| Offset | Size | Type | Field | Description |
|---|---|---|---|---|
| 0 | 4 | uint32 | compressed | Non-zero if the block has a 4-byte size prefix and may be compressed. |
| 4 | 4 | uint32 | address | The array's address in the running game, written as it was. On load the game compares only the element size and the count, so a save from a different exe layout still loads. |
| 8 | 4 | uint32 | element size | Bytes per element. |
| 12 | 4 | uint32 | count | Number of elements. The block holds element size times count bytes once decompressed. |
| 16 | 4 | uint32 | ptr | Purpose not established. |
Blocks and compression
A block with the compressed flag set starts with a signed 32-bit number. If it is positive it is the size of the compressed data that follows, and the data is PKWARE Data Compression Library output: the binary form, with a dictionary of 4, 5 or 6 bits. If it is negative the data that follows is stored raw at full size, which is what a writer does when compression would not make the block smaller. A block without the flag has no prefix and is raw.
This is the same PKWARE DCL that Caesar III's saves use, so the warning on that format's page applies here too: a zlib call on this data fails.
The entries that are identified
Element size by count, as the manifest of an unpatched save reports them. The record offsets are inside the element.
- Entry 28 - walkers
- 388 bytes by 2000. Offset 14 is non-zero while the walker exists. Offset 58 is a 16-bit index into the paths.
- Entry 29 - path owners
- 2 bytes by 1000. One 16-bit value per path.
- Entry 30 - paths
- 1 byte by 500,000. The game keeps 500 bytes for each of 1000 paths; the manifest counts them as single bytes.
- Entry 31 - army companies
- 156 bytes by 100. A free slot is all zeros; a used one has at least one non-zero byte.
- Entry 35 - buildings
- 280 bytes by 4000. Offset 0 is non-zero while the building exists.
- Entry 73 - building list
- 2 bytes by 4000. A 16-bit value per slot.
Saves from a patched executable
The Zeus Limit Patcher doubles the table sizes in Zeus.exe, and a save written by the patched game doubles the counts above to 4000, 2000, 8000 and 200, with new addresses (walkers move from 0xDBD788 to 0x1615E8C, buildings from 0x92E658 to 0x1886010). The original game can open a save from a patched one only by crashing. A patched game opens saves from either. The same project's save tool converts in both directions, and refuses to shrink a save that really uses the extra room.
A related container: MAPS
Used for scenario and world-map data. The same code reads and rewrites it.
- Header
- The four letters MAPS, then two uint32 version fields. The second is 33; the first has been seen between 227 and 321.
- Manifest
- The same 300 entries of 20 bytes, starting at offset 12. Blocks begin at entry 4 and stop at the first entry of size 0.
- World map elements - block 17
- 200 elements of 40 or 72 bytes. A byte at offset 0 is the variant, 0 meaning unused, and two uint16 at offsets 4 and 6 are the x and y position on the world map.
- World map routes - block 18
- 232 routes of 324 bytes. Points of 6 bytes each (x, y and a third value of unknown purpose) start at offset 8. The point count is the byte at offset 321 and a flag at 322 says the route exists.
- World map picture
- The world-map art is 838 by 738 pixels, and the coordinates above are in its space. The maps are named Zeus_MapOfGreece01 to 10 and Poseidon_map01 to 04.