MPD format

The MPD format is used to describe map data.

A note on convention: the coordinate system in this article treats positive x as east, positive y as down (that is, "forward"), and positive z as north, if you're looking at the map from above. This makes it a left-hand coordinate system.

Header
struct header { u16 n_chunks;    // #chunks in map file u16 n_actors;    // #actors in map file u16 unknown; u8 padding[10]; };

Chunk
The header is followed by n_chunks chunks. Each "chunk" is fixed-size, and contains map tiles, objects and event tiles. All map tile data is stored outside the chunks section, whereas objects and event tiles are stored within it (and thus there's a limit to the number of objects/events in a chunk).

struct chunk { struct chunk_header           header; struct chunk_object_entry     objects[32]; struct chunk_event_tile_entry event_tiles[16]; struct map_tile               weird_special_tile; };

Header
struct chunk_header { f32 map_offset_x; // (val - 6)/12 f32 unk1_1; f32 map_offset_z; // (val - 6)/12 f32 unk1_2; f32 unk1[7]; u16 n_tiles;     // #tiles within chunk u8 unk2, unk3; u16 index;       // index of chunk (starts at 0) u8 unk4[14]; };

The map_offset_x and map_offset_z fields warrant some explanation: the map editor allows you to shift the whole map around, and instead of updating all tiles individually, these chunk-wide settings get changed. Actors' coordinates are updated, and are not affected by this offset. Whenever tiles get read, a tile that has stored location (x, z) effectively ends up at (x + map_offset_x, z + map_offset_z) instead. Why are they floats, you say? No idea.

Object table
Each chunk fits up to 32 objects (padded with null bytes if there's fewer).

struct chunk_object_entry { i16 unk1, unk2, unk3, unk4, unk5; i16 unk6, unk7, unk8, unk9, unk10; u8 unk11, unk12, unk13, unk14, unk15, unk16; u8 pad[10]; };

Event tile table
Each chunk fits up to 16 event tiles (padded with null bytes if there's fewer).

struct chunk_event_tile_entry { i8 x, z;  u8  index; u8 pad1; };

Tile data
The number of tiles in the tile data section is the sum of n_tiles for all chunks. Presumably the tiles are assigned to chunks in the order they appear, so the first chunk[0].header.n_tiles tiles belong to chunk 0, etc.

struct texdata { u8 u, v; u8 unk[6];        // TBD };

struct map_tile { struct texdata textures[12]; // N, W, S, E, Top; same repeated with unknown meaning (repeated texture?); 2 unknown textures i8 corners[4];   // Height in each corner of the tile, negative = up; (SW, SE, NW, NE) (needs verification!) i8 corners2[4];  // \ Related to bottom corners of tile, somehow. All zero except for "floating platforms" (e.g. mp1302) i8 corners3[4];  // / u8 unk2[4];      // TBD u8 unk3; i8 x, z;  u8  unk4, unk5, unk6, unk7; u8 mobility;     // 0 = Unlimited, 1 = Fly only, 2 = Impassable u8 geo_color; u8 geo_mark;     // 0 = No geopanel, 100 = Has geopanel u8 pad2[6]; };

Actor data
The number of actors is given by n_actors in the file header.

struct map_actor { u16 id;         // Class ID  u16 level; u8 unk2; i8 x, z;  i8  rotation;    // -1 = W, 0 = N, 1 = E, 2 = S  u8  unk4; u8 ai;          // ? verify u8 unk5, unk6; u16 items[4]; u8 appearance;  // 0 = Appear Normal, 1 = Absent 2nd, 2 = Appear 2nd u8 unk7; u16 geo_effect; // Only(?) used for geosymbols, val%10 = color, val/10 = effect u16 unk8; u16 magic[4]; i8 unk[30];     // TBD };