Talk:Monster Bash Sprite Format
Image Format Flags Field
After doing some more analysis of the .exe, I can find two functions responsible for drawing sprites. The first draws the "white flashed" sprites by copying the transparency mask to all four graphics planes. The second function, which draws the normal sprites, first applies the mask, and then sets the map mask register based upon the value in the planebit field.
The lower four bytes of the UInt8 "iFlags" field in the image header appear to control the number of shifts. The high-four bytes (particularly bit 6, 0x40) appear to radically alter the manner in which the sprite is drawn. I haven't finished analyzing it yet, but it looks like the "big" sprites have bit 6 set, because the width-optimized drawing code doesn't handle cases larger than 64 pixels wide (8 bytes wide).
For sprites that don't have 0x40 set (which appears to be the majority of them in Monster Bash), then the low bit indicates whether or not the sprite has multiple "shifted" source copies or if the sprite is shifted as it is drawn. If the low bit is not set, then the flags value is either 2, 4, or 8, and this is the number of shifted copies found in memory. In Monster Bash, this only appears to apply to the "rock," which has an iFlags of 0x8, indicating 8 shifts. If the low bit is set, then the flags value is 1, meaning that there is only one copy of the sprite in memory, and it is shifted as it is drawn, allowing big sprites, which would take up too much memory if they were pre-shifted, to be drawn smoothly.
At least for the transparency plane, the function of the planeBits only seems to be to indicate the width of the sprite. This is evident in the following line of code:
We are looking at the start of the function that draws the white-flashed-sprites. You can see that, at E8DF, where we deal with non-0x40-masked sprites, the planebit is loaded into al and then exchanged into bl in the subsequent instruction. At E90A and E911, the game jumps to width-optimized drawing instructions based upon the value of bx. (One jump table is for sprites that are drawn starting at byte-boundaries, which includes pre-shifted sprites and non-shifted sprites that are lucky 1/8th of the time, while the other jump table is for sprites that are drawn off byte-boundaries).
Now looking at how Camoto messes up sprite import:
Here are the first 16 bytes of main_r as analyzed by Wombat. I'm comparing an unmodified DAT file, and one that has been modified by exporting and then importing main_r as a .PNG.
Unmodified: . FF6A 0201 2818 00F7 FFFF FF0C 0027 0003
Modified: ... FF6A 0201 2818 00F7 FFFF FF0C 0027 0001
You can see that byte 0xF, which is the "plane-bits" of the transparency plane belonging to the frame with Johnny standing to the right, equals 3, meaning that the sprite is three bytes wide. Camoto changes this to 1, for whatever reason. The game draws the sprite as an 8-pixel wide strip of garble, because it thinks that the sprite is 8 pixels wide.
Now in addition to all of that, take a look at E8D9. For sprites that have multiple shifts, there must be an array of word-length offsets that follows the standard 12-byte header, because SI is set based upon which shift is to be drawn. (In this case, the shift number is stored in BX and ES:SI points to the graphics source in conventional memory when drawing commences.) This means that any sprite frame with a flags value of 0x2,0x4,0x8, or 0x42, 0x44, or 0x48 should have an array of words, equal in size to the number of shifts, that slips in between the 12-byte header and the start of the graphics plane. Lemm (talk) 14:32, 1 November 2013 (GMT)