PAK Format (The Learning Company)
Format type | Tileset |
---|---|
Hardware | EGA |
Max tile count | 4294967295 (but limited by their offset index table using UINT16LE values) |
Palette | Shared |
Tile names? | No |
Minimum tile size (pixels) | 2×1 |
Maximum tile size (pixels) | 126×65535 |
Plane count | 1 |
Plane arrangement | Linear |
Transparent pixels? | Palette-based |
Hitmap pixels? | No |
Metadata? | X and Y offsets, some other unidentified data. |
Supports sub-tilesets? | No |
Compressed tiles? | Yes |
Hidden data? | Yes |
Games |
The PAK Format is the sprite format used in Treasure Mountain. It contains multiple 16-color sprites, along with some metadata used by the game.
File format
The file begins with the following structure:
Offset | Data type | Name | Description |
---|---|---|---|
0x00 | UINT32LE | ImageCount | Number of images in the file |
0x04 | UINT16LE | Unknown1 | Always 0x3E. Might be a fixed identifying value. |
0x06 | UINT16LE | Unknown2 | Always 0x3A. Might be a fixed identifying value. |
0x08 | UINT16LE[imageCount] | offsets | Array containing the offsets of all images. |
The offsets array is an index of UINT16LE values, each one pointing to the next image, so it contains imageCount items. The values in the array must be multiplied by 16 to get the actual image offset. The offsets are relative to the start of the file. With this format, the file can address image offsets up to index 0xFFFF0, or 1048560 decimal. Roughly speaking, this means these files can be up to about a megabyte in size.
Since all offsets are multiples of 16, there is generally open space between the header and the actual image offsets, and between the data of the different images. This space is filled with 0xFF values as padding.
The image data starts after this header, at the next multiple of 16 bytes.
Since this format has an index, extra space could be left between the images to store hidden data.
Image chunk
The data at the given offset starts with a header of in the following format:
Offset | Data type | Name | Description |
---|---|---|---|
0x00 | UINT16LE | Unknown0 | Always 0x0000 |
0x02 | UINT16LE | Width | Image width, in bytes |
0x04 | UINT16LE | Height | Image height in bytes |
0x06 | INT16LE | X-origin | X origin of image, in bytes. |
0x08 | INT16LE | Y-origin | Y origin of image |
0x0A | UINT16LE | Unknown1 | Seems to be bit flags; usually 0, 1, 4 or 8, but 5 is also used. |
0x0C | UINT16LE | Unknown2 | Possibly related to grouping animations together; clearing this caused animations to go out of sequence and use unrelated frames. Generally values around 120-150 |
0x0E | UINT16LE | Unknown3 | Almost always identical to Unknown2. |
This header is followed by the image data.
The exact usage of the X and Y origin seems to vary. On some sprites it is not used at all, and the values are just left as zero. On scenes like the game's title screen and the end-animation in the castle, it is used to position the sprite in the full screen frame. In a lot of cases, however, one or both of the values are negative, meaning they move the frame up and to the left from the position at which the game is told to draw it. This seems to indicate that the game keeps track of objects by their center position, and these offsets in the sprite data handle the correct positioning relative to that point.
Image data
This image data behind the image header is saved per line. Each line starts with a byte that contains the information on how to read the line. If the byte has its upper bit enabled (meaning, it is larger than 0x80), the data that follows are simply bytes of image data to copy straight into the image. If the upper bit is disabled, the following data are length/value pairs to perform an RLE decompression operation.
The remainder of the first byte, with the highest bit cut off (or, 0x80 subtracted from it), indicates how many bytes long the data for that one line is. Both types should always result in a completely filled line.
For example, a byte 0x08 indicates that the following data are 8 bytes of length/value pairs, meaning, four pairs, before the next line's data starts. A byte 0xA2 would indicate a line that is copied without repeat commands, and the length of the line is 0x22, or decimal 34.
The resulting image data is in 4bpp linear format, big endian packed, meaning values 0x12 0x34 would represent four pixels, left to right, of colour values 1, 2, 3 and 4. The colour value 0 is treated as transparent pixels by the game.
Format notes and quirks
- The width and height of the image can't be 0. Either of these will result in immediate graphical corruption in-game.
- There are some easy checks that can be done to see whether the lines are in the correct format: if a repeat is not used, the line length should always match the width value in the image header, and if repeats are used, the following values are always pairs of bytes, so the line length should always be an even number.
- Normally, lines of data always exactly fill an entire line. If the line overflows, the game seems to only paint the correct amount, but this is no guarantee that the overflow does not cause any corruption in memory. If the line is not completely filled, the remainder is filled up with random junk, as is typical for an uncleared buffer.
- As a side effect of the fact the line length is saved in a single byte without the highest bit, the maximum width of the images is technically 0x7F, or 127 bytes, meaning, 254 pixels long. Anything more than that can not be stored in a copy-command, so the only way it could exist is as a compressed line, if that would take 126 bytes or less.
- In the original game files, the compression is only used if the line data is at least two bytes smaller when compressed.
Image Colour Palette
The image colour palette is the following
Colour | Name | RGB |
---|---|---|
0 | blue | #0000AA |
1 | bright blue | #5555FF |
2 | brown | #AA5500 |
3 | bright red | #FF5555 |
4 | red | #AA0000 |
5 | magenta | #AA00AA |
6 | bright magenta | #FF55FF |
7 | cyan | #00AAAA |
8 | green | #00AA00 |
9 | bright green | #55FF55 |
10 | bright cyan | #55FFFF |
11 | yellow | #FFFF55 |
12 | white | #FFFFFF |
13 | light gray | #AAAAAA |
14 | dark gray | #555555 |
15 | black | #000000 |
Tools
The following tools are able to work with files in this format.
Name | Platform | View images in this format? | Convert/export to another file/format? | Import from another file/format? | Access hidden data? | Edit metadata? | Notes |
---|---|---|---|---|---|---|---|
Engie File Converter | Windows | Yes | Yes | Yes | N/A | N/A | Opening a .pak file and bringing up its save menu allows getting the metadata needed to re-save edited frames to the format. |
Credits
This file format was reverse engineered by Malvineous, with research into the compression done by Trogdor and Nyerguds. If you find this information helpful in a project you're working on, please give credit where credit is due. (A link back to this wiki would be nice too!)