SCUMM/Technical Reference/SCUMM 6 resource files
Scumm 6 data format
1. Introduction
The first SCUMM version was written for Maniac Mansion. At that time, floppy disk was the most common medium for games, so naturally the file formats reflect this. Basically each floppy contained one or more rooms with all the data needed to play in those rooms. Later games came on CD and all data was grouped into 2 files. The main data file is merely a big bunch of room files put together. The second file is an index to make random access easy.
1.1 Other resources
Other people are working on similar stuff. Some information came from these:
- "The inCompleat SCUMM Reference Guide":http://www.cowlark.com/scumm/
- "LucasHacks!":http://scumm.mixnmojo.com/
1.2 Basics
First of all, the data can be "encrypted". To decrypt just XOR each byte with a key. According to the ScummVM code, there are 3 keys in use: 0x00, 0xFF and 0x69. DOTT uses 0x69.
All SCUMM files are made of blocks like this:
type: 32 size: 32be data: ...
2. Index file
RNAM : room name list
vlc (end code 0x00, so room no starts at 1) room no : 8 name : 8*9 (binary inverted)
List the name of the rooms, note that you must apply a binary not on the names (name[i] = ~name[i]). The list must be terminated with a zero byte.
MAXS : maximal address for ...
max var : 16le unk : 16le (perhaps actors as it's 16 in dott, but that doesn't really fit with later versions) max bit var : 16le max local objs : 16le max arrays : 16le unk2 : 16le (really dunno as it's 0 in dott) max verb : 16le max fl objs : 16le max inv : 16le max room : 16le max scr : 16le max snds : 16le max chst : 16le max cost : 16le max glob obj : 16le
This is used by the VM to ensure resource address validity. So generally it doesn't represent the actual number of resources, in particular for variables, as most low addresses are reserved and might not be used at all in the scripts. max local objs is the maximum number of objects used inside a single room. It's set to 200 in DOTT, and I suppose this limit was simply set arbitrarily. max global obj is the highest valid object address, so usually the number of objects minus 17 (as object addresses 1-16 are used for actors). max bit var must be rounded up to the next multiple of 8, as apparently the original engine just divides by 8 to allocate the memory.
DROO : room idx
num entries : 16le file no : 8*num room off : 32le*num
This describes where to find each room: in which file and at which offset. So one can split the game into several files named gamename.xxx. The offset is to the beginning of the ROOM block (i.e. right after the LFLF header).
DSCR : script idx
num entries : 16le room no : 8*num room off : 32le*num
DSOU : sound idx
num entries : 16le room no : 8*num room off : 32le*num
DCOS : costume idx
num entries : 16le room no : 8*num room off : 32le*num
DCHR : charset idx
num entries : 16le room no : 8*num room off : 32le*num
All the above D??? blocks describe where the resources are found. The offset is relative to the beginning of the ROOM (i.e. the one given for the room in the DROO block).
DOBJ : object owners list
num entries : 16le obj owner/state : 8*num owner : 4 state : 4 class data : 32le*num
This block sets the owner, class and initial state of each object. Each object must have an owner and it is usually the room (0xF), but it can be any actor number.
AARY : array list
vlc (end code 0x0000) var no : 16le x size -1 : 16le y size -1 : 16le type : 16le (0: words, 1: bytes)
Finally we have a list of pre-allocated arrays, these will be allocated by the engine before running the boot script.
3. Main data file
3.1 Structure
- *LECF* main container
- *LOFF* room offset table
- *LFLF* disk block
- *ROOM* room block
- *RMHD* room header
- *CYCL* color cycle (vlc stop on 0x00)
- *TRNS* transparent color
- *PALS* palette data
- *WRAP* dummy container
- *OFFS* palette index
- *APAL* 256 entries rgb palette (include the others blocks size)
- *WRAP* dummy container
- *RMIM* room image
- *RMIH* number of z buffers
- *IM00* image data
- *SMAP* stripe table + plane 0
- *ZPnn* stripe table + z planes (nn >= 1)
- *OBIM* obj image
- *IMHD* image header
- *IMnn* image data (image for state nn, start with state 1 as state 0 just display nothing)
- *SMAP* plane 0 (see above)
- *ZPnn* other z planes (nn >= 1, again see above)
- *OBCD* object scripts
- *CDHD* code header
- *VERB* verb entries (the object scripts indexed by verbs. Several verbs may have the same code)
- *OBNA* object name (default object name, it may be overrided by the scripts)
- *EXCD* exit script (script run when leaving the room)
- *ENCD* entry script (script run when entering the room)
- *NLSC* number of local scripts
- *LSCR* local script
- *BOXD* box data (box 0 seems to be crap with all the points set to -32000,-32000)
- *BOXM* box matrix
- *SCAL*
- *SCRP* script
- *SOUN* sound, contain one of:
- *MIDI* midi data
- *SOU* container for the different versions
- *ROL* roland data
- *ADL* adlib data
- *GMD* general midi data
- *COST* costume
- *CHAR* charset
- *ROOM* room block
3.2 Blocks content
All the blocks not described here don't contain anything more than the blocks shown in the above structure. Or they are unknown (to me) atm ;)
3.2.1 LOFF
num rooms: 8 room id: 8 offset : 32le (absolute offset of the ROOM block)
3.2.2 RMHD
width : 16le height : 16le num objs : 16le
3.2.3 CYCL
cycles : variable length idx : 8 (valid range is [1-16]) unk : 16 Th freq : 16be (delay = 16384/freq) flags : 16be start : 8 (start/end entries in the palette) end : 8 close : 8 must be set to 0 to end the block
Defines the various parts of the palette that can be cycled. The only known flag is the second bit, which means the cycling should go backwards.
3.2.4 TRNS
val : 8 padding : 8
3.2.5 OFFS
offset table : block size imply the number of palette ? offset : 32le (offset starting from this OFFS block)
3.2.6 APAL
colors : 256 times r : 8 g : 8 b : 8 APAL : others APAL blocks may follow
Note that the APAL blocks are constructed recursively. If we have for example 3 palettes, the first APAL block contains its palette followed by 2 other APAL blocks, etc.
3.2.7 RMIH
num z buf: 16le (number of ZPnn in the IM00 block)
3.2.8 SMAP
strip off : 32le (offset from this SMAP. 1 per column of 8 pix) stripes codec : 8 data : variable length
3.2.9 ZPnn
strip off : 16le (offset from this ZPnn. 1 per column of 8 pix) stripes data : variable length
See SCUMM Image Resources for more information on the SMAP and ZPnn blocks.
3.2.10 IMHD
obj id : 16le num imnn : 16le num zpnn : 16le unknown : 16 x : 16le y : 16le width : 16le height : 16le num hotspots : 16le (usually one for each IMnn, but there is one even if no IMnn is present) hotspots x : 16le signed y : 16le signed
3.2.11 CDHD
obj id : 16le x : 16le (upper left corner) y : 16le w : 16le (size of the active area - it may not match the image size, I think) h : 16le flags : 8 parent : 8 unk : 2*16 actor dir : 8 (direction an actor should look at when standing in front of the object)
3.2.12 VERB
offset table : vlc entries : 8 (0x00 is end, 0xFF is default) offset : 16le code
3.2.13 OBNA
null terminated string
3.2.14 NLSC
val : 8 padding : 8
3.2.15 LSCR
idx : 8 (local script IDs start at 200) data
3.2.16 BOXD
num box : 16 ScummVM only uses the lower 8 bits ulx : 16le uly : 16le urx : 16le ury : 16le lrx : 16le lry : 16le llx : 16le lly : 16le mask : 8 flags : 8 scale : 16le
The mask indicates which Z plane should mask this box. The flags are used for certain parameters:
- 0x08 : X flip
- 0x10 : Y flip
- 0x20 : Ignore scale / Player only
- 0x40 : Locked
- 0x80 : Invisible
"scale" indicates the scaling to be used for actors in the box. If the highest bit is set, it defines a scale slot instead. See the SCAL block for more details on scaling.
3.2.17 BOXM
line : the matrix has one line for each box, terminated by 0xFF. box : list of the directly connected boxes start : 8 end : 8 box : 8 0xFF : 8
3.2.18 SCAL
scale data (repeat 4 times) scale1 : 16le y1 : 16le scale2 : 16le y2 : 16le
The SCAL block defines the room's scale slots. These allow the actors to be scaled as a function of their position in the room, instead of just having a fixed scale for a whole box. Each slot represents a linear function ranging from scale1 to scale2 for an input (the y coordinate) ranging from y1 to y2. Scale factors range from 1 to 255, with 255 being unscaled and 1 the minimal size (1 pixel or so :). I dunno yet if the real scale factor is s/255, but that seems the most logical.
s = ((scale2 - scale1) * (y - y1)) / (y2 - y1) + scale1; if(s > 0xFF) s = 0xFF; if(s < 1) s = 1;
3.2.19 COST
size : 32le can be 0 (see num anim) or the size (sometimes with an offset of one ??) header : 2*8 always contain "CO" num anim : 8 if(size) num_anim++ format : 8 bit 7 is a mirror flag, bit 0 is the palette size (0: 16 colors, 1: 32 colors) palette : 8*num colors coded in format anim cmds offset : 16le access the anim cmds array limbs offset : 16*16le access limb picture table anim offsets : 16le*num anim access anim definitions anim limb mask : 16le anim definitions : variable length, one definition for each bit set to 1 in the limb mask. 0xFFFF : 16le stopped limb code OR start : 16le noloop : 1 len : 7 anim cmds cmd : 8 limbs pict offset : 16le picts width : 16le height : 16le rel_x : s16le rel_y : s16le move_x : s16le move_y : s16le redir_limb : 8 only present if((format & 0x7E) == 0x60) redir_pict : 8 only present if((format & 0x7E) == 0x60) rle data
See SCUMM Costume Resources for more informations on costumes.
3.2.20 CHAR
size : 32le size-15 unknown : 2*8 always 0x6303 in dott palette : 15*8 bpp : 8 (font ptr) font height : 8 num char : 16le offset table : num*32le the offsets are relative to font ptr chars width : 8 height : 8 x offset : s8 y offset : s8 data : raw bit packed data
In ScummVM only bpp 1, 2, 4 and 8 are supported.
3.2.21 SOUN
This is apparently used to store music, and was also used for sound effects in older games. They can contain various data, but it seems only SOU is used in DOTT. Sam'n Max also has some MIDI blocks. A few others exist but they are probably not used in v6.
The SOU block again contains new blocks to store the various versions. In DOTT they generally contain 3 blocks: ROL, ADL and GMD (presumably Roland, AdLib, and General MIDI). Each seems to contain more or less standard MIDI data.
4. Voice file
All the voices and effects are in a separate file. In the original engine, the file is called MONSTER.SOU and uses VOC (creative voice) samples. ScummVM can use compressed samples and supports files named $GAME.SOU. Currently ScummVM supports MP3, Vorbis and FLAC.
4.1 Structure
main block header : scumm block header (SOU ) samples sync block header : scumm block header (VCTL) sync data : 16be*num voc data : sample data
The first block header at the start of the file has a zero size. The number of sync points is derived from the VCTL block size. The size of the VOC data can only be found by parsing it.