Skip to content

Scenario terrain data

Formats

Changed in 0.2.0

Stores a scenario's terrain cells in the Base64-encoded IsoMapPack sections.

Format
Kind
Configuration file
Filename
*.MAP, *.MPR

Scenario map files are INI files, but their terrain cells are stored as binary data. The data is Base64-encoded and split across the assignments of an IsoMapPack section. Each revision of the format has its own section, from [IsoMapPack] to [IsoMapPack5].

The loader decodes the assignment values in section order and ignores their keys. Keep each value to 127 characters or fewer. A longer value is cut short, which corrupts the data.

The loader reads all five sections in revision order and applies every one that is present, so a later revision can overwrite cells that an earlier one set. A missing section changes nothing.

A damaged [IsoMapPack4] or [IsoMapPack5] section stops the load. The game shows an error message, and the debug log names the section. A map loaded after this failure still uses its own theater’s resources. Damage in an older revision does not stop the load.

SectionCompressionCell data
[IsoMapPack]LCWTile type, sub-tile and height for the original 128 by 128 cell grid
[IsoMapPack2]LCWCell records, ending with a 0,0 coordinate
[IsoMapPack3]NoneCell records, ending with a 0,0 coordinate
[IsoMapPack4]LZOCell records, ending with a 0,0 coordinate
[IsoMapPack5]LZOCell records with the cell’s ice-growth flag, ending with a 0,0 coordinate

[IsoMapPack] stores no coordinates. It holds three runs of 16,384 entries, one entry per cell of the 128 by 128 grid, in rows of increasing Y with X increasing within each row. The first run holds every cell’s tile type in 2 bytes, the second every sub-tile in 1 byte, and the third every height in 1 byte.

The later revisions store a list of cell records, only for the cells they set. Each record holds these fields, in order, with multi-byte values little-endian:

FieldSize
X coordinate2 bytes
Y coordinate2 bytes
Tile type4 bytes
Sub-tile1 byte
Height1 byte, signed
Ice-growth flag1 byte, [IsoMapPack5] only

The list ends with an X and Y of 0 and no further fields, so cell 0,0 cannot have a record. A record for a cell outside the map is skipped.

Section size limits count decoded bytes: a section’s bytes after Base64 decoding and before decompression. [IsoMapPack5] accepts up to 5,784,964 decoded bytes, enough for a record for every cell of the 512 by 512 grid written in 8 KiB blocks. A larger section is damaged. The other four sections are read up to 512,000 decoded bytes, and anything past that is dropped. An [IsoMapPack4] section cut before its terminator this way is damaged.

[IsoMapPack4] and [IsoMapPack5] compress the record list with LZO in blocks. Each block starts with two 16-bit counts, the compressed size and then the uncompressed size, followed by the compressed bytes. Write blocks of at most 8 KiB of records. The size limit above assumes that block size, and a block that expands past 16 KiB is damaged.

An LZO section is damaged when any of these holds:

  • A block does not decompress, or expands to a size other than its header states.
  • The section ends partway through a block header or a block’s compressed bytes.
  • The records end before the 0,0 terminator, even when every block present decompresses.

[IsoMapPack] and [IsoMapPack2] use LCW blocks with the same two-count header. Each block expands to at most 8 KiB and takes at most 10,308 compressed bytes. The read ends at a block that breaks either limit, has a count of zero, or runs out of bytes.

When an [IsoMapPack], [IsoMapPack2] or [IsoMapPack3] read ends early, the load continues. Cells the read did not reach keep the terrain they had, except for these cells, which become clear ground:

  • In [IsoMapPack], every cell whose tile type was not reached.
  • In [IsoMapPack2] or [IsoMapPack3], a cell whose record was cut off between its coordinates and its tile type.

[OverlayPack] and [OverlayDataPack] store each cell’s overlay type and overlay frame for the whole 512 by 512 cell grid. Each holds one byte per cell, in rows of increasing Y with X increasing within each row, compressed in LCW blocks and Base64-encoded as [IsoMapPack] is. In [OverlayPack], 255 means no overlay.

The loader reads both sections only when NewINIFormat is above 1, and ignores the bytes for cells outside the playfield. It reads [OverlayPack] up to 512,000 decoded bytes and [OverlayDataPack] up to 256,000, and drops anything past that.

Source files

Linked at revision 51b52aa38392.

History

  1. Changed0.1.0

    Size IsoMapPack5 decoding from its terrain payload

  2. Changed0.2.0In development

    Refuse a scenario whose terrain data is damaged