Extracting Lode Runner 2's graphics data

A description of the XPK graphics format

Reverse-engineering of XPK format done by Toastline of SPG

Inside most of the .PRX files in the game Lode Runner 2, there are sections of data which store images.  I have figured out how this is done and now you can learn it and perhaps make a better extractor than I have. Mine is clumsy and not perfectly reliable, so I encourage someone to do so, in fact!
I think that the X in XPK stands for "extended," and the PK is short for "Pak." Presage used to use .prs and .prd files, .prs having contained Pak resources in them, which I believe were images.  I think the d in prd stood for directory, as they serve as a sort of directory for the prs. PRX is almost exactly the result of taking the prd and sticking it into a file with the prs immediately after it. I think the X in PRX is also short for "extended." I also think the PRX spec allows it to include arbitrary data types, and the prs spec did not.
This page describes XPKs which are not under the influence of an XMV.  For the fun ways that those change the things, see "43_XMV_and_XUI_resources.txt".

I'll use GearWG.PRX as an example, first.
The first XPK resource starts with this metadata:
58 50 4B 00 E8 03 00 00 00 00 00 00 00 00 00 00
00 00 00 00 00 00 00 00 F7 07 00 00
Where 58 50 4B is XPK in ascii. F7 07 00 00 is the size of the resource plus this metadata section, in little endian form, in bytes. That's starting at the very beginning of the entry (so the last address in the resource plus this section would be 0000 07F6 big-endian).  I don't know what the rest is.  It's possible that not all of this is metadata.

Then there's this thing which IS where I think the resource starts.  At this point I will treat the resource, for descriptive purposes, as its own file.  So think of this next series of bytes as being at the addresses 00-03, instead of considering their position inside the larger  .PRX file.
A5 7E 70 01
These will always be the same.
Then the next 12 bytes in this particular resource are
B0 02 00 01 00 00 01 74 00 00 01 84
The first two bytes tell you what kind of XPK this is. These bytes can also be B001 or C002. B002 uses a palette and run-length encoding, as you will see. The 4th byte here, which is 01, is the number of images.  Usually it will be 01, but sometimes multiple images are stored that use one palette, and you'll need to know how many there are to read them properly.  Maybe the byte before that is part of it too, but I haven't seen any occasions where there were that many frames.  01 74 tells what byte the palette ends on, minus one.  So the last byte that is part of the palette is byte 175 (hexadecimal).  I don't know what 01 84 is, but those bytes can not be consistently used to find the end of a palette.

Then the palette starts.  Each colour is 2 bytes long. The first one is
0C 20
and the last one is
7F F9
See the colour section in "tables.txt" to learn how this works.

After that is what I call the divider. The entry we're looking at has this in that section:
00 00 00 00 00 28 00 36 00 00 00 00 00 28 00 35 00 00 00 04
As far as I can tell, the first 4 bytes are always zeroes.
The bytes 00 28 are the x size in pixels, and the bytes 00 36 are the y size in pixels.
The next 4 bytes do something probably.  I don't know what. I think they're always zero as well.
The next 00 28 and then the 00 35 are offsets of some kind. I'm not entirely sure how they work, but it's not something obvious.
Also as far as I can tell, the last 4 bytes are always 00 00 00 04.

Once the divider is over, comes the first row of the image.
wx yz        - start of a new line which is wxyz bytes long (this will only occur at new rows before anything is drawn in them.  Commonly, wx is 00, but it does not have to be.)

Then there's the data that goes into drawing the row.

0x        - draws x+1 blank pixels
1x        - draws x+17 blank pixels
2x        - draws x+33 blank pixels
3x        - draws x+49 blank pixels
4x        - draws x+1 pixels, of the colours specified in the x+1 following bytes
5x        - draws x+17 pixels, of the colours specified in the x+17 following bytes
6x        - draws x+33 pixels, of the colours specified in the x+33 following bytes
7x         - draws x+49 pixels, of the colours specified in the x+49 following bytes
8x yz        - draws x+2 pixels of colour yz
9x yz        - draws x+18 pixels of colour yz
ax yz        - draws x+34 pixels of colour yz
bx yz        - draws x+50 pixels of colour yz
cx yz        - draws 1 pixel of colour yz with alpha (I made a table)
dx yz        - draws 1 pixel of colour yz with different alpha (I made a table)
ex yz        - same as cx yz?
fx yz        - same as dx yz?

I have question marks on those last 2 because they seem to be true, but it's possible that they are not always.

Once a row is completed (so you've read wxyz more bytes) there is another wxyz to read, and so on until the end of the image.

Reverse-engineering of XPK done by Toastline of SPG