Username:    Password:    Login
Main  Secrets  Links  Specs  Articles  Forum  News  Downloads  Utilities  SCUMM?  Games  Demos  Contact
Main  Secrets  Links  Specs  Articles  Forum  News  Downloads  Utilities  SCUMM?  Games  Demos  Contact

SCUMM file format specifications and documentation

The Really Useful SCUMM etc. Info File
Maniac Mansion .lfl-files
Additional .lfl info
AKOS format
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

(download file)

/* Some documentation of the Monkey Island 1 and 2 costume format. Perhaps it works with 
 * other LucasArts (tm) games as well.
 * By Ludde (, 1999-2001
 * Please contact me by mail, or by ICQ #1448580 if you need more info. Perhaps I can help you out.

/* definitions:
 * 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.

CostumeHeader {
    uint16 blockID;     
/* 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.
    ubint32 blockLen;   
    uint8 numanims;     /* numanims is the number of the highest animation */
    uint8 format;       
/* format & 0x7F:
 *  0x58 - 16 color costume
 *  0x59 - 32 color costume
 * format & 0x80:
 *  0x00 - normal alignment
 *  0x80 - different alignment
    uint8 palette[num_colors];

/* this follows CostumeHeader */
CostumeHeader2 {
    uint16 frameOffs;           //offset to frame block (array of uint8 with indexes for images)
    uint16 imageTableOffs[16];  //offset to ImageTables for the 16 slots
    uint16 animOffs[numanims+1];//offset to AnimationData:s for each animation that can be executed

ImageTable {
    uint16 imageOffs[unknown];

AnimationData {
    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
                        //automatically cleared.
    SlotModifier anims[];       //The count depends on the number of bits set above.

SlotModifier {
    uint16 frameIndex;
/* 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.
    uint8 frameLen;         
/* 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]]
Image {
    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 */
    uint8 unknown;
    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; */

    uint8 rawImage[];

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)



SCUMM Revisited screenshot
SCUMM Revisited

Quick & Easy
SCUMM Hacking Forum