The WAN file format is used in Pokémon Mystery Dungeon: Explorers of Time/Darkness/Sky to store animated character sprites along with map props, and even some UI elements.
This format is always wrapped by a SIR0 container, and it doesn't possess its own magic number. However, it does have its own header and structure. Its one of the most complex formats used in the game.
It can have a different file extension, depending on the type of sprite it contains. So far, WAN and WAT are both suffixes used for WAN sprites.
The file is read from bottom to the top. This is likely because of the way the content of the file is organized, and how the files are meant to be loaded into memory and used as data structures right away.
The content of the file is split in 5 categories.
The meta-frames are basically the virtual image that the animations are referring to. They're essentially an abstraction layer above the actual images, and contain data about these ranging from which image in the image pointer table a meta-frame refers to, the actual image's resolution, whether the image should be flipped vertically or horizontally, and even more.
Meta-frames can be "grouped" together in a sequence, with the last meta-frame in a group being indicated by as special bit flag. This allows the game to combine several small images together, to assemble a bigger one. The Offsets stored in the meta-frame allow positioning the images to properly assemble them. The animations refer to each meta frame, even single ones, as a meta-frame group, via index. The location of the first meta-frame of a group is stored in the Meta-Frame Groups Reference Table.
The actual images are stored as pixel strips, followed with an assembly table. The table contains a list of entries indicating how to rebuild the image. The main reason the images are stored that way seems to be to remove needless zeroes that normally make the bulk of most images. The table indicates in what order to insert either a pixel strip of a certain length, or to insert the specified amount of zeroes. All the lengths of the strips of pixels, or the amount of zero to insert is always divisible by 16.
The format of the image data can be either 4 bpp or 8bpp, as indicated in the WAN Header.
Each animation is made up of 3 things, a group, some sequences, and some frames.
The groups itself is the "handle" of the animation. You can label them with an action, like "Run" for example. For character sprites(non-character sprites or special sprites follow different rules), each groups has 8 slots, each slot refers to a sequence. One for each of the 8 directions of movement. Groups may refer to the same sequence in all their slots.
In character sprites, specific groups across all sprites/characters of the same type, have all the same use. For example, all character sprites' first group in the list is always the running animation!
Each sequence is a list of animation frames one after the other, terminated with a null frame. Each frames contains a display duration, the index of the meta-frame group to be displayed, an offset to move slightly the image relative to the logical center of the sprite, and an offset for the shadow blob displayed under the character.
Not much is known about those. They're a very long list of 16 bits signed integers, meant to be read 2 by 2. They indicate the offset to display particles, like sweat drops, along with exclamation marks and etc..
For now, its unknown how the game knows which is the correct one to pick for what.
This contains the palette used by all the images in the sprite. It also contains details as to where to store the palette in video memory.
Still not much is known about how exactly it all works, besides the actual color palette.
Here's an overview of how a WAN file is laid out.
|0x00||16||SIR0 Header||The SIR0 container's header. The first pointer points to the WAN Header. The second to the SIR0 Encoded Pointer Offsets List.|
|0x10||Varies||Meta-Frame Groups Block||This contains all the meta-frames groups.|
|After Meta-Frame Groups Block||Varies||Animation Sequences Block||Contains all the animation sequences, and the frames that makes them up.|
|After Animation Sequences Block||Varies||0xAA Padding Bytes (If needed)||Some padding to align the next block on an offset divisible by 4.|
|After Padding Bytes||Varies||Image Data Block||Contains all the image data.|
|After Image Data Block||Varies||Color Data Block||Contains the palette, along with some other color information.|
|After Color Data Block||Varies||Meta-Frames Reference Table||A list of 4 bytes pointers, containing the offset of the first meta-frame of every meta-frame groups located inside the Meta-Frame Groups Block.|
|After Meta-Frames Reference Table||Varies||Particle Offset Table||A list of made of pairs of 16 bits signed integers indicating offsets to display particle effects at.|
|After Particle Offset Table||Varies||Animation Groups' Sequences Reference Table||Several lists of 4 bytes pointers to animation sequences inside the Animation Sequences Block. Each list is pointed to by an entry in the Animation Groups Table.|
|After Animation Groups' Sequences Reference Table||Varies||Animation Groups Table||A list made up of a pair of 32 bits integers, one a pointer to a list of sequence in Animation Groups' Sequences Reference Table, the other a number indicating the length of that list.|
|After Animation Groups Table||Varies||Image Data Pointer Table||A list of 4 bytes pointers to the assembly table of every images in the Image Data Block.|
|After Image Data Pointer Table||Varies||Animation Info Structure||Contains info on, and pointers to the animation data.|
|After Animation Info Structure||Varies||Image Info Structure||Contains info on, and pointers to the Image Data Pointer Table, and Color Data Block.|
|After Image Info Structure||Varies||WAN Header||Contains 2 pointers to the the 2 structures above, along with a boolean indicating whether this is a prop, or an 8 way animated sprite.|
|After WAN Header||Varies||0xAA Padding Bytes (If needed)||Some padding bytes to make sure the next block starts on an offset divisible by 16.|
|After Padding Bytes||Varies||SIR0 Encoded Pointer Offsets List||A compressed list of every pointer pointer offsets in the file. Used to translate file-relative pointers to NDS memory relative pointers.|
|After SIR0 Encoded Pointer Offsets List||Varies||0xAA End Of File Padding Bytes (If needed)||Some padding bytes to make sure the file ends on an offset divisible by 16.|
The header is made up of 3 parts.
The first part is just a little chunk of 12 bytes with two pointers to the 2 main parts of the header. It also contains a boolean that indicates whether the sprite follows the same format as character sprites or not.
The animation info block contains various information related to how to animate the sprite, and where the various required elements to animate the sprite are located in the file.
The image data info block contains details on the format of the image data stored in the file, along with the color data that all images in this sprite uses.
|0x0||4||little||uint32||Ptr to Anim Info||A 4 bytes pointer to the part of the WAN header containing data on the sprite's animations.|
|0x4||4||little||uint32||Ptr to Image Data Info||A 4 bytes pointer to the part of the WAN header containing data on the sprite's images data.|
|0x8||2||little||uint16||Sprite Type||A 2 bytes integer value to indicate what kind of sprite this is. Known values are 0,1,3. Or Props/UI, Characters, and Unknonw, respectively.|
|0xA||2||little||uint16||Unknown #12||Unknown purpose. Referred to as Unknown #12 for now.|
|0x0||4||little||uint32||Pointer to Meta-Frames Reference Table||A 4 bytes pointer to the Meta-Frames Reference Table.|
|0x4||4||little||uint32||Pointer to Particle Offset Table||A 4 bytes pointer to the Particle Offset Table. This can be a null pointer, only for type 0 sprites! (UI sprites, and props) If a type 1(character sprite) sprite has no particle offsets, the pointer's value points to the end of the Meta-frame table.|
|0x8||4||little||uint32||Pointer to Animation Groups Table||A 4 bytes pointer to the Animation Groups Table.|
|0xA||2||little||uint16||Amount of animation groups||The amount of animation groups in the Animation Groups Table.|
|0xC||2||little||uint16||Unknown #6||(Uncertain)Possibly the amount of blocks(groups of 4 tiles, possibly ?) allocated for the image in video memory.|
|0xE||2||little||uint16||Unknown #7||Unknonw purpose.|
|0x10||2||little||uint16||Unknown #8||Unknonw purpose.|
|0x12||2||little||uint16||Unknown #9||Unknonw purpose.|
|0x14||2||little||uint16||Unknown #10||Unknonw purpose.|
Image Data Info
|0x0||4||little||uint32||Pointer to Image Data Pointer Table||A 4 bytes pointer to the Image Data Pointer Table.|
|0x4||4||little||uint32||Pointer to Color Data Block||A 4 bytes pointer to the Color Data Block.|
|0x8||2||little||uint16||Unknown #13||(uncertain) If 1, load the first row of tiles of each images one after the other, the the second, and so on. Seems to be for very large animated sprites!|
|0xA||2||little||uint16||Is 256 colors 8bpp||A boolean value indicating whether the sprite's images should be written to video memory as 8bpp, 256 colors images. If its 0, the images are written to memory as 4bpp, 16 colors. The game can write a 4bpp image as a 8bpp to video memory properly, but the palette needs to be moved to the extended palette area, possibly by messing around with other values. Another value in the color info block needs to be set for any of this to work properly!|
|0xC||2||little||uint16||Unknow #11||(Uncertain) Seems to move the palette around palette slots in the video memory.|
|0xE||2||little||uint16||Amount of images||The number of images in the Image Data Pointer Table.|
Image Data Pointer Table
This is a very simple list of 4 bytes pointers to the assembly table of every image in the file. The amount of pointer in this table is specified in the Image Data Info block.
Animation Groups Table
A list of entries, each representing an animation group or "action". For characters, this table is usually 13 entries long, for hero/partner characters, it is at least 35 entries long. For non-character sprites, the length varies.
Each entry is 8 bytes long, and made up of 2 values. The first is a 4 bytes pointer to the beginning of the list of sequence slots for this particular group in the Animation Groups' Sequences Reference Table. The Second value is a 4 bytes unsigned integer indicating the number of slots in the list, pointed to by the first value, for this particular group.
Entries may be completely null, and if that's the case, there must be a corresponding null pointer in the Animation Groups' Sequences Reference Table.
For example here's a typical group table( converted to big endian, as 4 bytes values, and displayed 1 entry per line! ):
0x00004AEC, 0x00000008, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00004B20, 0x00000008, 0x00004B40, 0x00000008, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00004B70, 0x00000008,
And the corresponding sequence table( laid out to better where are the sequence lists for each of the groups in the group table above starts and ends ):
0x000002D6, 0x00000312, 0x0000034E, 0x0000038A, 0x000003C6, 0x00000402, 0x0000043E, 0x0000047A, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x000004B6, 0x000004DA, 0x000004FE, 0x00000522, 0x00000546, 0x0000056A, 0x0000058E, 0x000005B2, 0x000005D6, 0x000005FA, 0x0000061E, 0x00000642, 0x00000666, 0x0000068A, 0x000006AE, 0x000006D2, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x000006F6, 0x0000076E, 0x000007E6, 0x0000085E, 0x000008D6, 0x0000094E, 0x000009C6, 0x00000A3E,
Notice how each null groups in the group table has a single corresponding null pointer in the sequence table below.
Animation Groups' Sequences Reference Table
As mentioned above this is simply a list containing pointers to animation sequences. Each entries can be though of as a slot assigned to one of the groups in the animation group table. The length of this table is determined by adding up the amount of animation sequence slots for each entries in the animation groups table. Taking care to count completely null groups as 1!
Particle Offset Table
Not much is known about this part. It can be completely omitted in non-character sprites.
It basically contains coordinates, offsets from the center of the sprite where to display particle effects. Things like sweat drops, exclamation marks, or battle effects. The length of this block varies indiscriminately from pokemon to pokemon. Hero/Partner pokemon have more entries than other pokemon.
Its unknown how the game finds what coordinate to use for what. It might be stored in another location in the game's file system.
Meta-Frames Groups Reference Table
This is another very simple pointer list, pointing to the first meta-frame of every meta-frame groups in the file.
Color Data Block
Image Data Block
Animation Sequences Block
Meta-Frame Groups Block
- Thanks to TruePikachu for finding out the link between the various parts of the file format!
Edited by evandixon