Difference between revisions of "MPD format"

From Netherworld Research
Jump to: navigation, search
(Fix coordinate system (duh...), add first stab at texture data)
m (Tile data)
 
(6 intermediate revisions by the same user not shown)
Line 28: Line 28:
 
<pre>
 
<pre>
 
struct chunk_header {
 
struct chunk_header {
   u8  unk1[24];
+
   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
 
   u16 n_tiles;      // #tiles within chunk
 
   u8  unk2, unk3;
 
   u8  unk2, unk3;
Line 35: Line 39:
 
};
 
};
 
</pre>
 
</pre>
 +
 +
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 ===
 
=== Object table ===
Line 60: Line 66:
  
 
== Tile data ==
 
== 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'' chunks belong to chunk 0, etc.
+
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.
  
 
<pre>
 
<pre>
Line 69: Line 75:
  
 
struct map_tile {
 
struct map_tile {
   struct texdata textures[5];   // N, W, S, E, Top
+
   struct texdata textures[12]; // N, W, S, E, Top; same repeated with unknown meaning (repeated texture?); 2 unknown textures
  struct texdata textures2[5]; // Same order, unknown meaning (maybe repeated texture)
+
   i8  corners[4];  // Height in each corner of the tile, negative = up; (SW, SE, NW, NE) (needs verification!)
  u8  unk1[0x10];   // TBD
+
  i8  corners2[4];  // \ Related to bottom corners of tile, somehow. All zero except for "floating platforms" (e.g. mp1302)
   i8  corners[4];  // Height in each corner of the tile, negative = up; (NE, SE, NW, SW)
+
  i8  corners3[4];  // /
   u8  unk2[0x0C];   // TBD
+
   u8  unk2[4];     // TBD
 
   u8  unk3;
 
   u8  unk3;
 
   i8  x, z;
 
   i8  x, z;
Line 100: Line 106:
 
   u8  appearance;  // 0 = Appear Normal, 1 = Absent 2nd, 2 = Appear 2nd
 
   u8  appearance;  // 0 = Appear Normal, 1 = Absent 2nd, 2 = Appear 2nd
 
   u8  unk7;
 
   u8  unk7;
   u16 geo_effect;  // Only used for geosymbols, val%10 = color, val/10 = effect
+
   u16 geo_effect;  // Only(?) used for geosymbols, val%10 = color, val/10 = effect
 
   u16 unk8;
 
   u16 unk8;
 
   u16 magic[4];
 
   u16 magic[4];

Latest revision as of 16:24, 8 September 2016

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
};