What follows is a description of the SLP format. The actual author wishes to remain unknown, please email bryce@lanset.com with your questions. However, I did not write this document. Header This structure totals 32 bytes and is packed to 1-byte boundaries. typedef struct Shape_File_Header { char Version[4]; // Usually '2.0N' long Num_Shapes; char Comment[24]; } Shape_File_Header; The header is immediately followed by an array of size "Num_Shapes" of structures with info for each shape. typedef struct Shape_Info { UInt32 Shape_Data_Offsets; UInt32 Shape_Outline_Offset; UInt32 Palette_Offset; UInt32 Properties; int Width; int Height; int Hotspot_X; int Hotspot_Y; } Shape_Info; The Shape_Data_Offsets and Shape_Outline_Offset point to arrays of data, each of length "Height". The "Shape_Data_Offsets" array is an array of UInt32 values, the "Shape_Outline_Offset" array consists of 2 UInt16 values. For each vertical line of data in the shape, the Shape_Data_Offsets array points to the start of the data for that line (for fast lookup in the blitter). The Shape_Outline_Offset array contians two x-values for each line of the sprite. The first 16-bit value defines how far from the left-edge the sprite data starts drawing, while the second value defines how far from the right-edge the sprite stops drawing. The (offset right - offset left) value thus gives the length in pixels of the vertical line of the sprite. I haven't seen a SLP with a value for the palette offset, so I'm not sure if it's used. The "Properties" field is more or less unused by the game. A value of 0x10 indicates to use the default game palette, and a value of 0x00 indicates to use the "global" palette. I believe both are the same for our purposes. The Hotspot_X and _Y values are used (I think) to represent the center of the SLP for purposes of moving and manipulating them. For SLPs that are cursors, they represent the trigger point. The actual SLP data starts at the "Shape_Data_Offset" for each line, and is run-length encoded using a set of 15 commands. You start by taking the first byte in the data for the line and acting on it as a command. The command code itself is stored in the low-nibble of the byte, e.g. command = data & 0x0f. case 0, 4, 8, 0x0c: Block Copy (short) In these cases, the length of the block copy is stored in the top 6 bits of the command byte, e.g. length = command >> 2. The data to copy follows the command byte and is "length" bytes long. Thus, these commands are good for small chunks of non-repeating data, up to a length of 64 bytes. case 1, 5, 9, 0x0d: Skip pixels (short) These commands skip a range of pixels, up to 64. The length is encoded like with the prior command, i.e. length = command >> 2. This command is mainly used to draw an empty space in the middle of a sprite, as it just moves the pointer to the drawing buffer forward. case 2: Block Copy (big) Like the first Block Copy, but supports ranges > 64 bytes. The top 4 bits of the command byte are shifted left 4 bits and added to the next byte in the command stream to get a length of 0-0xfff, i.e. length = ((command & 0xf0) << 4) + next_byte. Following that is the stream of data to copy, of size "length". case 3: Skip pixels (big) The length is determined just like the big block copy command, and it behaves like the other skip command in that it just moves the pointer to the drawing buffer. case 6: Copy & Transform block The length of this block is determined by the high 4 bits of the command byte. If they are non-zero, then the length is in the range of 1-15. If the high 4 bits are zero, then the next byte in the stream is read and used as the length. After that, a range of "length" bytes is read, and each byte is or-ed with the player color to determine the final color of the byte. The player color value is an index into the palette, and I believe the range is 0-15. case 7: Fill block The length is determined as with case 6. The next byte in the stream determines the color of the run. The run length is then filled with this color for "length" bytes. case 0x0a: Transform block The length is determined as in cases 6 and 7. The next byte in the stream determines the initial color of the block run, and it is and-ed to the shadow "and" mask, and then or-ed to the shadow "or" mask. These masks are typically something like 0xff00ff00 and 0x00ff00ff, and are used to draw shadow effects in the game. This is typically used to overlay a checkerboard shadow sprite onto the existing buffer. case 0x0b: Shadow pixels The length is determined as in cases 6, 7 and 0x0a. For the length of the run, the destination pixels already in the buffer are used as a lookup into a "shadow table" and this lookup pixel is then used to draw into the buffer. The shadow table is typically a color-tinted variation of the real color table, and is generally used to draw things like the red-tinted checkerboard sprites when you try to place a building in an area where it cannot be placed. case 0x0e: Extended commands The high 4 bits are used to determine an extended command, so the entire command byte is used. These commands are mainly used to draw the sprite outlines that you see when you move behind trees. The subcommands are as follows: 0x0e & 0x1e: These commands are used to hint to the renderer about the command that follows. (The byte immediately following this command is just a regular command byte.) If the special command is 0x0e, then the command that follows is only drawn if the sprite is not x-flipped. If the special command is 0x1e, then the command that follows is only drawn if the sprite is x-flipped. 0x2e & 0x3e: These set the transform color tables used in the regular commands. 0x2e sets the renderer for the normal transform color table, 0x3e sets it for the alternate transform color table. 0x4e & 0x6e: Draw "special color 1 or 2", 1 byte The destination draw buffer is filled with 1 byte, which is the color table value specified by "special color" 1 or 2 (depending on the command). These are typically the colors that are used to draw the outline color that you see when a sprite moves behind a tree. Special color 1 is usually the player color, special color 2 is (in the case of SWGB) typically black to enhance the outline. 0x5e & 0x7e: Draw "special color 1 or 2" as a run The byte following the special command is used to determine the length of the run. The destination buffer is filled with the special color 1 or 2 for "length" bytes. 0x8e through 0xfe. These are unused. case 0x0f: End of Line Presence of this command indicates that the sprite commands for the current line are finished and that the parser should move onto the next vertical line in the sprite.