Magic Pockets Sprite Format
| Format type | Image |
|---|---|
| Hardware | EGA, VGA |
| Colour depth | 4-bit (EGA) |
| Minimum size (pixels) | 16×16 |
| Maximum size (pixels) | 32×32 |
| Palette | External |
| Plane count | 4 |
| Transparent pixels? | Palette-based |
| Hitmap pixels? | No |
| Games |
Sprites in Magic Pockets are arrays of masked planar tiles in .pak files. They have an RNC method 1 wrapper. There are 19 sprite banks; the four blocks banks instead use Magic Pockets Tileset Format.
File format
After decompression there is no header, tile count, palette or frame directory. Choose the layout by filename, then divide the length by the tile size. Size divisibility alone is ambiguous.
| Files | Dimensions | Bytes per plane | Bytes per tile | Tiles per file |
|---|---|---|---|---|
| bitkid.pak, ape.pak, nasty1-4.pak | 32×32 | 128 | 640 | 60 |
| special1-4.pak, kidx1-4.pak | 32×32 | 128 | 640 | 20 |
| extras.pak | 16×16 | 32 | 160 | 240 |
| extrax1-4.pak | 16×16 | 32 | 160 | 80 |
Each tile stores five complete planes, consecutively: the AND mask followed by colour planes 0, 1, 2 and 3. Within a plane, rows are consecutive, with 4 bytes per row for 32-pixel tiles or 2 for 16-pixel tiles. The most significant bit is the leftmost pixel of each byte. Colour plane k supplies bit k of the 4-bit palette index.
For tile index t, width w, height h and bytes per plane P = (w / 8) * h:
mask byte = t * 5 * P + y * (w / 8) + floor(x / 8) colour-plane k byte = t * 5 * P + (k + 1) * P + y * (w / 8) + floor(x / 8) bit number = 7 - (x % 8)
Transparency
A mask bit of 1 preserves the destination pixel. A mask bit of 0 permits an opaque pixel. For RGBA export, use the mask for alpha; palette index 0 is not itself a transparency rule. The original renderer ANDs the destination with the mask before applying the colour planes.
Palette
No palette is stored in a sprite bank. Use the world's 16-colour palette from the executable. The palette decoder in the source section implements the game's VGA DAC conversion; a default EGA palette does not reproduce the game's colours.
Sprite numbering
The renderer uses executable-resident descriptors and frame streams to select tiles. A tile index is not an entity type or necessarily a complete animation frame. Several banks are assembled from a shared file and a world-specific extension:
| Runtime bank | Files, in order | Combined tile count |
|---|---|---|
| 2 | bitkid.pak + kidxN.pak | 80 |
| 3 | specialN.pak | 20 |
| 6 | extras.pak + extraxN.pak | 320 |
| 7 | nastyN.pak | 60 |
Here N is the world number. The 96 shape descriptors at GAMEU DS:B91A, the descriptor pointer table at DS:C39A and associated frame streams supply rendering metadata. They are not a header inside .pak.
Notes
- A 38400-byte file can mean 60 large sprites or 240 small sprites. Preserve the filename when extracting.
- These banks contain no hitmap or entity-placement records. Placement is in level scripts.
- The plane-to-index mapping is the identity mapping. An earlier palette-compensating plane permutation in the RE notes was superseded.
Source code
From re-magicpockets, the open-source browser port and reverse-engineering project:
- web/core/pak.js – bank layout selection and tile slicing
- web/core/ega.js – masked planar decoding
- web/core/palette.js – world palettes and DAC conversion
- web/core/exe-data.js – executable-resident metadata
- web/render/sprites.js – frame composition
- docs/formats/pak.md – consumer disassembly and layout evidence
Credits
This file format was reverse engineered by VorticonCmdr. Please credit this work in projects that use it; a link back to this wiki is appreciated.