SCUMM file format specifications and documentation
The Really Useful SCUMM etc. Info File
Maniac Mansion .lfl-files
Additional .lfl info
Preliminary SAN documentation
Monkey Island 1 & 2 costume format
Monkey Island 2 costume format
Monkey Island 2 SCUMM opcodes
SCUMM index files
.bun file format
.lab file format
EMI .lab file format
EMI .til file format
GF/EMI .laf fonts file format
EMI mesh specs
/* Some documentation of the Monkey Island 1 and 2 costume format. Perhaps it works with
* other LucasArts (tm) games as well.
* By Ludde (email@example.com), 1999-2001
* Please contact me by mail, or by ICQ #1448580 if you need more info. Perhaps I can help you out.
* uint8 = 8 bit unsigned integer
* uint16 = 16 bit unsigned integer
* int16 = 16 bit signed integer
* ubint32 = 32 bit big endian unsigned integer
/* The COST format allows up to 16 small images to be displayed simultaneously.
* This is what I call slot.
* Each slot can be paused, and it can also be an animation of max 127 frames, either stopping at the end
* or restarting the animation.
* When an animation is started, the slots are not always cleared automatically, so additional effects
* may be accomplished by first starting an animation and then later starting an other one that can
* reuse some of the slots that were initiated in the first animation.
/* When they changed to 4 byte block ID:s (MI2) instead of 2 byte as they used before (MI1) they
* didn't modify the costume format, so all offsets in MI2+ are 2 bytes too small.
* By skipping the first 2 bytes of the resource and assume the costume starts there for MI2+ costs,
* everything works fine. That's why blockID is 16 bit above.
uint8 numanims; /* numanims is the number of the highest animation */
/* format & 0x7F:
* 0x58 - 16 color costume
* 0x59 - 32 color costume
* format & 0x80:
* 0x00 - normal alignment
* 0x80 - different alignment
/* this follows CostumeHeader */
uint16 frameOffs; //offset to frame block (array of uint8 with indexes for images)
uint16 imageTableOffs; //offset to ImageTables for the 16 slots
uint16 animOffs[numanims+1];//offset to AnimationData:s for each animation that can be executed
uint16 activeSlots; //bitmask of which of the 16 slots that are to be modified in this animation.
//The slots that were active before this new animation are not
SlotModifier anims; //The count depends on the number of bits set above.
/* Start index in frameOffs table for this slot. The frameOffs table contains image indexes.
* an animation is accomplished by increasing this frameIndex value and the image with the
* index frameOffs[frameIndex] is drawn for this slot. There are separate image indexes for each slot (imageTableOffs).
* If frameIndex is 0xFFFF, the slot is disabled.
/* frameLen&0x7F - number of frames in animation for this slot.
* frameLen&0x80 - repeat the animation or not when it's finished
/* In the frameOffs table, only the low 7 bits are used as the image index (last bit is unknown).
Some indexes are magic:
0x79 - pause the slot until it is resumed (is only checked when a new animation is initiated)
0x7A - resume the slot - "" -
0x7B - don't draw an image
0x78 - increase animation counter 1 (may be retrieved from scripts)
0x7C - increase animation counter 2 (may be retrieved from scripts)
The actual offset of the image to draw is determined from something like (pseudo code):
(resourcePtr + imageTableOffs[slot]).imageOffs[(resourcePtr+frameOffs)[index_in_frameOffs_table]]
uint8 width; /* in MI2, width and height is only 8 bit */
uint8 unknown; /* perhaps this one is used as a width extension to 16 bit in later games */
uint8 height; /* same goes for height */
int16 x,y; /* x and y coordinate of image relative to the relPos. (relPos is cleared before starting to draw) */
int16 xinc,yinc; /* relPos.x+=xinc; relPos.y-=yinc; */
the image is rotated and compressed using a run length encoding algorithm that operate on bytes.
16 color mode (ccccllll)
cccc = color
llll = length (if llll=0, an additional byte is read with the length)
32 color mode (ccccclll)
ccccc = color
lll = length (if lll=0, an additional byte is read with the length)