-
Notifications
You must be signed in to change notification settings - Fork 20
Scumm 6 data format
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.
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/
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: ...
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.
-
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
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 ;)
num rooms: 8
room id: 8
offset : 32le (absolute offset of the ROOM block)
width : 16le
height : 16le
num objs : 16le
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.
val : 8
padding : 8
offset table : block size imply the number of palette ?
offset : 32le (offset starting from this OFFS block)
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.
num z buf: 16le (number of ZPnn in the IM00 block)
strip off : 32le (offset from this SMAP. 1 per column of 8 pix)
stripes
codec : 8
data : variable length
strip off : 16le (offset from this ZPnn. 1 per column of 8 pix)
stripes
data : variable length
See Scumm image formats for more information on the SMAP and ZPnn blocks.
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
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
parent_state : 8 (if parent != 0 this object only "exists" when the parent
object is in the given state)
parent : 8
unk : 2*16
actor dir : 8 (direction an actor should look at when standing in front
of the object)
offset table : vlc
entries : 8 (0x00 is end, 0xFF is default)
offset : 16le
code
null terminated string
val : 8
padding : 8
idx : 8 (local script IDs start at 200)
data
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.
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
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;
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 Costume formats for more informations on costumes.
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.
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.
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.
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.