I think it'd be nice to have more documentation for SCUMM (and indeed GRIME) especially at the moment while Lucashacks is down. The ScummVM Source is all well and good but not everyone can read C++ or understand it, plus its always nice to have things laid out seperately. More documentation will help us get/make some nice new tools too.
Here's the idea, in this thread you post various stuff, layout of blocks, image formats or whatever anything really and I'll post them all up neat in another sticky that I'll add to as more stuff is documented. It would be really good if those who can understand C++ could document from the ScummVM Source some of the stuff that hasnt been documented before like costumes etc..
Anyway its an idea, what do you all think?
This is outdated, I have a newer version of the specs than this, I havent finished it yet, if you need it just ask
My documentation of Index Files, the lfl stuff may be wrong:
IndexFiles
----------
00.lfl/000.lfl Used in V3/4
.000 Used in V5/6
.LA0 Used in V7/8
Conventions:
------------
All little endian unless stated
Chunk - a named part of the file, ie RNAM
Chunk sizes begin from the start of the chunk ie they include the
8 bytes for the chunk header and size
*=repeat until *=no of items, then move onto the next *
eg for DROO, read Room No until you've read in (No of items)
then do the same for offsets
#=do then move onto the next #item and loop until=no of objects
eg for RNAM, read Room No, them Room Name, then loop
Chunks
------
RNAM Room Names In V5+
MAXS Maximum Values In V5+
DROO Directory of Rooms In V5+
DRSC Direcory of Room Scripts In V8
DSCR Directory of Scripts In V5+
DSOU Directory of Sounds In V5+
DCOS Directory of Costumes In V5+
DCHR Directory of Charsets In V5+
DOBJ Directory of Objects In V5+
AARY List of Arrays In V6+
ANAM Animation Names? In V7
RM Room Names In V3/4
0R Directory Of Rooms In V3/4
0S Directory Of Scripts? In V3/4
0N Directory Of Sounds? In V3/4
0C Directory Of Costumes? In V3/4
0O Directory Of Objects? In V3/4
Scumm V5
--------
Files are xor'ed with 0x69
RNAM
----
Block Name (4 bytes)
Block Size (4 bytes BE)
#Room No (1 byte)
#Room Name (9 bytes) XOR'ed with FF
Blank (00) byte (1 byte) Marks end of chunk
MAXS
----
Block Name (4 bytes)
Block Size (4 bytes BE)
Variables (2 bytes)
Unknown (2 bytes)
Bit Variables (2 bytes)
Local Objects (2 bytes)
Unknown (2 bytes)
Character Sets (2 bytes)
Unknown (2 bytes)
Unknown (2 bytes)
Inventory Objects (2 bytes)
DROO
----
Block Name (4 bytes)
Block Size (4 bytes BE)
No of items (2 bytes)
*Room Number (1 byte)
*Offset (4 bytes)
DSCR
----
Block Name (4 bytes)
Block Size (4 bytes BE)
No of items (2 bytes)
*Room Number (1 byte)
*Offset (4 bytes)
DSOU
----
Block Name (4 bytes)
Block Size (4 bytes BE)
No of items (2 bytes)
*Room Number (1 byte)
*Offset (4 bytes)
DCOS
----
Block Name (4 bytes)
Block Size (4 bytes BE)
No of items (2 bytes)
*Room Number (1 byte)
*Offset (4 bytes)
DCHR
----
Block Name (4 bytes)
Block Size (4 bytes BE)
No of items (2 bytes)
*Room Number (1 byte)
*Offset (4 bytes)
DOBJ
----
Block Name (4 bytes)
Block Size (4 bytes BE)
No of items (2 bytes)
*Owner of Object (1 byte)
ScummV6
-------
Files are xor'ed with 0x69
RNAM
----
Blank Byte(00) (1 byte)
MAXS
----
Block Name (4 bytes)
Block Size (4 bytes BE)
Variables (2 bytes)
Unknown (2 bytes)
Bit Variables (2 bytes)
Local Objects (2 bytes)
Arrays (2 bytes)
Unknown (2 bytes)
Verbs (2 bytes)
Floating Objects (2 bytes)
Inventory Objects (2 bytes)
Rooms (2 bytes)
Scripts (2 bytes)
Sounds (2 bytes)
Character Sets (2 bytes)
Costumes (2 bytes)
Global Objects (2 bytes)
DROO
DSCR
DSOU
DCOS
DCHR
DOBJ
----
All as in V5
AARY
----
Block Name (4 bytes)
Block Size (4 bytes BE)
#Stop (2 bytes) Stops if 0x0000
#A (2 bytes)
#B (2 bytes)
#C (2 bytes)
num=AARY no (itinerate through in loop)
if c=1 then
AARY=(num, 1, a, b)
else
AARY=(num, 1, a, b)
If stop=0 you dont seek past the 6 bytes of A,B,C you just start the loop again.
ScummV7
------
Files aren't xor'ed
RNAM
----
As in V6
MAXS
----
Block Name (4 bytes)
Block Size (4 bytes BE)
Variables (2 bytes)
Bit Variables (2 bytes)
Unknown (2 bytes)
Global Objects (2 bytes)
Local Objects (2 bytes)
New Names (2 bytes)
Verbs (2 bytes)
Floating Objects (2 bytes)
Inventory Objects (2 bytes)
Arrays (2 bytes)
Rooms (2 bytes)
Scripts (2 bytes)
Sounds (2 bytes)
Character Sets (2 bytes)
Costumes (2 bytes)
DROO
DSCR
DSOU
DCOS
DCHR
DOBJ
AARY
----
All as in V5
ANAM
----
Block Name (4 bytes)
Block Size (4 bytes BE)
No of items (2 bytes
#Name (8 bytes)
#Blank (00) byte (1 byte)
Blank (FF) byte (1 byte) Marks end of chunk
ScummV8
-------
Files aren't xor'ed
RNAM
----
As in V6
MAXS
----
Block Name (4 bytes)
Block Size (4 bytes BE)
Variables (4 bytes)
Bit Variables (4 bytes)
Unknown (4 bytes)
Scripts (4 bytes)
Sounds (4 bytes)
Character Sets (4 bytes)
Costumes (4 bytes)
Rooms (4 bytes)
Unknown (4 bytes)
Global Objects (4 bytes)
Unknown (4 bytes)
Local Objects (4 bytes)
New Names (4 bytes)
Floating Objects (4 bytes)
Inventory Objects (4 bytes)
Arrays (4 bytes)
Verbs (4 bytes)
DROO
----
Block Name (4 bytes)
Block Size (4 bytes BE)
No of items (4 bytes)
*Room Number (1 byte)
*Offset (2 bytes)
DRSC
----
Block Name (4 bytes)
Block Size (4 bytes BE)
No of items (4 bytes)
*Room Number (1 byte)
*Offset (2 bytes)
DSCR
----
Block Name (4 bytes)
Block Size (4 bytes BE)
No of items (4 bytes)
*Room Number (1 byte)
*Offset (2 bytes)
DSOU
----
Block Name (4 bytes)
Block Size (4 bytes BE)
No of items (4 bytes)
*Room Number (1 byte)
*Offset (2 bytes)
DCOS
----
Block Name (4 bytes)
Block Size (4 bytes BE)
No of items (4 bytes)
*Room Number (1 byte)
*Offset (2 bytes)
DCHR
----
Block Name (4 bytes)
Block Size (4 bytes BE)
No of items (4 bytes)
*Room Number (1 byte)
*Offset (2 bytes)
DOBJ
AARY
----
All as in V5
Scumm V3/4
----------
File's aren't xor'ed
Block Size does not include the 4 block size bytes
RN
----
Block Size (4 bytes)
Block Name (2 bytes)
#Room No (1 byte)
#Room Name (9 bytes) XOR'ed with FF
Blank (00) byte (1 byte) Marks end of chunk
0R
----
Block Size (4 bytes)
Block Name (2 bytes)
No of items (2 bytes)
*Room Number (1 byte)
*Offset (4 bytes)
0S
----
Block Size (4 bytes)
Block Name (2 bytes)
No of items (2 bytes)
*Room Number (1 byte)
*Offset (4 bytes)
ON
----
Block Size (4 bytes)
Block Name (2 bytes)
No of items (2 bytes)
*Room Number (1 byte)
*Offset (4 bytes)
0C
----
Block Size (4 bytes)
Block Name (2 bytes)
No of items (2 bytes)
*Room Number (1 byte)
*Offset (4 bytes)
0O
----
Block Size (4 bytes)
Block Name (2 bytes)
No of items (2 bytes)
*Owner of Object (1 byte)
i'd like some kind of documentation for scummvm ..
ive found some scumm-documentation at this (
http://www.cowlark.com/scumm) loco...
Yeah, its still very incomplete though and abandoned if I remember rightly, I think its now part of the scummvm page.
Originally posted by bgbennyboy
Yeah, its still very incomplete though and abandoned if I remember rightly, I think its now part of the scummvm page.
Yeah, we were planning to finish it... Sometime. Maybe. :P
Post stuff here in the meantime then! People will be thinking that this is a poorly disguised attempt by me to get someone to document costumes...
Originally posted by bgbennyboy
Post stuff here in the meantime then! People will be thinking that this is a poorly disguised attempt by me to get someone to document costumes...
After ScummVM 0.5.0, I am planning to get a group together to work on documenting codecs and the like. But I'm too busy gearing up for 0.5.0 so far :)
AKOS: The Costume Format From Hell
WARNING: I do not guarantee all the information in this document is correct. I'm mainly interpreting from the ScummVM source code. If you have a correction to make, please do so!
ANOTHER WARNING: I won't be covering the AKSQ and AKCH stuff here. I tried, but the ScummVM code is messy, to say the least. Maybe one of its developers could document the sequence and animation stuff?
YET ANOTHER WARNING: This stuff may confuse you. I apologize for the inconvenience.
ONE MORE WARNING: Codec 16 still confuses me. I can't cover it. Sorry.
AKOS is an actor costume format. A costume is a set of graphics and animation which visualizes an actor (which is a good thing, otherwise Guybrush would be invisible). AKOSes are found in SCUMM versions 7 and 8, including Full Throttle, The Dig, and Curse of Monkey Island. Older SCUMM engines used the original "COST" costume format, but AKOS replaced it because it provided new stuff like larger images, better compression, and color effects like shadows.
Technical Stuff
Please make sure you understand how a palettized computer display works before you try to conquer the AKOS format.
You should probably know about SCUMM's actor palette system before reading on, so here you go:
Each actor contains its own special palette table. Whenever the AKOS renderer draws a pixel, that pixel's value (from the AKOS data) is translated into the actual pixel (to be drawn to the screen) using this palette table. For instance, if it has to draw "1", it will look in the first entry of the palette table for the pixel it should write to the display.
Why does it do this? Well, it really helps when the SCUMM engine needs to apply a color effect to the costume (also called a "remap"). Here's how it would make a costume slightly bluer, for example. For each entry in the actor's palette:
A) Compute the result color (which is slightly bluer) using the RGBS block as a reference (more on that below).
B) Search the hardware palette for a color which most closely matches the color it's looking for.
C) If that color is still not accurate enough, find an unused entry to change instead.
D) Remap the actor's palette table entry to the entry found in the hardware palette.
So, hopefully you can see the palette system's purpose.
The Chunks
An AKOS is based on the IFF format, and begins with the following header:
Name ("AKOS") (4 bytes)
Size (big endian) (4 bytes)
This is followed by a series of IFF chunks, described below:
AKHD: The AKOS Header, containing some important information about the costume.
AKPL: The AKOS Palette, containing the initial palette table for the actor. This block may be empty in some costumes!
RGBS: RGB Values, used by the SCUMM engine as a reference when applying a color effect to a costume. Contains the actual colors used in the costume. This block isn't used in some costumes!
AKOF: AKOS Offsets. This is used to find frame data in the AKCI and AKCD blocks.
AKCI: AKOS Costume Information. This contains the width, height, and position of each frame.
AKCD: AKOS Costume Data. The most important block! Contains the compressed costume frames.
AKHD
Name ("AKHD") (4 bytes)
Size (big endian) (4 bytes)
Unknown (2 bytes)
Flags (1 byte)
Unknown (1 byte)
Number of Animations (2 bytes)
Number of Frames (2 bytes)
Codec (2 bytes)
As you can see, a couple fields haven't been identified yet. However, the ScummVM source code labels "Number of Frames" as unknown, but I've figured it out. :)
There are only two known flags in the Flags field:
Bit 0: If set, the renderer will need to mirror frames for the actor to face certain directions.
Bit 1: If set, the actor can face 8 directions, rather than 4.
There are three codecs: Codec 1, Codec 5, and Codec 16. The codec specifies the type of compression used to compress the frames in the costume. Codec 1 is the same codec used in the old "COST" format, Codec 5 uses BOMP compression, and Codec 16 uses a bit stream encoding technique. I'll describe the codecs later.
AKPL and RGBS
The AKPL stores the actor's palette table and looks like this:
Name ("AKPL") (4 bytes)
Size (big endian) (4 bytes)
Palette Table Entries (1 byte, continues to end of block)
The RGBS stores the actor's colors, and looks like this:
Name ("RGBS") (4 bytes)
Size (big endian) (4 bytes)
[Until end of block:]
Red (1 byte)
Green (1 byte)
Blue (1 byte)
AKOF
This block is used to find frame data in the AKCI and AKCD blocks.
Name ("AKOF") (4 bytes)
Size (big endian) (4 bytes)
[Repeating until end of block:]
AKCD Offset (4 bytes)
AKCI Offset (2 bytes)
AKCI
This block contains information about each frame.
Name ("AKCI") (4 bytes)
Size (big endian) (4 bytes)
[Repeating until end of block:]
Width (2 bytes)
Height (2 bytes)
Relative X Position (2 bytes)
Relative Y Position (2 bytes)
X Movement (2 bytes)
Y Movement (2 bytes)
When the renderer wants to draw at an X, Y position, it will need to compute the actual position to render on the screen with the "Relative" fields. This lets the costume identify its position with the offset of, say, Guybrush's feet rather than the top left of the frame.
AKCD
Name ("AKCD") (4 bytes)
Size (big endian) (4 bytes)
Data (X bytes, until end of block)
The all-important AKCD block! It contains the compressed frame data itself. Let's take a look at the codecs:
Codec 1
This is the same codec as used in the old "COST" format. It works like this:
Byte Identification:
If NumColors = 32 then
5 bits for color, 3 bits for repeat.
Else if NumColors = 64 then
6 bits for color, 2 bits for repeat.
Else
4 bits for color, 4 bits for repeat.
For each byte in data:
If repeat = 0 then
repeat = next byte.
For repeat value:
Plot color at pixel. Advance row.
If row > height then
Back to original row. Advance column.
If column > width then
Done!
Codec 5
This is just BOMP disguised as an AKOS codec. It works like this:
For each row:
Code = next byte.
Repeat = (code >> 1) + 1.
If first bit in code is set then
Color = next byte.
For repeat value: Plot color at pixel. Advance column.
Else
For repeat value: Plot next byte at pixel. Advance column.
If column > width then next row!
Codec 16
This is the tricky one. It's a bit stream encoded thing that baffled the ScummVM developers for a while. Then one of them disassembled it and said, "This shouldn't be too hard," and implemented it. What the heck? I need somebody to explain it to me, really.
AkosView isn't dead! The next version will run in a window (using a magical thing called a DIBSection) and have improvements to its AKOS decoder. What I need is a way to extract AKOSes from SCUMM resource files so you don't have to use Scumm Revisited, preferably without going through the index file. Any help on this?
Nice one Nolan. I dont like bitstream stuff either, I tried to make an image/object viewer last week and I completely messed up the bitstream reading. I ended up about 10 bytes behind where I should have been every timeĀ¬
As for extracting AKOS' from resource files, you could just take the brute force approach.
Repeat until>EOF
Read 4 bytes to a BlockName var
If BlockName=LECF or LOFF or ROOM then - seek 4 bytes, past the block size
Else
begin
Read 4 bytes BE to a blocksize var
if Blockname=AKOS then
begin
A dumpfile procedure here.
Something like:
Seek -8 bytes so you are at the start of the block
Dump blocksize bytes to a file
Seek +8 bytes so the fileposition is back where it was for the loop
end
Seek BlockSize-8
end
This is simple to do in Delphi, I assume its just as easy in C++