https://wiki.scummvm.org/api.php?action=feedcontributions&user=Jestar+jokin&feedformat=atomScummVM :: Wiki - User contributions [en]2024-03-28T13:41:34ZUser contributionsMediaWiki 1.36.0https://wiki.scummvm.org/index.php?title=SCUMM/Technical_Reference/Index_File&diff=15955SCUMM/Technical Reference/Index File2011-02-19T07:51:31Z<p>Jestar jokin: Correct and clarify entries on AARY</p>
<hr />
<div>[[SCUMM/Technical Reference|SCUMM Technical Reference]] &rarr; ''SCUMM index file''<br />
<br />
<br />
= Introduction=<br />
<br />
Most of the information below are retrieved from the [http://scumm.mixnmojo.com/?page=specs&file=indexfiles.txt LucasHacks!] site and from the Pascal source code of the ''IndexFileReader 1.2'' (written by Ben Gorman (Bgbennyboy, http://quick.mixnmojo.com). In addition, ''ScummRevisited'' (written by Jimmi Thøgersen (Serge), http://www.mixnmojo.com/scumm/scummrev) turned out to be very useful in verifying the found offsets.<br />
<br />
The SCUMM index file contains special information to allow quick random access to the resources in the other game files. It also includes the room names and some max limits for the game. The following filenames are used:<br />
<br />
<br />
<table border="2" cellspacing="0" cellpadding="4"><br />
<tr><th width="100">filename</th><th>SCUMM version</th></tr><br />
<tr><td >00.lfl / 000.lfl</td><td>V3/4</td></tr><br />
<tr><td>.000</td><td>V5/6</td></tr><br />
<tr><td>.LA0</td><td>V7/8</td></tr><br />
</table><br />
<br />
<br />
Version 1 to 3 use hardcoded offsets and cannot be treated that easily. For the other games, the index file can be used to determine the [[SCUMM/Versions|SCUMM version]] because there have been slight changes in each version.<br />
<br />
* Version 4<br />
** the 5th and 6th byte match RN or OR<br />
* Version 5: <br />
** RNAM xor'ed with 0x69 at the beginning of the file<br />
** next 4 byte integer value xor'ed with 0x69 is &gt; 9<br />
* Version 6<br />
** RNAM xor'ed with 0x69 at the beginning<br />
** next 4 byte integer value xor'ed with 0x69 is 9 (actually it's the size of the chunk. In V6 games, no room names are stored so the size is 4 bytes (header) + 4 bytes (size) + 1 byte for the termination character).<br />
* Version 7<br />
** RNAM at the beginning of the file (not xor'ed this time)<br />
** next 4 bytes result in BE integer 9 (actually applies only to [[Full Throttle]])<br />
* Version 7 or 8<br />
** RNAM at the beginning of the file<br />
** next 4 bytes integer is &gt; 9<br />
<br />
<br />
How to distinguish between version 7 and 8? Not by looking at the first bytes, but the the size of the chunks is usually bigger because a 4 byte integer is used to store the number of objects.<br />
<br />
= Conventions =<br />
<br />
As usual, the [http://en.wikipedia.org/wiki/Endianness endianness (Wikipedia)] is important. Unless stated, little endianess (LE) is used. <br />
<br />
BE is used as abbreviation for big endianness. <br />
<br />
A '''Chunk''' is a named part of the file, e.g. RNAM. Each chunk has a header that contains at least the chunk name and its size. The following chunks are available:<br />
<br />
<br />
{| border="1" cellspacing="0" cellpadding="4"<br />
|RM Room Names<br />
|In V3/4<br />
|-<br />
|0R Directory Of Rooms<br />
|In V3/4<br />
|-<br />
|0S Directory Of Scripts<br />
|In V3/4<br />
|-<br />
|0N Directory Of Sounds<br />
|In V3/4<br />
|-<br />
|0C Directory Of Costumes<br />
|In V3/4<br />
|-<br />
|0O Directory Of Objects<br />
|In V3/4<br />
|-<br />
|RNAM Room Names<br />
|In V5+<br />
|-<br />
|MAXS Maximum Values<br />
|In V5+<br />
|-<br />
|DROO Directory of Rooms<br />
|In V5+<br />
|-<br />
|DSCR Directory of Scripts<br />
|In V5+<br />
|-<br />
|DSOU Directory of Sounds<br />
|In V5+<br />
|-<br />
|DCOS Directory of Costumes<br />
|In V5+<br />
|-<br />
|DCHR Directory of Charsets<br />
|In V5+<br />
|-<br />
|DOBJ Directory of Objects<br />
|In V5+<br />
|-<br />
|AARY List of Arrays<br />
|In V6+<br />
|-<br />
|ANAM Animation Names?<br />
|In V7<br />
|-<br />
|DRSC Direcory of Room Scripts<br />
|In V8<br />
|}<br />
<br />
= Scumm 3/4 =<br />
<br />
* File's aren't xor'ed<br />
<br />
To read in the data, the following pseudo-code can be used:<br />
<br />
Read Number of Items<br />
FROM 1 to "Number of Items" DO<br />
Read subvalue 1<br />
Read subvalue 2<br />
END<br />
<br />
<br />
==RN - Room names ==<br />
<br />
Block Size (4 bytes)<br />
Block Name (2 bytes)<br />
#Room No (1 byte)<br />
#Room Name (9 bytes) XOR'ed with FF<br />
Blank (00) byte (1 byte) Marks end of chunk<br />
<br />
<br />
==0R - Directory of Rooms==<br />
<br />
Block Size (4 bytes)<br />
Block Name (2 bytes)<br />
No of items (2 bytes)<br />
File Number (1 byte)<br />
Offset (4 bytes)<br />
<br />
''File Number'' is interesting if a game is splitted on multiple disks. 0 means ''not used''. <br />
<br />
For ''Offset'' only the value 0 seems to be used.<br />
<br />
==0S - Directory of Scripts ==<br />
<br />
Block Size (4 bytes)<br />
Block Name (2 bytes)<br />
No of items (2 bytes)<br />
Room Number (1 byte)<br />
Offset (4 bytes)<br />
<br />
The global scripts are stored in this directory. The offsets are relative to the room.<br />
<br />
==0N - Directory of Sounds ==<br />
<br />
Block Size (4 bytes)<br />
Block Name (2 bytes)<br />
No of items (2 bytes)<br />
Room Number (1 byte)<br />
Offset (4 bytes)<br />
<br />
Similar to scripts but holds indexes for sounds.<br />
<br />
==0C - Directory of Costumes ==<br />
<br />
Block Size (4 bytes)<br />
Block Name (2 bytes)<br />
No of items (2 bytes)<br />
Room Number (1 byte)<br />
Offset (4 bytes)<br />
<br />
Similar to scripts but holds indexes of customes. <br />
<br />
==0O - Directory of Objects==<br />
<br />
Block Size (4 bytes)<br />
Block Name (2 bytes)<br />
No of items (2 bytes)<br />
Class data (3 bytes)<br />
Owner+state (1 byte)<br />
<br />
The class data is LE. Class data can be as follows:<br />
<br />
No Class = 0<br />
kObjectClassYFlip = 18<br />
kObjectClassXFlip = 19<br />
kObjectClassNeverClip = 20<br />
kObjectClassAlwaysClip = 21<br />
kObjectClassIgnoreBoxes = 22<br />
kObjectClassPlayer = 23 // Actor is controlled by the player<br />
kObjectClassUntouchable = 24<br />
<br />
The Object owner and state are encoded in one byte. Example:<br />
<br />
0xA2 &rarr; Owner = 0xA, State = 0x2<br />
<br />
The pseudo decode code would be:<br />
<br />
Owner = ( (Owner+state Byte) AND 0xF0) >> 4<br />
State = (Owner+state Byte) AND 0x0F<br />
<br />
= Scumm 5 =<br />
<br />
* The files are xor'ed with 0x69<br />
<br />
== RNAM - Room Names ==<br />
<br />
Block Name (4 bytes)<br />
Block Size (4 bytes BE)<br />
#Room No (1 byte)<br />
#Room Name (9 bytes) XOR'ed with FF<br />
Blank (00) byte (1 byte) Marks end of chunk<br />
<br />
<br />
== MAXS ==<br />
<br />
Block Name (4 bytes)<br />
Block Size (4 bytes BE)<br />
Variables (2 bytes)<br />
Unknown (2 bytes)<br />
Bit Variables (2 bytes)<br />
Local Objects (2 bytes)<br />
New Names? (2 bytes)<br />
Character Sets (2 bytes)<br />
Verbs? (2 bytes)<br />
Array? (2 bytes)<br />
Inventory Objects (2 bytes)<br />
<br />
== DROO - Directory of Rooms ==<br />
<br />
Block Name (4 bytes)<br />
Block Size (4 bytes BE)<br />
No of items (2 bytes)<br />
*Room Number (1 byte)<br />
*Offset (4 bytes)<br />
<br />
The flow how to read in this kind of information has changed slightly from V3/4.<br />
<br />
Read "No of items"<br />
FROM 1 TO "No of items" DO<br />
Read "Room Number"<br />
END<br />
<br />
FROM 1 TO "No of items" DO<br />
Read "Offset"<br />
END<br />
<br />
First read in all room numbers, then read in all room offsets. <br />
<br />
<br />
== DSCR - Directory of Scripts ==<br />
<br />
Block Name (4 bytes)<br />
Block Size (4 bytes BE)<br />
No of items (2 bytes)<br />
*Room Number (1 byte)<br />
*Offset (4 bytes)<br />
<br />
Indexes for global scripts, see pseudo code above on how to read in the data.<br />
<br />
<br />
== DSOU - Directory of Sound == <br />
<br />
Block Name (4 bytes)<br />
Block Size (4 bytes BE)<br />
No of items (2 bytes)<br />
*Room Number (1 byte)<br />
*Offset (4 bytes)<br />
<br />
Indexes for sound objects.<br />
<br />
<br />
== DCOS - Directory of Costumes ==<br />
<br />
Block Name (4 bytes)<br />
Block Size (4 bytes BE)<br />
No of items (2 bytes)<br />
*Room Number (1 byte)<br />
*Offset (4 bytes)<br />
<br />
Indexes for costumes<br />
<br />
<br />
== DCHR - Director of Charsets ==<br />
<br />
Block Name (4 bytes)<br />
Block Size (4 bytes BE)<br />
No of items (2 bytes)<br />
*Room Number (1 byte)<br />
*Offset (4 bytes)<br />
<br />
Indexes for charsets.<br />
<br />
<br />
== DOBJ - Directory of Objects ==<br />
<br />
Block Name (4 bytes)<br />
Block Size (4 bytes BE)<br />
No of items (2 bytes)<br />
*Owner+state (1 byte)<br />
*Class data (4 bytes)<br />
<br />
Information about objects. See remarks in V3/4 section how the owner+state value should be interpreted. Note that the index files stores ALL owner+state values, followed by ALL class data values.<br />
<br />
Class data has change since V3/4:<br />
No class = 0<br />
kObjectClassNeverClip = 20<br />
kObjectClassAlwaysClip = 21<br />
kObjectClassIgnoreBoxes = 22<br />
kObjectClassYFlip = 29<br />
kObjectClassXFlip = 30<br />
kObjectClassPlayer = 31 // Actor is controlled by the player<br />
kObjectClassUntouchable = 32<br />
<br />
= Scumm 6 =<br />
<br />
* Files are xor'ed with 0x69<br />
<br />
<br />
== RNAM - Room Names ==<br />
<br />
Blank Byte(00) (1 byte)<br />
<br />
No room names are stored.<br />
<br />
<br />
== MAXS ==<br />
<br />
Block Name (4 bytes)<br />
Block Size (4 bytes BE)<br />
Variables (2 bytes)<br />
Unknown (2 bytes)<br />
Bit Variables (2 bytes)<br />
Local Objects (2 bytes)<br />
Arrays (2 bytes)<br />
Unknown (2 bytes)<br />
Verbs (2 bytes)<br />
Floating Objects (2 bytes)<br />
Inventory Objects (2 bytes)<br />
Rooms (2 bytes)<br />
Scripts (2 bytes)<br />
Sounds (2 bytes)<br />
Character Sets (2 bytes)<br />
Costumes (2 bytes)<br />
Global Objects (2 bytes)<br />
<br />
<br />
== DROO, DSCR, DSOU, DCOS, DCHR, DOBJ ==<br />
<br />
All as in V5<br />
<br />
<br />
== AARY - Array == <br />
<br />
Block Name (4 bytes)<br />
Block Size (4 bytes BE)<br />
#num (2 bytes) Stops if 0x0000<br />
#a (2 bytes)<br />
#b (2 bytes)<br />
#c (2 bytes)<br />
<br />
read num<br />
if num != 0:<br />
read a, b, c<br />
if c == 1:<br />
defineArray(num, kBitArray, a, b)<br />
else:<br />
defineArray(num, kIntArray, a, b)<br />
<br />
If num is 0, that marks the end of the AARY block, and there are no "a", "b", or "c" parameters afterwards.<br />
<br />
<br />
= Scumm 7 = <br />
<br />
* Files aren't xor'ed<br />
<br />
== RNAM - Room names ==<br />
<br />
* As in V6 ?!?!?!<br />
<br />
<br />
== MAXS ==<br />
<br />
Block Name (4 bytes)<br />
Block Size (4 bytes BE)<br />
Variables (2 bytes)<br />
Bit Variables (2 bytes)<br />
Unknown (2 bytes)<br />
Global Objects (2 bytes)<br />
Local Objects (2 bytes)<br />
New Names (2 bytes)<br />
Verbs (2 bytes)<br />
Floating Objects (2 bytes)<br />
Inventory Objects (2 bytes)<br />
Arrays (2 bytes)<br />
Rooms (2 bytes)<br />
Scripts (2 bytes)<br />
Sounds (2 bytes)<br />
Character Sets (2 bytes)<br />
Costumes (2 bytes)<br />
<br />
== AARY ==<br />
<br />
Mostly as in V6, except "Int" arrays are now "DWords".<br />
<br />
== DROO,DSCR,DSOU,DCOS,DCHR,DOBJ ==<br />
<br />
All as in V6<br />
<br />
<br />
== ANAM - Animation Names ==<br />
<br />
Block Name (4 bytes)<br />
Block Size (4 bytes BE)<br />
No of items (2 bytes<br />
#Name (8 bytes)<br />
#Blank (00) byte (1 byte)<br />
Blank (FF) byte (1 byte) Marks end of chunk<br />
<br />
<br />
= Scumm 8 =<br />
<br />
== RNAM - Room Names ==<br />
<br />
As in V6 ?<br />
<br />
<br />
== MAXS ==<br />
<br />
Block Name (4 bytes)<br />
Block Size (4 bytes BE)<br />
Variables (4 bytes)<br />
Bit Variables (4 bytes)<br />
Unknown (4 bytes)<br />
Scripts (4 bytes)<br />
Sounds (4 bytes)<br />
Character Sets (4 bytes)<br />
Costumes (4 bytes)<br />
Rooms (4 bytes)<br />
Unknown (4 bytes)<br />
Global Objects (4 bytes)<br />
Unknown (4 bytes)<br />
Local Objects (4 bytes)<br />
New Names (4 bytes)<br />
Floating Objects (4 bytes)<br />
Inventory Objects (4 bytes)<br />
Arrays (4 bytes)<br />
Verbs (4 bytes)<br />
<br />
<br />
== DROO - Directory of Rooms ==<br />
<br />
Block Name (4 bytes)<br />
Block Size (4 bytes BE)<br />
No of items (4 bytes)<br />
*Room Number (1 byte)<br />
*Offset (2 bytes)<br />
<br />
<br />
== DRSC - Directory of Room Scripts ==<br />
<br />
Block Name (4 bytes)<br />
Block Size (4 bytes BE)<br />
No of items (4 bytes)<br />
*Room Number (1 byte)<br />
*Offset (2 bytes)<br />
<br />
<br />
== DSCR - Directory of Scripts == <br />
<br />
Block Name (4 bytes)<br />
Block Size (4 bytes BE)<br />
No of items (4 bytes)<br />
*Room Number (1 byte)<br />
*Offset (2 bytes)<br />
<br />
<br />
== DSOU - Directory of Sound ==<br />
<br />
Block Name (4 bytes)<br />
Block Size (4 bytes BE)<br />
No of items (4 bytes)<br />
*Room Number (1 byte)<br />
*Offset (2 bytes)<br />
<br />
<br />
== DCOS - Directory of Costumes ==<br />
<br />
Block Name (4 bytes)<br />
Block Size (4 bytes BE)<br />
No of items (4 bytes)<br />
*Room Number (1 byte)<br />
*Offset (2 bytes)<br />
<br />
<br />
== DCHR - Directory of Charsets ==<br />
<br />
Block Name (4 bytes)<br />
Block Size (4 bytes BE)<br />
No of items (4 bytes)<br />
*Room Number (1 byte)<br />
*Offset (2 bytes)<br />
<br />
<br />
== AARY ==<br />
<br />
Mostly as in V7. AARY only has "a" and "b" parameters. "b" determines the order of the parameters when creating the array.<br />
<br />
Block Name (4 bytes)<br />
Block Size (4 bytes BE)<br />
#num (4 bytes) Stops if 0x00000000<br />
#a (4 bytes)<br />
#b (4 bytes)<br />
<br />
while num != 0:<br />
read a and b<br />
if b != 0:<br />
defineArray(num, kIntArray, b, a)<br />
else:<br />
defineArray(num, kIntArray, a, b)<br />
<br />
<br />
== DOBJ == <br />
<br />
As in V7.<br />
<br />
<br />
[[Category: SCUMM Technical Reference]]</div>Jestar jokinhttps://wiki.scummvm.org/index.php?title=User:Jestar_jokin&diff=15193User:Jestar jokin2010-10-21T12:30:50Z<p>Jestar jokin: </p>
<hr />
<div>HI! Let's have a party, just you and me and everyone we know! WOOOOHOOOO<br />
<br />
I have been mucking around hacking SCUMM games, which is only possible thanks to the fantastic work done by the ScummVM team and all the other reverse engineers out there.<br />
<br />
I have developed a few tools that let you modify or create SCUMM ''V5'' resources:<br />
* Scummbler - compiles SCUMM V3, 4, and 5 scripts from the text scripts based on descumm's output. This makes it relatively easy to modify existing script resources in a game.<br />
* ScummPacker - extract & repack the resource files of SCUMM V5 games. You can add new content to games, such as scripts created with Scummbler, or backgrounds created with SCUMM Image Encoder.<br />
* ScummSpeaks - making use of ScummTr, allows you to map sounds in a MONSTER.SOU file (compressed through ScummVM tools) to lines of text. Useful for re-dubbing translated games, or adding speech to sounds that did not originally have it.<br />
* SCUMM Image Encoder (mi2img) - convert between background resources extracted by ScummPacker and PNG files. It can only encode "lossless" backgrounds with a limited palette (around 160 colours).<br />
<br />
These are all made in Python. You can find them on [http://www.jestarjokin.net/ my website].<br />
<br />
Aside from plugging my toys on this wiki, I also hope to share the knowledge of SCUMM I've picked up in my adventures.<br />
<br />
(Also my name should be in lowercase, but MediaWiki is rubbish when it comes to rubbish names.)</div>Jestar jokinhttps://wiki.scummvm.org/index.php?title=SCUMM/Technical_Reference/Index_File&diff=14772SCUMM/Technical Reference/Index File2010-09-17T12:28:02Z<p>Jestar jokin: /* Conventions */ whoops, fix table</p>
<hr />
<div>[[SCUMM/Technical Reference|SCUMM Technical Reference]] &rarr; ''SCUMM index file''<br />
<br />
<br />
= Introduction=<br />
<br />
Most of the information below are retrieved from the [http://scumm.mixnmojo.com/?page=specs&file=indexfiles.txt LucasHacks!] site and from the Pascal source code of the ''IndexFileReader 1.2'' (written by Ben Gorman (Bgbennyboy, http://quick.mixnmojo.com). In addition, ''ScummRevisited'' (written by Jimmi Thøgersen (Serge), http://www.mixnmojo.com/scumm/scummrev) turned out to be very useful in verifying the found offsets.<br />
<br />
The SCUMM index file contains special information to allow quick random access to the resources in the other game files. It also includes the room names and some max limits for the game. The following filenames are used:<br />
<br />
<br />
<table border="2" cellspacing="0" cellpadding="4"><br />
<tr><th width="100">filename</th><th>SCUMM version</th></tr><br />
<tr><td >00.lfl / 000.lfl</td><td>V3/4</td></tr><br />
<tr><td>.000</td><td>V5/6</td></tr><br />
<tr><td>.LA0</td><td>V7/8</td></tr><br />
</table><br />
<br />
<br />
Version 1 to 3 use hardcoded offsets and cannot be treated that easily. For the other games, the index file can be used to determine the [[SCUMM/Versions|SCUMM version]] because there have been slight changes in each version.<br />
<br />
* Version 4<br />
** the 5th and 6th byte match RN or OR<br />
* Version 5: <br />
** RNAM xor'ed with 0x69 at the beginning of the file<br />
** next 4 byte integer value xor'ed with 0x69 is &gt; 9<br />
* Version 6<br />
** RNAM xor'ed with 0x69 at the beginning<br />
** next 4 byte integer value xor'ed with 0x69 is 9 (actually it's the size of the chunk. In V6 games, no room names are stored so the size is 4 bytes (header) + 4 bytes (size) + 1 byte for the termination character).<br />
* Version 7<br />
** RNAM at the beginning of the file (not xor'ed this time)<br />
** next 4 bytes result in BE integer 9 (actually applies only to [[Full Throttle]])<br />
* Version 7 or 8<br />
** RNAM at the beginning of the file<br />
** next 4 bytes integer is &gt; 9<br />
<br />
<br />
How to distinguish between version 7 and 8? Not by looking at the first bytes, but the the size of the chunks is usually bigger because a 4 byte integer is used to store the number of objects.<br />
<br />
= Conventions =<br />
<br />
As usual, the [http://en.wikipedia.org/wiki/Endianness endianness (Wikipedia)] is important. Unless stated, little endianess (LE) is used. <br />
<br />
BE is used as abbreviation for big endianness. <br />
<br />
A '''Chunk''' is a named part of the file, e.g. RNAM. Each chunk has a header that contains at least the chunk name and its size. The following chunks are available:<br />
<br />
<br />
{| border="1" cellspacing="0" cellpadding="4"<br />
|RM Room Names<br />
|In V3/4<br />
|-<br />
|0R Directory Of Rooms<br />
|In V3/4<br />
|-<br />
|0S Directory Of Scripts<br />
|In V3/4<br />
|-<br />
|0N Directory Of Sounds<br />
|In V3/4<br />
|-<br />
|0C Directory Of Costumes<br />
|In V3/4<br />
|-<br />
|0O Directory Of Objects<br />
|In V3/4<br />
|-<br />
|RNAM Room Names<br />
|In V5+<br />
|-<br />
|MAXS Maximum Values<br />
|In V5+<br />
|-<br />
|DROO Directory of Rooms<br />
|In V5+<br />
|-<br />
|DSCR Directory of Scripts<br />
|In V5+<br />
|-<br />
|DSOU Directory of Sounds<br />
|In V5+<br />
|-<br />
|DCOS Directory of Costumes<br />
|In V5+<br />
|-<br />
|DCHR Directory of Charsets<br />
|In V5+<br />
|-<br />
|DOBJ Directory of Objects<br />
|In V5+<br />
|-<br />
|AARY List of Arrays<br />
|In V6+<br />
|-<br />
|ANAM Animation Names?<br />
|In V7<br />
|-<br />
|DRSC Direcory of Room Scripts<br />
|In V8<br />
|}<br />
<br />
= Scumm 3/4 =<br />
<br />
* File's aren't xor'ed<br />
<br />
To read in the data, the following pseudo-code can be used:<br />
<br />
Read Number of Items<br />
FROM 1 to "Number of Items" DO<br />
Read subvalue 1<br />
Read subvalue 2<br />
END<br />
<br />
<br />
==RN - Room names ==<br />
<br />
Block Size (4 bytes)<br />
Block Name (2 bytes)<br />
#Room No (1 byte)<br />
#Room Name (9 bytes) XOR'ed with FF<br />
Blank (00) byte (1 byte) Marks end of chunk<br />
<br />
<br />
==0R - Directory of Rooms==<br />
<br />
Block Size (4 bytes)<br />
Block Name (2 bytes)<br />
No of items (2 bytes)<br />
File Number (1 byte)<br />
Offset (4 bytes)<br />
<br />
''File Number'' is interesting if a game is splitted on multiple disks. 0 means ''not used''. <br />
<br />
For ''Offset'' only the value 0 seems to be used.<br />
<br />
==0S - Directory of Scripts ==<br />
<br />
Block Size (4 bytes)<br />
Block Name (2 bytes)<br />
No of items (2 bytes)<br />
Room Number (1 byte)<br />
Offset (4 bytes)<br />
<br />
The global scripts are stored in this directory. The offsets are relative to the room.<br />
<br />
==0N - Directory of Sounds ==<br />
<br />
Block Size (4 bytes)<br />
Block Name (2 bytes)<br />
No of items (2 bytes)<br />
Room Number (1 byte)<br />
Offset (4 bytes)<br />
<br />
Similar to scripts but holds indexes for sounds.<br />
<br />
==0C - Directory of Costumes ==<br />
<br />
Block Size (4 bytes)<br />
Block Name (2 bytes)<br />
No of items (2 bytes)<br />
Room Number (1 byte)<br />
Offset (4 bytes)<br />
<br />
Similar to scripts but holds indexes of customes. <br />
<br />
==0O - Directory of Objects==<br />
<br />
Block Size (4 bytes)<br />
Block Name (2 bytes)<br />
No of items (2 bytes)<br />
Class data (3 bytes)<br />
Owner+state (1 byte)<br />
<br />
The class data is LE. Class data can be as follows:<br />
<br />
No Class = 0<br />
kObjectClassYFlip = 18<br />
kObjectClassXFlip = 19<br />
kObjectClassNeverClip = 20<br />
kObjectClassAlwaysClip = 21<br />
kObjectClassIgnoreBoxes = 22<br />
kObjectClassPlayer = 23 // Actor is controlled by the player<br />
kObjectClassUntouchable = 24<br />
<br />
The Object owner and state are encoded in one byte. Example:<br />
<br />
0xA2 &rarr; Owner = 0xA, State = 0x2<br />
<br />
The pseudo decode code would be:<br />
<br />
Owner = ( (Owner+state Byte) AND 0xF0) >> 4<br />
State = (Owner+state Byte) AND 0x0F<br />
<br />
= Scumm 5 =<br />
<br />
* The files are xor'ed with 0x69<br />
<br />
== RNAM - Room Names ==<br />
<br />
Block Name (4 bytes)<br />
Block Size (4 bytes BE)<br />
#Room No (1 byte)<br />
#Room Name (9 bytes) XOR'ed with FF<br />
Blank (00) byte (1 byte) Marks end of chunk<br />
<br />
<br />
== MAXS ==<br />
<br />
Block Name (4 bytes)<br />
Block Size (4 bytes BE)<br />
Variables (2 bytes)<br />
Unknown (2 bytes)<br />
Bit Variables (2 bytes)<br />
Local Objects (2 bytes)<br />
New Names? (2 bytes)<br />
Character Sets (2 bytes)<br />
Verbs? (2 bytes)<br />
Array? (2 bytes)<br />
Inventory Objects (2 bytes)<br />
<br />
== DROO - Directory of Rooms ==<br />
<br />
Block Name (4 bytes)<br />
Block Size (4 bytes BE)<br />
No of items (2 bytes)<br />
*Room Number (1 byte)<br />
*Offset (4 bytes)<br />
<br />
The flow how to read in this kind of information has changed slightly from V3/4.<br />
<br />
Read "No of items"<br />
FROM 1 TO "No of items" DO<br />
Read "Room Number"<br />
END<br />
<br />
FROM 1 TO "No of items" DO<br />
Read "Offset"<br />
END<br />
<br />
First read in all room numbers, then read in all room offsets. <br />
<br />
<br />
== DSCR - Directory of Scripts ==<br />
<br />
Block Name (4 bytes)<br />
Block Size (4 bytes BE)<br />
No of items (2 bytes)<br />
*Room Number (1 byte)<br />
*Offset (4 bytes)<br />
<br />
Indexes for global scripts, see pseudo code above on how to read in the data.<br />
<br />
<br />
== DSOU - Directory of Sound == <br />
<br />
Block Name (4 bytes)<br />
Block Size (4 bytes BE)<br />
No of items (2 bytes)<br />
*Room Number (1 byte)<br />
*Offset (4 bytes)<br />
<br />
Indexes for sound objects.<br />
<br />
<br />
== DCOS - Directory of Costumes ==<br />
<br />
Block Name (4 bytes)<br />
Block Size (4 bytes BE)<br />
No of items (2 bytes)<br />
*Room Number (1 byte)<br />
*Offset (4 bytes)<br />
<br />
Indexes for costumes<br />
<br />
<br />
== DCHR - Director of Charsets ==<br />
<br />
Block Name (4 bytes)<br />
Block Size (4 bytes BE)<br />
No of items (2 bytes)<br />
*Room Number (1 byte)<br />
*Offset (4 bytes)<br />
<br />
Indexes for charsets.<br />
<br />
<br />
== DOBJ - Directory of Objects ==<br />
<br />
Block Name (4 bytes)<br />
Block Size (4 bytes BE)<br />
No of items (2 bytes)<br />
*Owner+state (1 byte)<br />
*Class data (4 bytes)<br />
<br />
Information about objects. See remarks in V3/4 section how the owner+state value should be interpreted. Note that the index files stores ALL owner+state values, followed by ALL class data values.<br />
<br />
Class data has change since V3/4:<br />
No class = 0<br />
kObjectClassNeverClip = 20<br />
kObjectClassAlwaysClip = 21<br />
kObjectClassIgnoreBoxes = 22<br />
kObjectClassYFlip = 29<br />
kObjectClassXFlip = 30<br />
kObjectClassPlayer = 31 // Actor is controlled by the player<br />
kObjectClassUntouchable = 32<br />
<br />
= Scumm 6 =<br />
<br />
* Files are xor'ed with 0x69<br />
<br />
<br />
== RNAM - Room Names ==<br />
<br />
Blank Byte(00) (1 byte)<br />
<br />
No room names are stored.<br />
<br />
<br />
== MAXS ==<br />
<br />
Block Name (4 bytes)<br />
Block Size (4 bytes BE)<br />
Variables (2 bytes)<br />
Unknown (2 bytes)<br />
Bit Variables (2 bytes)<br />
Local Objects (2 bytes)<br />
Arrays (2 bytes)<br />
Unknown (2 bytes)<br />
Verbs (2 bytes)<br />
Floating Objects (2 bytes)<br />
Inventory Objects (2 bytes)<br />
Rooms (2 bytes)<br />
Scripts (2 bytes)<br />
Sounds (2 bytes)<br />
Character Sets (2 bytes)<br />
Costumes (2 bytes)<br />
Global Objects (2 bytes)<br />
<br />
<br />
== DROO, DSCR, DSOU, DCOS, DCHR, DOBJ ==<br />
<br />
All as in V5<br />
<br />
<br />
== AARY - Array == <br />
<br />
Block Name (4 bytes)<br />
Block Size (4 bytes BE)<br />
#Stop (2 bytes) Stops if 0x0000<br />
#A (2 bytes)<br />
#B (2 bytes)<br />
#C (2 bytes)<br />
<br />
num=AARY no (itinerate through in loop)<br />
if c=1 then<br />
AARY=(num, 1, a, b)<br />
else<br />
AARY=(num, 1, a, b)<br />
<br />
If stop=0 you dont seek past the 6 bytes of A,B,C you just start the loop again.<br />
<br />
<br />
= Scumm 7 = <br />
<br />
* Files aren't xor'ed<br />
<br />
== RNAM - Room names ==<br />
<br />
* As in V6 ?!?!?!<br />
<br />
<br />
== MAXS ==<br />
<br />
Block Name (4 bytes)<br />
Block Size (4 bytes BE)<br />
Variables (2 bytes)<br />
Bit Variables (2 bytes)<br />
Unknown (2 bytes)<br />
Global Objects (2 bytes)<br />
Local Objects (2 bytes)<br />
New Names (2 bytes)<br />
Verbs (2 bytes)<br />
Floating Objects (2 bytes)<br />
Inventory Objects (2 bytes)<br />
Arrays (2 bytes)<br />
Rooms (2 bytes)<br />
Scripts (2 bytes)<br />
Sounds (2 bytes)<br />
Character Sets (2 bytes)<br />
Costumes (2 bytes)<br />
<br />
<br />
== DROO,DSCR,DSOU,DCOS,DCHR,DOBJ,AARY ==<br />
<br />
All as in V5<br />
<br />
<br />
== ANAM - Animation Names ==<br />
<br />
Block Name (4 bytes)<br />
Block Size (4 bytes BE)<br />
No of items (2 bytes<br />
#Name (8 bytes)<br />
#Blank (00) byte (1 byte)<br />
Blank (FF) byte (1 byte) Marks end of chunk<br />
<br />
<br />
= Scumm 8 =<br />
<br />
== RNAM - Room Names ==<br />
<br />
As in V6 ?<br />
<br />
<br />
== MAXS ==<br />
<br />
Block Name (4 bytes)<br />
Block Size (4 bytes BE)<br />
Variables (4 bytes)<br />
Bit Variables (4 bytes)<br />
Unknown (4 bytes)<br />
Scripts (4 bytes)<br />
Sounds (4 bytes)<br />
Character Sets (4 bytes)<br />
Costumes (4 bytes)<br />
Rooms (4 bytes)<br />
Unknown (4 bytes)<br />
Global Objects (4 bytes)<br />
Unknown (4 bytes)<br />
Local Objects (4 bytes)<br />
New Names (4 bytes)<br />
Floating Objects (4 bytes)<br />
Inventory Objects (4 bytes)<br />
Arrays (4 bytes)<br />
Verbs (4 bytes)<br />
<br />
<br />
== DROO - Directory of Rooms ==<br />
<br />
Block Name (4 bytes)<br />
Block Size (4 bytes BE)<br />
No of items (4 bytes)<br />
*Room Number (1 byte)<br />
*Offset (2 bytes)<br />
<br />
<br />
== DRSC - Directory of Room Scripts ==<br />
<br />
Block Name (4 bytes)<br />
Block Size (4 bytes BE)<br />
No of items (4 bytes)<br />
*Room Number (1 byte)<br />
*Offset (2 bytes)<br />
<br />
<br />
== DSCR - Directory of Scripts == <br />
<br />
Block Name (4 bytes)<br />
Block Size (4 bytes BE)<br />
No of items (4 bytes)<br />
*Room Number (1 byte)<br />
*Offset (2 bytes)<br />
<br />
<br />
== DSOU - Directory of Sound ==<br />
<br />
Block Name (4 bytes)<br />
Block Size (4 bytes BE)<br />
No of items (4 bytes)<br />
*Room Number (1 byte)<br />
*Offset (2 bytes)<br />
<br />
<br />
== DCOS - Directory of Costumes ==<br />
<br />
Block Name (4 bytes)<br />
Block Size (4 bytes BE)<br />
No of items (4 bytes)<br />
*Room Number (1 byte)<br />
*Offset (2 bytes)<br />
<br />
<br />
== DCHR - Directory of Charsets ==<br />
<br />
Block Name (4 bytes)<br />
Block Size (4 bytes BE)<br />
No of items (4 bytes)<br />
*Room Number (1 byte)<br />
*Offset (2 bytes)<br />
<br />
<br />
== DOBJ,AARY ==<br />
<br />
As in V7<br />
<br />
<br />
[[Category: SCUMM Technical Reference]]</div>Jestar jokinhttps://wiki.scummvm.org/index.php?title=SCUMM/Technical_Reference/Index_File&diff=14771SCUMM/Technical Reference/Index File2010-09-17T12:27:07Z<p>Jestar jokin: /* Conventions */ sort table by SCUMM version. remove question marks.</p>
<hr />
<div>[[SCUMM/Technical Reference|SCUMM Technical Reference]] &rarr; ''SCUMM index file''<br />
<br />
<br />
= Introduction=<br />
<br />
Most of the information below are retrieved from the [http://scumm.mixnmojo.com/?page=specs&file=indexfiles.txt LucasHacks!] site and from the Pascal source code of the ''IndexFileReader 1.2'' (written by Ben Gorman (Bgbennyboy, http://quick.mixnmojo.com). In addition, ''ScummRevisited'' (written by Jimmi Thøgersen (Serge), http://www.mixnmojo.com/scumm/scummrev) turned out to be very useful in verifying the found offsets.<br />
<br />
The SCUMM index file contains special information to allow quick random access to the resources in the other game files. It also includes the room names and some max limits for the game. The following filenames are used:<br />
<br />
<br />
<table border="2" cellspacing="0" cellpadding="4"><br />
<tr><th width="100">filename</th><th>SCUMM version</th></tr><br />
<tr><td >00.lfl / 000.lfl</td><td>V3/4</td></tr><br />
<tr><td>.000</td><td>V5/6</td></tr><br />
<tr><td>.LA0</td><td>V7/8</td></tr><br />
</table><br />
<br />
<br />
Version 1 to 3 use hardcoded offsets and cannot be treated that easily. For the other games, the index file can be used to determine the [[SCUMM/Versions|SCUMM version]] because there have been slight changes in each version.<br />
<br />
* Version 4<br />
** the 5th and 6th byte match RN or OR<br />
* Version 5: <br />
** RNAM xor'ed with 0x69 at the beginning of the file<br />
** next 4 byte integer value xor'ed with 0x69 is &gt; 9<br />
* Version 6<br />
** RNAM xor'ed with 0x69 at the beginning<br />
** next 4 byte integer value xor'ed with 0x69 is 9 (actually it's the size of the chunk. In V6 games, no room names are stored so the size is 4 bytes (header) + 4 bytes (size) + 1 byte for the termination character).<br />
* Version 7<br />
** RNAM at the beginning of the file (not xor'ed this time)<br />
** next 4 bytes result in BE integer 9 (actually applies only to [[Full Throttle]])<br />
* Version 7 or 8<br />
** RNAM at the beginning of the file<br />
** next 4 bytes integer is &gt; 9<br />
<br />
<br />
How to distinguish between version 7 and 8? Not by looking at the first bytes, but the the size of the chunks is usually bigger because a 4 byte integer is used to store the number of objects.<br />
<br />
= Conventions =<br />
<br />
As usual, the [http://en.wikipedia.org/wiki/Endianness endianness (Wikipedia)] is important. Unless stated, little endianess (LE) is used. <br />
<br />
BE is used as abbreviation for big endianness. <br />
<br />
A '''Chunk''' is a named part of the file, e.g. RNAM. Each chunk has a header that contains at least the chunk name and its size. The following chunks are available:<br />
<br />
<br />
{| border="1" cellspacing="0" cellpadding="4"<br />
|RNAM Room Names<br />
|RM Room Names<br />
|In V3/4<br />
|-<br />
|0R Directory Of Rooms<br />
|In V3/4<br />
|-<br />
|0S Directory Of Scripts<br />
|In V3/4<br />
|-<br />
|0N Directory Of Sounds<br />
|In V3/4<br />
|-<br />
|0C Directory Of Costumes<br />
|In V3/4<br />
|-<br />
|0O Directory Of Objects<br />
|In V3/4<br />
|-<br />
|In V5+<br />
|-<br />
|MAXS Maximum Values<br />
|In V5+<br />
|-<br />
|DROO Directory of Rooms<br />
|In V5+<br />
|-<br />
|DSCR Directory of Scripts<br />
|In V5+<br />
|-<br />
|DSOU Directory of Sounds<br />
|In V5+<br />
|-<br />
|DCOS Directory of Costumes<br />
|In V5+<br />
|-<br />
|DCHR Directory of Charsets<br />
|In V5+<br />
|-<br />
|DOBJ Directory of Objects<br />
|In V5+<br />
|-<br />
|AARY List of Arrays<br />
|In V6+<br />
|-<br />
|ANAM Animation Names?<br />
|In V7<br />
|-<br />
|DRSC Direcory of Room Scripts<br />
|In V8<br />
|}<br />
<br />
= Scumm 3/4 =<br />
<br />
* File's aren't xor'ed<br />
<br />
To read in the data, the following pseudo-code can be used:<br />
<br />
Read Number of Items<br />
FROM 1 to "Number of Items" DO<br />
Read subvalue 1<br />
Read subvalue 2<br />
END<br />
<br />
<br />
==RN - Room names ==<br />
<br />
Block Size (4 bytes)<br />
Block Name (2 bytes)<br />
#Room No (1 byte)<br />
#Room Name (9 bytes) XOR'ed with FF<br />
Blank (00) byte (1 byte) Marks end of chunk<br />
<br />
<br />
==0R - Directory of Rooms==<br />
<br />
Block Size (4 bytes)<br />
Block Name (2 bytes)<br />
No of items (2 bytes)<br />
File Number (1 byte)<br />
Offset (4 bytes)<br />
<br />
''File Number'' is interesting if a game is splitted on multiple disks. 0 means ''not used''. <br />
<br />
For ''Offset'' only the value 0 seems to be used.<br />
<br />
==0S - Directory of Scripts ==<br />
<br />
Block Size (4 bytes)<br />
Block Name (2 bytes)<br />
No of items (2 bytes)<br />
Room Number (1 byte)<br />
Offset (4 bytes)<br />
<br />
The global scripts are stored in this directory. The offsets are relative to the room.<br />
<br />
==0N - Directory of Sounds ==<br />
<br />
Block Size (4 bytes)<br />
Block Name (2 bytes)<br />
No of items (2 bytes)<br />
Room Number (1 byte)<br />
Offset (4 bytes)<br />
<br />
Similar to scripts but holds indexes for sounds.<br />
<br />
==0C - Directory of Costumes ==<br />
<br />
Block Size (4 bytes)<br />
Block Name (2 bytes)<br />
No of items (2 bytes)<br />
Room Number (1 byte)<br />
Offset (4 bytes)<br />
<br />
Similar to scripts but holds indexes of customes. <br />
<br />
==0O - Directory of Objects==<br />
<br />
Block Size (4 bytes)<br />
Block Name (2 bytes)<br />
No of items (2 bytes)<br />
Class data (3 bytes)<br />
Owner+state (1 byte)<br />
<br />
The class data is LE. Class data can be as follows:<br />
<br />
No Class = 0<br />
kObjectClassYFlip = 18<br />
kObjectClassXFlip = 19<br />
kObjectClassNeverClip = 20<br />
kObjectClassAlwaysClip = 21<br />
kObjectClassIgnoreBoxes = 22<br />
kObjectClassPlayer = 23 // Actor is controlled by the player<br />
kObjectClassUntouchable = 24<br />
<br />
The Object owner and state are encoded in one byte. Example:<br />
<br />
0xA2 &rarr; Owner = 0xA, State = 0x2<br />
<br />
The pseudo decode code would be:<br />
<br />
Owner = ( (Owner+state Byte) AND 0xF0) >> 4<br />
State = (Owner+state Byte) AND 0x0F<br />
<br />
= Scumm 5 =<br />
<br />
* The files are xor'ed with 0x69<br />
<br />
== RNAM - Room Names ==<br />
<br />
Block Name (4 bytes)<br />
Block Size (4 bytes BE)<br />
#Room No (1 byte)<br />
#Room Name (9 bytes) XOR'ed with FF<br />
Blank (00) byte (1 byte) Marks end of chunk<br />
<br />
<br />
== MAXS ==<br />
<br />
Block Name (4 bytes)<br />
Block Size (4 bytes BE)<br />
Variables (2 bytes)<br />
Unknown (2 bytes)<br />
Bit Variables (2 bytes)<br />
Local Objects (2 bytes)<br />
New Names? (2 bytes)<br />
Character Sets (2 bytes)<br />
Verbs? (2 bytes)<br />
Array? (2 bytes)<br />
Inventory Objects (2 bytes)<br />
<br />
== DROO - Directory of Rooms ==<br />
<br />
Block Name (4 bytes)<br />
Block Size (4 bytes BE)<br />
No of items (2 bytes)<br />
*Room Number (1 byte)<br />
*Offset (4 bytes)<br />
<br />
The flow how to read in this kind of information has changed slightly from V3/4.<br />
<br />
Read "No of items"<br />
FROM 1 TO "No of items" DO<br />
Read "Room Number"<br />
END<br />
<br />
FROM 1 TO "No of items" DO<br />
Read "Offset"<br />
END<br />
<br />
First read in all room numbers, then read in all room offsets. <br />
<br />
<br />
== DSCR - Directory of Scripts ==<br />
<br />
Block Name (4 bytes)<br />
Block Size (4 bytes BE)<br />
No of items (2 bytes)<br />
*Room Number (1 byte)<br />
*Offset (4 bytes)<br />
<br />
Indexes for global scripts, see pseudo code above on how to read in the data.<br />
<br />
<br />
== DSOU - Directory of Sound == <br />
<br />
Block Name (4 bytes)<br />
Block Size (4 bytes BE)<br />
No of items (2 bytes)<br />
*Room Number (1 byte)<br />
*Offset (4 bytes)<br />
<br />
Indexes for sound objects.<br />
<br />
<br />
== DCOS - Directory of Costumes ==<br />
<br />
Block Name (4 bytes)<br />
Block Size (4 bytes BE)<br />
No of items (2 bytes)<br />
*Room Number (1 byte)<br />
*Offset (4 bytes)<br />
<br />
Indexes for costumes<br />
<br />
<br />
== DCHR - Director of Charsets ==<br />
<br />
Block Name (4 bytes)<br />
Block Size (4 bytes BE)<br />
No of items (2 bytes)<br />
*Room Number (1 byte)<br />
*Offset (4 bytes)<br />
<br />
Indexes for charsets.<br />
<br />
<br />
== DOBJ - Directory of Objects ==<br />
<br />
Block Name (4 bytes)<br />
Block Size (4 bytes BE)<br />
No of items (2 bytes)<br />
*Owner+state (1 byte)<br />
*Class data (4 bytes)<br />
<br />
Information about objects. See remarks in V3/4 section how the owner+state value should be interpreted. Note that the index files stores ALL owner+state values, followed by ALL class data values.<br />
<br />
Class data has change since V3/4:<br />
No class = 0<br />
kObjectClassNeverClip = 20<br />
kObjectClassAlwaysClip = 21<br />
kObjectClassIgnoreBoxes = 22<br />
kObjectClassYFlip = 29<br />
kObjectClassXFlip = 30<br />
kObjectClassPlayer = 31 // Actor is controlled by the player<br />
kObjectClassUntouchable = 32<br />
<br />
= Scumm 6 =<br />
<br />
* Files are xor'ed with 0x69<br />
<br />
<br />
== RNAM - Room Names ==<br />
<br />
Blank Byte(00) (1 byte)<br />
<br />
No room names are stored.<br />
<br />
<br />
== MAXS ==<br />
<br />
Block Name (4 bytes)<br />
Block Size (4 bytes BE)<br />
Variables (2 bytes)<br />
Unknown (2 bytes)<br />
Bit Variables (2 bytes)<br />
Local Objects (2 bytes)<br />
Arrays (2 bytes)<br />
Unknown (2 bytes)<br />
Verbs (2 bytes)<br />
Floating Objects (2 bytes)<br />
Inventory Objects (2 bytes)<br />
Rooms (2 bytes)<br />
Scripts (2 bytes)<br />
Sounds (2 bytes)<br />
Character Sets (2 bytes)<br />
Costumes (2 bytes)<br />
Global Objects (2 bytes)<br />
<br />
<br />
== DROO, DSCR, DSOU, DCOS, DCHR, DOBJ ==<br />
<br />
All as in V5<br />
<br />
<br />
== AARY - Array == <br />
<br />
Block Name (4 bytes)<br />
Block Size (4 bytes BE)<br />
#Stop (2 bytes) Stops if 0x0000<br />
#A (2 bytes)<br />
#B (2 bytes)<br />
#C (2 bytes)<br />
<br />
num=AARY no (itinerate through in loop)<br />
if c=1 then<br />
AARY=(num, 1, a, b)<br />
else<br />
AARY=(num, 1, a, b)<br />
<br />
If stop=0 you dont seek past the 6 bytes of A,B,C you just start the loop again.<br />
<br />
<br />
= Scumm 7 = <br />
<br />
* Files aren't xor'ed<br />
<br />
== RNAM - Room names ==<br />
<br />
* As in V6 ?!?!?!<br />
<br />
<br />
== MAXS ==<br />
<br />
Block Name (4 bytes)<br />
Block Size (4 bytes BE)<br />
Variables (2 bytes)<br />
Bit Variables (2 bytes)<br />
Unknown (2 bytes)<br />
Global Objects (2 bytes)<br />
Local Objects (2 bytes)<br />
New Names (2 bytes)<br />
Verbs (2 bytes)<br />
Floating Objects (2 bytes)<br />
Inventory Objects (2 bytes)<br />
Arrays (2 bytes)<br />
Rooms (2 bytes)<br />
Scripts (2 bytes)<br />
Sounds (2 bytes)<br />
Character Sets (2 bytes)<br />
Costumes (2 bytes)<br />
<br />
<br />
== DROO,DSCR,DSOU,DCOS,DCHR,DOBJ,AARY ==<br />
<br />
All as in V5<br />
<br />
<br />
== ANAM - Animation Names ==<br />
<br />
Block Name (4 bytes)<br />
Block Size (4 bytes BE)<br />
No of items (2 bytes<br />
#Name (8 bytes)<br />
#Blank (00) byte (1 byte)<br />
Blank (FF) byte (1 byte) Marks end of chunk<br />
<br />
<br />
= Scumm 8 =<br />
<br />
== RNAM - Room Names ==<br />
<br />
As in V6 ?<br />
<br />
<br />
== MAXS ==<br />
<br />
Block Name (4 bytes)<br />
Block Size (4 bytes BE)<br />
Variables (4 bytes)<br />
Bit Variables (4 bytes)<br />
Unknown (4 bytes)<br />
Scripts (4 bytes)<br />
Sounds (4 bytes)<br />
Character Sets (4 bytes)<br />
Costumes (4 bytes)<br />
Rooms (4 bytes)<br />
Unknown (4 bytes)<br />
Global Objects (4 bytes)<br />
Unknown (4 bytes)<br />
Local Objects (4 bytes)<br />
New Names (4 bytes)<br />
Floating Objects (4 bytes)<br />
Inventory Objects (4 bytes)<br />
Arrays (4 bytes)<br />
Verbs (4 bytes)<br />
<br />
<br />
== DROO - Directory of Rooms ==<br />
<br />
Block Name (4 bytes)<br />
Block Size (4 bytes BE)<br />
No of items (4 bytes)<br />
*Room Number (1 byte)<br />
*Offset (2 bytes)<br />
<br />
<br />
== DRSC - Directory of Room Scripts ==<br />
<br />
Block Name (4 bytes)<br />
Block Size (4 bytes BE)<br />
No of items (4 bytes)<br />
*Room Number (1 byte)<br />
*Offset (2 bytes)<br />
<br />
<br />
== DSCR - Directory of Scripts == <br />
<br />
Block Name (4 bytes)<br />
Block Size (4 bytes BE)<br />
No of items (4 bytes)<br />
*Room Number (1 byte)<br />
*Offset (2 bytes)<br />
<br />
<br />
== DSOU - Directory of Sound ==<br />
<br />
Block Name (4 bytes)<br />
Block Size (4 bytes BE)<br />
No of items (4 bytes)<br />
*Room Number (1 byte)<br />
*Offset (2 bytes)<br />
<br />
<br />
== DCOS - Directory of Costumes ==<br />
<br />
Block Name (4 bytes)<br />
Block Size (4 bytes BE)<br />
No of items (4 bytes)<br />
*Room Number (1 byte)<br />
*Offset (2 bytes)<br />
<br />
<br />
== DCHR - Directory of Charsets ==<br />
<br />
Block Name (4 bytes)<br />
Block Size (4 bytes BE)<br />
No of items (4 bytes)<br />
*Room Number (1 byte)<br />
*Offset (2 bytes)<br />
<br />
<br />
== DOBJ,AARY ==<br />
<br />
As in V7<br />
<br />
<br />
[[Category: SCUMM Technical Reference]]</div>Jestar jokinhttps://wiki.scummvm.org/index.php?title=SCUMM/Technical_Reference/Index_File&diff=14770SCUMM/Technical Reference/Index File2010-09-17T12:25:27Z<p>Jestar jokin: /* DOBJ - Directory of Objects */ add possible class data</p>
<hr />
<div>[[SCUMM/Technical Reference|SCUMM Technical Reference]] &rarr; ''SCUMM index file''<br />
<br />
<br />
= Introduction=<br />
<br />
Most of the information below are retrieved from the [http://scumm.mixnmojo.com/?page=specs&file=indexfiles.txt LucasHacks!] site and from the Pascal source code of the ''IndexFileReader 1.2'' (written by Ben Gorman (Bgbennyboy, http://quick.mixnmojo.com). In addition, ''ScummRevisited'' (written by Jimmi Thøgersen (Serge), http://www.mixnmojo.com/scumm/scummrev) turned out to be very useful in verifying the found offsets.<br />
<br />
The SCUMM index file contains special information to allow quick random access to the resources in the other game files. It also includes the room names and some max limits for the game. The following filenames are used:<br />
<br />
<br />
<table border="2" cellspacing="0" cellpadding="4"><br />
<tr><th width="100">filename</th><th>SCUMM version</th></tr><br />
<tr><td >00.lfl / 000.lfl</td><td>V3/4</td></tr><br />
<tr><td>.000</td><td>V5/6</td></tr><br />
<tr><td>.LA0</td><td>V7/8</td></tr><br />
</table><br />
<br />
<br />
Version 1 to 3 use hardcoded offsets and cannot be treated that easily. For the other games, the index file can be used to determine the [[SCUMM/Versions|SCUMM version]] because there have been slight changes in each version.<br />
<br />
* Version 4<br />
** the 5th and 6th byte match RN or OR<br />
* Version 5: <br />
** RNAM xor'ed with 0x69 at the beginning of the file<br />
** next 4 byte integer value xor'ed with 0x69 is &gt; 9<br />
* Version 6<br />
** RNAM xor'ed with 0x69 at the beginning<br />
** next 4 byte integer value xor'ed with 0x69 is 9 (actually it's the size of the chunk. In V6 games, no room names are stored so the size is 4 bytes (header) + 4 bytes (size) + 1 byte for the termination character).<br />
* Version 7<br />
** RNAM at the beginning of the file (not xor'ed this time)<br />
** next 4 bytes result in BE integer 9 (actually applies only to [[Full Throttle]])<br />
* Version 7 or 8<br />
** RNAM at the beginning of the file<br />
** next 4 bytes integer is &gt; 9<br />
<br />
<br />
How to distinguish between version 7 and 8? Not by looking at the first bytes, but the the size of the chunks is usually bigger because a 4 byte integer is used to store the number of objects.<br />
<br />
= Conventions =<br />
<br />
As usual, the [http://en.wikipedia.org/wiki/Endianness endianness (Wikipedia)] is important. Unless stated, little endianess (LE) is used. <br />
<br />
BE is used as abbreviation for big endianness. <br />
<br />
A '''Chunk''' is a named part of the file, e.g. RNAM. Each chunk has a header that contains at least the chunk name and its size. The following chunks are available:<br />
<br />
<br />
{| border="1" cellspacing="0" cellpadding="4"<br />
|RNAM Room Names<br />
|In V5+<br />
|-<br />
|MAXS Maximum Values<br />
|In V5+<br />
|-<br />
|DROO Directory of Rooms<br />
|In V5+<br />
|-<br />
|DRSC Direcory of Room Scripts<br />
|In V8<br />
|-<br />
|DSCR Directory of Scripts<br />
|In V5+<br />
|-<br />
|DSOU Directory of Sounds<br />
|In V5+<br />
|-<br />
|DCOS Directory of Costumes<br />
|In V5+<br />
|-<br />
|DCHR Directory of Charsets<br />
|In V5+<br />
|-<br />
|DOBJ Directory of Objects<br />
|In V5+<br />
|-<br />
|AARY List of Arrays<br />
|In V6+<br />
|-<br />
|ANAM Animation Names?<br />
|In V7<br />
|-<br />
|RM Room Names<br />
|In V3/4<br />
|-<br />
|0R Directory Of Rooms<br />
|In V3/4<br />
|-<br />
|0S Directory Of Scripts?<br />
|In V3/4<br />
|-<br />
|0N Directory Of Sounds?<br />
|In V3/4<br />
|-<br />
|0C Directory Of Costumes?<br />
|In V3/4<br />
|-<br />
|0O Directory Of Objects?<br />
|In V3/4<br />
|}<br />
<br />
<br />
= Scumm 3/4 =<br />
<br />
* File's aren't xor'ed<br />
<br />
To read in the data, the following pseudo-code can be used:<br />
<br />
Read Number of Items<br />
FROM 1 to "Number of Items" DO<br />
Read subvalue 1<br />
Read subvalue 2<br />
END<br />
<br />
<br />
==RN - Room names ==<br />
<br />
Block Size (4 bytes)<br />
Block Name (2 bytes)<br />
#Room No (1 byte)<br />
#Room Name (9 bytes) XOR'ed with FF<br />
Blank (00) byte (1 byte) Marks end of chunk<br />
<br />
<br />
==0R - Directory of Rooms==<br />
<br />
Block Size (4 bytes)<br />
Block Name (2 bytes)<br />
No of items (2 bytes)<br />
File Number (1 byte)<br />
Offset (4 bytes)<br />
<br />
''File Number'' is interesting if a game is splitted on multiple disks. 0 means ''not used''. <br />
<br />
For ''Offset'' only the value 0 seems to be used.<br />
<br />
==0S - Directory of Scripts ==<br />
<br />
Block Size (4 bytes)<br />
Block Name (2 bytes)<br />
No of items (2 bytes)<br />
Room Number (1 byte)<br />
Offset (4 bytes)<br />
<br />
The global scripts are stored in this directory. The offsets are relative to the room.<br />
<br />
==0N - Directory of Sounds ==<br />
<br />
Block Size (4 bytes)<br />
Block Name (2 bytes)<br />
No of items (2 bytes)<br />
Room Number (1 byte)<br />
Offset (4 bytes)<br />
<br />
Similar to scripts but holds indexes for sounds.<br />
<br />
==0C - Directory of Costumes ==<br />
<br />
Block Size (4 bytes)<br />
Block Name (2 bytes)<br />
No of items (2 bytes)<br />
Room Number (1 byte)<br />
Offset (4 bytes)<br />
<br />
Similar to scripts but holds indexes of customes. <br />
<br />
==0O - Directory of Objects==<br />
<br />
Block Size (4 bytes)<br />
Block Name (2 bytes)<br />
No of items (2 bytes)<br />
Class data (3 bytes)<br />
Owner+state (1 byte)<br />
<br />
The class data is LE. Class data can be as follows:<br />
<br />
No Class = 0<br />
kObjectClassYFlip = 18<br />
kObjectClassXFlip = 19<br />
kObjectClassNeverClip = 20<br />
kObjectClassAlwaysClip = 21<br />
kObjectClassIgnoreBoxes = 22<br />
kObjectClassPlayer = 23 // Actor is controlled by the player<br />
kObjectClassUntouchable = 24<br />
<br />
The Object owner and state are encoded in one byte. Example:<br />
<br />
0xA2 &rarr; Owner = 0xA, State = 0x2<br />
<br />
The pseudo decode code would be:<br />
<br />
Owner = ( (Owner+state Byte) AND 0xF0) >> 4<br />
State = (Owner+state Byte) AND 0x0F<br />
<br />
= Scumm 5 =<br />
<br />
* The files are xor'ed with 0x69<br />
<br />
== RNAM - Room Names ==<br />
<br />
Block Name (4 bytes)<br />
Block Size (4 bytes BE)<br />
#Room No (1 byte)<br />
#Room Name (9 bytes) XOR'ed with FF<br />
Blank (00) byte (1 byte) Marks end of chunk<br />
<br />
<br />
== MAXS ==<br />
<br />
Block Name (4 bytes)<br />
Block Size (4 bytes BE)<br />
Variables (2 bytes)<br />
Unknown (2 bytes)<br />
Bit Variables (2 bytes)<br />
Local Objects (2 bytes)<br />
New Names? (2 bytes)<br />
Character Sets (2 bytes)<br />
Verbs? (2 bytes)<br />
Array? (2 bytes)<br />
Inventory Objects (2 bytes)<br />
<br />
== DROO - Directory of Rooms ==<br />
<br />
Block Name (4 bytes)<br />
Block Size (4 bytes BE)<br />
No of items (2 bytes)<br />
*Room Number (1 byte)<br />
*Offset (4 bytes)<br />
<br />
The flow how to read in this kind of information has changed slightly from V3/4.<br />
<br />
Read "No of items"<br />
FROM 1 TO "No of items" DO<br />
Read "Room Number"<br />
END<br />
<br />
FROM 1 TO "No of items" DO<br />
Read "Offset"<br />
END<br />
<br />
First read in all room numbers, then read in all room offsets. <br />
<br />
<br />
== DSCR - Directory of Scripts ==<br />
<br />
Block Name (4 bytes)<br />
Block Size (4 bytes BE)<br />
No of items (2 bytes)<br />
*Room Number (1 byte)<br />
*Offset (4 bytes)<br />
<br />
Indexes for global scripts, see pseudo code above on how to read in the data.<br />
<br />
<br />
== DSOU - Directory of Sound == <br />
<br />
Block Name (4 bytes)<br />
Block Size (4 bytes BE)<br />
No of items (2 bytes)<br />
*Room Number (1 byte)<br />
*Offset (4 bytes)<br />
<br />
Indexes for sound objects.<br />
<br />
<br />
== DCOS - Directory of Costumes ==<br />
<br />
Block Name (4 bytes)<br />
Block Size (4 bytes BE)<br />
No of items (2 bytes)<br />
*Room Number (1 byte)<br />
*Offset (4 bytes)<br />
<br />
Indexes for costumes<br />
<br />
<br />
== DCHR - Director of Charsets ==<br />
<br />
Block Name (4 bytes)<br />
Block Size (4 bytes BE)<br />
No of items (2 bytes)<br />
*Room Number (1 byte)<br />
*Offset (4 bytes)<br />
<br />
Indexes for charsets.<br />
<br />
<br />
== DOBJ - Directory of Objects ==<br />
<br />
Block Name (4 bytes)<br />
Block Size (4 bytes BE)<br />
No of items (2 bytes)<br />
*Owner+state (1 byte)<br />
*Class data (4 bytes)<br />
<br />
Information about objects. See remarks in V3/4 section how the owner+state value should be interpreted. Note that the index files stores ALL owner+state values, followed by ALL class data values.<br />
<br />
Class data has change since V3/4:<br />
No class = 0<br />
kObjectClassNeverClip = 20<br />
kObjectClassAlwaysClip = 21<br />
kObjectClassIgnoreBoxes = 22<br />
kObjectClassYFlip = 29<br />
kObjectClassXFlip = 30<br />
kObjectClassPlayer = 31 // Actor is controlled by the player<br />
kObjectClassUntouchable = 32<br />
<br />
= Scumm 6 =<br />
<br />
* Files are xor'ed with 0x69<br />
<br />
<br />
== RNAM - Room Names ==<br />
<br />
Blank Byte(00) (1 byte)<br />
<br />
No room names are stored.<br />
<br />
<br />
== MAXS ==<br />
<br />
Block Name (4 bytes)<br />
Block Size (4 bytes BE)<br />
Variables (2 bytes)<br />
Unknown (2 bytes)<br />
Bit Variables (2 bytes)<br />
Local Objects (2 bytes)<br />
Arrays (2 bytes)<br />
Unknown (2 bytes)<br />
Verbs (2 bytes)<br />
Floating Objects (2 bytes)<br />
Inventory Objects (2 bytes)<br />
Rooms (2 bytes)<br />
Scripts (2 bytes)<br />
Sounds (2 bytes)<br />
Character Sets (2 bytes)<br />
Costumes (2 bytes)<br />
Global Objects (2 bytes)<br />
<br />
<br />
== DROO, DSCR, DSOU, DCOS, DCHR, DOBJ ==<br />
<br />
All as in V5<br />
<br />
<br />
== AARY - Array == <br />
<br />
Block Name (4 bytes)<br />
Block Size (4 bytes BE)<br />
#Stop (2 bytes) Stops if 0x0000<br />
#A (2 bytes)<br />
#B (2 bytes)<br />
#C (2 bytes)<br />
<br />
num=AARY no (itinerate through in loop)<br />
if c=1 then<br />
AARY=(num, 1, a, b)<br />
else<br />
AARY=(num, 1, a, b)<br />
<br />
If stop=0 you dont seek past the 6 bytes of A,B,C you just start the loop again.<br />
<br />
<br />
= Scumm 7 = <br />
<br />
* Files aren't xor'ed<br />
<br />
== RNAM - Room names ==<br />
<br />
* As in V6 ?!?!?!<br />
<br />
<br />
== MAXS ==<br />
<br />
Block Name (4 bytes)<br />
Block Size (4 bytes BE)<br />
Variables (2 bytes)<br />
Bit Variables (2 bytes)<br />
Unknown (2 bytes)<br />
Global Objects (2 bytes)<br />
Local Objects (2 bytes)<br />
New Names (2 bytes)<br />
Verbs (2 bytes)<br />
Floating Objects (2 bytes)<br />
Inventory Objects (2 bytes)<br />
Arrays (2 bytes)<br />
Rooms (2 bytes)<br />
Scripts (2 bytes)<br />
Sounds (2 bytes)<br />
Character Sets (2 bytes)<br />
Costumes (2 bytes)<br />
<br />
<br />
== DROO,DSCR,DSOU,DCOS,DCHR,DOBJ,AARY ==<br />
<br />
All as in V5<br />
<br />
<br />
== ANAM - Animation Names ==<br />
<br />
Block Name (4 bytes)<br />
Block Size (4 bytes BE)<br />
No of items (2 bytes<br />
#Name (8 bytes)<br />
#Blank (00) byte (1 byte)<br />
Blank (FF) byte (1 byte) Marks end of chunk<br />
<br />
<br />
= Scumm 8 =<br />
<br />
== RNAM - Room Names ==<br />
<br />
As in V6 ?<br />
<br />
<br />
== MAXS ==<br />
<br />
Block Name (4 bytes)<br />
Block Size (4 bytes BE)<br />
Variables (4 bytes)<br />
Bit Variables (4 bytes)<br />
Unknown (4 bytes)<br />
Scripts (4 bytes)<br />
Sounds (4 bytes)<br />
Character Sets (4 bytes)<br />
Costumes (4 bytes)<br />
Rooms (4 bytes)<br />
Unknown (4 bytes)<br />
Global Objects (4 bytes)<br />
Unknown (4 bytes)<br />
Local Objects (4 bytes)<br />
New Names (4 bytes)<br />
Floating Objects (4 bytes)<br />
Inventory Objects (4 bytes)<br />
Arrays (4 bytes)<br />
Verbs (4 bytes)<br />
<br />
<br />
== DROO - Directory of Rooms ==<br />
<br />
Block Name (4 bytes)<br />
Block Size (4 bytes BE)<br />
No of items (4 bytes)<br />
*Room Number (1 byte)<br />
*Offset (2 bytes)<br />
<br />
<br />
== DRSC - Directory of Room Scripts ==<br />
<br />
Block Name (4 bytes)<br />
Block Size (4 bytes BE)<br />
No of items (4 bytes)<br />
*Room Number (1 byte)<br />
*Offset (2 bytes)<br />
<br />
<br />
== DSCR - Directory of Scripts == <br />
<br />
Block Name (4 bytes)<br />
Block Size (4 bytes BE)<br />
No of items (4 bytes)<br />
*Room Number (1 byte)<br />
*Offset (2 bytes)<br />
<br />
<br />
== DSOU - Directory of Sound ==<br />
<br />
Block Name (4 bytes)<br />
Block Size (4 bytes BE)<br />
No of items (4 bytes)<br />
*Room Number (1 byte)<br />
*Offset (2 bytes)<br />
<br />
<br />
== DCOS - Directory of Costumes ==<br />
<br />
Block Name (4 bytes)<br />
Block Size (4 bytes BE)<br />
No of items (4 bytes)<br />
*Room Number (1 byte)<br />
*Offset (2 bytes)<br />
<br />
<br />
== DCHR - Directory of Charsets ==<br />
<br />
Block Name (4 bytes)<br />
Block Size (4 bytes BE)<br />
No of items (4 bytes)<br />
*Room Number (1 byte)<br />
*Offset (2 bytes)<br />
<br />
<br />
== DOBJ,AARY ==<br />
<br />
As in V7<br />
<br />
<br />
[[Category: SCUMM Technical Reference]]</div>Jestar jokinhttps://wiki.scummvm.org/index.php?title=SCUMM/Technical_Reference/Index_File&diff=14769SCUMM/Technical Reference/Index File2010-09-17T12:14:23Z<p>Jestar jokin: /* 0O - Directory of Objects */ checked ScummVM source; definitely class data, just in the wrong order. Added possible class values</p>
<hr />
<div>[[SCUMM/Technical Reference|SCUMM Technical Reference]] &rarr; ''SCUMM index file''<br />
<br />
<br />
= Introduction=<br />
<br />
Most of the information below are retrieved from the [http://scumm.mixnmojo.com/?page=specs&file=indexfiles.txt LucasHacks!] site and from the Pascal source code of the ''IndexFileReader 1.2'' (written by Ben Gorman (Bgbennyboy, http://quick.mixnmojo.com). In addition, ''ScummRevisited'' (written by Jimmi Thøgersen (Serge), http://www.mixnmojo.com/scumm/scummrev) turned out to be very useful in verifying the found offsets.<br />
<br />
The SCUMM index file contains special information to allow quick random access to the resources in the other game files. It also includes the room names and some max limits for the game. The following filenames are used:<br />
<br />
<br />
<table border="2" cellspacing="0" cellpadding="4"><br />
<tr><th width="100">filename</th><th>SCUMM version</th></tr><br />
<tr><td >00.lfl / 000.lfl</td><td>V3/4</td></tr><br />
<tr><td>.000</td><td>V5/6</td></tr><br />
<tr><td>.LA0</td><td>V7/8</td></tr><br />
</table><br />
<br />
<br />
Version 1 to 3 use hardcoded offsets and cannot be treated that easily. For the other games, the index file can be used to determine the [[SCUMM/Versions|SCUMM version]] because there have been slight changes in each version.<br />
<br />
* Version 4<br />
** the 5th and 6th byte match RN or OR<br />
* Version 5: <br />
** RNAM xor'ed with 0x69 at the beginning of the file<br />
** next 4 byte integer value xor'ed with 0x69 is &gt; 9<br />
* Version 6<br />
** RNAM xor'ed with 0x69 at the beginning<br />
** next 4 byte integer value xor'ed with 0x69 is 9 (actually it's the size of the chunk. In V6 games, no room names are stored so the size is 4 bytes (header) + 4 bytes (size) + 1 byte for the termination character).<br />
* Version 7<br />
** RNAM at the beginning of the file (not xor'ed this time)<br />
** next 4 bytes result in BE integer 9 (actually applies only to [[Full Throttle]])<br />
* Version 7 or 8<br />
** RNAM at the beginning of the file<br />
** next 4 bytes integer is &gt; 9<br />
<br />
<br />
How to distinguish between version 7 and 8? Not by looking at the first bytes, but the the size of the chunks is usually bigger because a 4 byte integer is used to store the number of objects.<br />
<br />
= Conventions =<br />
<br />
As usual, the [http://en.wikipedia.org/wiki/Endianness endianness (Wikipedia)] is important. Unless stated, little endianess (LE) is used. <br />
<br />
BE is used as abbreviation for big endianness. <br />
<br />
A '''Chunk''' is a named part of the file, e.g. RNAM. Each chunk has a header that contains at least the chunk name and its size. The following chunks are available:<br />
<br />
<br />
{| border="1" cellspacing="0" cellpadding="4"<br />
|RNAM Room Names<br />
|In V5+<br />
|-<br />
|MAXS Maximum Values<br />
|In V5+<br />
|-<br />
|DROO Directory of Rooms<br />
|In V5+<br />
|-<br />
|DRSC Direcory of Room Scripts<br />
|In V8<br />
|-<br />
|DSCR Directory of Scripts<br />
|In V5+<br />
|-<br />
|DSOU Directory of Sounds<br />
|In V5+<br />
|-<br />
|DCOS Directory of Costumes<br />
|In V5+<br />
|-<br />
|DCHR Directory of Charsets<br />
|In V5+<br />
|-<br />
|DOBJ Directory of Objects<br />
|In V5+<br />
|-<br />
|AARY List of Arrays<br />
|In V6+<br />
|-<br />
|ANAM Animation Names?<br />
|In V7<br />
|-<br />
|RM Room Names<br />
|In V3/4<br />
|-<br />
|0R Directory Of Rooms<br />
|In V3/4<br />
|-<br />
|0S Directory Of Scripts?<br />
|In V3/4<br />
|-<br />
|0N Directory Of Sounds?<br />
|In V3/4<br />
|-<br />
|0C Directory Of Costumes?<br />
|In V3/4<br />
|-<br />
|0O Directory Of Objects?<br />
|In V3/4<br />
|}<br />
<br />
<br />
= Scumm 3/4 =<br />
<br />
* File's aren't xor'ed<br />
<br />
To read in the data, the following pseudo-code can be used:<br />
<br />
Read Number of Items<br />
FROM 1 to "Number of Items" DO<br />
Read subvalue 1<br />
Read subvalue 2<br />
END<br />
<br />
<br />
==RN - Room names ==<br />
<br />
Block Size (4 bytes)<br />
Block Name (2 bytes)<br />
#Room No (1 byte)<br />
#Room Name (9 bytes) XOR'ed with FF<br />
Blank (00) byte (1 byte) Marks end of chunk<br />
<br />
<br />
==0R - Directory of Rooms==<br />
<br />
Block Size (4 bytes)<br />
Block Name (2 bytes)<br />
No of items (2 bytes)<br />
File Number (1 byte)<br />
Offset (4 bytes)<br />
<br />
''File Number'' is interesting if a game is splitted on multiple disks. 0 means ''not used''. <br />
<br />
For ''Offset'' only the value 0 seems to be used.<br />
<br />
==0S - Directory of Scripts ==<br />
<br />
Block Size (4 bytes)<br />
Block Name (2 bytes)<br />
No of items (2 bytes)<br />
Room Number (1 byte)<br />
Offset (4 bytes)<br />
<br />
The global scripts are stored in this directory. The offsets are relative to the room.<br />
<br />
==0N - Directory of Sounds ==<br />
<br />
Block Size (4 bytes)<br />
Block Name (2 bytes)<br />
No of items (2 bytes)<br />
Room Number (1 byte)<br />
Offset (4 bytes)<br />
<br />
Similar to scripts but holds indexes for sounds.<br />
<br />
==0C - Directory of Costumes ==<br />
<br />
Block Size (4 bytes)<br />
Block Name (2 bytes)<br />
No of items (2 bytes)<br />
Room Number (1 byte)<br />
Offset (4 bytes)<br />
<br />
Similar to scripts but holds indexes of customes. <br />
<br />
==0O - Directory of Objects==<br />
<br />
Block Size (4 bytes)<br />
Block Name (2 bytes)<br />
No of items (2 bytes)<br />
Class data (3 bytes)<br />
Owner+state (1 byte)<br />
<br />
The class data is LE. Class data can be as follows:<br />
<br />
No Class = 0<br />
kObjectClassYFlip = 18<br />
kObjectClassXFlip = 19<br />
kObjectClassNeverClip = 20<br />
kObjectClassAlwaysClip = 21<br />
kObjectClassIgnoreBoxes = 22<br />
kObjectClassPlayer = 23 // Actor is controlled by the player<br />
kObjectClassUntouchable = 24<br />
<br />
The Object owner and state are encoded in one byte. Example:<br />
<br />
0xA2 &rarr; Owner = 0xA, State = 0x2<br />
<br />
The pseudo decode code would be:<br />
<br />
Owner = ( (Owner+state Byte) AND 0xF0) >> 4<br />
State = (Owner+state Byte) AND 0x0F<br />
<br />
= Scumm 5 =<br />
<br />
* The files are xor'ed with 0x69<br />
<br />
== RNAM - Room Names ==<br />
<br />
Block Name (4 bytes)<br />
Block Size (4 bytes BE)<br />
#Room No (1 byte)<br />
#Room Name (9 bytes) XOR'ed with FF<br />
Blank (00) byte (1 byte) Marks end of chunk<br />
<br />
<br />
== MAXS ==<br />
<br />
Block Name (4 bytes)<br />
Block Size (4 bytes BE)<br />
Variables (2 bytes)<br />
Unknown (2 bytes)<br />
Bit Variables (2 bytes)<br />
Local Objects (2 bytes)<br />
New Names? (2 bytes)<br />
Character Sets (2 bytes)<br />
Verbs? (2 bytes)<br />
Array? (2 bytes)<br />
Inventory Objects (2 bytes)<br />
<br />
== DROO - Directory of Rooms ==<br />
<br />
Block Name (4 bytes)<br />
Block Size (4 bytes BE)<br />
No of items (2 bytes)<br />
*Room Number (1 byte)<br />
*Offset (4 bytes)<br />
<br />
The flow how to read in this kind of information has changed slightly from V3/4.<br />
<br />
Read "No of items"<br />
FROM 1 TO "No of items" DO<br />
Read "Room Number"<br />
END<br />
<br />
FROM 1 TO "No of items" DO<br />
Read "Offset"<br />
END<br />
<br />
First read in all room numbers, then read in all room offsets. <br />
<br />
<br />
== DSCR - Directory of Scripts ==<br />
<br />
Block Name (4 bytes)<br />
Block Size (4 bytes BE)<br />
No of items (2 bytes)<br />
*Room Number (1 byte)<br />
*Offset (4 bytes)<br />
<br />
Indexes for global scripts, see pseudo code above on how to read in the data.<br />
<br />
<br />
== DSOU - Directory of Sound == <br />
<br />
Block Name (4 bytes)<br />
Block Size (4 bytes BE)<br />
No of items (2 bytes)<br />
*Room Number (1 byte)<br />
*Offset (4 bytes)<br />
<br />
Indexes for sound objects.<br />
<br />
<br />
== DCOS - Directory of Costumes ==<br />
<br />
Block Name (4 bytes)<br />
Block Size (4 bytes BE)<br />
No of items (2 bytes)<br />
*Room Number (1 byte)<br />
*Offset (4 bytes)<br />
<br />
Indexes for costumes<br />
<br />
<br />
== DCHR - Director of Charsets ==<br />
<br />
Block Name (4 bytes)<br />
Block Size (4 bytes BE)<br />
No of items (2 bytes)<br />
*Room Number (1 byte)<br />
*Offset (4 bytes)<br />
<br />
Indexes for charsets.<br />
<br />
<br />
== DOBJ - Directory of Objects ==<br />
<br />
Block Name (4 bytes)<br />
Block Size (4 bytes BE)<br />
No of items (2 bytes)<br />
*Owner+state (1 byte)<br />
*Class data (4 bytes)<br />
<br />
Information about objects. See remarks in V3/4 section how the owner+state value should be interpreted. Note that the index files stores ALL owner+state values, followed by ALL class data values.<br />
<br />
= Scumm 6 =<br />
<br />
* Files are xor'ed with 0x69<br />
<br />
<br />
== RNAM - Room Names ==<br />
<br />
Blank Byte(00) (1 byte)<br />
<br />
No room names are stored.<br />
<br />
<br />
== MAXS ==<br />
<br />
Block Name (4 bytes)<br />
Block Size (4 bytes BE)<br />
Variables (2 bytes)<br />
Unknown (2 bytes)<br />
Bit Variables (2 bytes)<br />
Local Objects (2 bytes)<br />
Arrays (2 bytes)<br />
Unknown (2 bytes)<br />
Verbs (2 bytes)<br />
Floating Objects (2 bytes)<br />
Inventory Objects (2 bytes)<br />
Rooms (2 bytes)<br />
Scripts (2 bytes)<br />
Sounds (2 bytes)<br />
Character Sets (2 bytes)<br />
Costumes (2 bytes)<br />
Global Objects (2 bytes)<br />
<br />
<br />
== DROO, DSCR, DSOU, DCOS, DCHR, DOBJ ==<br />
<br />
All as in V5<br />
<br />
<br />
== AARY - Array == <br />
<br />
Block Name (4 bytes)<br />
Block Size (4 bytes BE)<br />
#Stop (2 bytes) Stops if 0x0000<br />
#A (2 bytes)<br />
#B (2 bytes)<br />
#C (2 bytes)<br />
<br />
num=AARY no (itinerate through in loop)<br />
if c=1 then<br />
AARY=(num, 1, a, b)<br />
else<br />
AARY=(num, 1, a, b)<br />
<br />
If stop=0 you dont seek past the 6 bytes of A,B,C you just start the loop again.<br />
<br />
<br />
= Scumm 7 = <br />
<br />
* Files aren't xor'ed<br />
<br />
== RNAM - Room names ==<br />
<br />
* As in V6 ?!?!?!<br />
<br />
<br />
== MAXS ==<br />
<br />
Block Name (4 bytes)<br />
Block Size (4 bytes BE)<br />
Variables (2 bytes)<br />
Bit Variables (2 bytes)<br />
Unknown (2 bytes)<br />
Global Objects (2 bytes)<br />
Local Objects (2 bytes)<br />
New Names (2 bytes)<br />
Verbs (2 bytes)<br />
Floating Objects (2 bytes)<br />
Inventory Objects (2 bytes)<br />
Arrays (2 bytes)<br />
Rooms (2 bytes)<br />
Scripts (2 bytes)<br />
Sounds (2 bytes)<br />
Character Sets (2 bytes)<br />
Costumes (2 bytes)<br />
<br />
<br />
== DROO,DSCR,DSOU,DCOS,DCHR,DOBJ,AARY ==<br />
<br />
All as in V5<br />
<br />
<br />
== ANAM - Animation Names ==<br />
<br />
Block Name (4 bytes)<br />
Block Size (4 bytes BE)<br />
No of items (2 bytes<br />
#Name (8 bytes)<br />
#Blank (00) byte (1 byte)<br />
Blank (FF) byte (1 byte) Marks end of chunk<br />
<br />
<br />
= Scumm 8 =<br />
<br />
== RNAM - Room Names ==<br />
<br />
As in V6 ?<br />
<br />
<br />
== MAXS ==<br />
<br />
Block Name (4 bytes)<br />
Block Size (4 bytes BE)<br />
Variables (4 bytes)<br />
Bit Variables (4 bytes)<br />
Unknown (4 bytes)<br />
Scripts (4 bytes)<br />
Sounds (4 bytes)<br />
Character Sets (4 bytes)<br />
Costumes (4 bytes)<br />
Rooms (4 bytes)<br />
Unknown (4 bytes)<br />
Global Objects (4 bytes)<br />
Unknown (4 bytes)<br />
Local Objects (4 bytes)<br />
New Names (4 bytes)<br />
Floating Objects (4 bytes)<br />
Inventory Objects (4 bytes)<br />
Arrays (4 bytes)<br />
Verbs (4 bytes)<br />
<br />
<br />
== DROO - Directory of Rooms ==<br />
<br />
Block Name (4 bytes)<br />
Block Size (4 bytes BE)<br />
No of items (4 bytes)<br />
*Room Number (1 byte)<br />
*Offset (2 bytes)<br />
<br />
<br />
== DRSC - Directory of Room Scripts ==<br />
<br />
Block Name (4 bytes)<br />
Block Size (4 bytes BE)<br />
No of items (4 bytes)<br />
*Room Number (1 byte)<br />
*Offset (2 bytes)<br />
<br />
<br />
== DSCR - Directory of Scripts == <br />
<br />
Block Name (4 bytes)<br />
Block Size (4 bytes BE)<br />
No of items (4 bytes)<br />
*Room Number (1 byte)<br />
*Offset (2 bytes)<br />
<br />
<br />
== DSOU - Directory of Sound ==<br />
<br />
Block Name (4 bytes)<br />
Block Size (4 bytes BE)<br />
No of items (4 bytes)<br />
*Room Number (1 byte)<br />
*Offset (2 bytes)<br />
<br />
<br />
== DCOS - Directory of Costumes ==<br />
<br />
Block Name (4 bytes)<br />
Block Size (4 bytes BE)<br />
No of items (4 bytes)<br />
*Room Number (1 byte)<br />
*Offset (2 bytes)<br />
<br />
<br />
== DCHR - Directory of Charsets ==<br />
<br />
Block Name (4 bytes)<br />
Block Size (4 bytes BE)<br />
No of items (4 bytes)<br />
*Room Number (1 byte)<br />
*Offset (2 bytes)<br />
<br />
<br />
== DOBJ,AARY ==<br />
<br />
As in V7<br />
<br />
<br />
[[Category: SCUMM Technical Reference]]</div>Jestar jokinhttps://wiki.scummvm.org/index.php?title=SCUMM/Technical_Reference/Index_File&diff=14768SCUMM/Technical Reference/Index File2010-09-17T07:50:21Z<p>Jestar jokin: /* 0O - Directory of Objects */ add extra 3 bytes</p>
<hr />
<div>[[SCUMM/Technical Reference|SCUMM Technical Reference]] &rarr; ''SCUMM index file''<br />
<br />
<br />
= Introduction=<br />
<br />
Most of the information below are retrieved from the [http://scumm.mixnmojo.com/?page=specs&file=indexfiles.txt LucasHacks!] site and from the Pascal source code of the ''IndexFileReader 1.2'' (written by Ben Gorman (Bgbennyboy, http://quick.mixnmojo.com). In addition, ''ScummRevisited'' (written by Jimmi Thøgersen (Serge), http://www.mixnmojo.com/scumm/scummrev) turned out to be very useful in verifying the found offsets.<br />
<br />
The SCUMM index file contains special information to allow quick random access to the resources in the other game files. It also includes the room names and some max limits for the game. The following filenames are used:<br />
<br />
<br />
<table border="2" cellspacing="0" cellpadding="4"><br />
<tr><th width="100">filename</th><th>SCUMM version</th></tr><br />
<tr><td >00.lfl / 000.lfl</td><td>V3/4</td></tr><br />
<tr><td>.000</td><td>V5/6</td></tr><br />
<tr><td>.LA0</td><td>V7/8</td></tr><br />
</table><br />
<br />
<br />
Version 1 to 3 use hardcoded offsets and cannot be treated that easily. For the other games, the index file can be used to determine the [[SCUMM/Versions|SCUMM version]] because there have been slight changes in each version.<br />
<br />
* Version 4<br />
** the 5th and 6th byte match RN or OR<br />
* Version 5: <br />
** RNAM xor'ed with 0x69 at the beginning of the file<br />
** next 4 byte integer value xor'ed with 0x69 is &gt; 9<br />
* Version 6<br />
** RNAM xor'ed with 0x69 at the beginning<br />
** next 4 byte integer value xor'ed with 0x69 is 9 (actually it's the size of the chunk. In V6 games, no room names are stored so the size is 4 bytes (header) + 4 bytes (size) + 1 byte for the termination character).<br />
* Version 7<br />
** RNAM at the beginning of the file (not xor'ed this time)<br />
** next 4 bytes result in BE integer 9 (actually applies only to [[Full Throttle]])<br />
* Version 7 or 8<br />
** RNAM at the beginning of the file<br />
** next 4 bytes integer is &gt; 9<br />
<br />
<br />
How to distinguish between version 7 and 8? Not by looking at the first bytes, but the the size of the chunks is usually bigger because a 4 byte integer is used to store the number of objects.<br />
<br />
= Conventions =<br />
<br />
As usual, the [http://en.wikipedia.org/wiki/Endianness endianness (Wikipedia)] is important. Unless stated, little endianess (LE) is used. <br />
<br />
BE is used as abbreviation for big endianness. <br />
<br />
A '''Chunk''' is a named part of the file, e.g. RNAM. Each chunk has a header that contains at least the chunk name and its size. The following chunks are available:<br />
<br />
<br />
{| border="1" cellspacing="0" cellpadding="4"<br />
|RNAM Room Names<br />
|In V5+<br />
|-<br />
|MAXS Maximum Values<br />
|In V5+<br />
|-<br />
|DROO Directory of Rooms<br />
|In V5+<br />
|-<br />
|DRSC Direcory of Room Scripts<br />
|In V8<br />
|-<br />
|DSCR Directory of Scripts<br />
|In V5+<br />
|-<br />
|DSOU Directory of Sounds<br />
|In V5+<br />
|-<br />
|DCOS Directory of Costumes<br />
|In V5+<br />
|-<br />
|DCHR Directory of Charsets<br />
|In V5+<br />
|-<br />
|DOBJ Directory of Objects<br />
|In V5+<br />
|-<br />
|AARY List of Arrays<br />
|In V6+<br />
|-<br />
|ANAM Animation Names?<br />
|In V7<br />
|-<br />
|RM Room Names<br />
|In V3/4<br />
|-<br />
|0R Directory Of Rooms<br />
|In V3/4<br />
|-<br />
|0S Directory Of Scripts?<br />
|In V3/4<br />
|-<br />
|0N Directory Of Sounds?<br />
|In V3/4<br />
|-<br />
|0C Directory Of Costumes?<br />
|In V3/4<br />
|-<br />
|0O Directory Of Objects?<br />
|In V3/4<br />
|}<br />
<br />
<br />
= Scumm 3/4 =<br />
<br />
* File's aren't xor'ed<br />
<br />
To read in the data, the following pseudo-code can be used:<br />
<br />
Read Number of Items<br />
FROM 1 to "Number of Items" DO<br />
Read subvalue 1<br />
Read subvalue 2<br />
END<br />
<br />
<br />
==RN - Room names ==<br />
<br />
Block Size (4 bytes)<br />
Block Name (2 bytes)<br />
#Room No (1 byte)<br />
#Room Name (9 bytes) XOR'ed with FF<br />
Blank (00) byte (1 byte) Marks end of chunk<br />
<br />
<br />
==0R - Directory of Rooms==<br />
<br />
Block Size (4 bytes)<br />
Block Name (2 bytes)<br />
No of items (2 bytes)<br />
File Number (1 byte)<br />
Offset (4 bytes)<br />
<br />
''File Number'' is interesting if a game is splitted on multiple disks. 0 means ''not used''. <br />
<br />
For ''Offset'' only the value 0 seems to be used.<br />
<br />
==0S - Directory of Scripts ==<br />
<br />
Block Size (4 bytes)<br />
Block Name (2 bytes)<br />
No of items (2 bytes)<br />
Room Number (1 byte)<br />
Offset (4 bytes)<br />
<br />
The global scripts are stored in this directory. The offsets are relative to the room.<br />
<br />
==0N - Directory of Sounds ==<br />
<br />
Block Size (4 bytes)<br />
Block Name (2 bytes)<br />
No of items (2 bytes)<br />
Room Number (1 byte)<br />
Offset (4 bytes)<br />
<br />
Similar to scripts but holds indexes for sounds.<br />
<br />
==0C - Directory of Costumes ==<br />
<br />
Block Size (4 bytes)<br />
Block Name (2 bytes)<br />
No of items (2 bytes)<br />
Room Number (1 byte)<br />
Offset (4 bytes)<br />
<br />
Similar to scripts but holds indexes of customes. <br />
<br />
==0O - Directory of Objects==<br />
<br />
Block Size (4 bytes)<br />
Block Name (2 bytes)<br />
No of items (2 bytes)<br />
Owner+state (1 byte)<br />
??? (3 bytes) - possibly class data?<br />
<br />
The Object owner and state are encoded in one byte. Example:<br />
<br />
0xA2 &rarr; Owner = 0xA, State = 0x2<br />
<br />
The pseudo decode code would be:<br />
<br />
Owner = ( (Owner+state Byte) AND 0xF0) >> 4<br />
State = (Owner+state Byte) AND 0x0F<br />
<br />
= Scumm 5 =<br />
<br />
* The files are xor'ed with 0x69<br />
<br />
== RNAM - Room Names ==<br />
<br />
Block Name (4 bytes)<br />
Block Size (4 bytes BE)<br />
#Room No (1 byte)<br />
#Room Name (9 bytes) XOR'ed with FF<br />
Blank (00) byte (1 byte) Marks end of chunk<br />
<br />
<br />
== MAXS ==<br />
<br />
Block Name (4 bytes)<br />
Block Size (4 bytes BE)<br />
Variables (2 bytes)<br />
Unknown (2 bytes)<br />
Bit Variables (2 bytes)<br />
Local Objects (2 bytes)<br />
New Names? (2 bytes)<br />
Character Sets (2 bytes)<br />
Verbs? (2 bytes)<br />
Array? (2 bytes)<br />
Inventory Objects (2 bytes)<br />
<br />
== DROO - Directory of Rooms ==<br />
<br />
Block Name (4 bytes)<br />
Block Size (4 bytes BE)<br />
No of items (2 bytes)<br />
*Room Number (1 byte)<br />
*Offset (4 bytes)<br />
<br />
The flow how to read in this kind of information has changed slightly from V3/4.<br />
<br />
Read "No of items"<br />
FROM 1 TO "No of items" DO<br />
Read "Room Number"<br />
END<br />
<br />
FROM 1 TO "No of items" DO<br />
Read "Offset"<br />
END<br />
<br />
First read in all room numbers, then read in all room offsets. <br />
<br />
<br />
== DSCR - Directory of Scripts ==<br />
<br />
Block Name (4 bytes)<br />
Block Size (4 bytes BE)<br />
No of items (2 bytes)<br />
*Room Number (1 byte)<br />
*Offset (4 bytes)<br />
<br />
Indexes for global scripts, see pseudo code above on how to read in the data.<br />
<br />
<br />
== DSOU - Directory of Sound == <br />
<br />
Block Name (4 bytes)<br />
Block Size (4 bytes BE)<br />
No of items (2 bytes)<br />
*Room Number (1 byte)<br />
*Offset (4 bytes)<br />
<br />
Indexes for sound objects.<br />
<br />
<br />
== DCOS - Directory of Costumes ==<br />
<br />
Block Name (4 bytes)<br />
Block Size (4 bytes BE)<br />
No of items (2 bytes)<br />
*Room Number (1 byte)<br />
*Offset (4 bytes)<br />
<br />
Indexes for costumes<br />
<br />
<br />
== DCHR - Director of Charsets ==<br />
<br />
Block Name (4 bytes)<br />
Block Size (4 bytes BE)<br />
No of items (2 bytes)<br />
*Room Number (1 byte)<br />
*Offset (4 bytes)<br />
<br />
Indexes for charsets.<br />
<br />
<br />
== DOBJ - Directory of Objects ==<br />
<br />
Block Name (4 bytes)<br />
Block Size (4 bytes BE)<br />
No of items (2 bytes)<br />
*Owner+state (1 byte)<br />
*Class data (4 bytes)<br />
<br />
Information about objects. See remarks in V3/4 section how the owner+state value should be interpreted. Note that the index files stores ALL owner+state values, followed by ALL class data values.<br />
<br />
= Scumm 6 =<br />
<br />
* Files are xor'ed with 0x69<br />
<br />
<br />
== RNAM - Room Names ==<br />
<br />
Blank Byte(00) (1 byte)<br />
<br />
No room names are stored.<br />
<br />
<br />
== MAXS ==<br />
<br />
Block Name (4 bytes)<br />
Block Size (4 bytes BE)<br />
Variables (2 bytes)<br />
Unknown (2 bytes)<br />
Bit Variables (2 bytes)<br />
Local Objects (2 bytes)<br />
Arrays (2 bytes)<br />
Unknown (2 bytes)<br />
Verbs (2 bytes)<br />
Floating Objects (2 bytes)<br />
Inventory Objects (2 bytes)<br />
Rooms (2 bytes)<br />
Scripts (2 bytes)<br />
Sounds (2 bytes)<br />
Character Sets (2 bytes)<br />
Costumes (2 bytes)<br />
Global Objects (2 bytes)<br />
<br />
<br />
== DROO, DSCR, DSOU, DCOS, DCHR, DOBJ ==<br />
<br />
All as in V5<br />
<br />
<br />
== AARY - Array == <br />
<br />
Block Name (4 bytes)<br />
Block Size (4 bytes BE)<br />
#Stop (2 bytes) Stops if 0x0000<br />
#A (2 bytes)<br />
#B (2 bytes)<br />
#C (2 bytes)<br />
<br />
num=AARY no (itinerate through in loop)<br />
if c=1 then<br />
AARY=(num, 1, a, b)<br />
else<br />
AARY=(num, 1, a, b)<br />
<br />
If stop=0 you dont seek past the 6 bytes of A,B,C you just start the loop again.<br />
<br />
<br />
= Scumm 7 = <br />
<br />
* Files aren't xor'ed<br />
<br />
== RNAM - Room names ==<br />
<br />
* As in V6 ?!?!?!<br />
<br />
<br />
== MAXS ==<br />
<br />
Block Name (4 bytes)<br />
Block Size (4 bytes BE)<br />
Variables (2 bytes)<br />
Bit Variables (2 bytes)<br />
Unknown (2 bytes)<br />
Global Objects (2 bytes)<br />
Local Objects (2 bytes)<br />
New Names (2 bytes)<br />
Verbs (2 bytes)<br />
Floating Objects (2 bytes)<br />
Inventory Objects (2 bytes)<br />
Arrays (2 bytes)<br />
Rooms (2 bytes)<br />
Scripts (2 bytes)<br />
Sounds (2 bytes)<br />
Character Sets (2 bytes)<br />
Costumes (2 bytes)<br />
<br />
<br />
== DROO,DSCR,DSOU,DCOS,DCHR,DOBJ,AARY ==<br />
<br />
All as in V5<br />
<br />
<br />
== ANAM - Animation Names ==<br />
<br />
Block Name (4 bytes)<br />
Block Size (4 bytes BE)<br />
No of items (2 bytes<br />
#Name (8 bytes)<br />
#Blank (00) byte (1 byte)<br />
Blank (FF) byte (1 byte) Marks end of chunk<br />
<br />
<br />
= Scumm 8 =<br />
<br />
== RNAM - Room Names ==<br />
<br />
As in V6 ?<br />
<br />
<br />
== MAXS ==<br />
<br />
Block Name (4 bytes)<br />
Block Size (4 bytes BE)<br />
Variables (4 bytes)<br />
Bit Variables (4 bytes)<br />
Unknown (4 bytes)<br />
Scripts (4 bytes)<br />
Sounds (4 bytes)<br />
Character Sets (4 bytes)<br />
Costumes (4 bytes)<br />
Rooms (4 bytes)<br />
Unknown (4 bytes)<br />
Global Objects (4 bytes)<br />
Unknown (4 bytes)<br />
Local Objects (4 bytes)<br />
New Names (4 bytes)<br />
Floating Objects (4 bytes)<br />
Inventory Objects (4 bytes)<br />
Arrays (4 bytes)<br />
Verbs (4 bytes)<br />
<br />
<br />
== DROO - Directory of Rooms ==<br />
<br />
Block Name (4 bytes)<br />
Block Size (4 bytes BE)<br />
No of items (4 bytes)<br />
*Room Number (1 byte)<br />
*Offset (2 bytes)<br />
<br />
<br />
== DRSC - Directory of Room Scripts ==<br />
<br />
Block Name (4 bytes)<br />
Block Size (4 bytes BE)<br />
No of items (4 bytes)<br />
*Room Number (1 byte)<br />
*Offset (2 bytes)<br />
<br />
<br />
== DSCR - Directory of Scripts == <br />
<br />
Block Name (4 bytes)<br />
Block Size (4 bytes BE)<br />
No of items (4 bytes)<br />
*Room Number (1 byte)<br />
*Offset (2 bytes)<br />
<br />
<br />
== DSOU - Directory of Sound ==<br />
<br />
Block Name (4 bytes)<br />
Block Size (4 bytes BE)<br />
No of items (4 bytes)<br />
*Room Number (1 byte)<br />
*Offset (2 bytes)<br />
<br />
<br />
== DCOS - Directory of Costumes ==<br />
<br />
Block Name (4 bytes)<br />
Block Size (4 bytes BE)<br />
No of items (4 bytes)<br />
*Room Number (1 byte)<br />
*Offset (2 bytes)<br />
<br />
<br />
== DCHR - Directory of Charsets ==<br />
<br />
Block Name (4 bytes)<br />
Block Size (4 bytes BE)<br />
No of items (4 bytes)<br />
*Room Number (1 byte)<br />
*Offset (2 bytes)<br />
<br />
<br />
== DOBJ,AARY ==<br />
<br />
As in V7<br />
<br />
<br />
[[Category: SCUMM Technical Reference]]</div>Jestar jokinhttps://wiki.scummvm.org/index.php?title=SCUMM/Technical_Reference/SCUMM_6_resource_files&diff=14659SCUMM/Technical Reference/SCUMM 6 resource files2010-09-03T02:04:59Z<p>Jestar jokin: Copy information from ScummC wiki by Alban Bedel, from archive here: http://wiki.github.com/jamesu/scummc/scumm6-data-format</p>
<hr />
<div>== Scumm 6 data format ==<br />
<br />
=== 1. Introduction ===<br />
<br />
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.<br />
<br />
==== 1.1 Other resources ====<br />
<br />
Other people are working on similar stuff. Some information came from these:<br />
<br />
* "The inCompleat SCUMM Reference Guide":http://www.cowlark.com/scumm/<br />
* "LucasHacks!":http://scumm.mixnmojo.com/<br />
<br />
==== 1.2 Basics ====<br />
<br />
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.<br />
<br />
All SCUMM files are made of blocks like this:<br />
<br />
<pre> type: 32<br />
size: 32be<br />
data: ...<br />
</pre><br />
<br />
=== 2. Index file ===<br />
<br />
'''RNAM''' : room name list<br />
<br />
<pre> vlc (end code 0x00, so room no starts at 1)<br />
room no : 8<br />
name : 8*9 (binary inverted)<br />
</pre><br />
<br />
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.<br />
<br />
'''MAXS''' : maximal address for ...<br />
<br />
<pre> max var : 16le<br />
unk : 16le (perhaps actors as it's 16 in dott, but that<br />
doesn't really fit with later versions)<br />
max bit var : 16le<br />
max local objs : 16le<br />
max arrays : 16le<br />
unk2 : 16le (really dunno as it's 0 in dott)<br />
max verb : 16le<br />
max fl objs : 16le<br />
max inv : 16le<br />
max room : 16le<br />
max scr : 16le<br />
max snds : 16le<br />
max chst : 16le<br />
max cost : 16le<br />
max glob obj : 16le<br />
</pre><br />
<br />
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.<br />
<br />
'''DROO''' : room idx<br />
<br />
<pre> num entries : 16le<br />
file no : 8*num<br />
room off : 32le*num<br />
</pre><br />
<br />
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).<br />
<br />
'''DSCR''' : script idx<br />
<br />
<pre> num entries : 16le<br />
room no : 8*num<br />
room off : 32le*num<br />
</pre><br />
<br />
'''DSOU''' : sound idx<br />
<br />
<pre> num entries : 16le<br />
room no : 8*num<br />
room off : 32le*num<br />
</pre><br />
<br />
'''DCOS''' : costume idx<br />
<br />
<pre> num entries : 16le<br />
room no : 8*num<br />
room off : 32le*num<br />
</pre><br />
<br />
'''DCHR''' : charset idx<br />
<br />
<pre> num entries : 16le<br />
room no : 8*num<br />
room off : 32le*num<br />
</pre><br />
<br />
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).<br />
<br />
'''DOBJ''' : object owners list<br />
<br />
<pre> num entries : 16le<br />
obj owner/state : 8*num<br />
owner : 4<br />
state : 4<br />
class data : 32le*num<br />
</pre><br />
<br />
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.<br />
<br />
'''AARY''' : array list<br />
<br />
<pre> vlc (end code 0x0000)<br />
var no : 16le<br />
x size -1 : 16le<br />
y size -1 : 16le<br />
type : 16le (0: words, 1: bytes)<br />
</pre><br />
<br />
Finally we have a list of pre-allocated arrays, these will be allocated by the engine before running the boot script.<br />
<br />
=== 3. Main data file ===<br />
<br />
==== 3.1 Structure ====<br />
<br />
* *LECF* main container<br />
** *LOFF* room offset table<br />
** *LFLF* disk block<br />
*** *ROOM* room block<br />
**** *RMHD* room header<br />
**** *CYCL* color cycle (vlc stop on 0x00)<br />
**** *TRNS* transparent color<br />
**** *PALS* palette data<br />
***** *WRAP* dummy container<br />
****** *OFFS* palette index<br />
****** *APAL* 256 entries rgb palette (include the others blocks size)<br />
**** *RMIM* room image<br />
***** *RMIH* number of z buffers<br />
***** *IM00* image data<br />
****** *SMAP* stripe table + plane 0<br />
****** *ZPnn* stripe table + z planes (nn >= 1)<br />
**** *OBIM* obj image<br />
***** *IMHD* image header<br />
***** *IMnn* image data (image for state nn, start with state 1 as state 0 just display nothing)<br />
****** *SMAP* plane 0 (see above)<br />
****** *ZPnn* other z planes (nn >= 1, again see above)<br />
**** *OBCD* object scripts<br />
***** *CDHD* code header<br />
***** *VERB* verb entries (the object scripts indexed by verbs. Several verbs may have the same code)<br />
***** *OBNA* object name (default object name, it may be overrided by the scripts)<br />
**** *EXCD* exit script (script run when leaving the room)<br />
**** *ENCD* entry script (script run when entering the room)<br />
**** *NLSC* number of local scripts<br />
**** *LSCR* local script<br />
**** *BOXD* box data (box 0 seems to be crap with all the points set to -32000,-32000)<br />
**** *BOXM* box matrix<br />
**** *SCAL*<br />
*** *SCRP* script<br />
*** *SOUN* sound, contain one of:<br />
**** *MIDI* midi data<br />
**** *SOU* container for the different versions<br />
***** *ROL* roland data<br />
***** *ADL* adlib data<br />
***** *GMD* general midi data<br />
*** *COST* costume<br />
*** *CHAR* charset<br />
<br />
==== 3.2 Blocks content ====<br />
<br />
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 ;)<br />
<br />
===== 3.2.1 LOFF =====<br />
<br />
<pre> num rooms: 8<br />
room id: 8<br />
offset : 32le (absolute offset of the ROOM block)<br />
</pre><br />
<br />
===== 3.2.2 RMHD =====<br />
<br />
<pre> width : 16le<br />
height : 16le<br />
num objs : 16le<br />
</pre><br />
<br />
===== 3.2.3 CYCL =====<br />
<br />
<pre> cycles : variable length<br />
idx : 8 (valid range is [1-16])<br />
unk : 16 Th<br />
freq : 16be (delay = 16384/freq)<br />
flags : 16be<br />
start : 8 (start/end entries in the palette)<br />
end : 8<br />
close : 8 must be set to 0 to end the block<br />
</pre><br />
<br />
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.<br />
<br />
===== 3.2.4 TRNS =====<br />
<br />
<pre> val : 8<br />
padding : 8<br />
</pre><br />
<br />
===== 3.2.5 OFFS =====<br />
<br />
<pre> offset table : block size imply the number of palette ?<br />
offset : 32le (offset starting from this OFFS block)<br />
</pre><br />
<br />
===== 3.2.6 APAL =====<br />
<br />
<pre> colors : 256 times<br />
r : 8<br />
g : 8<br />
b : 8<br />
APAL : others APAL blocks may follow<br />
</pre><br />
<br />
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.<br />
<br />
===== 3.2.7 RMIH =====<br />
<br />
<pre> num z buf: 16le (number of ZPnn in the IM00 block)</pre><br />
<br />
===== 3.2.8 SMAP =====<br />
<br />
<pre> strip off : 32le (offset from this SMAP. 1 per column of 8 pix)<br />
stripes<br />
codec : 8<br />
data : variable length<br />
</pre><br />
<br />
===== 3.2.9 ZPnn =====<br />
<br />
<pre> strip off : 16le (offset from this ZPnn. 1 per column of 8 pix)<br />
stripes<br />
data : variable length<br />
</pre><br />
<br />
See [[SCUMM/Technical_Reference/Image_resources| SCUMM Image Resources]] for more information on the SMAP and ZPnn blocks.<br />
<br />
===== 3.2.10 IMHD =====<br />
<br />
<pre> obj id : 16le<br />
num imnn : 16le<br />
num zpnn : 16le<br />
unknown : 16<br />
x : 16le<br />
y : 16le<br />
width : 16le<br />
height : 16le<br />
num hotspots : 16le (usually one for each IMnn, but there is one even<br />
if no IMnn is present)<br />
hotspots<br />
x : 16le signed<br />
y : 16le signed<br />
</pre><br />
<br />
===== 3.2.11 CDHD =====<br />
<br />
<pre> obj id : 16le<br />
x : 16le (upper left corner)<br />
y : 16le<br />
w : 16le (size of the active area - it may not match the image<br />
size, I think)<br />
h : 16le<br />
flags : 8<br />
parent : 8<br />
unk : 2*16<br />
actor dir : 8 (direction an actor should look at when standing in front<br />
of the object)<br />
</pre><br />
<br />
===== 3.2.12 VERB =====<br />
<br />
<pre> offset table : vlc<br />
entries : 8 (0x00 is end, 0xFF is default)<br />
offset : 16le<br />
code<br />
</pre><br />
<br />
===== 3.2.13 OBNA =====<br />
<br />
<pre> null terminated string</pre><br />
<br />
===== 3.2.14 NLSC =====<br />
<br />
<pre> val : 8<br />
padding : 8<br />
</pre><br />
<br />
===== 3.2.15 LSCR =====<br />
<br />
<pre> idx : 8 (local script IDs start at 200)<br />
data<br />
</pre><br />
<br />
===== 3.2.16 BOXD =====<br />
<br />
<pre> num box : 16 ScummVM only uses the lower 8 bits<br />
ulx : 16le<br />
uly : 16le<br />
urx : 16le<br />
ury : 16le<br />
lrx : 16le<br />
lry : 16le<br />
llx : 16le<br />
lly : 16le<br />
mask : 8<br />
flags : 8<br />
scale : 16le<br />
</pre><br />
<br />
The mask indicates which Z plane should mask this box. The flags are used for certain parameters:<br />
<br />
* 0x08 : X flip<br />
* 0x10 : Y flip<br />
* 0x20 : Ignore scale / Player only<br />
* 0x40 : Locked<br />
* 0x80 : Invisible<br />
<br />
"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.<br />
<br />
===== 3.2.17 BOXM =====<br />
<br />
<pre> line : the matrix has one line for each box, terminated by 0xFF.<br />
box : list of the directly connected boxes<br />
start : 8<br />
end : 8<br />
box : 8<br />
0xFF : 8<br />
</pre><br />
<br />
===== 3.2.18 SCAL =====<br />
<br />
<pre> scale data (repeat 4 times)<br />
scale1 : 16le<br />
y1 : 16le<br />
scale2 : 16le<br />
y2 : 16le<br />
</pre><br />
<br />
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.<br />
<br />
<pre> s = ((scale2 - scale1) * (y - y1)) / (y2 - y1) + scale1;<br />
if(s > 0xFF) s = 0xFF;<br />
if(s < 1) s = 1;<br />
</pre><br />
<br />
===== 3.2.19 COST =====<br />
<br />
<pre> size : 32le can be 0 (see num anim) or the size<br />
(sometimes with an offset of one ??)<br />
header : 2*8 always contain "CO"<br />
num anim : 8 if(size) num_anim++<br />
format : 8 bit 7 is a mirror flag, bit 0 is the palette<br />
size (0: 16 colors, 1: 32 colors)<br />
palette : 8*num colors coded in format<br />
anim cmds offset : 16le access the anim cmds array<br />
limbs offset : 16*16le access limb picture table<br />
anim offsets : 16le*num anim access anim definitions<br />
anim<br />
limb mask : 16le<br />
anim definitions : variable length, one definition for each bit set<br />
to 1 in the limb mask.<br />
0xFFFF : 16le stopped limb code<br />
OR<br />
start : 16le<br />
noloop : 1<br />
len : 7<br />
anim cmds<br />
cmd : 8<br />
limbs<br />
pict offset : 16le<br />
picts<br />
width : 16le<br />
height : 16le<br />
rel_x : s16le<br />
rel_y : s16le<br />
move_x : s16le<br />
move_y : s16le<br />
redir_limb : 8 only present if((format & 0x7E) == 0x60)<br />
redir_pict : 8 only present if((format & 0x7E) == 0x60)<br />
rle data<br />
</pre><br />
<br />
See [[SCUMM/Technical_Reference/Costume_resources|SCUMM Costume Resources]] for more informations on costumes.<br />
<br />
===== 3.2.20 CHAR =====<br />
<br />
<pre> size : 32le size-15<br />
unknown : 2*8 always 0x6303 in dott<br />
palette : 15*8<br />
bpp : 8 (font ptr)<br />
font height : 8<br />
num char : 16le<br />
offset table : num*32le the offsets are relative to font ptr<br />
chars<br />
width : 8<br />
height : 8<br />
x offset : s8<br />
y offset : s8<br />
data : raw bit packed data<br />
</pre><br />
<br />
In ScummVM only bpp 1, 2, 4 and 8 are supported.<br />
<br />
===== 3.2.21 SOUN =====<br />
<br />
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.<br />
<br />
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.<br />
<br />
=== 4. Voice file ===<br />
<br />
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.<br />
<br />
==== 4.1 Structure ====<br />
<br />
<pre> main block header : scumm block header (SOU )<br />
samples<br />
sync block header : scumm block header (VCTL)<br />
sync data : 16be*num<br />
voc data : sample data<br />
</pre><br />
<br />
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.</div>Jestar jokinhttps://wiki.scummvm.org/index.php?title=SCUMM/Technical_Reference&diff=14658SCUMM/Technical Reference2010-09-03T02:00:34Z<p>Jestar jokin: Add entry for SCUMM 6 resource files summary. Replace dead link to ScummC wiki.</p>
<hr />
<div>Here we are trying to gather all sorts of information we have about the SCUMM/SPUTM engine.<br />
<br />
This needs to be extended. A lot of information can be found directly in the ScummVM source, the heads of its developers, and the external links I found below. Feel free to try and tap each of these sources to gain more information and add it here (note: no brain surgery recommended. For external sources, permission from the authors should be recieved before blatantly copying stuff).<br />
<br />
== General ==<br />
* [[SCUMM/Virtual Machine|SCUMM Virtual Machine]]<br />
* [[SCUMM/Arrays and Strings|SCUMM Arrays and Strings]]<br />
* [[SCUMM/Versions|SCUMM Versions]]<br />
* [[SCUMM/Terminology|SCUMM Terminology]]<br />
<br />
== Resource and data formats ==<br />
Information about the formats of various resource types used in SCUMM games.<br />
* [[SCUMM/Technical_Reference/Index File|Index File]]<br />
* [[SCUMM/Technical_Reference/Box resources|Box resources]]<br />
* [[SCUMM/Technical_Reference/Charset resources|Charset resources]]<br />
* [[SCUMM/Technical_Reference/Costume resources|Costume resources]]<br />
* [[SCUMM/Technical_Reference/Image resources|Image resources]]<br />
* [[SCUMM/Technical_Reference/Object resources|Object resources]]<br />
* [[SCUMM/Technical_Reference/Script resources|Script resources]]<br />
* [[SCUMM/Technical_Reference/Sound resources|Sound resources]]<br />
* [[SCUMM/Technical_Reference/iMuse data|iMuse data]]<br />
* [[SCUMM/Technical_Reference/String format|String format]]<br />
* [[SCUMM/Technical_Reference/SCUMM 6 resource files|SCUMM 6 resource files]]<br />
<br />
== Opcode tables ==<br />
* [[SCUMM/V0 opcodes|SCUMM V0 opcodes]]<br />
* [[SCUMM/V2 opcodes|SCUMM V2 opcodes]] (V1 is very similar)<br />
* [[SCUMM/V5 opcodes|SCUMM V5 opcodes]] (V3 and V4 are very similar)<br />
* [[SCUMM/V6 opcodes|SCUMM V6 opcodes]] (V7 is very similar)<br />
* [[SCUMM/V8 opcodes|SCUMM V8 opcodes]]<br />
<br />
== External links ==<br />
* http://wiki.github.com/jamesu/scummc/<br />
* http://www.scummvm.org/docs/specs/index.php<br />
* http://www.lucasforums.com/showthread.php?s=&postid=1199968#post1217901<br />
* http://scumm.mixnmojo.com/?page=articles<br />
* http://scumm.mixnmojo.com/?page=specs<br />
* http://scumm.mixnmojo.com/?page=utils</div>Jestar jokinhttps://wiki.scummvm.org/index.php?title=SCUMM/Technical_Reference/Sound_resources&diff=14657SCUMM/Technical Reference/Sound resources2010-09-03T01:48:54Z<p>Jestar jokin: /* iMUSE */ replace dead external link with ScummVM wiki link</p>
<hr />
<div>=Music=<br />
<br />
==Early v5==<br />
<br />
Going from Monkey Island 2 (MI2), music blocks are stored in LFLF blocks, outside of the ROOMs, so they can be accessed globally. The containing sound block looks like this:<br />
<br />
Block name 4 bytes ("SOUN")<br />
Block size 4 bytes<br />
Block name 4 bytes ("SOU ")<br />
Block size 4 bytes<br />
Music block variable<br />
<br />
The redundant header is possibly due to building on a legacy implementation, or for easier identification in the table stored in the .000 index file.<br />
<br />
The music block may contain any combination of ROL (Roland MT-32), ADL (AdLib/OPL FM), or SPK (PC speaker) blocks. They can also store a single SBL block for digitized sound (described in a later section). Aside from SBL, each of these blocks follow the same basic pattern.<br />
<br />
Block name 4 bytes ("ROL ", or "ADL ", or "SPK ")<br />
Block size 4 bytes<br />
MIDI data variable<br />
<br />
Every track is stored in MIDI format, in order to make use of the iMUSE technology through System Exclusive (SysEx) messages.<br />
<br />
Due to the predominance of the Sound Blaster and AdLib/OPL FM technology at the time, in at least MI2 every musical SOUN block contains an ADL block.<br />
<br />
==iMUSE==<br />
<br />
From SCUMM v5 onwards, LucasArts games used a dynamic music playback system called iMUSE. This basically consists of standard MIDI data, with embedded System Exclusive (SysEx) messages that act as markers in the song. iMUSE allows operations like conditional jumping & looping, adjusting the volume of parts, turning parts on and off, changing instruments, and detuning parts.<br />
<br />
You can find the original patent document [http://pat2pdf.org/pat2pdf/foo.pl?number=5315057 here], and some technical details [[SCUMM/Technical Reference/iMuse data|can be found here]].<br />
<br />
==Mac0==<br />
<br />
From Markus Magnuson (superqult) we got this information:<br />
<br />
4 bytes - 'SOUN'<br />
BE 4 bytes - block length<br />
<br />
4 bytes - 'Mac0'<br />
BE 4 bytes - (blockLength - 27)<br />
28 bytes - ???<br />
<br />
do this three times (once for each channel):<br />
4 bytes - 'Chan'<br />
BE 4 bytes - channel length<br />
4 bytes - instrument name (e.g. 'MARI')<br />
<br />
do this for ((chanLength-24)/4) times:<br />
2 bytes - note duration<br />
1 byte - note value<br />
1 byte - note velocity<br />
<br />
4 bytes - ???<br />
4 bytes - 'Loop'/'Done'<br />
4 bytes - ???<br />
1 byte - 0x09<br />
<br />
Instruments (and General Midi equivalent):<br />
"MARI" - Marimba (12)<br />
"PLUC" - Pizzicato Strings (45)<br />
"HARM" - Harmonica (22)<br />
"PIPE" - Church Organ? (19) or Flute? (73) or Bag Pipe (109)<br />
"TROM" - Trombone (57)<br />
"STRI" - String Ensemble (48 or 49)<br />
"HORN" - French Horn? (60) or English Horn? (69)<br />
"VIBE" - Vibraphone (11)<br />
"SHAK" - Shakuhachi? (77)<br />
"PANP" - Pan Flute (75)<br />
"WHIS" - Whistle (78) / Bottle (76)<br />
"ORGA" - Drawbar Organ (16; but could also be 17-20)<br />
"BONG" - Woodblock? (115)<br />
"BASS" - Bass (32-39)<br />
<br />
=Digitized Sounds=<br />
<br />
==Early v5 - SBL blocks==<br />
<br />
Digitized sounds first appeared in Monkey Island 1 & 2. They are contained in the .001 resource files, and are sub-blocks of "SOUN" blocks (see the music section above).<br />
<br />
Block name 4 bytes ("SBL ")<br />
Block size 4 bytes<br />
Sound header 4 bytes ("AUhd" or "WVhd")<br />
Block size 4 bytes<br />
Unknown 3 bytes (always 00 00 80)<br />
Data header 4 bytes ("AUdt" or "WVdt")<br />
Block size 4 bytes<br />
VOC data variable<br />
<br />
AUhd and AUdt are used in Monkey Island, while WVhd and WVdt are used in the non-interactive demo of Sam & Max. The actual sound data is stored in the Creative VOC format, without the header information. The implied data offset is 0x1A, and the VOC version is 0x010A.<br />
<br />
==Early v5 - CD tracks==<br />
<br />
Games that use CD tracks (Loom/CD, MI1/CD, Zak256/FM-TOWNS) are a bit different. For MI1/CD at least, the "SOUN" block size is always 32 bytes and presumably points to the CD track to play.<br />
<br />
Here's some notes by cocomonk22:<br />
Values from offsets 0-23 (0x00-0x17) are all the same, so just copy data from an existing SOUN.<br />
At offset 24 (0x18) track number in hex format (for new music not in original start with track decimal 24 or hex 18).<br />
At offset 25 (0x19) seems to be loop, opening uses 01, scummbar uses ff.<br />
The six remaining values 26-31 (0x1a-0x1f) are all 00 if you want the music to start at the beginning of the track.<br />
<br />
An example of music not starting at the beginning:<br />
The scene at the lookout following the intro uses the same music as the opening, but starts at position 1 min 36 sec. Hex values are 01 23 30 00 00 00. 01 23 30 is equivalent to 1 35 48 in decimal.<br />
<br />
==v5-v6 - MONSTER.SOU==<br />
<br />
===Original===<br />
<br />
From Indy 4 onwards, sound effects and speech are stored in a separate resource file called "MONSTER.SOU". The format is:<br />
<br />
Block name 4 bytes ("SOU ")<br />
Block size 4 bytes<br />
One or more:<br />
Block name 4 bytes ("VCTL")<br />
Block size 4 bytes<br />
Lip-sync tags variable * 2 bytes LE<br />
Sound data variable ("Crea" block / VOC file)<br />
<br />
The lip-sync tags provide timing information, and are 16-bit LE values, representing positions in the speech file. Lip synching is basically just toggling the speaking animation on and off whenever the speech goes past the positions listed in the lip-synch tags. In v5 the number of tags is stored in the calling text, according to the formula (num_tags << 1) + 8. The "Crea" block is an entire Creative VOC file.<br />
<br />
===Compressed===<br />
<br />
ScummVM can use compressed monster.sou files created with the tool "compress_scumm_sou.exe". Aside from using either MP3, OGG, or FLAC formats for the sound data, they contain a mapping table followed by the sound data, like so:<br />
<br />
size_of_table : uint32<br />
size_of_table / 16 times {<br />
orig_offset : uint32<br />
actual_offset : uint32<br />
num_tags : uint32<br />
sound_size : unit32<br />
}<br />
size_of_table / 16 times {<br />
num_tags times {<br />
tag : uint8<br />
}<br />
sound : sound_size (sound file - MP3/OGG/FLAC)<br />
} <br />
<br />
Each entry in the table has 4 items, each item is 4 bytes, so a table with one entry has a size of 16.<br />
<br />
The original offset is what the game will try to play, the actual offset is taken from after the index table.<br />
<br />
Each sound is directly preceded by its lip-synch tags.<br />
<br />
=Sound block types=<br />
This information is gleaned from the ScummVM source code. Any block name with only three characters has a space at the end.<br />
MIDI \ Midi<br />
iMUS /<br />
<br />
SOU subtypes<br />
TOWS - FM Towns<br />
SBL - Sound Blaster digitized sound (Creative VOC file)<br />
ADL - AdLib (OPL FM)<br />
AMI - Amiga MOD<br />
ROL - Roland MT-32<br />
GMD - General MIDI<br />
MAC - Macintosh (occurs in MI2, FOA)<br />
SPK - PC speaker<br />
<br />
Mac0 - Macintosh music type 0<br />
<br />
Mac1 \<br />
RIFF |<br />
TALK > Creative VOC file<br />
DIGI |<br />
Crea /<br />
<br />
HSHD - HE sound type without SOUN header<br />
<br />
FMUS - Used in 3DO versions of HE games</div>Jestar jokinhttps://wiki.scummvm.org/index.php?title=SCUMM/Technical_Reference/iMuse_data&diff=14656SCUMM/Technical Reference/iMuse data2010-09-03T01:46:53Z<p>Jestar jokin: Copy information from ScummC wiki by Alban Bedel, from archive here: http://wiki.github.com/jamesu/scummc/imuse</p>
<hr />
<div>== iMuse ==<br />
<br />
iMuse is the system used for the music. It main feature is to allow perfect integration of the music; with some talent, the game music can appear as a continuous soundtrack to the player.<br />
<br />
== SCUMM interface ==<br />
<br />
Imuse is a subsystem of the SCUMM engine with its own set of commands. From a SCUMM script the following functions are avaible:<br />
<br />
* startSound(snd)<br />
* stopSound(snd)<br />
* startMusic(m)<br />
* isSoundRunning(snd)<br />
* soundKludge([cmd_list])<br />
<br />
As you can see, that is pretty spartan: all the power is in the soundKludge function. This will need some pretty good abstraction in the compiler, probably by adding a block similar to inline asm in C.<br />
<br />
== Command list ==<br />
<br />
* '''0x0006''' : imSetMasterVolume(volume)<br />
<pre> volume : [0-127]</pre><br />
* '''0x0007''' : imGetMasterVolume()<br />
* '''0x0008''' : imStartSound(sound)<br />
* '''0x0009''' : imStopSound(sound)<br />
* '''0x000A''' : imStopAllSounds() ???<br />
* '''0x000B''' : imStopAllSounds()<br />
* '''0x000C''' : imPlayerSet(player, ???, cmd, params ...)<br />
Used in S&M<br />
* '''0x000D''' : imGetSoundStatus(sound)<br />
sound == -1 returns the first active sound<br />
* '''0x000E''' : imFadeSound(player, ????, fader_p1, fader_p2, fader_p3)<br />
S&M only ?<br />
* '''0x000F''' : imMaybeHook(player, ????, param)<br />
S&M<br />
* '''0x0010''' : imSetVolchan(sound,volchan)<br />
* '''0x0011''' : imSetChannelVolume(chan,volume)<br />
In S&M: set/clear trigger<br />
* '''0x0012''' : imSetVolchanEntry(volchan,val)<br />
S&M: ImCheckTrigger<br />
* '''0x0013''' : imClearTrigger(a,b)<br />
* '''0x0100''' : imPlayerGetParam(player,param,chan)<br />
In DOTT this is often called with only 2 args, in that case it seems to default to chan=0.<br />
S&M: Beat suff<br />
* '''0x0101''' : imPlayerSetPriority(player,prio)<br />
* '''0x0102''' : imPlayerSetVolume(player,volume)<br />
<pre> volume : [0:127]</pre><br />
* '''0x0103''' : imPlayerSetPan(player,pan)<br />
* '''0x0104''' : imPlayerSetTranspose(player,relative,val)<br />
<pre> val : [-24:24]</pre><br />
* '''0x0105''' : imPlayerSetDetune(player,detune)<br />
* '''0x0106''' : imPlayerSetSpeed(player,speed)<br />
* '''0x0107''' : imPlayerJump(player,track,beat,tick)<br />
* '''0x0108''' : imPlayerScan(player,toTrack,toBeat,toTick)<br />
* '''0x0109''' : imPlayerSetLoop(player,count,toBeat,toTick,fromBeat,fromTick)<br />
* '''0x010A''' : imPlayerClearLoop(player)<br />
* '''0x010B''' : imPlayerSetOnOff(player,chan,status)<br />
* '''0x010C''' : imPlayerSetHook(player,type,value,chan)<br />
* '''0x010D''' : imPlayerFade(player,target,time)<br />
* '''0x010E''' : imQueueTrigger(a,b)<br />
* '''0x010F''' : imQueueCommand(cmd,arg1,arg2,arg3,arg4,arg5,arg6)<br />
* '''0x0110''' : imClearQueue()<br />
* '''0x0111''' : ??? Live MIDI ON<br />
* '''0x0112''' : ??? Live MIDI OFF<br />
* '''0x0113''' : imPlayerGetParam(player,param,chan)<br />
* '''0x0114''' : imPlayerSetHook(player,type,value,chan)<br />
* '''0x0115''' : ???<br />
* '''0x0116''' : imPlayerSetVolume(player,part,vol)<br />
* '''0x0117''' : imQueryQueue(param)<br />
** param:<br />
*** 0: trigger count<br />
*** 1: last trigger type<br />
*** 2: last trigger sound<br />
* '''0x0118''' : ???<br />
<br />
== Player parameters ==<br />
<br />
* '''0x00''': priority<br />
* '''0x01''': volume<br />
* '''0x02''': pan<br />
* '''0x03''': transpose<br />
* '''0x04''': detune<br />
* '''0x05''': speed<br />
* '''0x06''': track index<br />
* '''0x07''': beat index<br />
* '''0x08''': tick index<br />
* '''0x09''': loop counter<br />
* '''0x0A''': loop to beat<br />
* '''0x0B''': loop to tick<br />
* '''0x0C''': loop from tick<br />
* '''0x0D''': loop from tick<br />
* '''0x0E''': part on<br />
* '''0x0F''': part vol<br />
* '''0x10''': part instrument<br />
* '''0x11''': part transpose<br />
* '''0x12''': jump hook<br />
* '''0x13''': transpose hook<br />
* '''0x14''': part onoff hook<br />
* '''0x15''': part volume hook<br />
* '''0x16''': part program hook<br />
* '''0x17''': part transpose hook<br />
<br />
== Hook types ==<br />
<br />
* '''0x00''': jump<br />
* '''0x01''': transpose<br />
* '''0x02''': chan on/off (0x0F == all)<br />
* '''0x03''': chan volume (0x0F == all)<br />
* '''0x04''': chan part program<br />
* '''0x05''': chan transpose<br />
<br />
== MIDI SysEx ==<br />
<br />
The MIDI data fed to iMUSE can contain (and to some extent needs) some special SysEx commands. The manufacturer ID 0x7D is used for these SysExes and the first byte indicates the command.<br />
<br />
In the SysEx data, only the first 7 bits are significant (value in the 0x80-0xFF range are used for real-time messages among other things), so values larger than 7 bits use 1 nibble per byte in big endian order (most significant nibble first). In the following descriptions, each line corresponds to one or more bytes of data.<br />
<br />
The relevant code in ScummVM 0.9 is in engines/scumm/imuse/sysex_scumm.cpp and engines/scumm/imuse/imuse_player.cpp.<br />
<br />
* '''0x00''': Allocate new part<br />
<pre> part : 4<br />
unknown : 7<br />
flags : 2 bit 0 turn the part on/off<br />
bit 1 turn the reverb on/off<br />
priority : 7<br />
volume : 8<br />
pan : 8<br />
flags2 : 7 bit 3 set percussion mode<br />
pitchbend : 8<br />
program : 8<br />
</pre><br />
* '''0x01''': Shut down a part<br />
<pre> part : 4</pre><br />
* '''0x02''': Start of song <br />
This command is ignored by ScummVM 0.9.<br />
* '''0x10''': Adlib instrument definition (Part)<br />
<pre> part : 4<br />
hw type : 7<br />
adlib data : 60*8<br />
</pre><br />
* '''0x11''': Adlib instrument definition (Global)<br />
<pre> unknown : 7<br />
hw type : 7<br />
intrument : 7<br />
adlib data : 60*8<br />
</pre><br />
* '''0x21''': Parameter adjust<br />
<pre> part : 4<br />
hw type : 7<br />
param : 16be<br />
value : 16be<br />
</pre><br />
* '''0x30''': Hook - jump<br />
<pre> unknown : 7<br />
cmd : 8<br />
track : 16be<br />
beat : 16be<br />
tick : 16be<br />
</pre><br />
* '''0x31''': Hook - global transpose<br />
<pre> unknown : 7<br />
cmd : 8<br />
relative : 8<br />
value : s8<br />
</pre><br />
* '''0x32''': Hook - part on/off<br />
<pre> chan : 4<br />
cmd : 8<br />
value : 8<br />
</pre><br />
* '''0x33''': Hook - set volume<br />
<pre> chan : 4<br />
cmd : 8<br />
value : 8<br />
</pre><br />
* '''0x34''': Hook - set program<br />
<pre> chan : 4<br />
cmd : 8<br />
value : 8<br />
</pre><br />
* '''0x35''': Hook - set transpose<br />
<pre> chan : 4<br />
cmd : 8<br />
relative : 8<br />
value : s8<br />
</pre><br />
* '''0x40''': Marker<br />
<pre> unknown : 7<br />
marker : 7*n<br />
</pre><br />
* '''0x50''': Set loop<br />
<pre> unknown : 7<br />
count : 16be<br />
tobeat : 16be<br />
totick : 16be<br />
frombeat : 16be<br />
fromtick : 16be<br />
</pre><br />
* '''0x51''': Clear loop <br />
No arguments (or at least unused by ScummVM).<br />
* '''0x60''': Set instrument<br />
<pre> chan : 4<br />
instrument : 16be<br />
</pre><br />
<br />
== Adlib instrument ==<br />
<br />
See some Adlib/Soundblaster documentation: http://www.shipbrook.com/jeff/sb.html<br />
<pre><br />
operators : 8*5*2<br />
characteristic : 8 (port 0x20)<br />
scalingOutputLevel : 8 (port 0x40)<br />
attackDecay : 8 (port 0x60)<br />
sustainRelease : 8 (port 0x80)<br />
waveformSelect : 8 (port 0xE0)<br />
feedback : 8 (port 0xC0)<br />
flags_a : 8<br />
extra_a : 8*8<br />
flags_b : 8<br />
extra_b : 8*8<br />
duration : 8<br />
</pre></div>Jestar jokinhttps://wiki.scummvm.org/index.php?title=SCUMM/Technical_Reference/String_format&diff=14655SCUMM/Technical Reference/String format2010-09-03T01:41:11Z<p>Jestar jokin: Copy information from ScummC wiki by Alban Bedel, from archive here: http://wiki.github.com/jamesu/scummc/scumm6-strings</p>
<hr />
<div>== Scumm 6 strings ==<br />
<br />
In SCUMM strings can contain some escapes to code a few special things. Escapes start with 0xFF followed by a byte which codes the escape type, and are generally followed by some parameters.<br />
<br />
=== 0x01: New line ===<br />
<br />
=== 0x02: Keep ===<br />
<br />
=== 0x03: Wait ===<br />
<br />
=== 0x04xxxx: Integer ===<br />
<br />
Expands to the integer value of the variable at the given address.<br />
<br />
=== 0x05xxxx: Verb ===<br />
<br />
Expands to the verb referenced in the variable at the given address.<br />
<br />
=== 0x06xxxx: Name ===<br />
<br />
Expands to the name of the object or actor referenced in the variable at the given address.<br />
<br />
=== 0x07xxxx: String ===<br />
<br />
Expands to the string contained in the array referenced in the variable at the given address.<br />
<br />
=== 0x09xxxx: Start actor anim ===<br />
<br />
Starts the given animation. Only works on the talking actor, if any.<br />
<br />
=== 0x0Axxxx: Voice ===<br />
<br />
Plays a sound sample, mostly used for voices. This escape takes quite a lot of arguments. To avoid yet another special case when computing the string length, etc., the escape is repeated several times to code two 32 bits values (LE). The first value is the position of the sample in the sound file. The second value is the size of the VCTL header found before the audio data.<br />
<br />
=== 0x0Cxxxx: Color ===<br />
<br />
=== 0x0Dxxxx: Unknown ===<br />
<br />
=== 0x0Exxxx: Charset ===</div>Jestar jokinhttps://wiki.scummvm.org/index.php?title=SCUMM/Technical_Reference/Costume_resources&diff=14654SCUMM/Technical Reference/Costume resources2010-09-03T01:30:03Z<p>Jestar jokin: Copy information from ScummC wiki by Alban Bedel, from archive here: http://wiki.github.com/jamesu/scummc/scumm-costume-formats</p>
<hr />
<div>== Costume formats ==<br />
<br />
=== 1. COST ===<br />
<br />
Costumes store the animations used for characters in the game. The format is relatively complex. It basically consists of a bunch of frames and commands to make use of them :) I had a hard time really figuring out how this works.<br />
<br />
<pre> size : 32le can be 0 (see num anim) or the size<br />
(sometimes with an offset of one ??)<br />
header : 2*8 always contain "CO"<br />
num anim : 8 if(size) num_anim++<br />
format : 8 bit 7 set means that west anims must NOT be mirrored,<br />
bit 0 is the palette size (0: 16 colors, 1: 32 colors)<br />
palette : 8*num colors coded in format<br />
anim cmds offset : 16le access the anim cmds array<br />
limbs offset : 16*16le access limb picture table<br />
anim offsets : 16le*num anim access anim definitions<br />
anim<br />
limb mask : 16le<br />
anim definitions : variable length, one definition for each bit set<br />
to 1 in the limb mask.<br />
0xFFFF : 16le disabled limb code<br />
OR<br />
start : 16le<br />
noloop : 1<br />
end offset : 7 offset of the last frame, or len-1<br />
anim cmds<br />
cmd : 8<br />
limbs<br />
pict offset : 16le<br />
picts<br />
width : 16le<br />
height : 16le<br />
rel_x : s16le<br />
rel_y : s16le<br />
move_x : s16le<br />
move_y : s16le<br />
redir_limb : 8 only present if((format & 0x7E) == 0x60)<br />
redir_pict : 8 only present if((format & 0x7E) == 0x60)<br />
rle data<br />
</pre><br />
<br />
Each animation can have up to 16 ''limbs'', each with its own sequence of pictures. The sequences are defined in the ''anim'' block. A definition starts with a 16le mask telling which limbs are used. Each bit of the mask stands for a limb. After the mask is a 16le index, giving the start position of the sequence in the ''anim cmds'' array. An index of 0xFFFF is used to turn off the limb; if the index is not 0xFFFF, then it's followed by the length of the sequence (8 bits). The highest bit of the length is used to indicate whether the sequence should loop, if it is set the animation doesn't loop.<br />
<br />
So an animation is defined by a part of the ''anim cmds'' array. This array contains either picture numbers or some special values used to fire sounds, etc. Now to access the pictures, one has to look in the ''limb'' table. The table again contains offsets which finally allow us to find the right picture. So each limb has its own set of pictures, although sometimes several limbs share the same table.<br />
<br />
As you can see, the format 0x60 has 2 extra fields in the picture header. If they are not 0xFF, they indicate a redirection to the picture ''redir_pict'' of the limb ''redir_limb''. Also note that sometimes several entries in the limb table will point to the same picture.<br />
<br />
It seems the data is always properly ordered. That is, the first picture of the first limb comes right after the last limb table. The first limb table start right after the cmd array, and so on. Currently this seems to be the only way to determine how long the cmd array is, or how long the last limb table is. Clumsy but it works, however a simple decoder doesn't need to compute these lengths :)<br />
<br />
Note: All the offsets are relative to the block start (without the standard 8 byte SCUMM block header).<br />
<br />
WARNING: When one numbers the limbs from their corresponding bit in the limb masks, they are then indexed in reverse order. This means the first entry in the limb table is limb 15, then comes limb 14, etc. The same holds for the anim definitions. Rendering should also be done in that order.<br />
<br />
Note 2: The transparent color is always 0.<br />
<br />
==== 1.2 Commands ====<br />
<br />
There are very few commands available and they have no arguments.<br />
<br />
* '''0x71-0x78''': addSound()<br />
In Lucas games add sound cmd-0x71, in Humongous games add sound 0x78-cmd.<br />
* '''0x79''': stop()<br />
* '''0x7A''': start()<br />
* '''0x7B''': hide()<br />
* '''0x7C''': skipFrame()<br />
<br />
==== 1.3 RLE compression ====<br />
<br />
The compression used for the costume data is a simple byte based RLE compression. However, it works by columns, not by lines. Each byte contains the color in the high bits and the repetition count in the low bits. If the repetition count is 0, then the next byte contains the actual repetition count. How many bits are used for the color depends on the palette size: for a 16 color palette, 4 bits are used for the color; for 32 colors, 5 bits are used.<br />
<br />
<pre> if(palette_size == 16) {<br />
shift = 4;<br />
mask = 0xF;<br />
} else {<br />
shift = 3;<br />
mask = 0x7;<br />
}<br />
<br />
while(1) {<br />
rep = read_byte();<br />
color = rep >> shift;<br />
rep &= mask;<br />
if(!rep)<br />
rep = read_byte();<br />
while(rep > 0) {<br />
set_pixel(x,y,color);<br />
rep--;<br />
y++;<br />
if(y >= height) {<br />
y = 0;<br />
x++;<br />
if(x >= width) break;<br />
}<br />
}<br />
}<br />
</pre><br />
<br />
==== 1.4 Animations ====<br />
<br />
Costume animations are always grouped in blocks of 4, one for each direction. The four directions are:<br />
<br />
* 0: WEST (or right)<br />
* 1: EAST (or left)<br />
* 2: SOUTH (or down)<br />
* 3: NORTH (or up)<br />
<br />
Costumes used for normal actors have some predefined animations:<br />
<br />
* 00-03: unknown<br />
* 04-07: init<br />
* 08-11: walk<br />
* 12-15: stand<br />
* 16-19: talk start<br />
* 20-23: talk stop<br />
<br />
ScummVM maps the following animations:<br />
<br />
* 56: init frame (04)<br />
* 57: walk frame (08)<br />
* 58: stand frame (12)<br />
* 59: talk start frame (16)<br />
* 60: talk stop frame (20)<br />
<br />
There is also an assert preventing 62 (0x3E), but I really have no clue why.<br />
<br />
When actor animations are selected these have a special effect:<br />
<br />
* 244-247: turn to new direction<br />
* 248-251: change direction immediately<br />
* 252-255: stop walking<br />
<br />
So as far as I can tell, this leaves the ranges 24-55, 64-112 and perhaps 125-243 free for other animations. In DOTT, Hoaggi's costume uses the following:<br />
<br />
* 32-35: pick something up raising the arm<br />
* 36-39: pick something up in front<br />
* 40-43: pick something up off the ground<br />
* 44-47: smile<br />
<br />
=== 2. AKOS ===<br />
<br />
AKOS, which are used in SCUMM 7 and 8, are much more powerful than the old COST and their data structure seems much cleaner. Could it be worst than the COST ? ;)<br />
<br />
Note: some of this come from "LucasHacks":http://scumm.mixnmojo.com/!<br />
<br />
==== 2.1 Structure ====<br />
<br />
An AKOS block is made of some block unlike the COST.<br />
<br />
* '''AKHD''': Header<br />
* '''AKPL''': Palette (optional)<br />
* '''RGBS''': RGB Values (optional)<br />
* '''AKSQ''': Commands sequence<br />
* '''AKCH''': Anim offset table and definitions<br />
* '''AKOF''': Offset table<br />
* '''AKCI''': Frames definition<br />
* '''AKCD''': Frames data<br />
<br />
I found these in the code but not in comi, so i suppose it's only used by he engines.<br />
<br />
* '''AKCT''': Condition table ???<br />
* '''AKST''': Sequence table (set seq3, apparenly only used by he games) ???<br />
* '''AKSF''': Sequence table (set seq1 and seq2, apparenly only used by he games) ???<br />
* '''AKFO''': Sequence jump table, 16 bits list<br />
<br />
==== 2.2 Blocks content ====<br />
<br />
==== 2.2.1 AKHD ====<br />
<br />
<pre> unk1 : 16<br />
flags : 8<br />
unk2 : 8<br />
num anims : 16le<br />
num frames : 16le<br />
codec : 16le<br />
</pre><br />
<br />
Flags: bit 0 is mirror, bit 1 is the number of directions the costume have (4 or 8)<br />
<br />
==== 2.2.2 AKPL ====<br />
<br />
AKPL blocks are just a list of 8 bits values.<br />
<br />
==== 2.2.3 RGBS ====<br />
<br />
RGBS blocks are just a list of 8 bits triplet coding colors.<br />
<br />
==== 2.2.4 AKOF ====<br />
<br />
<pre> frames<br />
AKCD offset : 32le<br />
AKCI offset : 16le<br />
</pre><br />
<br />
==== 2.2.5 AKCI ====<br />
<br />
<pre> frames<br />
width : 16le<br />
height : 16le<br />
rel_x : s16le<br />
rel_y : s16le<br />
move_x : s16le<br />
move_y : s16le<br />
</pre><br />
<br />
==== 2.2.6 AKCD ====<br />
<br />
Just all the commpressed frames packed together.<br />
<br />
==== 2.2.7 AKCH ====<br />
<br />
The AKCH block define the various animations, they are pretty similar to the anim definitions in the COST. It start with an offset table giving access to all entries, followed by all definitions. The definitions start with a mask indicating which limb are active, followed by the actual limb definitions.<br />
<br />
<pre> offset table : num anims time<br />
offset : 16le<br />
definitions : num anims time<br />
limb mask : 16le<br />
mode : 8<br />
start : 16le<br />
len : 16le<br />
</pre><br />
<br />
The <TT>start</TT> and <TT>end</TT> are there only if <TT>mode</TT> is not equal to 1, 4 or 5.<br />
<br />
<tt>mode</tt><br />
<br />
* '''0''': Disabled<br />
* '''1''': Single frame, no commands ???<br />
* '''2''': Loop<br />
* '''3''': Play once<br />
* '''4''': Stop limb<br />
* '''5''': Start limb<br />
* '''6''': Ignore first commande/pic mode ?<br />
* '''7''': Unk<br />
* '''8''': Same as mode 6 ?<br />
<br />
==== 2.2.8 AKSQ ====<br />
<br />
In AKOS the picture index are mixed with the commands like in the COST, they are found in the AKSQ block. The AKOS have a lot more commands than the old COST so the stream is a mix of 8 and 16 bits values. It is read with something like this:<br />
<br />
<pre> code = p[0];<br />
if(code & 0x80)<br />
code = (code << 8) | p[1];<br />
</pre><br />
<br />
8 bits values are always picture index. All 16 bits value with 0xC0 in the MSB are commands, the rest are picture index to which a mask of 0xFFF is applied.<br />
<br />
==== 2.3 Commands ====<br />
<br />
* '''0xC001''': return()<br />
* '''0xC010''': setVar(word value,byte *var)<br />
* '''0xC015''': startSound(byte snd)<br />
* '''0xC016''': ifVarSoundIsRunning(uword jmp,byte *snd)<br />
* '''0xC017''': ifVarSoundIsNotRunning(uword jmp,byte *snd)<br />
* '''0xC018''': ifSoundIsRunning(uword jmp,byte snd)<br />
* '''0xC019''': ifSoundIsNotRunning(uword jmp,byte snd)<br />
* '''0xC020''': complexChan(word ???,byte ???)<br />
Use an alternative rendering mode, apparently it render the limb several time, moving it betwen each frame.<br />
* '''0xC021''': ???(byte narg,...)<br />
load seq3Idx with the list and switch to complexChan limb rendering<br />
* '''0xC022''': ???(byte narg,...)<br />
load seq3Idx with the list and switch to complexChan2 limb rendering<br />
* '''0xC025''': complexChan2(word ???,word ????)<br />
Similar to complexChan but with a subtile difference, which ??<br />
* '''0xC030''': jump(uword jmp)<br />
* '''0xC031''': jumpIfSet(uword jmp,byte *var)<br />
* '''0xC040''': addVar(word val,byte *var)<br />
* '''0xC042''': startSound(byte snd)<br />
* '''0xC044''': startVarSound(byte *snd)<br />
* '''0xC045''': setUserCondition(byte narg,byte slot,byte *set)<br />
* '''0xC046''': isUserConditionSet(byte narg,byte slot,byte *ret)<br />
* '''0xC047''': setTalkCondition(byte narg,byte slot)<br />
* '''0xC048''': isTalkConditionSet(byte narg,byte slot,byte *ret)<br />
* '''0xC050''': ignore()<br />
* '''0xC060''': incVar0()<br />
* '''0xC061''': startSound0()<br />
* '''0xC070''': jumpE(uword jmp,byte *a, word b)<br />
* '''0xC071''': jumpNE(uword jmp,byte *a, word b)<br />
* '''0xC072''': jumpL(uword jmp,byte *a, word b)<br />
* '''0xC073''': jumpLE(uword jmp,byte *a, word b)<br />
* '''0xC074''': jumpG(uword jmp,byte *a, word b)<br />
* '''0xC075''': jumpGE(uword jmp,byte *a, word b)<br />
* '''0xC080''': startAnim(byte anim)<br />
* '''0xC081''': startVarAnim(byte *anim)<br />
* '''0xC082''': random(word min,word max,byte *ret)<br />
* '''0xC083''': setActorClip(byte val)<br />
* '''0xC084''': startAnimInActor(byte *actor,byte *anim)<br />
* '''0xC085''': setVarInActor(byte *actor,byte *var,word val)<br />
* '''0xC086''': hideActor()<br />
* '''0xC087''': setDrawOffs(word a,word b)<br />
* '''0xC088''': jumpTable(byte *entry)<br />
* '''0xC089''': soundStuff(byte snd,byte ???,byte cmd,byte ???,byte val)<br />
* '''0xC08A''': flip(word val)<br />
* '''0xC08B''': cmd3(byte ???,byte ???, byte ???, byte ???)<br />
* '''0xC08C''': ignore3(byte ???)<br />
* '''0xC08D''': ignore2(byte ???)<br />
* '''0xC08E''': resetVolume(word snd)<br />
* '''0xC090''': skipE(word a, byte *b)<br />
* '''0xC091''': skipNE(word a, byte *b)<br />
* '''0xC092''': skipL(word a, byte *b)<br />
* '''0xC093''': skipLE(word a, byte *b)<br />
* '''0xC094''': skipG(word a, byte *b)<br />
* '''0xC095''': skipGE(word a, byte *b)<br />
* '''0xC09F''': clearFlag()<br />
* '''0xC0A0''': resetPan(byte snd,byte ???)<br />
* '''0xC0A1''': jumpIfTalking(uword jmp)<br />
* '''0xC0A2''': jumpIfNotTalking(uword jmp)<br />
* '''0xC0A3''': resetVarPan(byte *snd)<br />
* '''0xC0A4''': ???<br />
* '''0xC0A5''': ???<br />
* '''0xC0A6''': ???<br />
* '''0xC0A7''': ???<br />
* '''0xC0FF''': enqSeq<br />
<br />
==== 2.4 Codecs ====<br />
<br />
There are 4 known codec: 1, 5, 16 and 32. The latter is only supported by HE engines.<br />
<br />
==== 2.4.1 Codec 1 ====<br />
<br />
This codec seems identical to the one used in the old COST, except it also support 64 colors. I suppose it's not very efficient in 64 colors mode as any repeat of more than 3 will need 2 bytes.<br />
<br />
==== 2.4.2 Codec 5 ====<br />
<br />
This one use the same encoding as BMOP image. See [[Scumm Image formats]].<br />
<br />
==== 2.4.3 Codec 16 ====<br />
<br />
<pre><br />
bpp = read_byte();<br />
color = read_byte();<br />
repeat = 0;<br />
while(pos < width*height) {<br />
write_pixel(pos%width,pos/width,color);<br />
if(repeat > 0) repeat--;<br />
else if(read_bit()) {<br />
if(read_bit()) {<br />
delta = read_bits(3);<br />
if(delta != 4)<br />
color += delta-4;<br />
else<br />
repeat = read_bits(8) - 1;<br />
} else<br />
color = read_bits(bpp);<br />
}<br />
pos++;<br />
}<br />
</pre></div>Jestar jokinhttps://wiki.scummvm.org/index.php?title=SCUMM/Technical_Reference&diff=14653SCUMM/Technical Reference2010-09-03T01:14:48Z<p>Jestar jokin: Re-arrange resource/data formats section, in preperation for copying information from the dead ScummC wiki.</p>
<hr />
<div>Here we are trying to gather all sorts of information we have about the SCUMM/SPUTM engine.<br />
<br />
This needs to be extended. A lot of information can be found directly in the ScummVM source, the heads of its developers, and the external links I found below. Feel free to try and tap each of these sources to gain more information and add it here (note: no brain surgery recommended. For external sources, permission from the authors should be recieved before blatantly copying stuff).<br />
<br />
== General ==<br />
* [[SCUMM/Virtual Machine|SCUMM Virtual Machine]]<br />
* [[SCUMM/Arrays and Strings|SCUMM Arrays and Strings]]<br />
* [[SCUMM/Versions|SCUMM Versions]]<br />
* [[SCUMM/Terminology|SCUMM Terminology]]<br />
<br />
== Resource and data formats ==<br />
Information about the formats of various resource types used in SCUMM games.<br />
* [[SCUMM/Technical_Reference/Index File|Index File]]<br />
* [[SCUMM/Technical_Reference/Box resources|Box resources]]<br />
* [[SCUMM/Technical_Reference/Charset resources|Charset resources]]<br />
* [[SCUMM/Technical_Reference/Costume resources|Costume resources]]<br />
* [[SCUMM/Technical_Reference/Image resources|Image resources]]<br />
* [[SCUMM/Technical_Reference/Object resources|Object resources]]<br />
* [[SCUMM/Technical_Reference/Script resources|Script resources]]<br />
* [[SCUMM/Technical_Reference/Sound resources|Sound resources]]<br />
* [[SCUMM/Technical_Reference/iMuse data|iMuse data]]<br />
* [[SCUMM/Technical_Reference/String format|String format]]<br />
<br />
== Opcode tables ==<br />
* [[SCUMM/V0 opcodes|SCUMM V0 opcodes]]<br />
* [[SCUMM/V2 opcodes|SCUMM V2 opcodes]] (V1 is very similar)<br />
* [[SCUMM/V5 opcodes|SCUMM V5 opcodes]] (V3 and V4 are very similar)<br />
* [[SCUMM/V6 opcodes|SCUMM V6 opcodes]] (V7 is very similar)<br />
* [[SCUMM/V8 opcodes|SCUMM V8 opcodes]]<br />
<br />
== External links ==<br />
* http://alban.dotsec.net/7.html<br />
* http://www.scummvm.org/docs/specs/index.php<br />
* http://www.lucasforums.com/showthread.php?s=&postid=1199968#post1217901<br />
* http://scumm.mixnmojo.com/?page=articles<br />
* http://scumm.mixnmojo.com/?page=specs<br />
* http://scumm.mixnmojo.com/?page=utils</div>Jestar jokinhttps://wiki.scummvm.org/index.php?title=SCUMM/V5_opcodes&diff=14359SCUMM/V5 opcodes2010-08-03T07:57:34Z<p>Jestar jokin: Correct opcode for drawObject, some entries to do with aux opcode values.</p>
<hr />
<div>=SCUMM V5 opcodes=<br />
The following conventions are used in the encoding descriptions.<br />
<br />
{| border="1" cellpadding="2" width=100%<br />
|- style="background:whitesmoke"<br />
|Term||Description<br />
|-<br />
|opcode||The instruction's opcode, with the appropriate bits set according to the parameters.<br />
|-<br />
|aux||An aux opcode that stores parameter bits and no other information. (the base aux opcode is usually $01, but can differ for each instruction)<br />
|-<br />
|sub-opcode||An aux opcode that indicates a specific function to perform (e.g. the "wait" instruction has sub-opcodes to "wait for message", "wait for actor" etc), as well as storing parameter bits if necessary.<br />
|-<br />
|result||A result pointer. (A standard word pointer, always a LE word.)<br />
|-<br />
|var||A variable pointer. Same as above, but is not written to. Because this is always a variable, the opcode is not affected like it would be with a normal parameter (described below).<br />
|-<br />
|value[8]||An 8-bit constant (a byte).<br />
|-<br />
|value[16]||A 16-bit constant (a word LE).<br />
|-<br />
|value[p8]||An 8-bit parameter. This may be encoded as a word LE if it's a pointer, or a byte if it's a constant.<br />
|-<br />
|value[p16]||A 16-bit parameter. This is always encoded as a word LE, and may be a pointer or constant.<br />
|-<br />
|value[v16]||A variable number of word LE parameters. These are encoded as a sequence of aux[8] param[p16]; param; aux contains the parameter bit to describe param (and is always $01, ignoring the parameter bits). A byte of $FF terminates the sequence. (actually always shown as "value[v16]...")<br />
|-<br />
|value[o]||The offset word for parameter value. This is only encoded if needed, but always at the position indicated. If not specified, the offset word occurs immediately after the parameter.<br />
|-<br />
|value[c]||An ASCII character. Because some instructions use null-terminated strings and some use $FF, the exact format of a string is described in the instruction. Almost always appears as "value[c]..."<br />
|-<br />
|term...||One or more terms.<br />
|}<br />
<br />
Of course, due to the non-orthogonality of the opcodes, there are lots of exceptions.<br />
<br />
<br />
==actorFollowCamera ($52)==<br />
<br />
===Encoding===<br />
opcode actor[p8]<br />
<br />
===Operation===<br />
Sets the camera to follow the given actor?<br />
<br />
<br />
==actorFromPos ($15)==<br />
<br />
===Encoding===<br />
opcode result x[p16] y[p16]<br />
<br />
===Operation===<br />
Returns the actor located at the given co-ordinates.<br />
<br />
<br />
==actorOps ($13)==<br />
parameters depend on auxiliary opcode; terminated by $FF<br />
<br />
===Encoding===<br />
opcode actor[p8] sub-opcode... $FF<br />
<br />
sub-opcodes:<br />
$00 arg1[p8]<br />
$01 costume[p8]<br />
$02 xspeed[p8] yspeed[p8]<br />
$03 sound[p8]<br />
$04 walkframe[p8]<br />
$05 starttalk[p8] endtalk[p8]<br />
$06 standframe[p8]<br />
$07 arg1[p8] arg2[p8] arg3[p8]<br />
$08<br />
$09 elevation[p16]<br />
$0A<br />
$0B index[p8] value[p8]<br />
$0C colour[p8]<br />
$0D name[c]... $00<br />
$0E initframe[p8]<br />
$10 width[p8]<br />
$11 xscale[p8] yscale[p8]<br />
$12<br />
$13 zplane[p8]<br />
$14<br />
$15 <br />
$16 animspeed[p8]<br />
$17 shadow[p8]<br />
<br />
===Operation===<br />
Miscellaneous actions on actors.<br />
<br />
{| border="1" cellpadding="2" width=100%<br />
|- style="background:whitesmoke"<br />
|Opcode||Meaning||Description<br />
|-<br />
|$00||dummy||A dummy case, does nothing (in ScummVM).<br />
|-<br />
|$01||SO_COSTUME||Sets the actor's costume.<br />
|-<br />
|$02||SO_STEP_DIST||Sets the actor's walking speed for x and y.<br />
|-<br />
|$03||SO_SOUND||Associates a sound with the actor (footsteps?)<br />
|-<br />
|$04||SO_WALK_ANIMATION||Sets the current frame of the walking animation.<br />
|-<br />
|$05||SO_TALK_ANIMATION||Sets the start and stop frames of the talking animation.<br />
|-<br />
|$06||SO_STAND_ANIMATION||Sets the current frame of the standing animation.<br />
|-<br />
|$07||SO_ANIMATION||Unknown; seems to be unused in ScummVM.<br />
|-<br />
|$08||SO_DEFAULT||Initializes actor.<br />
|-<br />
|$09||SO_ELEVATION||Sets the actor's elevation to the given value.<br />
|-<br />
|$0A||SO_ANIMATION_DEFAULT||Initializes the actor's animation frames.<br>Init frame = 1<br>Walk frame = 2<br>Stand frame = 3<br>Talk start frame = 4<br>Talk stop frame = 5<br />
|-<br />
|$0B||SO_PALETTE||Sets the colour at the given index to a new value (another entry in the colour lookup table/CLUT). Index must be between 0 and 31 (the number of colours in a costume).<br />
|-<br />
|$0C||SO_TALK_COLOR||Sets the actor's talk colour.<br />
|-<br />
|$0D||SO_ACTOR_NAME||Sets the actor's name to the given null-terminated string.<br />
|-<br />
|$0E||SO_INIT_ANIMATION||Sets the current frame of the initial animation.<br />
|-<br />
|$10||SO_ACTOR_WIDTH||Sets the actor's width.<br />
|-<br />
|$11||SO_ACTOR_SCALE||Sets the actor's X and Y scales.<br />
|-<br />
|$12||SO_NEVER_ZCLIP||Turns off all Z-clipping for the actor.<br />
|-<br />
|$13||SO_ALWAYS_ZCLIP||Forces the actor's Z-clipping for the given Z-plane?<br />
|-<br />
|$14||SO_IGNORE_BOXES||Ignores boxes, turns off Z-clipping, and puts actor somewhere if the actor is in the current room?<br />
|-<br />
|$15||SO_FOLLOW_BOXES||Follows boxes, turns off Z-clipping, and puts actor somewhere if the actor is in the current room?<br />
|-<br />
|$16||SO_ANIMATION_SPEED||Sets the animation speed.<br />
|-<br />
|$17||SO_SHADOW||Sets the shadow mode.<br />
|}<br />
<br />
===Variants===<br />
In SCUMM V3 and V4, the opcode values are slightly different.<br />
<br />
{| border="1" cellpadding="2" width=50%<br />
|- style="background:whitesmoke"<br />
|Opcode||Meaning<br />
|-<br />
|$00||dummy<br />
|-<br />
|$01||SO_COSTUME<br />
|-<br />
|$04||SO_STEP_DIST<br />
|-<br />
|$05||SO_SOUND<br />
|-<br />
|$06||SO_WALK_ANIMATION<br />
|-<br />
|$07||SO_TALK_ANIMATION<br />
|-<br />
|$08||SO_STAND_ANIMATION<br />
|-<br />
|$09||SO_ANIMATION<br />
|-<br />
|$0A||SO_DEFAULT<br />
|-<br />
|$0B||SO_ELEVATION<br />
|-<br />
|$0C||SO_ANIMATION_DEFAULT<br />
|-<br />
|$0D||SO_PALETTE<br />
|-<br />
|$0E||SO_TALK_COLOR<br />
|-<br />
|$0F||SO_ACTOR_NAME<br />
|-<br />
|$10||SO_INIT_ANIMATION<br />
|-<br />
|$12||SO_ACTOR_WIDTH<br />
|-<br />
|$13||SO_ACTOR_SCALE<br />
|-<br />
|$14||SO_IGNORE_BOXES<br />
|}<br />
<br />
Also in V3 and V4, sub-opcode $13 (SO_ACTOR_SCALE) only takes one parameter, so X and Y scaling is done at a 1:1 ratio.<br />
<br />
<br />
==actorSetClass ($5D)==<br />
<br />
===Encoding===<br />
opcode object[p16] classes[v16]...<br />
<br />
===Operation===<br />
Makes object inherit from all of the given classes. A class of "0" will clear all of the object's existing class data.<br />
<br />
<br />
==add ($5A)==<br />
<br />
===Encoding===<br />
opcode result value[p16]<br />
<br />
===Operation===<br />
result := result + value<br />
<br />
The variable pointed to by result is read, value is added to it, and the result written back.<br />
<br />
<br />
==and ($17)==<br />
one parameter, uses result<br />
<br />
===Encoding===<br />
opcode result value[p16]<br />
<br />
===Operation===<br />
result := result and value<br />
<br />
The variable pointed to by result is read, logically ANDed with value, and the result written back.<br />
<br />
<br />
==animateActor ($11)==<br />
<br />
===Encoding===<br />
opcode actor[p8] anim[p8]<br />
<br />
===Operation===<br />
Starts the given animation for the given actor.<br />
<br />
<br />
==breakHere ($80)==<br />
no parameters<br />
<br />
===Encoding===<br />
opcode<br />
<br />
===Operation===<br />
Deschedules the currently running thread. Execution continues at the next instruction when the thread's next timeslot comes around.<br />
<br />
<br />
==chainScript ($42)==<br />
one parameter plus varargs<br />
<br />
===Encoding===<br />
opcode script[p8] args[v16]...<br />
<br />
===Operation===<br />
Replaces the currently running script with another one. The current script is terminated immediately and the new script (determined by the given script ID), is executed in the same thread. The new script has its local variables initialised to the list args. Uninitialised variables have undefined values.<br />
<br />
<br />
==cursorCommand ($2C)==<br />
parameters depend on auxiliary opcode<br />
<br />
===Encoding===<br />
opcode sub-opcode<br />
<br />
sub-opcode can be any of the following:<br />
$01<br />
... $01 through $08 take the same arguments ...<br />
$08<br />
$0A cursornum[p8] charletter[p8]<br />
$0B index[p8] x[p8] y[p8]<br />
$0C cursor[p8]<br />
$0D charset[p8]<br />
$0E colours[v16]...<br />
<br />
===Operation===<br />
Miscellaneous actions on cursors & charsets.<br />
<br />
{| border="1" cellpadding="2" width=100%<br />
|- style="background:whitesmoke"<br />
|Opcode||Meaning||Description<br />
|-<br />
|$01||SO_CURSOR_ON||Turns the cursor on.<br />
|-<br />
|$02||SO_CURSOR_OFF||Turns the cursor off.<br />
|-<br />
|$03||SO_USERPUT_ON||Enables user input.<br />
|-<br />
|$04||SO_USERPUT_OFF||Disables user input.<br />
|-<br />
|$05||SO_CURSOR_SOFT_ON||Increments the cursor's state?<br />
|-<br />
|$06||SO_CURSOR_SOFT_OFF||Decrements the cursor's state?<br />
|-<br />
|$07||SO_USERPUT_SOFT_ON||Increments "user input" counter (when greater than 0, user input is enabled).<br />
|-<br />
|$08||SO_USERPUT_SOFT_OFF||Decrements "user input" counter (when 0 or less, user input is disabled).<br />
|-<br />
|$0A||SO_CURSOR_IMAGE||Changes the cursor image to a new one, based on image in a character set. Only used in Loom.<br />
|-<br />
|$0B||SO_CURSOR_HOTSPOT||Changes the hotspot of a cursor. Only used in Loom.<br />
|-<br />
|$0C||SO_CURSOR_SET||Changes the current cursor. Must be between 0 and 3 inclusive.<br />
|-<br />
|$0D||SO_CHARSET_SET||Initializes the given character set.<br />
|-<br />
|$0E||SO_CHARSET_COLORS||Initializes the character set data & colours to the given arguments? Must have 16 arguments?<br />
|}<br />
<br />
===Variants===<br />
In SCUMM V3, sub-opcode $0E performs a different function, to load/initialize a character set.<br />
<br />
opcode $0E arg1[p8] arg2[p8]<br />
<br />
<br />
==cutScene ($40)==<br />
<br />
===Encoding===<br />
opcode args[v16]...<br />
<br />
===Operation===<br />
??? If required, runs a script passing the given arguments. Cutscene data given by the first argument?<br />
<br />
<br />
==debug ($6B)==<br />
one parameter, no result<br />
<br />
===Encoding===<br />
opcode param[p16]<br />
<br />
===Operation===<br />
Passes the parameter to the interpreter's debugger. What this does is entirely platform-specific (and may do nothing).<br />
<br />
<br />
==decrement ($C6)==<br />
no parameters, uses result<br />
<br />
===Encoding===<br />
opcode result<br />
<br />
===Operation===<br />
result := result - 1<br />
<br />
Reads the variable pointed to by result, decrements it, and writes it back. <br />
<br />
<br />
==delay ($2E)==<br />
one constant parameter<br />
<br />
===Encoding===<br />
opcode param[24]<br />
<br />
===Operation===<br />
Suspends the current thread for the appropriate number of 1/60ths of a second. Yes, that really is a 24-bit LE constant.<br />
<br />
<br />
==delayVariable ($2B)==<br />
one constant parameter<br />
<br />
===Encoding===<br />
opcode var<br />
<br />
===Operation===<br />
var is dereferenced and the current thread suspended for that number of 1/60ths of a second.<br />
<br />
<br />
==divide ($5B)==<br />
one parameter, uses result<br />
<br />
===Encoding===<br />
opcode result value[p16]<br />
<br />
===Operation===<br />
result := result / value<br />
<br />
The variable pointed to by result is read, divided by value, and the result written back. If value is zero, the result is undefined (and the interpeter may halt with an error). <br />
<br />
<br />
==doSentence ($19)==<br />
<br />
===Encoding===<br />
opcode verb[p8] objectA[p16] objectB[p16]<br />
<br />
===Operation===<br />
Performs a verb sentence action, e.g. "Use monkey on hydrant". If verb is $FE, the current sentence script is stopped, status cleared etc.<br />
<br />
<br />
==drawBox ($3F)==<br />
two parameters, does not use result, supplementary opcode byte with three more subsequent parameters<br />
<br />
===Encoding===<br />
opcode left[p16] top[p16] auxopcode[8] right[p16] bottom[p16] colour[p8]<br />
<br />
===Operation===<br />
Draws a solid box on the backbuffer from (left, top) to (right, bottom) in the given colour.<br />
<br />
The only part of auxopcode that is relevant are the parameter bits. The rest of the opcode is ignored. However, the aux opcode's initial value is $05.<br />
<br />
<br />
==drawObject ($05)==<br />
<br />
===Encoding===<br />
opcode object[p16] sub-opcode<br />
<br />
sub-opcodes:<br />
$01 xpos[p16] ypos[p16]<br />
$02 state[p16]<br />
$FF<br />
<br />
===Operation===<br />
{| border="1" cellpadding="2" width=100%<br />
|- style="background:whitesmoke"<br />
|Opcode||Meaning||Description<br />
|-<br />
|$01||Draw At||Moves the given object to the given co-ordinates, and adds it to the drawing queue.<br />
|-<br />
|$02||Set State||Sets the state of the object, adds it to the drawing queue.<br />
|-<br />
|$FF||Draw||Does not change the object's position (or state?), still adds it to the drawing queue.<br />
|}<br />
<br />
===Variants===<br />
Small header games (v3 and v4) only support the parameters used with sub-opcode $01, e.g:<br />
opcode object[p16] xpos[p16] ypos[p16]<br />
Accordingly, they have three parameter bits, and hence more possible opcodes.<br />
<br />
<br />
==dummy ($A7)==<br />
<br />
===Encoding===<br />
opcode<br />
<br />
===Operation===<br />
V5 specific - The KIXX XL release of Monkey Island 2 (Amiga disk) used this opcode as a dummy, in order to remove copy protection and keep level selection.<br />
<br />
===Variants===<br />
In SCUMM V3 and V4, this opcode is used for the saveLoadVars instruction.<br />
<br />
<br />
==endCutScene ($C0)==<br />
<br />
===Encoding===<br />
opcode<br />
<br />
===Operation===<br />
Ends the cutscene, performing cleanup if necessary.<br />
<br />
<br />
==equalZero ($28)==<br />
jumps<br />
<br />
===Encoding===<br />
opcode var target[16]<br />
<br />
===Operation===<br />
unless (var == 0) goto target<br />
<br />
Target is a byte offset (measured from after this instruction), which will be added to the instruction pointer.<br />
<br />
<br />
==expression ($AC)==<br />
<br />
===Encoding===<br />
opcode result subopcode... $FF<br />
<br />
sub-opcodes:<br />
$01 value[p16]<br />
$02<br />
... $02 through $05 take the same arguments ...<br />
$05<br />
$06 nested-opcode<br />
<br />
===Operation===<br />
Expression mode operates on a stack. Values are pushed on, and operators are applied to the top two items on the stack.<br />
<br />
{| border="1" cellpadding="2" width=100%<br />
|- style="background:whitesmoke"<br />
|Opcode||Meaning||Description<br />
|-<br />
|$01||Value||Pushes a value onto the top of the stack.<br />
|-<br />
|$02||Add||stack[top - 1] + stack[top]<br />
|-<br />
|$03||Subtract||stack[top - 1] - stack[top]<br />
|-<br />
|$04||Multiply||stack[top - 1] * stack[top]<br />
|-<br />
|$05||Divide||stack[top - 1] / stack[top] (if stack[top] is 0 an error occurs)<br />
|-<br />
|$06||Nested Opcode||An entire instruction that returns a result, such as getActorScale. This is interpreted like a normal opcode, but the result is pushed onto the expression stack. (The opcode is passed the special "VAR_RESULT" parameter for "result")<br />
|}<br />
<br />
<br />
==faceActor ($09)==<br />
<br />
===Encoding===<br />
opcode actor[p8] object[p16]<br />
<br />
===Operation===<br />
Dereferences actor, tells actor to face object (presumably based on X/Y co-ordinates).<br />
<br />
<br />
==findInventory ($3D)==<br />
<br />
===Encoding===<br />
opcode result owner[p8] index[p8]<br />
<br />
===Operation===<br />
object := owner.inventory[index]<br />
Searches for all objects owned by owner (an actor or object), and returns the one at the given index (offset).<br />
<br />
<br />
==findObject ($35)==<br />
<br />
===Encoding===<br />
opcode result x[p8] y[p8]<br />
<br />
===Operation===<br />
Returns the first "touchable" local object at the given co-ordinates. Will not match on the bottom or right-hand edges of an object.<br />
<br />
<br />
==freezeScripts ($60)==<br />
<br />
===Encoding===<br />
opcode flag[p8]<br />
<br />
===Operation===<br />
Freezes all scripts (by setting the high bit on each script's status). If flag is >= $80, all freeze resistent scripts will also be frozen. If flag is 0, all scripts are unfrozen. Freezing effects are cumulative - i.e. if script A is frozen twice, and unfrozen once, it will still be frozen until it is unfrozen a second time. A script's frozen status is indicated by the high bit.<br />
<br />
<br />
==getActorCostume ($71)==<br />
<br />
===Encoding===<br />
opcode result actor[p8]<br />
<br />
===Operation===<br />
Returns the actor's current costume.<br />
<br />
<br />
==getActorElevation ($06)==<br />
<br />
===Encoding===<br />
opcode result actor[p8]<br />
<br />
===Operation===<br />
Returns the actor's current elevation.<br />
<br />
<br />
==getActorFacing ($63)==<br />
<br />
===Encoding===<br />
opcode result actor[p8]<br />
<br />
===Operation===<br />
Returns the current direction the actor is facing.<br />
<br />
<br />
==getActorMoving ($56)==<br />
<br />
===Encoding===<br />
opcode result actor[p8]<br />
<br />
===Operation===<br />
Returns the actor's moving status (0 or 1).<br />
<br />
<br />
==getActorRoom ($03)==<br />
<br />
===Encoding===<br />
opcode result actor[p8]<br />
<br />
===Operation===<br />
Returns the room the actor currently occupies?<br />
<br />
<br />
==getActorScale ($3B)==<br />
<br />
===Encoding===<br />
opcode result actor[p8]<br />
<br />
===Operation===<br />
Returns the actor's current scale.<br />
<br />
===Variants===<br />
In Indy3, this opcode is used for waitForActor.<br />
<br />
<br />
==getActorWalkBox ($7B)==<br />
<br />
===Encoding===<br />
opcode result actor[p8]<br />
<br />
===Operation===<br />
Returns the actor's walkbox.<br />
<br />
<br />
==getActorWidth ($6C)==<br />
<br />
===Encoding===<br />
opcode result actor[p8]<br />
<br />
===Operation===<br />
Returns the actor's width.<br />
<br />
<br />
==getActorX ($43)==<br />
<br />
===Encoding===<br />
opcode result actor[p16]<br />
<br />
===Operation===<br />
Returns the actor's current X co-ordinate.<br />
<br />
===Variants===<br />
In Indy3, actor is only one byte.<br />
opcode result actor[p8]<br />
<br />
<br />
==getActorY ($23)==<br />
<br />
===Encoding===<br />
opcode result actor[p16]<br />
<br />
===Operation===<br />
Returns the actor's current Y co-ordinate.<br />
<br />
===Variants===<br />
In Indy3, actor is only one byte.<br />
opcode result actor[p8]<br />
<br />
<br />
==getAnimCounter ($22)==<br />
<br />
===Encoding===<br />
opcode result actor[p8]<br />
<br />
===Operation===<br />
Returns the actor's animation counter.<br />
<br />
===Variants===<br />
This opcode is used for saveLoadGame in SCUMM V3.<br />
<br />
<br />
==getClosestObjActor ($66)==<br />
<br />
===Encoding===<br />
opcode result actor[p16]<br />
<br />
===Operation===<br />
Returns the object closest to the actor. Items that are more than 255 units (pixels in newer games, characters in older games) away from the actor will not be detected.<br />
<br />
<br />
==getDist ($34)==<br />
<br />
===Encoding===<br />
opcode result objA[p16] objB[p16]<br />
<br />
===Operation===<br />
Returns the distance between two actors/objects (objA and objB).<br />
<br />
<br />
==getInventoryCount ($31)==<br />
<br />
===Encoding===<br />
opcode result actor[p8]<br />
<br />
===Operation===<br />
Returns the number of items in an actor's inventory?<br />
<br />
<br />
==getObjectOwner ($10)==<br />
<br />
===Encoding===<br />
opcode result object[p16]<br />
<br />
===Operation===<br />
Returns the owner of an object.<br />
<br />
<br />
==getObjectState ($0F)==<br />
<br />
===Encoding===<br />
opcode result object[p16]<br />
<br />
===Operation===<br />
Returns the state of the object.<br />
<br />
===Variants===<br />
In small header games, this opcode is used for the "ifState" instruction.<br />
<br />
<br />
==getRandomNumber ($16)==<br />
<br />
===Encoding===<br />
opcode result seed[p8]<br />
<br />
===Operation===<br />
Returns a new random number based on the given seed.<br />
<br />
<br />
==getScriptRunning ($68)==<br />
<br />
===Encoding===<br />
opcode result script[p8]<br />
<br />
===Operation===<br />
Returns 1 if the given script is running, 0 if it's not.<br />
<br />
<br />
==getStringWidth ($67)==<br />
<br />
===Encoding===<br />
opcode result strptr[p8]<br />
<br />
===Operation===<br />
Gets the length of the string pointed to by strptr (either a variable or direct byte), stores the returned value in result.<br />
<br />
<br />
==getVerbEntryPoint ($0B)==<br />
<br />
===Encoding===<br />
opcode result object[p16] verb[p16]<br />
<br />
===Operation===<br />
Returns the entry point for the response code/script for when the given verb is applied to the given object? i.e. gets the start of the script to run for the specific user interaction.<br />
<br />
<br />
==ifClassOfIs ($1D)==<br />
jumps<br />
<br />
===Encoding===<br />
opcode value[p16] args[v16]... target[16]<br />
<br />
===Operation===<br />
unless (value.class is one of [args.class]) goto target<br />
<br />
Compares the value's class with all classes given in args.<br />
<br />
Target is a byte offset (measured from after this instruction), which will be added to the instruction pointer.<br />
<br />
<br />
==ifNotState ($2F) (V3-4)==<br />
This opcode is not present in SCUMM V5.<br />
<br />
===Encoding===<br />
opcode object[p16] state[p8] target[16]<br />
<br />
===Operation===<br />
unless (getState(object) != state) goto target<br />
<br />
<br />
==ifState ($0F) (V3-4)==<br />
This opcode is not present in SCUMM V5.<br />
<br />
===Encoding===<br />
opcode object[p16] state[p8] target[16]<br />
<br />
===Operation===<br />
unless (getState(object) == state) goto target<br />
<br />
<br />
==increment ($46)==<br />
no parameters, uses result<br />
<br />
===Encoding===<br />
opcode result<br />
<br />
===Operation===<br />
result := result + 1<br />
<br />
Reads the variable pointed to by result, increments it, and writes it back. <br />
<br />
<br />
==isActorInBox ($1F)==<br />
<br />
===Encoding===<br />
opcode actor[p8] box[p8] target[16]<br />
<br />
===Operation===<br />
Unless the actor's co-ordinates are within the bounds of the given box, jump to target.<br />
<br />
Target is a byte offset (measured from after this instruction), which will be added to the instruction pointer.<br />
<br />
<br />
==isEqual ($48)==<br />
<br />
===Encoding===<br />
opcode var value[p16] target[16]<br />
<br />
===Operation===<br />
unless (value == var) goto target<br />
<br />
Target is a byte offset (measured from after this instruction), which will be added to the instruction pointer.<br />
<br />
<br />
==isGreater ($78)==<br />
<br />
===Encoding===<br />
opcode var value[p16] target[16]<br />
<br />
===Operation===<br />
unless (value > var) goto target<br />
<br />
Target is a byte offset (measured from after this instruction), which will be added to the instruction pointer.<br />
<br />
<br />
==isGreaterEqual ($04)==<br />
<br />
===Encoding===<br />
opcode var value[p16] target[16]<br />
<br />
===Operation===<br />
unless (value >= var) goto target<br />
<br />
Target is a byte offset (measured from after this instruction), which will be added to the instruction pointer.<br />
<br />
<br />
==isLess ($44)==<br />
<br />
===Encoding===<br />
opcode var value[p16] target[16]<br />
<br />
===Operation===<br />
unless (value < var) goto target<br />
<br />
Target is a byte offset (measured from after this instruction), which will be added to the instruction pointer.<br />
<br />
<br />
==isNotEqual ($08)==<br />
<br />
===Encoding===<br />
opcode var value[p16] target[16]<br />
<br />
===Operation===<br />
unless (value != var) goto target<br />
<br />
Target is a byte offset (measured from after this instruction), which will be added to the instruction pointer.<br />
<br />
<br />
==isSoundRunning ($7C)==<br />
<br />
===Encoding===<br />
opcode result sound[p8]<br />
<br />
===Operation===<br />
Returns 1 if sound is running, returns 0 if sound is not running or if the given sound is 0.<br />
<br />
<br />
==jumpRelative ($18)==<br />
jumps<br />
<br />
===Encoding===<br />
opcode target[16]<br />
<br />
===Operation===<br />
PC := PC + target<br />
<br />
The inline constant target is read as a signed word and added to the program counter after the instruction has been read. Therefore, if target is zero, the instruction will do nothing; if target is -3, an infinite loop will result. <br />
<br />
<br />
==lessOrEqual ($38)==<br />
jumps<br />
<br />
===Encoding===<br />
opcode var value[p16] target[16]<br />
<br />
===Operation===<br />
unless (value <= var) goto target<br />
<br />
Target is a byte offset (measured from after this instruction), which will be added to the instruction pointer.<br />
<br />
<br />
==lights ($70)==<br />
<br />
===Encoding===<br />
opcode arg1[p8] arg2[8] arg3[8]<br />
<br />
===Operation===<br />
If arg3 is 0, the "current lights" variable is set to arg1.<br />
If arg3 is 1, the size of the "flashlight" light is determined by arg1 and arg2, for width and height in stripes (which are equivalent to 8 pixels each; see [[SCUMM/Technical Reference/Image resources]]).<br />
<br />
<br />
==loadRoom ($72)==<br />
<br />
===Encoding===<br />
opcode room[p8]<br />
<br />
===Operation===<br />
Loads the given room into memory.<br />
<br />
<br />
==loadRoomWithEgo ($24)==<br />
<br />
===Encoding===<br />
opcode object[p16] room[p8] x[16] y[16]<br />
<br />
===Operation===<br />
Places the Ego actor in room at object's position. If x is not -1, Ego will start moving towards the given x and y co-ordinates. If object is not in the given room an error will occur.<br />
(I think...)<br />
<br />
<br />
==matrixOp ($30)==<br />
<br />
===Encoding===<br />
opcode sub-opcode<br />
<br />
sub-opcodes:<br />
$01 box[p8] val[p8]<br />
$02 box[p8] val[p8]<br />
$03 box[p8] val[p8]<br />
$04<br />
<br />
===Operation===<br />
This instruction manipulates boxes.<br />
<br />
{| border="1" cellpadding="2" width=100%<br />
|- style="background:whitesmoke"<br />
|Opcode||Meaning||Description<br />
|-<br />
|$01||setBoxFlags||Sets the box's flags to the given value.<br />
|-<br />
|$02||setBoxScale||Sets the box's scale.<br />
|-<br />
|$03||setBoxScale||Sets the box's scale to ((val - 1) OR $8000).<br />
|-<br />
|$04||createBoxMatrix||Initializes the matrix of boxes, by determining the distances and shortest paths between boxes.<br />
|}<br />
<br />
===Variants===<br />
SCUMM V3 only has the one instruction, which behaves like setBoxFlags:<br />
opcode box[p8] val[8]<br />
<br />
<br />
==move ($1A)==<br />
<br />
===Encoding===<br />
opcode result value[p16]<br />
<br />
===Operation===<br />
result := value<br />
<br />
Value is moved into result.<br />
<br />
<br />
==multiply ($1B)==<br />
<br />
===Encoding===<br />
opcode result value[p16]<br />
<br />
===Operation===<br />
result := result * value<br />
<br />
The variable pointed to by result is read, multiplied by value, and written back.<br />
<br />
<br />
==notEqualZero ($A8)==<br />
<br />
===Encoding===<br />
opcode var target[16]<br />
<br />
===Operation===<br />
unless (var != 0) goto target<br />
<br />
Target is a byte offset (measured from after this instruction), which will be added to the instruction pointer.<br />
<br />
<br />
==oldRoomEffect ($5C) (V3-4)==<br />
This opcode/instruction not present in SCUMM V5.<br />
<br />
===Encoding===<br />
opcode sub-opcode<br />
<br />
sub-opcodes:<br />
$03 effect[p16]<br />
$?? effect[p16]<br />
<br />
===Operation===<br />
Performs like sub-opcode SO_ROOM_FADE of the roomOps instruction (fade in if effect != 0, otherwise fade out).<br />
<br />
This information may not be correct; descumm says if the sub-opcode is 3, to "set" the effect, but if the sub-opcode is anything else to fade in with the given effect.<br />
<br />
===Variants===<br />
FM-Towns SCUMM V3 performs a different effect, not fully implemented in ScummVM. At the moment ScummVM just forces a redraw of the screen background.<br />
<br />
<br />
==or ($57)==<br />
one parameter, uses result<br />
<br />
===Encoding===<br />
opcode result value[p16]<br />
<br />
===Operation===<br />
result := result or value<br />
<br />
The variable pointed to by result is read, logically ORed with value, and the result written back.<br />
<br />
<br />
==override ($58)==<br />
<br />
===Encoding===<br />
opcode sub-opcode<br />
<br />
sub-opcodes:<br />
$00<br />
$01 $18 target[16]<br />
<br />
===Operation===<br />
If the sub-opcode is 0, marks the end of an override section.<br><br />
If the sub-opcode is not 0, marks the beginning of an override section. The instruction is immediately followed by a "jumpRelative" instruction.<br><br />
Overrides are used by cutscenes; if a cutscene is skipped (if the user presses the ESC key), the script will jump by the given target (offset from the beginOverride instruction).<br />
<br />
<br />
==panCameraTo ($12)==<br />
<br />
===Encoding===<br />
opcode x[p16]<br />
<br />
===Operation===<br />
Starts the camera panning to the given x co-ordinate.<br />
<br />
<br />
==pickupObject ($25) (v5)==<br />
This instruction is only present in SCUMM V5.<br />
<br />
===Encoding===<br />
opcode object[p16] room[p8]<br />
<br />
===Operation===<br />
Adds the given object (located in the given room) to the Ego actor's inventory.<br />
<br />
===Variants===<br />
In SCUMM V3 and V4, this opcode is used for drawObject.<br />
<br />
<br />
==pickupObject ($50) (V3-4)==<br />
This opcode/instruction is not present in SCUMM V5.<br />
<br />
===Encoding===<br />
opcode object[p16]<br />
<br />
===Operation===<br />
Adds the given object (located in the given room) to the Ego actor's inventory. If object < 1, an error is raised. If the object is not found or the object is already in the inventory, this function ends gracefully.<br />
<br />
<br />
==print ($14)==<br />
<br />
===Encoding===<br />
opcode actor[p8] sub-opcode<br />
<br />
sub-opcodes<br />
$00 xpos[p16] ypos[p16]<br />
$01 colour[p8]<br />
$02 right[p16]<br />
$03 width[p16] height[p16]<br />
$04<br />
$06<br />
$07<br />
$08 offset[p16] delay[p16]<br />
$0F string[c]... $FF<br />
<br />
===Operation===<br />
Sets text properties and displays dialogue.<br />
<br />
{| border="1" cellpadding="2" width=100%<br />
|- style="background:whitesmoke"<br />
|Opcode||Meaning||Description<br />
|-<br />
|$00||SO_AT||Sets the position of the text that follows.<br />
|-<br />
|$01||SO_COLOR||Sets the colour of the text.<br />
|-<br />
|$02||SO_CLIPPED||Clips the text's right-hand side (for wrapping?).<br />
|-<br />
|$03||SO_ERASE||Erases characters (not used in ScummVM).<br />
|-<br />
|$04||SO_CENTER||Centres the text.<br />
|-<br />
|$06||SO_LEFT||Left-aligns the text.<br />
|-<br />
|$07||SO_OVERHEAD||Overhead-aligns the text.<br />
|-<br />
|$0F||SO_TEXTSTRING||Prints the text string that follows. Terminated by $FF.<br />
|}<br />
<br />
===Variants===<br />
In SCUMM V3, text function $06 sets the height of the text:<br />
$06 height[p16]<br />
<br />
In Loom CD (SCUMM V4), there is an additional text function $08 (SO_SAY_VOICE), which plays a portion of the CD audio track.<br />
$08 offset[p16] delay[p16]<br />
<br />
<br />
==printEgo ($D8)==<br />
<br />
===Encoding===<br />
opcode sub-opcode<br />
<br />
===Operation===<br />
Exactly the same as print, except the actor is implicitly Ego. See the entry for "print" for further explanation.<br />
<br />
<br />
==pseudoRoom ($CC)==<br />
<br />
===Encoding===<br />
opcode val[8] res[8]... $00<br />
<br />
===Operation===<br />
forall (res) {<br />
if (res >= $80) {<br />
_resourceMapper[res & $7F] := val<br />
}<br />
}<br />
<br />
What does this actually do? We may never know.<br />
<br />
It looks like res values always have the high bit set, e.g. 0x01 becomes 0x81.<br />
<br />
<br />
==putActor ($01)==<br />
<br />
===Encoding===<br />
opcode actor[p8] x[p16] y[p16]<br />
<br />
===Operation===<br />
Puts the actor at the given co-ordinates.<br />
<br />
<br />
==putActorAtObject ($0E)==<br />
<br />
===Encoding===<br />
opcode actor[p8] object[p16]<br />
<br />
===Operation===<br />
Puts the actor at the given object's position. If the object can not be found, a default position is returned (the centre of the screen in ScummVM).<br />
<br />
<br />
==putActorInRoom ($2D)==<br />
<br />
===Encoding===<br />
opcode actor[p8] room[p8]<br />
<br />
===Operation===<br />
Puts the actor in the given room.<br />
<br />
<br />
==resourceRoutines ($0C)==<br />
<br />
===Encoding===<br />
opcode sub-opcode<br />
<br />
sub-opcodes:<br />
$01 resID[p8]<br />
... $01 through $10 take the same arguments ...<br />
$10 resID[p8]<br />
$11<br />
$12 resID[p8]<br />
$13 resID[p8]<br />
$14 room[p8] object[p16]<br />
<br />
===Operation===<br />
resID is unique only within the resource type (e.g. script 11 will not conflict with sound 11).<br />
<br />
{| border="1" cellpadding="2" width=100%<br />
|- style="background:whitesmoke"<br />
|Opcode||Meaning||Description<br />
|-<br />
|$01||SO_LOAD_SCRIPT||Loads the given script into memory.<br />
|-<br />
|$02||SO_LOAD_SOUND||Loads the given sound into memory.<br />
|-<br />
|$03||SO_LOAD_COSTUME||Loads the given costume into memory.<br />
|-<br />
|$04||SO_LOAD_ROOM||Loads the given room into memory.<br />
|-<br />
|$05||SO_NUKE_SCRIPT||Obliterates the given script from memory.<br />
|-<br />
|$06||SO_NUKE_SOUND||Obliterates the given sound from memory.<br />
|-<br />
|$07||SO_NUKE_COSTUME||Obliterates the given costume from memory.<br />
|-<br />
|$08||SO_NUKE_ROOM||Obliterates the given room from memory.<br />
|-<br />
|$09||SO_LOCK_SCRIPT||Locks the given script.<br />
|-<br />
|$0A||SO_LOCK_SOUND||Locks the given sound.<br />
|-<br />
|$0B||SO_LOCK_COSTUME||Locks the given costume.<br />
|-<br />
|$0C||SO_LOCK_ROOM||Locks the given room.<br />
|-<br />
|$0D||SO_UNLOCK_SCRIPT||Unlocks the given script.<br />
|-<br />
|$0E||SO_UNLOCK_SOUND||Unlocks the given sound.<br />
|-<br />
|$0F||SO_UNLOCK_COSTUME||Unlocks the given costume.<br />
|-<br />
|$10||SO_UNLOCK_ROOM||Unlocks the given room.<br />
|-<br />
|$11||SO_CLEAR_HEAP||Clears the heap.<br />
|-<br />
|$12||SO_LOAD_CHARSET||Loads the given character set into memory.<br />
|-<br />
|$13||SO_NUKE_CHARSET||Obliterates the given character set from memory.<br />
|-<br />
|$14||SO_LOAD_OBJECT||Loads the given object from the given room resource.<br />
|}<br />
<br />
===Variants===<br />
FM-Towns games add the following sub-opcodes (these are not confirmed nor implemented in ScummVM):<br />
{| border="1" cellpadding="2" width=100%<br />
|- style="background:whitesmoke"<br />
|Opcode||Meaning||Description<br />
|-<br />
|$20||Unknown||Does nothing, not used in-game.<br />
|-<br />
|$21||Unknown||Does nothing, not used in-game.<br />
|-<br />
|$23||CD Volume||Possibly changes the volume of CD tracks (Loom CD). Takes 1 byte.<br />
|-<br />
|$24||Sound Volume||Sets the loudness of a sound resource. Used in Indy3 and Zak. Takes 2 bytes (left/right volumes?).<br />
|-<br />
|$25||Sound Pitch||Sets the pitch of a sound resource. Used in Indy3 and Zak. Takes 1 byte (pitch = "foo" - "center" semitones. Center is at $32 in the sound resource.)<br />
|}<br />
<br />
<br />
==roomOps ($33)==<br />
<br />
===Encoding===<br />
opcode sub-opcode<br />
<br />
sub-opcodes:<br />
$01 minX[p16] maxX[p16]<br />
$03 b[p16] h[p16]<br />
$04 red[p16] green[p16] blue[p16] aux index[p8]<br />
$05<br />
$06<br />
$07 scale1[p8] y1[p8] aux scale2[p8] y2[p8] aux slot[p8]<br />
$08 scale[p8] startcolour[p8] endcolour[p8]<br />
$09 loadflag[p8] loadslot[p8]<br />
$0A effect[p16]<br />
$0B redscale[p16] greenscale[p16] bluescale[p16] aux startcolour[p8] endcolour[p8]<br />
$0C redscale[p16] greenscale[p16] bluescale[p16] aux startcolour[p8] endcolour[p8]<br />
$0D resID[p8] filename[c]... $00<br />
$0E resID[p8] filename[c]... $00<br />
$0F resID[p8] aux start[p8] end[p8] aux time[p8]<br />
$10 colindex[p8] delay[p8]<br />
<br />
===Operation===<br />
{| border="1" cellpadding="2" width=100%<br />
|- style="background:whitesmoke"<br />
|Opcode||Meaning||Description<br />
|-<br />
|$01||SO_ROOM_SCROLL||Clamps the given arguments so scrolling does not extend past the width of the room or screen.<br />
|-<br />
|$03||SO_ROOM_SCREEN||Initialises a screen.<br />
|-<br />
|$04||SO_ROOM_PALETTE||Adjusts the room's palette. Aux opcode's initial value is $04.<br />
|-<br />
|$05||SO_ROOM_SHAKE_ON||Starts the room shaking.<br />
|-<br />
|$06||SO_ROOM_SHAKE_OFF||Ends the room shaking.<br />
|-<br />
|$07||SO_ROOM_SCALE||Sets the room's y scales? (slot is 1 greater than actual slot?)<br />
|-<br />
|$08||SO_ROOM_INTENSITY||Lightens/darkens the room's palette.<br />
|-<br />
|$09||SO_ROOM_SAVEGAME||Saves temporary state of the room/game?<br />
|-<br />
|$0A||SO_ROOM_FADE||If effect is 0, fades in the room. Otherwise, fades out with the given effect (taken from the high byte of effect).<br>1 = iris effect<br>2 = box wipe (upper-left to bottom-right)<br>3 = box wipe (upper-right to bottem-left)<br>4 = inverse box wipe.<br />
|-<br />
|$0B||SO_RGB_ROOM_INTENSITY||Lightens/darkens the room's palette, with different scales for red, green and blue. Aux opcode's initial value is $0B.<br />
|-<br />
|$0C||SO_ROOM_SHADOW||Lightens/darkens the shadow palette, with different scales for red, green, and blue.<br />
|-<br />
|$0D||SO_SAVE_STRING||Saves a string resource to the given file?<br />
|-<br />
|$0E||SO_LOAD_STRING||Loads a string resource from a given file?<br />
|-<br />
|$0F||SO_ROOM_TRANSFORM||Manipulates palettes, strings?<br />
|-<br />
|$10||SO_CYCLE_SPEED||Starts colour cycling with delay? colIndex is between 0 and 16<br />
|}<br />
<br />
===Variants===<br />
SCUMM V3 (non-PC Engine) encodes the arguments before the sub-opcode:<br />
opcode arg1[p16] arg2[p16] sub-opcode<br />
<br />
Small header games (V3 and V4) include an extra sub-opcode, $02 (SO_ROOM_COLOR), which adjusts the room's palette:<br />
opcode $02 colour[p16] index[p16]<br />
... or for V3 games ...<br />
opcode colour[p16] index[p16] $02<br />
<br />
In small header games, sub-opcode $04 (SO_ROOM_PALETTE) affects the shadow palette, and only accepts two arguments, a "room colour slot" (palette entry? between 0 and 256) and an index:<br />
opcode $04 colour[p16] index[p16]<br />
... or for V3 games ...<br />
opcode colour[p16] index[p16] $04<br />
<br />
In FM-Towns games, sub-opcode $0A performs a different function and has its own sub-opcodes (some unknown and all not yet implemented in ScummVM):<br />
opcode $0A sub-opcode<br />
<br />
{| border="1" cellpadding="2" width=100%<br />
|- style="background:whitesmoke"<br />
|Opcode||Meaning||Description<br />
|-<br />
|$08||||compose kMainVirtScreen over a screen buffer<br />
|-<br />
|$09||||call 0x110:0x20 _ax=0x601 _edx=2<br />
|-<br />
|$0A||||call 0x110:0x20 _ax=0x601 _edx=3<br />
|-<br />
|$0B||||clear screen 0x1C:0x45000 sizeof(640 * 320)<br />
|-<br />
|$0C||||call 0x110:0x20 _ax=0x601 _edx=0<br />
|-<br />
|$0D||||call 0x110:0x20 _ax=0x601 _edx=1<br />
|-<br />
|$10||||enable clearing of a screen buffer in drawBitmap()<br />
|-<br />
|$11||||disable clearing of a screen buffer in drawBitmap()<br />
|-<br />
|$12||||clear a screen buffer<br />
|-<br />
|$13||||enable palette operations (palManipulate(), cyclePalette() etc.)<br />
|-<br />
|$14||||disable palette operations<br />
|-<br />
|$15||||disable clearing of screen 0x1C:0x5000 sizeof(640 * 320) in initScreens()<br />
|-<br />
|$16||||enable clearing of screen 0x1C:0x5000 sizeof(640 * 320) in initScreens()<br />
|-<br />
|$1E||||Unknown<br />
|}<br />
<br />
<br />
==saveLoadGame ($22) (V3-4)==<br />
This instruction is not present in SCUMM V5; its opcode is used for "getAnimCounter".<br />
<br />
===Encoding===<br />
opcode result arg1[p8]<br />
<br />
===Operation===<br />
The slot is determined by taking the lower 5 bits of arg1. The upper 3 bits determine an aux opcode, that performs an action described in the table below.<br />
<br />
{| border="1" cellpadding="2" width=100%<br />
|- style="background:whitesmoke"<br />
|Opcode||Meaning||Description<br />
|-<br />
|$00||Num. Available Slots||Returns the number of save slots available.<br />
|-<br />
|$20||Drive||In V3, returns the type of drive (0 = ???, 1 = A or B [floppy], 2 = hard drive).<br>In V4, sets the current drive (returns 1).<br />
|-<br />
|$40||Load Game||Loads a game from the given slot (returns 3 if successful, 5 otherwise).<br />
|-<br />
|$80||Save Game||Saves a game to the given slot (returns 0 if successful, 2 otherwise).<br />
|-<br />
|$C0||Test For Game||Tests if a save exists in the given slot (returns 6 if so, 7 otherwise).<br />
|}<br />
<br />
<br />
==saveLoadVars ($A7) (V3-4)==<br />
This instruction is not present in SCUMM V5; its opcode is used as a dummy.<br />
<br />
===Encoding===<br />
opcode sub-opcode<br />
<br />
sub-opcodes:<br />
$01 sub-sub-opcode... $00<br />
$02 sub-sub-opcode... $00<br />
<br />
$01 (save) sub-sub-opcodes:<br />
$01 resultA resultB<br />
$02 arg1[p8] arg2[p8]<br />
$03 filename[c]... $00<br />
$04<br />
$1F<br />
<br />
$02 (load) sub-sub-opcodes:<br />
$01 resultA resultB<br />
$02 arg1[p8] arg2[p8]<br />
$03 filename[c]... $00<br />
$04<br />
$1F<br />
<br />
===Operation===<br />
{| border="1" cellpadding="2" width=100%<br />
|- style="background:whitesmoke"<br />
|Opcode||Meaning||Description<br />
|-<br />
|$01||SO_SAVE_VARS||Saves variables (for saving games?)<br />
|-<br />
|$02?||SO_RESTORE_VERBS||Loads variables (for saving games?)<br>(I have not verified that restore vars is $02, as the ScummVM code only compares to $01.)<br />
|}<br />
<br />
{| border="1" cellpadding="2" width=100%<br />
|- style="background:whitesmoke"<br />
|Opcode||Meaning||Description<br />
|-<br />
|$01||Write Vars||Writes a range of variables.<br />
|-<br />
|$02||Write Strings||Writes a range of string variables.<br />
|-<br />
|$03||Open File||Opens a file for writing.<br />
|-<br />
|$04||Dummy||Does nothing.<br />
|-<br />
|$1F||Close File||Closes the last opened file.<br />
|}<br />
<br />
{| border="1" cellpadding="2" width=100%<br />
|- style="background:whitesmoke"<br />
|Opcode||Meaning||Description<br />
|-<br />
|$01||Read Vars||Reads a range of variables.<br />
|-<br />
|$02||Read Strings||Reads a range of string variables.<br />
|-<br />
|$03||Open File||Opens a file for reading.<br />
|-<br />
|$04||Dummy||Does nothing.<br />
|-<br />
|$1F||Close File||Closes the last opened file.<br />
|}<br />
<br />
<br />
==saveRestoreVerbs ($AB)==<br />
<br />
===Encoding=== <br />
opcode sub-opcode<br />
<br />
sub-opcodes: <br />
$01 start[p8] end[p8] mode[p8]<br />
$02 start[p8] end[p8] mode[p8]<br />
$03 start[p8] end[p8] mode[p8]<br />
<br />
===Operation===<br />
{| border="1" cellpadding="2" width=100%<br />
|- style="background:whitesmoke"<br />
|Opcode||Meaning||Description<br />
|-<br />
|$01||SO_SAVE_VERBS||For all verbs between start and end, sets the "saveid" to mode. <br />
|-<br />
|$02||SO_RESTORE_VERBS||For all verbs between start and end and matching mode, kills any existing verb, sets the saveid to 0 and generally inits the verb.<br />
|-<br />
|$03||SO_DELETE_VERBS||For all verbs between start and end and matching mode, kills any existing verb.<br />
|}<br />
<br />
<br />
==setCameraAt ($32)==<br />
<br />
===Encoding===<br />
opcode x[p16]<br />
<br />
===Operation===<br />
Sets the camera's x position.<br />
<br />
<br />
==setObjectName ($54)==<br />
<br />
===Encoding===<br />
opcode object[p16] name[c]... $00<br />
<br />
===Operation===<br />
Sets the given object's name.<br />
<br />
<br />
==setOwnerOf ($29)==<br />
<br />
===Encoding===<br />
opcode object[p16] owner[p8]<br />
<br />
===Operation===<br />
Sets the owner of the object.<br />
<br />
<br />
==setState ($07)==<br />
<br />
===Encoding===<br />
opcode object[p16] state[p8]<br />
<br />
===Operation===<br />
Sets the state of the object.<br />
<br />
<br />
==setVarRange ($26)==<br />
non-standard encoding<br />
<br />
===Encoding===<br />
opcode result number[8] values[8]...<br />
or<br />
opcode result number[8] values[16]...<br />
<br />
===Operation===<br />
for (i = 0; i < number; i++) {<br />
&#42;result + i := values[i];<br />
}<br />
<br />
This sets a number of variables to the given parameters. The starting variable is given as "result", and the number of variables to modify is given as "number". This is followed by the same number of values, which will be put into the variable locations. The values are constants, and can be either 16-bit, if the highest bit of the opcode is set, i.e. $A6; or 8-bit, if the highest bit of the opcode is not set, i.e. $26. Note that all values are affected by the opcode's high bit; you can't mix 8 and 16-bit values.<br />
<br />
descumm example:<br />
setVarRange(Var[178],9,[0,0,0,0,0,0,0,0,0]);<br />
<br />
This sets variables 178 to 186 (inclusive) to 0.<br />
<br />
<br />
==soundKludge ($4C)==<br />
<br />
===Encoding===<br />
opcode items[v16]...<br />
<br />
===Operation===<br />
If the first item is -1, the existing sound queue is processed. Otherwise, the list of items is added to the queue.<br />
<br />
===Variants===<br />
In SCUMM V3 and V4 (small header) games, this opcode is used for the WaitForSentence instruction.<br />
<br />
<br />
==startMusic ($02)==<br />
<br />
===Encoding===<br />
opcode music[p8]<br />
<br />
===Operation===<br />
Adds the music in to the queue to be played.<br />
<br />
===Variants===<br />
In FM-Towns (SCUMM V3) games, this instruction performs different functions (some kind of Audio CD status query function; some partially implemented in ScummVM):<br />
opcode result sub-opcode<br />
<br />
{| border="1" cellpadding="2" width=100%<br />
|- style="background:whitesmoke"<br />
|Opcode||Meaning||Description<br />
|-<br />
|$00||Is Playing||Returns true if a CD audio track is currently playing.<br />
|-<br />
|$FC||Unpause CD||Unpauses the CD audio track.<br />
|-<br />
|$FD||Pause CD||Pauses the CD audio track.<br />
|-<br />
|$FE||Get CD Sound||Returns the current CD sound.<br />
|-<br />
|$FF||CD Volume||Might return the the current CD volume in FM-Towns Loom.<br />
|-<br />
|other||Track Length||Returns the track length in seconds.<br />
|}<br />
<br />
<br />
==startObject ($37)==<br />
<br />
===Encoding===<br />
opcode object[p16] script[p8] args[v16]...<br />
<br />
===Operation===<br />
Starts the object's script (OBCD blocks), passing the given arguments.<br />
<br />
<br />
==startScript ($0A)==<br />
one parameter plus varargs, extra encoding in opcode<br />
<br />
===Encoding===<br />
opcode script[p8] args[v16]...<br />
<br />
===Operation===<br />
Spawns a new thread running the code in script script. The new script has its local variables initialised to the list args. Uninitialised variables have undefined values.<br />
<br />
The opcode carries extra information: <br />
<br />
{| border="1" cellpadding="2" width=10%<br />
|- style="background:whitesmoke"<br />
|7||6||5||4 0<br />
|-<br />
|P1||R||F||$0A<br />
|}<br />
<br />
P1 = standard parameter bit<br><br />
R = indicates that the script is recursive<br><br />
F = indicates that the script is freeze resistant (a call to freezeScripts will skip this script, unless the "force freeze" bit of the freezeScripts opcode is set).<br />
<br />
<br />
==startSound ($1C)==<br />
<br />
===Encoding===<br />
opcode sound[p8]<br />
<br />
===Operation===<br />
Adds the given sound to the sound queue to be played.<br />
<br />
<br />
==stopMusic ($20)==<br />
<br />
===Encoding===<br />
opcode<br />
<br />
===Operation===<br />
Stops all sounds.<br />
<br />
<br />
==stopObjectCode ($A0 or $00)==<br />
<br />
===Encoding===<br />
opcode<br />
<br />
===Operation===<br />
Marks the calling script as dead, to be later pruned from the thread pool. Cleans up residual arrays. Should always be the last instruction in a script.<br />
<br />
$A0 is used in local and global scripts (LSCR and SCRP blocks in the V5 resource files), $00 is used in room entry, room exit, and verb/object scripts (ENCD, EXCD, VERB blocks).<br />
<br />
<br />
==stopObjectScript ($6E)==<br />
<br />
===Encoding===<br />
opcode script[p16]<br />
<br />
===Operation===<br />
Marks the given object script as dead, to be later pruned from the thread pool. Cleans up residual arrays.<br />
<br />
<br />
==stopScript ($62)==<br />
<br />
===Encoding===<br />
opcode script[p8]<br />
<br />
===Operation===<br />
Marks the given script as dead, to be later pruned from the thread pool. Cleans up residual arrays.<br />
<br />
<br />
==stopSound ($3C)==<br />
<br />
===Encoding===<br />
opcode sound[p8]<br />
<br />
===Operation===<br />
Stops the given sound.<br />
<br />
<br />
==stringOps ($27)==<br />
parameters depend on sub-opcode<br />
<br />
===Encoding===<br />
opcode sub-opcode<br />
<br />
sub-opcodes:<br />
$01 stringID[p8] string[c]... $00<br />
$02 destID[p8] srcID[p8]<br />
$03 stringID[p8] index[p8] char[c]<br />
$04 result stringID[p8] index[p8]<br />
$05 stringID[p8] size[p8]<br />
<br />
===Operation===<br />
Miscellaneous actions on strings (Arrays, referred to by resource number).<br />
<br />
{| border="1" cellpadding="2" width=100%<br />
|- style="background:whitesmoke"<br />
|Opcode||Meaning||Description<br />
|-<br />
|$01||Load String||Loads the inline null-terminated string into the resource slot given by stringID.<br />
|-<br />
|$02||Copy String||Creates a duplicate of the string at resource slot srcID into destID. The old string at destID is lost.<br />
|-<br />
|$03||Write Character||Writes char at the given index (offset) of the string resource located at slot stringID. Out of bounds accesses cause undefined behaviour.<br />
|-<br />
|$04||Read Character||Reads a byte (character) at the given index (offset) of the string resource located at slot stringID, and writes it to result. Out of bounds accesses cause undefined behaviour.<br />
|-<br />
|$05||New String||Allocates or frees a string (Array), located at resource slot stringID. The string is initialised to size; if size is zero, the string is freed.<br />
|}<br />
<br />
<br />
==subtract ($3A)==<br />
<br />
===Encoding===<br />
opcode result value[p16]<br />
<br />
===Operation===<br />
result := result - value<br />
<br />
The variable pointed to by result is read, value is subtracted from it, and the result written back.<br />
<br />
<br />
==systemOps ($98)==<br />
<br />
===Encoding===<br />
opcode sub-opcode<br />
<br />
sub-opcodes:<br />
$01<br />
$02<br />
$03<br />
<br />
===Operation===<br />
{| border="1" cellpadding="2" width=100%<br />
|- style="background:whitesmoke"<br />
|Opcode||Meaning||Description<br />
|-<br />
|$01||SO_RESTART||Restarts the game.<br />
|-<br />
|$02||SO_PAUSE||Pauses/unpauses the game.<br />
|-<br />
|$03||SO_QUIT||Quits the game.<br />
|}<br />
<br />
<br />
==verbOps ($7A)==<br />
<br />
===Encoding===<br />
opcode verbID[p8] sub-opcode... $FF<br />
<br />
sub-opcodes:<br />
$01 object[p16]<br />
$02 name[c]... $00<br />
$03 colour[p8]<br />
$04 hicolour[p8]<br />
$05 left[p16] top[p16]<br />
$06<br />
$07<br />
$08<br />
$09<br />
$10 colour[p8]<br />
$11<br />
$12 key[p8]<br />
$13<br />
$14 stringID[p16]<br />
$16 object[p16] room[p8]<br />
$17 colour[p8]<br />
<br />
===Operation===<br />
{| border="1" cellpadding="2" width=100%<br />
|- style="background:whitesmoke"<br />
|Opcode||Meaning||Description<br />
|-<br />
|$01||SO_VERB_IMAGE||Assigns an object (image) to a verb.<br />
|-<br />
|$02||SO_VERB_NAME||Assigns the in-line name to the verb slot.<br />
|-<br />
|$03||SO_VERB_COLOR||Sets the colour of the verb.<br />
|-<br />
|$04||SO_VERB_HICOLOR||Sets the highlight colour of the verb.<br />
|-<br />
|$05||SO_VERB_AT||Sets the verb's top-left co-ordinates.<br />
|-<br />
|$06||SO_VERB_ON||Makes this verb active.<br />
|-<br />
|$07||SO_VERB_OFF||Makes this verb inactive.<br />
|-<br />
|$08||SO_VERB_DELETE||Kills this verb.<br />
|-<br />
|$09||SO_VERB_NEW||Creates a verb in the slot for the given verbID. If the slot is 0 (verb doesn't already exist), will add it to the next unusued slot; if this exceeds the global maximum number of verbs an error will be raised.<br />
|-<br />
|$10||SO_VERB_DIMCOLOR||Sets the dim colour of the verb.<br />
|-<br />
|$11||SO_VERB_DIM||Dims this verb.<br />
|-<br />
|$12||SO_VERB_KEY||Sets the key code (maybe ASCII char?) associated with this verb.<br />
|-<br />
|$13||SO_VERB_CENTER||Centres the verb?<br />
|-<br />
|$14||SO_VERB_NAME_STR||Loads the given string resource into the verb's slot. If either the string resource or verb slot is not found (0), the verb resource is nuked.<br />
|-<br />
|$16||Assign Object||Assigns an object from the given room to the verb (if the object's image index is not already assigned to the given object).<br />
|-<br />
|$17||Set Back Colour||Sets the background colour of the verb?<br />
|}<br />
<br />
<br />
==wait ($AE)==<br />
<br />
===Encoding===<br />
opcode sub-opcode<br />
<br />
sub-opcodes:<br />
$01 actor[p8]<br />
$02 <br />
$03<br />
$04<br />
<br />
===Operation===<br />
{| border="1" cellpadding="2" width=100%<br />
|- style="background:whitesmoke"<br />
|Opcode||Meaning||Description<br />
|-<br />
|$01||SO_WAIT_FOR_ACTOR||If the given actor is moving, breaks and resumes at this instruction again.<br />
|-<br />
|$02||SO_WAIT_FOR_MESSAGE||If the global variable VAR_HAVE_MSG (Var[3]) is not zero, breaks and resumes at this instruction again.<br />
|-<br />
|$03||SO_WAIT_FOR_CAMERA||If the camera has not reached its destination x position, breaks and resumes at this instruction again.<br />
|-<br />
|$04||SO_WAIT_FOR_SENTENCE||If there is a sentence present?, breaks and resumes at this instruction again<br />
|}<br />
<br />
===Variants===<br />
In Indy3 (non-Macintosh), this opcode only acts as SO_WAIT_FOR_MESSAGE and omits the sub-opcode.<br />
opcode<br />
<br />
<br />
==walkActorTo ($1E)==<br />
<br />
===Encoding===<br />
opcode actor[p8] x[p16] y[p16]<br />
<br />
===Operation===<br />
Sets the actor to begin walking to the given position.<br />
<br />
<br />
==walkActorToActor ($0D)==<br />
<br />
===Encoding===<br />
opcode walker[p8] walkee[p8] distance[8]<br />
<br />
===Operation===<br />
Walks walker towards walkee's position by the given distance. Walker and walkee are both actors.<br />
<br />
<br />
==walkActorToObject ($36)==<br />
<br />
===Encoding===<br />
opcode actor[p8] object[p16]<br />
<br />
===Operation===<br />
Sets the actor to begin walking to the given object's position.<br />
<br />
=Variables=<br />
<br />
A number of variables are reserved for use by the SPUTM/SCUMM engine. Here is a list of known variables and their corresponding numbers, taken from the ScummVM source code.<br />
<br />
VAR_RESULT = 0; // descumm claims var 0 is the result var (for expressions)<br />
VAR_KEYPRESS = 0; // script_v5_.cpp claims var 0 is for keypresses...<br />
VAR_EGO = 1;<br />
VAR_CAMERA_POS_X = 2;<br />
VAR_HAVE_MSG = 3;<br />
VAR_ROOM = 4;<br />
VAR_OVERRIDE = 5;<br />
VAR_MACHINE_SPEED = 6;<br />
VAR_ME = 7;<br />
VAR_NUM_ACTOR = 8;<br />
VAR_CURRENT_LIGHTS = 9;<br />
VAR_CURRENTDRIVE = 10;<br />
VAR_TMR_1 = 11;<br />
VAR_TMR_2 = 12;<br />
VAR_TMR_3 = 13;<br />
VAR_MUSIC_TIMER = 14;<br />
VAR_ACTOR_RANGE_MIN = 15;<br />
VAR_ACTOR_RANGE_MAX = 16;<br />
VAR_CAMERA_MIN_X = 17;<br />
VAR_CAMERA_MAX_X = 18;<br />
VAR_TIMER_NEXT = 19;<br />
VAR_VIRT_MOUSE_X = 20;<br />
VAR_VIRT_MOUSE_Y = 21;<br />
VAR_ROOM_RESOURCE = 22;<br />
VAR_LAST_SOUND = 23;<br />
VAR_CUTSCENEEXIT_KEY = 24;<br />
VAR_TALK_ACTOR = 25;<br />
VAR_CAMERA_FAST_X = 26;<br />
VAR_SCROLL_SCRIPT = 27;<br />
VAR_ENTRY_SCRIPT = 28;<br />
VAR_ENTRY_SCRIPT2 = 29;<br />
VAR_EXIT_SCRIPT = 30;<br />
VAR_EXIT_SCRIPT2 = 31;<br />
VAR_VERB_SCRIPT = 32;<br />
VAR_SENTENCE_SCRIPT = 33;<br />
VAR_INVENTORY_SCRIPT = 34;<br />
VAR_CUTSCENE_START_SCRIPT = 35;<br />
VAR_CUTSCENE_END_SCRIPT = 36;<br />
VAR_CHARINC = 37;<br />
VAR_WALKTO_OBJ = 38;<br />
VAR_DEBUGMODE = 39;<br />
VAR_HEAPSPACE = 40;<br />
VAR_RESTART_KEY = 42;<br />
VAR_PAUSE_KEY = 43;<br />
VAR_MOUSE_X = 44;<br />
VAR_MOUSE_Y = 45;<br />
VAR_TIMER = 46;<br />
VAR_TIMER_TOTAL = 47;<br />
VAR_SOUNDCARD = 48;<br />
VAR_VIDEOMODE = 49;<br />
VAR_MAINMENU_KEY = 50;<br />
VAR_FIXEDDISK = 51;<br />
VAR_CURSORSTATE = 52;<br />
VAR_USERPUT = 53;<br />
VAR_V5_TALK_STRING_Y = 54;<br />
VAR_SOUNDRESULT = 56;<br />
VAR_TALKSTOP_KEY = 57;<br />
VAR_FADE_DELAY = 59;<br />
VAR_NOSUBTITLES = 60;<br />
VAR_SOUNDPARAM = 64;<br />
VAR_SOUNDPARAM2 = 65;<br />
VAR_SOUNDPARAM3 = 66;<br />
VAR_INPUTMODE = 67; // 1 is keyboard, 2 is joystick, 3 is mouse<br />
VAR_MEMORY_PERFORMANCE = 68;<br />
VAR_VIDEO_PERFORMANCE = 69;<br />
VAR_ROOM_FLAG = 70;<br />
VAR_GAME_LOADED = 71;<br />
VAR_NEW_ROOM = 72;<br />
<br />
<br />
=Table of Parameters=<br />
Please see the wiki page [[SCUMM/V5_opcodes/Table]] for a concise rendition of the above information (with a few omissions dues to the complexity of the instructions).</div>Jestar jokinhttps://wiki.scummvm.org/index.php?title=Talk:GSoC_Tools_status&diff=13038Talk:GSoC Tools status2010-02-23T13:30:40Z<p>Jestar jokin: Notes on defects in descumm</p>
<hr />
<div>Not sure if this is relevant, but I'm aware of two defects in descumm:<br />
<br />
* V0-5: Incorrect parsing of escape sequences in strings, such as in print and printEgo instructions. Sometimes interprets a valid value of '\x00' as the null-terminating character. (Monkey Island 2, global script 12)<br />
* V0-5, maybe 6+: if/else generation sometimes incorrect with complex control flows. Output is correct when if/else statements are disabled. (Monkey Island 2, global script 22)<br />
<br />
However, since these weren't introduced in the GSoC update (and have probably been around for many years), I don't know if they should be mentioned. First issue should be easy to fix, just copy the escape sequence handling from the v6+ part of descumm. The second part would probably need to implement some control flow graph analysis (could try and copy code from the GSoC generic bytecode decompilers, if it's useable).<br />
--[[User:Jestar jokin|Jestar jokin]] 13:30, 23 February 2010 (UTC)</div>Jestar jokinhttps://wiki.scummvm.org/index.php?title=SCUMM/Technical_Reference/Object_resources&diff=13037SCUMM/Technical Reference/Object resources2010-02-23T13:07:03Z<p>Jestar jokin: Add info on SCUMM v4 object code blocks</p>
<hr />
<div>=== V6 Objects ===<br />
<br />
In v6 objects are split in 2 chunks: OBIM and OBCD. OBIM store the images, zplanes, etc, while OBCD mostly store the scripts.<br />
<br />
==== OBIM ====<br />
<br />
* OBIM<br />
** IMHD : header<br />
** IMnn : images<br />
*** SMAP (or BMOP)<br />
*** ZPnn<br />
<br />
Note: In IMnn and ZPnn nn represent an hexadecimal number.<br />
<br />
===== IMHD =====<br />
<br />
<pre><br />
obj id : 16le<br />
num imnn : 16le<br />
num zpnn : 16le (per IMnn block)<br />
flags : 8<br />
unknown : 8<br />
x : 16le<br />
y : 16le<br />
width : 16le<br />
height : 16le<br />
num hotspots : 16le (usually one for each IMnn, but their is one even<br />
if no IMnn is present)<br />
hotspots<br />
x : 16le signed<br />
y : 16le signed<br />
</pre><br />
<br />
The hotspots indicate where the actors should stand when they walk to the object.<br />
<br />
Each IMnn contain an image for a state. As state 0 display nothing they start at 01. IMnn chunks contain a SMAP or BMOP chunk enventually followed by some ZPnn blocks. See [[Image resources]] for more details on these.<br />
<br />
==== OBCD ====<br />
<br />
* OBCD<br />
** CDHD : header<br />
** VERB : script<br />
** OBNA : name<br />
<br />
===== CDHD =====<br />
<br />
<pre><br />
obj id : 16le<br />
x : 16le<br />
y : 16le<br />
width : 16le<br />
height : 16le<br />
flags : 8<br />
parent : 8<br />
walk_x : 16le signed<br />
walk_y : 16le signed<br />
actor dir : 8 (direction the actor will look at when standing in front<br />
of the object)<br />
</pre><br />
<br />
Note that the size and position must match those in the IMHD.<br />
<br />
===== VERB =====<br />
<br />
The VERB chunk hold the scripts. It start with a table giving the offset of the entry point for each verb handled by the object code, followed by the code.<br />
<br />
<pre><br />
offset table : vlc<br />
verb : 8 (0xFF is default)<br />
offset : 16le<br />
table end : 8 (must be 0)<br />
code<br />
</pre><br />
<br />
The OBNA chunk simply contain a null terminated string.<br />
<br />
=== V5 Objects ===<br />
V5 objects are a lot like V6 Objects, with minor differences.<br />
<br />
===== IMHD =====<br />
<br />
<pre><br />
obj id : 16le<br />
num imnn : 16le<br />
num zpnn : 16le (per IMnn block)<br />
flags : 8<br />
unknown : 8<br />
x : 16le<br />
y : 16le<br />
width : 16le<br />
height : 16le<br />
</pre><br />
<br />
IMHD omits the hotspots.<br />
<br />
===== CDHD =====<br />
<br />
<pre><br />
obj id : 16le<br />
x : 8<br />
y : 8<br />
width : 8<br />
height : 8<br />
flags : 8<br />
parent : 8<br />
walk_x : 16le signed<br />
walk_y : 16le signed<br />
actor dir : 8 (direction the actor will look at when standing in front<br />
of the object)<br />
</pre><br />
<br />
x, y, width, and height are bytes. Their values should be multiplied by 8 (the size of an image strip).<br />
<br />
=== V4 Objects ===<br />
<br />
In v4 objects are split in 2 chunks: OI and OC. OC does not have any sub-blocks like v5 or v6 objects; it contains all header information and the SCUMM script.<br />
<br />
===== OC =====<br />
<br />
<pre><br />
obj id : 16le<br />
unknown : 8<br />
x : 8<br />
y, parent state : 8 (parent state is AND 0x80, y is AND 0x7F)<br />
width : 8<br />
parent : 8<br />
walk_x : 16le signed(?)<br />
walk_y : 16le signed(?)<br />
height, actor dir : 8 (height is AND 0xF8, actor dir is AND 0x07)<br />
name offset : 8 (point to location of object name, from start of OC block)<br />
verb table : variable<br />
object name : variable, null-terminated string<br />
SCUMM script : variable<br />
</pre><br />
<br />
The verb table is made up of multiple entries, each looks like this:<br />
<br />
<pre><br />
verb ID : 8<br />
offset : 16le (from start of script?)<br />
</pre><br />
<br />
The number of entries will vary depending on the interactions defined for the object.</div>Jestar jokinhttps://wiki.scummvm.org/index.php?title=SCUMM/Technical_Reference/Index_File&diff=12747SCUMM/Technical Reference/Index File2009-12-21T05:34:09Z<p>Jestar jokin: I misunderstood the ScummVM code</p>
<hr />
<div>[[SCUMM/Technical Reference|SCUMM Technical Reference]] &rarr; ''SCUMM index file''<br />
<br />
<br />
= Introduction=<br />
<br />
Most of the information below are retrieved from the [http://scumm.mixnmojo.com/?page=specs&file=indexfiles.txt LucasHacks!] site and from the Pascal source code of the ''IndexFileReader 1.2'' (written by Ben Gorman (Bgbennyboy, http://quick.mixnmojo.com). In addition, ''ScummRevisited'' (written by Jimmi Thøgersen (Serge), http://www.mixnmojo.com/scumm/scummrev) turned out to be very useful in verifying the found offsets.<br />
<br />
The SCUMM index file contains special information to allow quick random access to the resources in the other game files. It also includes the room names and some max limits for the game. The following filenames are used:<br />
<br />
<br />
<table border="2" cellspacing="0" cellpadding="4"><br />
<tr><th width="100">filename</th><th>SCUMM version</th></tr><br />
<tr><td >00.lfl / 000.lfl</td><td>V3/4</td></tr><br />
<tr><td>.000</td><td>V5/6</td></tr><br />
<tr><td>.LA0</td><td>V7/8</td></tr><br />
</table><br />
<br />
<br />
Version 1 to 3 use hardcoded offsets and cannot be treated that easily. For the other games, the index file can be used to determine the [[SCUMM/Versions|SCUMM version]] because there have been slight changes in each version.<br />
<br />
* Version 4<br />
** the 5th and 6th byte match RN or OR<br />
* Version 5: <br />
** RNAM xor'ed with 0x69 at the beginning of the file<br />
** next 4 byte integer value xor'ed with 0x69 is &gt; 9<br />
* Version 6<br />
** RNAM xor'ed with 0x69 at the beginning<br />
** next 4 byte integer value xor'ed with 0x69 is 9 (actually it's the size of the chunk. In V6 games, no room names are stored so the size is 4 bytes (header) + 4 bytes (size) + 1 byte for the termination character).<br />
* Version 7<br />
** RNAM at the beginning of the file (not xor'ed this time)<br />
** next 4 bytes result in BE integer 9 (actually applies only to [[Full Throttle]])<br />
* Version 7 or 8<br />
** RNAM at the beginning of the file<br />
** next 4 bytes integer is &gt; 9<br />
<br />
<br />
How to distinguish between version 7 and 8? Not by looking at the first bytes, but the the size of the chunks is usually bigger because a 4 byte integer is used to store the number of objects.<br />
<br />
= Conventions =<br />
<br />
As usual, the [http://en.wikipedia.org/wiki/Endianness endianness (Wikipedia)] is important. Unless stated, little endianess (LE) is used. <br />
<br />
BE is used as abbreviation for big endianness. <br />
<br />
A '''Chunk''' is a named part of the file, e.g. RNAM. Each chunk has a header that contains at least the chunk name and its size. The following chunks are available:<br />
<br />
<br />
{| border="1" cellspacing="0" cellpadding="4"<br />
|RNAM Room Names<br />
|In V5+<br />
|-<br />
|MAXS Maximum Values<br />
|In V5+<br />
|-<br />
|DROO Directory of Rooms<br />
|In V5+<br />
|-<br />
|DRSC Direcory of Room Scripts<br />
|In V8<br />
|-<br />
|DSCR Directory of Scripts<br />
|In V5+<br />
|-<br />
|DSOU Directory of Sounds<br />
|In V5+<br />
|-<br />
|DCOS Directory of Costumes<br />
|In V5+<br />
|-<br />
|DCHR Directory of Charsets<br />
|In V5+<br />
|-<br />
|DOBJ Directory of Objects<br />
|In V5+<br />
|-<br />
|AARY List of Arrays<br />
|In V6+<br />
|-<br />
|ANAM Animation Names?<br />
|In V7<br />
|-<br />
|RM Room Names<br />
|In V3/4<br />
|-<br />
|0R Directory Of Rooms<br />
|In V3/4<br />
|-<br />
|0S Directory Of Scripts?<br />
|In V3/4<br />
|-<br />
|0N Directory Of Sounds?<br />
|In V3/4<br />
|-<br />
|0C Directory Of Costumes?<br />
|In V3/4<br />
|-<br />
|0O Directory Of Objects?<br />
|In V3/4<br />
|}<br />
<br />
<br />
= Scumm 3/4 =<br />
<br />
* File's aren't xor'ed<br />
<br />
To read in the data, the following pseudo-code can be used:<br />
<br />
Read Number of Items<br />
FROM 1 to "Number of Items" DO<br />
Read subvalue 1<br />
Read subvalue 2<br />
END<br />
<br />
<br />
==RN - Room names ==<br />
<br />
Block Size (4 bytes)<br />
Block Name (2 bytes)<br />
#Room No (1 byte)<br />
#Room Name (9 bytes) XOR'ed with FF<br />
Blank (00) byte (1 byte) Marks end of chunk<br />
<br />
<br />
==0R - Directory of Rooms==<br />
<br />
Block Size (4 bytes)<br />
Block Name (2 bytes)<br />
No of items (2 bytes)<br />
File Number (1 byte)<br />
Offset (4 bytes)<br />
<br />
''File Number'' is interesting if a game is splitted on multiple disks. 0 means ''not used''. <br />
<br />
For ''Offset'' only the value 0 seems to be used.<br />
<br />
==0S - Directory of Scripts ==<br />
<br />
Block Size (4 bytes)<br />
Block Name (2 bytes)<br />
No of items (2 bytes)<br />
Room Number (1 byte)<br />
Offset (4 bytes)<br />
<br />
The global scripts are stored in this directory. The offsets are relative to the room.<br />
<br />
==0N - Directory of Sounds ==<br />
<br />
Block Size (4 bytes)<br />
Block Name (2 bytes)<br />
No of items (2 bytes)<br />
Room Number (1 byte)<br />
Offset (4 bytes)<br />
<br />
Similar to scripts but holds indexes for sounds.<br />
<br />
==0C - Directory of Costumes ==<br />
<br />
Block Size (4 bytes)<br />
Block Name (2 bytes)<br />
No of items (2 bytes)<br />
Room Number (1 byte)<br />
Offset (4 bytes)<br />
<br />
Similar to scripts but holds indexes of customes. <br />
<br />
==0O - Directory of Objects==<br />
<br />
Block Size (4 bytes)<br />
Block Name (2 bytes)<br />
No of items (2 bytes)<br />
Owner+state (1 byte)<br />
<br />
The Object owner and state are encoded in one byte. Example:<br />
<br />
0xA2 &rarr; Owner = 0xA, State = 0x2<br />
<br />
The pseudo decode code would be:<br />
<br />
Owner = ( (Owner+state Byte) AND 0xF0) >> 4<br />
State = (Owner+state Byte) AND 0x0F<br />
<br />
= Scumm 5 =<br />
<br />
* The files are xor'ed with 0x69<br />
<br />
== RNAM - Room Names ==<br />
<br />
Block Name (4 bytes)<br />
Block Size (4 bytes BE)<br />
#Room No (1 byte)<br />
#Room Name (9 bytes) XOR'ed with FF<br />
Blank (00) byte (1 byte) Marks end of chunk<br />
<br />
<br />
== MAXS ==<br />
<br />
Block Name (4 bytes)<br />
Block Size (4 bytes BE)<br />
Variables (2 bytes)<br />
Unknown (2 bytes)<br />
Bit Variables (2 bytes)<br />
Local Objects (2 bytes)<br />
New Names? (2 bytes)<br />
Character Sets (2 bytes)<br />
Verbs? (2 bytes)<br />
Array? (2 bytes)<br />
Inventory Objects (2 bytes)<br />
<br />
== DROO - Directory of Rooms ==<br />
<br />
Block Name (4 bytes)<br />
Block Size (4 bytes BE)<br />
No of items (2 bytes)<br />
*Room Number (1 byte)<br />
*Offset (4 bytes)<br />
<br />
The flow how to read in this kind of information has changed slightly from V3/4.<br />
<br />
Read "No of items"<br />
FROM 1 TO "No of items" DO<br />
Read "Room Number"<br />
END<br />
<br />
FROM 1 TO "No of items" DO<br />
Read "Offset"<br />
END<br />
<br />
First read in all room numbers, then read in all room offsets. <br />
<br />
<br />
== DSCR - Directory of Scripts ==<br />
<br />
Block Name (4 bytes)<br />
Block Size (4 bytes BE)<br />
No of items (2 bytes)<br />
*Room Number (1 byte)<br />
*Offset (4 bytes)<br />
<br />
Indexes for global scripts, see pseudo code above on how to read in the data.<br />
<br />
<br />
== DSOU - Directory of Sound == <br />
<br />
Block Name (4 bytes)<br />
Block Size (4 bytes BE)<br />
No of items (2 bytes)<br />
*Room Number (1 byte)<br />
*Offset (4 bytes)<br />
<br />
Indexes for sound objects.<br />
<br />
<br />
== DCOS - Directory of Costumes ==<br />
<br />
Block Name (4 bytes)<br />
Block Size (4 bytes BE)<br />
No of items (2 bytes)<br />
*Room Number (1 byte)<br />
*Offset (4 bytes)<br />
<br />
Indexes for costumes<br />
<br />
<br />
== DCHR - Director of Charsets ==<br />
<br />
Block Name (4 bytes)<br />
Block Size (4 bytes BE)<br />
No of items (2 bytes)<br />
*Room Number (1 byte)<br />
*Offset (4 bytes)<br />
<br />
Indexes for charsets.<br />
<br />
<br />
== DOBJ - Directory of Objects ==<br />
<br />
Block Name (4 bytes)<br />
Block Size (4 bytes BE)<br />
No of items (2 bytes)<br />
*Owner+state (1 byte)<br />
*Class data (4 bytes)<br />
<br />
Information about objects. See remarks in V3/4 section how the owner+state value should be interpreted. Note that the index files stores ALL owner+state values, followed by ALL class data values.<br />
<br />
= Scumm 6 =<br />
<br />
* Files are xor'ed with 0x69<br />
<br />
<br />
== RNAM - Room Names ==<br />
<br />
Blank Byte(00) (1 byte)<br />
<br />
No room names are stored.<br />
<br />
<br />
== MAXS ==<br />
<br />
Block Name (4 bytes)<br />
Block Size (4 bytes BE)<br />
Variables (2 bytes)<br />
Unknown (2 bytes)<br />
Bit Variables (2 bytes)<br />
Local Objects (2 bytes)<br />
Arrays (2 bytes)<br />
Unknown (2 bytes)<br />
Verbs (2 bytes)<br />
Floating Objects (2 bytes)<br />
Inventory Objects (2 bytes)<br />
Rooms (2 bytes)<br />
Scripts (2 bytes)<br />
Sounds (2 bytes)<br />
Character Sets (2 bytes)<br />
Costumes (2 bytes)<br />
Global Objects (2 bytes)<br />
<br />
<br />
== DROO, DSCR, DSOU, DCOS, DCHR, DOBJ ==<br />
<br />
All as in V5<br />
<br />
<br />
== AARY - Array == <br />
<br />
Block Name (4 bytes)<br />
Block Size (4 bytes BE)<br />
#Stop (2 bytes) Stops if 0x0000<br />
#A (2 bytes)<br />
#B (2 bytes)<br />
#C (2 bytes)<br />
<br />
num=AARY no (itinerate through in loop)<br />
if c=1 then<br />
AARY=(num, 1, a, b)<br />
else<br />
AARY=(num, 1, a, b)<br />
<br />
If stop=0 you dont seek past the 6 bytes of A,B,C you just start the loop again.<br />
<br />
<br />
= Scumm 7 = <br />
<br />
* Files aren't xor'ed<br />
<br />
== RNAM - Room names ==<br />
<br />
* As in V6 ?!?!?!<br />
<br />
<br />
== MAXS ==<br />
<br />
Block Name (4 bytes)<br />
Block Size (4 bytes BE)<br />
Variables (2 bytes)<br />
Bit Variables (2 bytes)<br />
Unknown (2 bytes)<br />
Global Objects (2 bytes)<br />
Local Objects (2 bytes)<br />
New Names (2 bytes)<br />
Verbs (2 bytes)<br />
Floating Objects (2 bytes)<br />
Inventory Objects (2 bytes)<br />
Arrays (2 bytes)<br />
Rooms (2 bytes)<br />
Scripts (2 bytes)<br />
Sounds (2 bytes)<br />
Character Sets (2 bytes)<br />
Costumes (2 bytes)<br />
<br />
<br />
== DROO,DSCR,DSOU,DCOS,DCHR,DOBJ,AARY ==<br />
<br />
All as in V5<br />
<br />
<br />
== ANAM - Animation Names ==<br />
<br />
Block Name (4 bytes)<br />
Block Size (4 bytes BE)<br />
No of items (2 bytes<br />
#Name (8 bytes)<br />
#Blank (00) byte (1 byte)<br />
Blank (FF) byte (1 byte) Marks end of chunk<br />
<br />
<br />
= Scumm 8 =<br />
<br />
== RNAM - Room Names ==<br />
<br />
As in V6 ?<br />
<br />
<br />
== MAXS ==<br />
<br />
Block Name (4 bytes)<br />
Block Size (4 bytes BE)<br />
Variables (4 bytes)<br />
Bit Variables (4 bytes)<br />
Unknown (4 bytes)<br />
Scripts (4 bytes)<br />
Sounds (4 bytes)<br />
Character Sets (4 bytes)<br />
Costumes (4 bytes)<br />
Rooms (4 bytes)<br />
Unknown (4 bytes)<br />
Global Objects (4 bytes)<br />
Unknown (4 bytes)<br />
Local Objects (4 bytes)<br />
New Names (4 bytes)<br />
Floating Objects (4 bytes)<br />
Inventory Objects (4 bytes)<br />
Arrays (4 bytes)<br />
Verbs (4 bytes)<br />
<br />
<br />
== DROO - Directory of Rooms ==<br />
<br />
Block Name (4 bytes)<br />
Block Size (4 bytes BE)<br />
No of items (4 bytes)<br />
*Room Number (1 byte)<br />
*Offset (2 bytes)<br />
<br />
<br />
== DRSC - Directory of Room Scripts ==<br />
<br />
Block Name (4 bytes)<br />
Block Size (4 bytes BE)<br />
No of items (4 bytes)<br />
*Room Number (1 byte)<br />
*Offset (2 bytes)<br />
<br />
<br />
== DSCR - Directory of Scripts == <br />
<br />
Block Name (4 bytes)<br />
Block Size (4 bytes BE)<br />
No of items (4 bytes)<br />
*Room Number (1 byte)<br />
*Offset (2 bytes)<br />
<br />
<br />
== DSOU - Directory of Sound ==<br />
<br />
Block Name (4 bytes)<br />
Block Size (4 bytes BE)<br />
No of items (4 bytes)<br />
*Room Number (1 byte)<br />
*Offset (2 bytes)<br />
<br />
<br />
== DCOS - Directory of Costumes ==<br />
<br />
Block Name (4 bytes)<br />
Block Size (4 bytes BE)<br />
No of items (4 bytes)<br />
*Room Number (1 byte)<br />
*Offset (2 bytes)<br />
<br />
<br />
== DCHR - Directory of Charsets ==<br />
<br />
Block Name (4 bytes)<br />
Block Size (4 bytes BE)<br />
No of items (4 bytes)<br />
*Room Number (1 byte)<br />
*Offset (2 bytes)<br />
<br />
<br />
== DOBJ,AARY ==<br />
<br />
As in V7<br />
<br />
<br />
[[Category: SCUMM Technical Reference]]</div>Jestar jokinhttps://wiki.scummvm.org/index.php?title=SCUMM/Technical_Reference/Index_File&diff=12746SCUMM/Technical Reference/Index File2009-12-21T04:53:35Z<p>Jestar jokin: Add class data to DOBJ</p>
<hr />
<div>[[SCUMM/Technical Reference|SCUMM Technical Reference]] &rarr; ''SCUMM index file''<br />
<br />
<br />
= Introduction=<br />
<br />
Most of the information below are retrieved from the [http://scumm.mixnmojo.com/?page=specs&file=indexfiles.txt LucasHacks!] site and from the Pascal source code of the ''IndexFileReader 1.2'' (written by Ben Gorman (Bgbennyboy, http://quick.mixnmojo.com). In addition, ''ScummRevisited'' (written by Jimmi Thøgersen (Serge), http://www.mixnmojo.com/scumm/scummrev) turned out to be very useful in verifying the found offsets.<br />
<br />
The SCUMM index file contains special information to allow quick random access to the resources in the other game files. It also includes the room names and some max limits for the game. The following filenames are used:<br />
<br />
<br />
<table border="2" cellspacing="0" cellpadding="4"><br />
<tr><th width="100">filename</th><th>SCUMM version</th></tr><br />
<tr><td >00.lfl / 000.lfl</td><td>V3/4</td></tr><br />
<tr><td>.000</td><td>V5/6</td></tr><br />
<tr><td>.LA0</td><td>V7/8</td></tr><br />
</table><br />
<br />
<br />
Version 1 to 3 use hardcoded offsets and cannot be treated that easily. For the other games, the index file can be used to determine the [[SCUMM/Versions|SCUMM version]] because there have been slight changes in each version.<br />
<br />
* Version 4<br />
** the 5th and 6th byte match RN or OR<br />
* Version 5: <br />
** RNAM xor'ed with 0x69 at the beginning of the file<br />
** next 4 byte integer value xor'ed with 0x69 is &gt; 9<br />
* Version 6<br />
** RNAM xor'ed with 0x69 at the beginning<br />
** next 4 byte integer value xor'ed with 0x69 is 9 (actually it's the size of the chunk. In V6 games, no room names are stored so the size is 4 bytes (header) + 4 bytes (size) + 1 byte for the termination character).<br />
* Version 7<br />
** RNAM at the beginning of the file (not xor'ed this time)<br />
** next 4 bytes result in BE integer 9 (actually applies only to [[Full Throttle]])<br />
* Version 7 or 8<br />
** RNAM at the beginning of the file<br />
** next 4 bytes integer is &gt; 9<br />
<br />
<br />
How to distinguish between version 7 and 8? Not by looking at the first bytes, but the the size of the chunks is usually bigger because a 4 byte integer is used to store the number of objects.<br />
<br />
= Conventions =<br />
<br />
As usual, the [http://en.wikipedia.org/wiki/Endianness endianness (Wikipedia)] is important. Unless stated, little endianess (LE) is used. <br />
<br />
BE is used as abbreviation for big endianness. <br />
<br />
A '''Chunk''' is a named part of the file, e.g. RNAM. Each chunk has a header that contains at least the chunk name and its size. The following chunks are available:<br />
<br />
<br />
{| border="1" cellspacing="0" cellpadding="4"<br />
|RNAM Room Names<br />
|In V5+<br />
|-<br />
|MAXS Maximum Values<br />
|In V5+<br />
|-<br />
|DROO Directory of Rooms<br />
|In V5+<br />
|-<br />
|DRSC Direcory of Room Scripts<br />
|In V8<br />
|-<br />
|DSCR Directory of Scripts<br />
|In V5+<br />
|-<br />
|DSOU Directory of Sounds<br />
|In V5+<br />
|-<br />
|DCOS Directory of Costumes<br />
|In V5+<br />
|-<br />
|DCHR Directory of Charsets<br />
|In V5+<br />
|-<br />
|DOBJ Directory of Objects<br />
|In V5+<br />
|-<br />
|AARY List of Arrays<br />
|In V6+<br />
|-<br />
|ANAM Animation Names?<br />
|In V7<br />
|-<br />
|RM Room Names<br />
|In V3/4<br />
|-<br />
|0R Directory Of Rooms<br />
|In V3/4<br />
|-<br />
|0S Directory Of Scripts?<br />
|In V3/4<br />
|-<br />
|0N Directory Of Sounds?<br />
|In V3/4<br />
|-<br />
|0C Directory Of Costumes?<br />
|In V3/4<br />
|-<br />
|0O Directory Of Objects?<br />
|In V3/4<br />
|}<br />
<br />
<br />
= Scumm 3/4 =<br />
<br />
* File's aren't xor'ed<br />
<br />
To read in the data, the following pseudo-code can be used:<br />
<br />
Read Number of Items<br />
FROM 1 to "Number of Items" DO<br />
Read subvalue 1<br />
Read subvalue 2<br />
END<br />
<br />
<br />
==RN - Room names ==<br />
<br />
Block Size (4 bytes)<br />
Block Name (2 bytes)<br />
#Room No (1 byte)<br />
#Room Name (9 bytes) XOR'ed with FF<br />
Blank (00) byte (1 byte) Marks end of chunk<br />
<br />
<br />
==0R - Directory of Rooms==<br />
<br />
Block Size (4 bytes)<br />
Block Name (2 bytes)<br />
No of items (2 bytes)<br />
File Number (1 byte)<br />
Offset (4 bytes)<br />
<br />
''File Number'' is interesting if a game is splitted on multiple disks. 0 means ''not used''. <br />
<br />
For ''Offset'' only the value 0 seems to be used.<br />
<br />
==0S - Directory of Scripts ==<br />
<br />
Block Size (4 bytes)<br />
Block Name (2 bytes)<br />
No of items (2 bytes)<br />
Room Number (1 byte)<br />
Offset (4 bytes)<br />
<br />
The global scripts are stored in this directory. The offsets are relative to the room.<br />
<br />
==0N - Directory of Sounds ==<br />
<br />
Block Size (4 bytes)<br />
Block Name (2 bytes)<br />
No of items (2 bytes)<br />
Room Number (1 byte)<br />
Offset (4 bytes)<br />
<br />
Similar to scripts but holds indexes for sounds.<br />
<br />
==0C - Directory of Costumes ==<br />
<br />
Block Size (4 bytes)<br />
Block Name (2 bytes)<br />
No of items (2 bytes)<br />
Room Number (1 byte)<br />
Offset (4 bytes)<br />
<br />
Similar to scripts but holds indexes of customes. <br />
<br />
==0O - Directory of Objects==<br />
<br />
Block Size (4 bytes)<br />
Block Name (2 bytes)<br />
No of items (2 bytes)<br />
Owner+state (1 byte)<br />
<br />
The Object owner and state are encoded in one byte. Example:<br />
<br />
0xA2 &rarr; Owner = 0xA, State = 0x2<br />
<br />
The pseudo decode code would be:<br />
<br />
Owner = ( (Owner+state Byte) AND 0xF0) >> 4<br />
State = (Owner+state Byte) AND 0x0F<br />
<br />
= Scumm 5 =<br />
<br />
* The files are xor'ed with 0x69<br />
<br />
== RNAM - Room Names ==<br />
<br />
Block Name (4 bytes)<br />
Block Size (4 bytes BE)<br />
#Room No (1 byte)<br />
#Room Name (9 bytes) XOR'ed with FF<br />
Blank (00) byte (1 byte) Marks end of chunk<br />
<br />
<br />
== MAXS ==<br />
<br />
Block Name (4 bytes)<br />
Block Size (4 bytes BE)<br />
Variables (2 bytes)<br />
Unknown (2 bytes)<br />
Bit Variables (2 bytes)<br />
Local Objects (2 bytes)<br />
New Names? (2 bytes)<br />
Character Sets (2 bytes)<br />
Verbs? (2 bytes)<br />
Array? (2 bytes)<br />
Inventory Objects (2 bytes)<br />
<br />
== DROO - Directory of Rooms ==<br />
<br />
Block Name (4 bytes)<br />
Block Size (4 bytes BE)<br />
No of items (2 bytes)<br />
*Room Number (1 byte)<br />
*Offset (4 bytes)<br />
<br />
The flow how to read in this kind of information has changed slightly from V3/4.<br />
<br />
Read "No of items"<br />
FROM 1 TO "No of items" DO<br />
Read "Room Number"<br />
END<br />
<br />
FROM 1 TO "No of items" DO<br />
Read "Offset"<br />
END<br />
<br />
First read in all room numbers, then read in all room offsets. <br />
<br />
<br />
== DSCR - Directory of Scripts ==<br />
<br />
Block Name (4 bytes)<br />
Block Size (4 bytes BE)<br />
No of items (2 bytes)<br />
*Room Number (1 byte)<br />
*Offset (4 bytes)<br />
<br />
Indexes for global scripts, see pseudo code above on how to read in the data.<br />
<br />
<br />
== DSOU - Directory of Sound == <br />
<br />
Block Name (4 bytes)<br />
Block Size (4 bytes BE)<br />
No of items (2 bytes)<br />
*Room Number (1 byte)<br />
*Offset (4 bytes)<br />
<br />
Indexes for sound objects.<br />
<br />
<br />
== DCOS - Directory of Costumes ==<br />
<br />
Block Name (4 bytes)<br />
Block Size (4 bytes BE)<br />
No of items (2 bytes)<br />
*Room Number (1 byte)<br />
*Offset (4 bytes)<br />
<br />
Indexes for costumes<br />
<br />
<br />
== DCHR - Director of Charsets ==<br />
<br />
Block Name (4 bytes)<br />
Block Size (4 bytes BE)<br />
No of items (2 bytes)<br />
*Room Number (1 byte)<br />
*Offset (4 bytes)<br />
<br />
Indexes for charsets.<br />
<br />
<br />
== DOBJ - Directory of Objects ==<br />
<br />
Block Name (4 bytes)<br />
Block Size (4 bytes BE)<br />
No of items (2 bytes)<br />
*Owner+state (1 byte)<br />
*Class data (4 bytes)<br />
<br />
Information about objects. See remarks in V3/4 section how the owner+state value should be interpreted. Note that the index files stores ALL owner+state values, followed by ALL class data values. (Also, it may be that only Big Endian SCUMM games store the class data?)<br />
<br />
= Scumm 6 =<br />
<br />
* Files are xor'ed with 0x69<br />
<br />
<br />
== RNAM - Room Names ==<br />
<br />
Blank Byte(00) (1 byte)<br />
<br />
No room names are stored.<br />
<br />
<br />
== MAXS ==<br />
<br />
Block Name (4 bytes)<br />
Block Size (4 bytes BE)<br />
Variables (2 bytes)<br />
Unknown (2 bytes)<br />
Bit Variables (2 bytes)<br />
Local Objects (2 bytes)<br />
Arrays (2 bytes)<br />
Unknown (2 bytes)<br />
Verbs (2 bytes)<br />
Floating Objects (2 bytes)<br />
Inventory Objects (2 bytes)<br />
Rooms (2 bytes)<br />
Scripts (2 bytes)<br />
Sounds (2 bytes)<br />
Character Sets (2 bytes)<br />
Costumes (2 bytes)<br />
Global Objects (2 bytes)<br />
<br />
<br />
== DROO, DSCR, DSOU, DCOS, DCHR, DOBJ ==<br />
<br />
All as in V5<br />
<br />
<br />
== AARY - Array == <br />
<br />
Block Name (4 bytes)<br />
Block Size (4 bytes BE)<br />
#Stop (2 bytes) Stops if 0x0000<br />
#A (2 bytes)<br />
#B (2 bytes)<br />
#C (2 bytes)<br />
<br />
num=AARY no (itinerate through in loop)<br />
if c=1 then<br />
AARY=(num, 1, a, b)<br />
else<br />
AARY=(num, 1, a, b)<br />
<br />
If stop=0 you dont seek past the 6 bytes of A,B,C you just start the loop again.<br />
<br />
<br />
= Scumm 7 = <br />
<br />
* Files aren't xor'ed<br />
<br />
== RNAM - Room names ==<br />
<br />
* As in V6 ?!?!?!<br />
<br />
<br />
== MAXS ==<br />
<br />
Block Name (4 bytes)<br />
Block Size (4 bytes BE)<br />
Variables (2 bytes)<br />
Bit Variables (2 bytes)<br />
Unknown (2 bytes)<br />
Global Objects (2 bytes)<br />
Local Objects (2 bytes)<br />
New Names (2 bytes)<br />
Verbs (2 bytes)<br />
Floating Objects (2 bytes)<br />
Inventory Objects (2 bytes)<br />
Arrays (2 bytes)<br />
Rooms (2 bytes)<br />
Scripts (2 bytes)<br />
Sounds (2 bytes)<br />
Character Sets (2 bytes)<br />
Costumes (2 bytes)<br />
<br />
<br />
== DROO,DSCR,DSOU,DCOS,DCHR,DOBJ,AARY ==<br />
<br />
All as in V5<br />
<br />
<br />
== ANAM - Animation Names ==<br />
<br />
Block Name (4 bytes)<br />
Block Size (4 bytes BE)<br />
No of items (2 bytes<br />
#Name (8 bytes)<br />
#Blank (00) byte (1 byte)<br />
Blank (FF) byte (1 byte) Marks end of chunk<br />
<br />
<br />
= Scumm 8 =<br />
<br />
== RNAM - Room Names ==<br />
<br />
As in V6 ?<br />
<br />
<br />
== MAXS ==<br />
<br />
Block Name (4 bytes)<br />
Block Size (4 bytes BE)<br />
Variables (4 bytes)<br />
Bit Variables (4 bytes)<br />
Unknown (4 bytes)<br />
Scripts (4 bytes)<br />
Sounds (4 bytes)<br />
Character Sets (4 bytes)<br />
Costumes (4 bytes)<br />
Rooms (4 bytes)<br />
Unknown (4 bytes)<br />
Global Objects (4 bytes)<br />
Unknown (4 bytes)<br />
Local Objects (4 bytes)<br />
New Names (4 bytes)<br />
Floating Objects (4 bytes)<br />
Inventory Objects (4 bytes)<br />
Arrays (4 bytes)<br />
Verbs (4 bytes)<br />
<br />
<br />
== DROO - Directory of Rooms ==<br />
<br />
Block Name (4 bytes)<br />
Block Size (4 bytes BE)<br />
No of items (4 bytes)<br />
*Room Number (1 byte)<br />
*Offset (2 bytes)<br />
<br />
<br />
== DRSC - Directory of Room Scripts ==<br />
<br />
Block Name (4 bytes)<br />
Block Size (4 bytes BE)<br />
No of items (4 bytes)<br />
*Room Number (1 byte)<br />
*Offset (2 bytes)<br />
<br />
<br />
== DSCR - Directory of Scripts == <br />
<br />
Block Name (4 bytes)<br />
Block Size (4 bytes BE)<br />
No of items (4 bytes)<br />
*Room Number (1 byte)<br />
*Offset (2 bytes)<br />
<br />
<br />
== DSOU - Directory of Sound ==<br />
<br />
Block Name (4 bytes)<br />
Block Size (4 bytes BE)<br />
No of items (4 bytes)<br />
*Room Number (1 byte)<br />
*Offset (2 bytes)<br />
<br />
<br />
== DCOS - Directory of Costumes ==<br />
<br />
Block Name (4 bytes)<br />
Block Size (4 bytes BE)<br />
No of items (4 bytes)<br />
*Room Number (1 byte)<br />
*Offset (2 bytes)<br />
<br />
<br />
== DCHR - Directory of Charsets ==<br />
<br />
Block Name (4 bytes)<br />
Block Size (4 bytes BE)<br />
No of items (4 bytes)<br />
*Room Number (1 byte)<br />
*Offset (2 bytes)<br />
<br />
<br />
== DOBJ,AARY ==<br />
<br />
As in V7<br />
<br />
<br />
[[Category: SCUMM Technical Reference]]</div>Jestar jokinhttps://wiki.scummvm.org/index.php?title=SCUMM/Technical_Reference/Sound_resources&diff=11723SCUMM/Technical Reference/Sound resources2009-08-04T04:42:14Z<p>Jestar jokin: /* Early v5 - SBL blocks */ add block size bits for AUhd and AUdt</p>
<hr />
<div>=Music=<br />
<br />
==Early v5==<br />
<br />
Going from Monkey Island 2 (MI2), music blocks are stored in LFLF blocks, outside of the ROOMs, so they can be accessed globally. The containing sound block looks like this:<br />
<br />
Block name 4 bytes ("SOUN")<br />
Block size 4 bytes<br />
Block name 4 bytes ("SOU ")<br />
Block size 4 bytes<br />
Music block variable<br />
<br />
The redundant header is possibly due to building on a legacy implementation, or for easier identification in the table stored in the .000 index file.<br />
<br />
The music block may contain any combination of ROL (Roland MT-32), ADL (Adlib/OPL FM), or SPK (PC speaker) blocks. They can also store a single SBL block for digitized sound (described in a later section). Aside from SBL, each of these blocks follow the same basic pattern.<br />
<br />
Block name 4 bytes ("ROL ", or "ADL ", or "SPK ")<br />
Block size 4 bytes<br />
MIDI data variable<br />
<br />
Every track is stored in MIDI format, in order to make use of the iMUSE technology through System Exclusive (SysEx) messages.<br />
<br />
Due to the predominance of the Sound Blaster and Adlib/OPL FM technology at the time, in at least MI2 every musical SOUN block contains an ADL block.<br />
<br />
==iMUSE==<br />
<br />
From SCUMM v5 onwards, LucasArts games used a dynamic music playback system called iMUSE. This basically consists of standard MIDI data, with embedded System Exclusive (SysEx) messages that act as markers in the song. iMUSE allows operations like conditional jumping & looping, adjusting the volume of parts, turning parts on and off, changing instruments, and detuning parts.<br />
<br />
You can find the original patent document [http://pat2pdf.org/pat2pdf/foo.pl?number=5315057 here], and some technical details can be found [http://alban.dotsec.net/15.html here].<br />
<br />
==Mac0==<br />
<br />
From Markus Magnuson (superqult) we got this information:<br />
<br />
4 bytes - 'SOUN'<br />
BE 4 bytes - block length<br />
<br />
4 bytes - 'Mac0'<br />
BE 4 bytes - (blockLength - 27)<br />
28 bytes - ???<br />
<br />
do this three times (once for each channel):<br />
4 bytes - 'Chan'<br />
BE 4 bytes - channel length<br />
4 bytes - instrument name (e.g. 'MARI')<br />
<br />
do this for ((chanLength-24)/4) times:<br />
2 bytes - note duration<br />
1 byte - note value<br />
1 byte - note velocity<br />
<br />
4 bytes - ???<br />
4 bytes - 'Loop'/'Done'<br />
4 bytes - ???<br />
1 byte - 0x09<br />
<br />
Instruments (and General Midi equivalent):<br />
"MARI" - Marimba (12)<br />
"PLUC" - Pizzicato Strings (45)<br />
"HARM" - Harmonica (22)<br />
"PIPE" - Church Organ? (19) or Flute? (73) or Bag Pipe (109)<br />
"TROM" - Trombone (57)<br />
"STRI" - String Ensemble (48 or 49)<br />
"HORN" - French Horn? (60) or English Horn? (69)<br />
"VIBE" - Vibraphone (11)<br />
"SHAK" - Shakuhachi? (77)<br />
"PANP" - Pan Flute (75)<br />
"WHIS" - Whistle (78) / Bottle (76)<br />
"ORGA" - Drawbar Organ (16; but could also be 17-20)<br />
"BONG" - Woodblock? (115)<br />
"BASS" - Bass (32-39)<br />
<br />
=Digitized Sounds=<br />
<br />
==Early v5 - SBL blocks==<br />
<br />
Digitized sounds first appeared in Monkey Island 1 & 2. They are contained in the .001 resource files, and are sub-blocks of "SOUN" blocks (see the music section above).<br />
<br />
Block name 4 bytes ("SBL ")<br />
Block size 4 bytes<br />
Sound header 4 bytes ("AUhd" or "WVhd")<br />
Block size 4 bytes<br />
Unknown 3 bytes (always 00 00 80)<br />
Data header 4 bytes ("AUdt" or "WVdt")<br />
Block size 4 bytes<br />
VOC data variable<br />
<br />
AUhd and AUdt are used in Monkey Island, while WVhd and WVdt are used in the non-interactive demo of Sam & Max. The actual sound data is stored in the Creative VOC format, without the header information. The implied data offset is 0x1A, and the VOC version is 0x010A.<br />
<br />
==Early v5 - CD tracks==<br />
<br />
Games that use CD tracks (Loom/CD, MI1/CD, Zak256/FM-TOWNS) are a bit different. For MI1/CD at least, the "SOUN" block size is always 32 bytes and presumably points to the CD track to play.<br />
<br />
Here's some notes by cocomonk22:<br />
Values from offsets 0-23 (0x00-0x17) are all the same, so just copy data from an existing SOUN.<br />
At offset 24 (0x18) track number in hex format (for new music not in original start with track decimal 24 or hex 18).<br />
At offset 25 (0x19) seems to be loop, opening uses 01, scummbar uses ff.<br />
The six remaining values 26-31 (0x1a-0x1f) are all 00 if you want the music to start at the beginning of the track.<br />
<br />
An example of music not starting at the beginning:<br />
The scene at the lookout following the intro uses the same music as the opening, but starts at position 1 min 36 sec. Hex values are 01 23 30 00 00 00. 01 23 30 is equivalent to 1 35 48 in decimal.<br />
<br />
==v5-v6 - MONSTER.SOU==<br />
<br />
===Original===<br />
<br />
From Indy 4 onwards, sound effects and speech are stored in a separate resource file called "MONSTER.SOU". The format is:<br />
<br />
Block name 4 bytes ("SOU ")<br />
Block size 4 bytes<br />
One or more:<br />
Block name 4 bytes ("VCTL")<br />
Block size 4 bytes<br />
Lip-sync tags variable * 2 bytes LE<br />
Sound data variable ("Crea" block / VOC file)<br />
<br />
The lip-sync tags provide timing information, and are 16-bit LE values, representing positions in the speech file. Lip synching is basically just toggling the speaking animation on and off whenever the speech goes past the positions listed in the lip-synch tags. In v5 the number of tags is stored in the calling text, according to the formula (num_tags << 1) + 8. The "Crea" block is an entire Creative VOC file.<br />
<br />
===Compressed===<br />
<br />
ScummVM can use compressed monster.sou files created with the tool "compress_scumm_sou.exe". Aside from using either MP3, OGG, or FLAC formats for the sound data, they contain a mapping table followed by the sound data, like so:<br />
<br />
size_of_table : uint32<br />
size_of_table / 16 times {<br />
orig_offset : uint32<br />
actual_offset : uint32<br />
num_tags : uint32<br />
sound_size : unit32<br />
}<br />
size_of_table / 16 times {<br />
num_tags times {<br />
tag : uint8<br />
}<br />
sound : sound_size (sound file - MP3/OGG/FLAC)<br />
} <br />
<br />
Each entry in the table has 4 items, each item is 4 bytes, so a table with one entry has a size of 16.<br />
<br />
The original offset is what the game will try to play, the actual offset is taken from after the index table.<br />
<br />
Each sound is directly preceded by its lip-synch tags.<br />
<br />
=Sound block types=<br />
This information is gleaned from the ScummVM source code. Any block name with only three characters has a space at the end.<br />
MIDI \ Midi<br />
iMUS /<br />
<br />
SOU subtypes<br />
TOWS - FM Towns<br />
SBL - Sound Blaster digitized sound (Creative VOC file)<br />
ADL - Adlib (OPL FM)<br />
AMI - Amiga MOD<br />
ROL - Roland MT-32<br />
GMD - General MIDI<br />
MAC - Macintosh (occurs in MI2, FOA)<br />
SPK - PC speaker<br />
<br />
Mac0 - Macintosh music type 0<br />
<br />
Mac1 \<br />
RIFF |<br />
TALK > Creative VOC file<br />
DIGI |<br />
Crea /<br />
<br />
HSHD - HE sound type without SOUN header<br />
<br />
FMUS - Used in 3DO versions of HE games</div>Jestar jokinhttps://wiki.scummvm.org/index.php?title=SCUMM/Technical_Reference/Sound_resources&diff=11722SCUMM/Technical Reference/Sound resources2009-08-04T01:45:16Z<p>Jestar jokin: /* Early v5 - SBL blocks */ implied VOC header info</p>
<hr />
<div>=Music=<br />
<br />
==Early v5==<br />
<br />
Going from Monkey Island 2 (MI2), music blocks are stored in LFLF blocks, outside of the ROOMs, so they can be accessed globally. The containing sound block looks like this:<br />
<br />
Block name 4 bytes ("SOUN")<br />
Block size 4 bytes<br />
Block name 4 bytes ("SOU ")<br />
Block size 4 bytes<br />
Music block variable<br />
<br />
The redundant header is possibly due to building on a legacy implementation, or for easier identification in the table stored in the .000 index file.<br />
<br />
The music block may contain any combination of ROL (Roland MT-32), ADL (Adlib/OPL FM), or SPK (PC speaker) blocks. They can also store a single SBL block for digitized sound (described in a later section). Aside from SBL, each of these blocks follow the same basic pattern.<br />
<br />
Block name 4 bytes ("ROL ", or "ADL ", or "SPK ")<br />
Block size 4 bytes<br />
MIDI data variable<br />
<br />
Every track is stored in MIDI format, in order to make use of the iMUSE technology through System Exclusive (SysEx) messages.<br />
<br />
Due to the predominance of the Sound Blaster and Adlib/OPL FM technology at the time, in at least MI2 every musical SOUN block contains an ADL block.<br />
<br />
==iMUSE==<br />
<br />
From SCUMM v5 onwards, LucasArts games used a dynamic music playback system called iMUSE. This basically consists of standard MIDI data, with embedded System Exclusive (SysEx) messages that act as markers in the song. iMUSE allows operations like conditional jumping & looping, adjusting the volume of parts, turning parts on and off, changing instruments, and detuning parts.<br />
<br />
You can find the original patent document [http://pat2pdf.org/pat2pdf/foo.pl?number=5315057 here], and some technical details can be found [http://alban.dotsec.net/15.html here].<br />
<br />
==Mac0==<br />
<br />
From Markus Magnuson (superqult) we got this information:<br />
<br />
4 bytes - 'SOUN'<br />
BE 4 bytes - block length<br />
<br />
4 bytes - 'Mac0'<br />
BE 4 bytes - (blockLength - 27)<br />
28 bytes - ???<br />
<br />
do this three times (once for each channel):<br />
4 bytes - 'Chan'<br />
BE 4 bytes - channel length<br />
4 bytes - instrument name (e.g. 'MARI')<br />
<br />
do this for ((chanLength-24)/4) times:<br />
2 bytes - note duration<br />
1 byte - note value<br />
1 byte - note velocity<br />
<br />
4 bytes - ???<br />
4 bytes - 'Loop'/'Done'<br />
4 bytes - ???<br />
1 byte - 0x09<br />
<br />
Instruments (and General Midi equivalent):<br />
"MARI" - Marimba (12)<br />
"PLUC" - Pizzicato Strings (45)<br />
"HARM" - Harmonica (22)<br />
"PIPE" - Church Organ? (19) or Flute? (73) or Bag Pipe (109)<br />
"TROM" - Trombone (57)<br />
"STRI" - String Ensemble (48 or 49)<br />
"HORN" - French Horn? (60) or English Horn? (69)<br />
"VIBE" - Vibraphone (11)<br />
"SHAK" - Shakuhachi? (77)<br />
"PANP" - Pan Flute (75)<br />
"WHIS" - Whistle (78) / Bottle (76)<br />
"ORGA" - Drawbar Organ (16; but could also be 17-20)<br />
"BONG" - Woodblock? (115)<br />
"BASS" - Bass (32-39)<br />
<br />
=Digitized Sounds=<br />
<br />
==Early v5 - SBL blocks==<br />
<br />
Digitized sounds first appeared in Monkey Island 1 & 2. They are contained in the .001 resource files, and are sub-blocks of "SOUN" blocks (see the music section above).<br />
<br />
Block name 4 bytes ("SBL ")<br />
Block size 4 bytes<br />
Sound header 4 bytes ("AUhd" or "WVhd")<br />
Unknown 3 bytes (always 00 00 80)<br />
Data header 4 bytes ("AUdt" or "WVdt")<br />
VOC data variable<br />
<br />
AUhd and AUdt are used in Monkey Island, while WVhd and WVdt are used in the non-interactive demo of Sam & Max. The actual sound data is stored in the Creative VOC format, without the header information. The implied data offset is 0x1A, and the VOC version is 0x010A.<br />
<br />
==Early v5 - CD tracks==<br />
<br />
Games that use CD tracks (Loom/CD, MI1/CD, Zak256/FM-TOWNS) are a bit different. For MI1/CD at least, the "SOUN" block size is always 32 bytes and presumably points to the CD track to play.<br />
<br />
Here's some notes by cocomonk22:<br />
Values from offsets 0-23 (0x00-0x17) are all the same, so just copy data from an existing SOUN.<br />
At offset 24 (0x18) track number in hex format (for new music not in original start with track decimal 24 or hex 18).<br />
At offset 25 (0x19) seems to be loop, opening uses 01, scummbar uses ff.<br />
The six remaining values 26-31 (0x1a-0x1f) are all 00 if you want the music to start at the beginning of the track.<br />
<br />
An example of music not starting at the beginning:<br />
The scene at the lookout following the intro uses the same music as the opening, but starts at position 1 min 36 sec. Hex values are 01 23 30 00 00 00. 01 23 30 is equivalent to 1 35 48 in decimal.<br />
<br />
==v5-v6 - MONSTER.SOU==<br />
<br />
===Original===<br />
<br />
From Indy 4 onwards, sound effects and speech are stored in a separate resource file called "MONSTER.SOU". The format is:<br />
<br />
Block name 4 bytes ("SOU ")<br />
Block size 4 bytes<br />
One or more:<br />
Block name 4 bytes ("VCTL")<br />
Block size 4 bytes<br />
Lip-sync tags variable * 2 bytes LE<br />
Sound data variable ("Crea" block / VOC file)<br />
<br />
The lip-sync tags provide timing information, and are 16-bit LE values, representing positions in the speech file. Lip synching is basically just toggling the speaking animation on and off whenever the speech goes past the positions listed in the lip-synch tags. In v5 the number of tags is stored in the calling text, according to the formula (num_tags << 1) + 8. The "Crea" block is an entire Creative VOC file.<br />
<br />
===Compressed===<br />
<br />
ScummVM can use compressed monster.sou files created with the tool "compress_scumm_sou.exe". Aside from using either MP3, OGG, or FLAC formats for the sound data, they contain a mapping table followed by the sound data, like so:<br />
<br />
size_of_table : uint32<br />
size_of_table / 16 times {<br />
orig_offset : uint32<br />
actual_offset : uint32<br />
num_tags : uint32<br />
sound_size : unit32<br />
}<br />
size_of_table / 16 times {<br />
num_tags times {<br />
tag : uint8<br />
}<br />
sound : sound_size (sound file - MP3/OGG/FLAC)<br />
} <br />
<br />
Each entry in the table has 4 items, each item is 4 bytes, so a table with one entry has a size of 16.<br />
<br />
The original offset is what the game will try to play, the actual offset is taken from after the index table.<br />
<br />
Each sound is directly preceded by its lip-synch tags.<br />
<br />
=Sound block types=<br />
This information is gleaned from the ScummVM source code. Any block name with only three characters has a space at the end.<br />
MIDI \ Midi<br />
iMUS /<br />
<br />
SOU subtypes<br />
TOWS - FM Towns<br />
SBL - Sound Blaster digitized sound (Creative VOC file)<br />
ADL - Adlib (OPL FM)<br />
AMI - Amiga MOD<br />
ROL - Roland MT-32<br />
GMD - General MIDI<br />
MAC - Macintosh (occurs in MI2, FOA)<br />
SPK - PC speaker<br />
<br />
Mac0 - Macintosh music type 0<br />
<br />
Mac1 \<br />
RIFF |<br />
TALK > Creative VOC file<br />
DIGI |<br />
Crea /<br />
<br />
HSHD - HE sound type without SOUN header<br />
<br />
FMUS - Used in 3DO versions of HE games</div>Jestar jokinhttps://wiki.scummvm.org/index.php?title=SCUMM/Technical_Reference/Sound_resources&diff=11699SCUMM/Technical Reference/Sound resources2009-08-03T03:41:09Z<p>Jestar jokin: /* Original */ more info on lip-synch tags</p>
<hr />
<div>=Music=<br />
<br />
==Early v5==<br />
<br />
Going from Monkey Island 2 (MI2), music blocks are stored in LFLF blocks, outside of the ROOMs, so they can be accessed globally. The containing sound block looks like this:<br />
<br />
Block name 4 bytes ("SOUN")<br />
Block size 4 bytes<br />
Block name 4 bytes ("SOU ")<br />
Block size 4 bytes<br />
Music block variable<br />
<br />
The redundant header is possibly due to building on a legacy implementation, or for easier identification in the table stored in the .000 index file.<br />
<br />
The music block may contain any combination of ROL (Roland MT-32), ADL (Adlib/OPL FM), or SPK (PC speaker) blocks. They can also store a single SBL block for digitized sound (described in a later section). Aside from SBL, each of these blocks follow the same basic pattern.<br />
<br />
Block name 4 bytes ("ROL ", or "ADL ", or "SPK ")<br />
Block size 4 bytes<br />
MIDI data variable<br />
<br />
Every track is stored in MIDI format, in order to make use of the iMUSE technology through System Exclusive (SysEx) messages.<br />
<br />
Due to the predominance of the Sound Blaster and Adlib/OPL FM technology at the time, in at least MI2 every musical SOUN block contains an ADL block.<br />
<br />
==iMUSE==<br />
<br />
From SCUMM v5 onwards, LucasArts games used a dynamic music playback system called iMUSE. This basically consists of standard MIDI data, with embedded System Exclusive (SysEx) messages that act as markers in the song. iMUSE allows operations like conditional jumping & looping, adjusting the volume of parts, turning parts on and off, changing instruments, and detuning parts.<br />
<br />
You can find the original patent document [http://pat2pdf.org/pat2pdf/foo.pl?number=5315057 here], and some technical details can be found [http://alban.dotsec.net/15.html here].<br />
<br />
==Mac0==<br />
<br />
From Markus Magnuson (superqult) we got this information:<br />
<br />
4 bytes - 'SOUN'<br />
BE 4 bytes - block length<br />
<br />
4 bytes - 'Mac0'<br />
BE 4 bytes - (blockLength - 27)<br />
28 bytes - ???<br />
<br />
do this three times (once for each channel):<br />
4 bytes - 'Chan'<br />
BE 4 bytes - channel length<br />
4 bytes - instrument name (e.g. 'MARI')<br />
<br />
do this for ((chanLength-24)/4) times:<br />
2 bytes - note duration<br />
1 byte - note value<br />
1 byte - note velocity<br />
<br />
4 bytes - ???<br />
4 bytes - 'Loop'/'Done'<br />
4 bytes - ???<br />
1 byte - 0x09<br />
<br />
Instruments (and General Midi equivalent):<br />
"MARI" - Marimba (12)<br />
"PLUC" - Pizzicato Strings (45)<br />
"HARM" - Harmonica (22)<br />
"PIPE" - Church Organ? (19) or Flute? (73) or Bag Pipe (109)<br />
"TROM" - Trombone (57)<br />
"STRI" - String Ensemble (48 or 49)<br />
"HORN" - French Horn? (60) or English Horn? (69)<br />
"VIBE" - Vibraphone (11)<br />
"SHAK" - Shakuhachi? (77)<br />
"PANP" - Pan Flute (75)<br />
"WHIS" - Whistle (78) / Bottle (76)<br />
"ORGA" - Drawbar Organ (16; but could also be 17-20)<br />
"BONG" - Woodblock? (115)<br />
"BASS" - Bass (32-39)<br />
<br />
=Digitized Sounds=<br />
<br />
==Early v5 - SBL blocks==<br />
<br />
Digitized sounds first appeared in Monkey Island 1 & 2. They are contained in the .001 resource files, and are sub-blocks of "SOUN" blocks (see the music section above).<br />
<br />
Block name 4 bytes ("SBL ")<br />
Block size 4 bytes<br />
Sound header 4 bytes ("AUhd" or "WVhd")<br />
Unknown 3 bytes (always 00 00 80)<br />
Data header 4 bytes ("AUdt" or "WVdt")<br />
VOC data variable<br />
<br />
AUhd and AUdt are used in Monkey Island, while WVhd and WVdt are used in the non-interactive demo of Sam & Max. The actual sound data is stored in the Creative VOC format, without the identifying header.<br />
<br />
==Early v5 - CD tracks==<br />
<br />
Games that use CD tracks (Loom/CD, MI1/CD, Zak256/FM-TOWNS) are a bit different. For MI1/CD at least, the "SOUN" block size is always 32 bytes and presumably points to the CD track to play.<br />
<br />
Here's some notes by cocomonk22:<br />
Values from offsets 0-23 (0x00-0x17) are all the same, so just copy data from an existing SOUN.<br />
At offset 24 (0x18) track number in hex format (for new music not in original start with track decimal 24 or hex 18).<br />
At offset 25 (0x19) seems to be loop, opening uses 01, scummbar uses ff.<br />
The six remaining values 26-31 (0x1a-0x1f) are all 00 if you want the music to start at the beginning of the track.<br />
<br />
An example of music not starting at the beginning:<br />
The scene at the lookout following the intro uses the same music as the opening, but starts at position 1 min 36 sec. Hex values are 01 23 30 00 00 00. 01 23 30 is equivalent to 1 35 48 in decimal.<br />
<br />
==v5-v6 - MONSTER.SOU==<br />
<br />
===Original===<br />
<br />
From Indy 4 onwards, sound effects and speech are stored in a separate resource file called "MONSTER.SOU". The format is:<br />
<br />
Block name 4 bytes ("SOU ")<br />
Block size 4 bytes<br />
One or more:<br />
Block name 4 bytes ("VCTL")<br />
Block size 4 bytes<br />
Lip-sync tags variable * 2 bytes LE<br />
Sound data variable ("Crea" block / VOC file)<br />
<br />
The lip-sync tags provide timing information, and are 16-bit LE values, representing positions in the speech file. Lip synching is basically just toggling the speaking animation on and off whenever the speech goes past the positions listed in the lip-synch tags. In v5 the number of tags is stored in the calling text, according to the formula (num_tags << 1) + 8. The "Crea" block is an entire Creative VOC file.<br />
<br />
===Compressed===<br />
<br />
ScummVM can use compressed monster.sou files created with the tool "compress_scumm_sou.exe". Aside from using either MP3, OGG, or FLAC formats for the sound data, they contain a mapping table followed by the sound data, like so:<br />
<br />
size_of_table : uint32<br />
size_of_table / 16 times {<br />
orig_offset : uint32<br />
actual_offset : uint32<br />
num_tags : uint32<br />
sound_size : unit32<br />
}<br />
size_of_table / 16 times {<br />
num_tags times {<br />
tag : uint8<br />
}<br />
sound : sound_size (sound file - MP3/OGG/FLAC)<br />
} <br />
<br />
Each entry in the table has 4 items, each item is 4 bytes, so a table with one entry has a size of 16.<br />
<br />
The original offset is what the game will try to play, the actual offset is taken from after the index table.<br />
<br />
Each sound is directly preceded by its lip-synch tags.<br />
<br />
=Sound block types=<br />
This information is gleaned from the ScummVM source code. Any block name with only three characters has a space at the end.<br />
MIDI \ Midi<br />
iMUS /<br />
<br />
SOU subtypes<br />
TOWS - FM Towns<br />
SBL - Sound Blaster digitized sound (Creative VOC file)<br />
ADL - Adlib (OPL FM)<br />
AMI - Amiga MOD<br />
ROL - Roland MT-32<br />
GMD - General MIDI<br />
MAC - Macintosh (occurs in MI2, FOA)<br />
SPK - PC speaker<br />
<br />
Mac0 - Macintosh music type 0<br />
<br />
Mac1 \<br />
RIFF |<br />
TALK > Creative VOC file<br />
DIGI |<br />
Crea /<br />
<br />
HSHD - HE sound type without SOUN header<br />
<br />
FMUS - Used in 3DO versions of HE games</div>Jestar jokinhttps://wiki.scummvm.org/index.php?title=SCUMM/Technical_Reference/Sound_resources&diff=11698SCUMM/Technical Reference/Sound resources2009-08-03T03:06:56Z<p>Jestar jokin: /* Early v5 - CD tracks */ SOUN instead of SOU block for CD tracks</p>
<hr />
<div>=Music=<br />
<br />
==Early v5==<br />
<br />
Going from Monkey Island 2 (MI2), music blocks are stored in LFLF blocks, outside of the ROOMs, so they can be accessed globally. The containing sound block looks like this:<br />
<br />
Block name 4 bytes ("SOUN")<br />
Block size 4 bytes<br />
Block name 4 bytes ("SOU ")<br />
Block size 4 bytes<br />
Music block variable<br />
<br />
The redundant header is possibly due to building on a legacy implementation, or for easier identification in the table stored in the .000 index file.<br />
<br />
The music block may contain any combination of ROL (Roland MT-32), ADL (Adlib/OPL FM), or SPK (PC speaker) blocks. They can also store a single SBL block for digitized sound (described in a later section). Aside from SBL, each of these blocks follow the same basic pattern.<br />
<br />
Block name 4 bytes ("ROL ", or "ADL ", or "SPK ")<br />
Block size 4 bytes<br />
MIDI data variable<br />
<br />
Every track is stored in MIDI format, in order to make use of the iMUSE technology through System Exclusive (SysEx) messages.<br />
<br />
Due to the predominance of the Sound Blaster and Adlib/OPL FM technology at the time, in at least MI2 every musical SOUN block contains an ADL block.<br />
<br />
==iMUSE==<br />
<br />
From SCUMM v5 onwards, LucasArts games used a dynamic music playback system called iMUSE. This basically consists of standard MIDI data, with embedded System Exclusive (SysEx) messages that act as markers in the song. iMUSE allows operations like conditional jumping & looping, adjusting the volume of parts, turning parts on and off, changing instruments, and detuning parts.<br />
<br />
You can find the original patent document [http://pat2pdf.org/pat2pdf/foo.pl?number=5315057 here], and some technical details can be found [http://alban.dotsec.net/15.html here].<br />
<br />
==Mac0==<br />
<br />
From Markus Magnuson (superqult) we got this information:<br />
<br />
4 bytes - 'SOUN'<br />
BE 4 bytes - block length<br />
<br />
4 bytes - 'Mac0'<br />
BE 4 bytes - (blockLength - 27)<br />
28 bytes - ???<br />
<br />
do this three times (once for each channel):<br />
4 bytes - 'Chan'<br />
BE 4 bytes - channel length<br />
4 bytes - instrument name (e.g. 'MARI')<br />
<br />
do this for ((chanLength-24)/4) times:<br />
2 bytes - note duration<br />
1 byte - note value<br />
1 byte - note velocity<br />
<br />
4 bytes - ???<br />
4 bytes - 'Loop'/'Done'<br />
4 bytes - ???<br />
1 byte - 0x09<br />
<br />
Instruments (and General Midi equivalent):<br />
"MARI" - Marimba (12)<br />
"PLUC" - Pizzicato Strings (45)<br />
"HARM" - Harmonica (22)<br />
"PIPE" - Church Organ? (19) or Flute? (73) or Bag Pipe (109)<br />
"TROM" - Trombone (57)<br />
"STRI" - String Ensemble (48 or 49)<br />
"HORN" - French Horn? (60) or English Horn? (69)<br />
"VIBE" - Vibraphone (11)<br />
"SHAK" - Shakuhachi? (77)<br />
"PANP" - Pan Flute (75)<br />
"WHIS" - Whistle (78) / Bottle (76)<br />
"ORGA" - Drawbar Organ (16; but could also be 17-20)<br />
"BONG" - Woodblock? (115)<br />
"BASS" - Bass (32-39)<br />
<br />
=Digitized Sounds=<br />
<br />
==Early v5 - SBL blocks==<br />
<br />
Digitized sounds first appeared in Monkey Island 1 & 2. They are contained in the .001 resource files, and are sub-blocks of "SOUN" blocks (see the music section above).<br />
<br />
Block name 4 bytes ("SBL ")<br />
Block size 4 bytes<br />
Sound header 4 bytes ("AUhd" or "WVhd")<br />
Unknown 3 bytes (always 00 00 80)<br />
Data header 4 bytes ("AUdt" or "WVdt")<br />
VOC data variable<br />
<br />
AUhd and AUdt are used in Monkey Island, while WVhd and WVdt are used in the non-interactive demo of Sam & Max. The actual sound data is stored in the Creative VOC format, without the identifying header.<br />
<br />
==Early v5 - CD tracks==<br />
<br />
Games that use CD tracks (Loom/CD, MI1/CD, Zak256/FM-TOWNS) are a bit different. For MI1/CD at least, the "SOUN" block size is always 32 bytes and presumably points to the CD track to play.<br />
<br />
Here's some notes by cocomonk22:<br />
Values from offsets 0-23 (0x00-0x17) are all the same, so just copy data from an existing SOUN.<br />
At offset 24 (0x18) track number in hex format (for new music not in original start with track decimal 24 or hex 18).<br />
At offset 25 (0x19) seems to be loop, opening uses 01, scummbar uses ff.<br />
The six remaining values 26-31 (0x1a-0x1f) are all 00 if you want the music to start at the beginning of the track.<br />
<br />
An example of music not starting at the beginning:<br />
The scene at the lookout following the intro uses the same music as the opening, but starts at position 1 min 36 sec. Hex values are 01 23 30 00 00 00. 01 23 30 is equivalent to 1 35 48 in decimal.<br />
<br />
==v5-v6 - MONSTER.SOU==<br />
<br />
===Original===<br />
<br />
From Indy 4 onwards, sound effects and speech are stored in a separate resource file called "MONSTER.SOU". The format is:<br />
<br />
Block name 4 bytes ("SOU ")<br />
Block size 4 bytes<br />
One or more:<br />
Block name 4 bytes ("VCTL")<br />
Block size 4 bytes<br />
Lip-sync tags variable<br />
Sound data variable ("Crea" block / VOC file)<br />
<br />
The lip-sync tags provide timing information. In v5 the number of tags is stored in the calling text, according to the formula ((num_tags / 2) << 1) + 8. The "Crea" block is an entire Creative VOC file.<br />
<br />
===Compressed===<br />
<br />
ScummVM can use compressed monster.sou files created with the tool "compress_scumm_sou.exe". Aside from using either MP3, OGG, or FLAC formats for the sound data, they contain a mapping table followed by the sound data, like so:<br />
<br />
size_of_table : uint32<br />
size_of_table / 16 times {<br />
orig_offset : uint32<br />
actual_offset : uint32<br />
num_tags : uint32<br />
sound_size : unit32<br />
}<br />
size_of_table / 16 times {<br />
num_tags times {<br />
tag : uint8<br />
}<br />
sound : sound_size (sound file - MP3/OGG/FLAC)<br />
} <br />
<br />
Each entry in the table has 4 items, each item is 4 bytes, so a table with one entry has a size of 16.<br />
<br />
The original offset is what the game will try to play, the actual offset is taken from after the index table.<br />
<br />
Each sound is directly preceded by its lip-synch tags.<br />
<br />
=Sound block types=<br />
This information is gleaned from the ScummVM source code. Any block name with only three characters has a space at the end.<br />
MIDI \ Midi<br />
iMUS /<br />
<br />
SOU subtypes<br />
TOWS - FM Towns<br />
SBL - Sound Blaster digitized sound (Creative VOC file)<br />
ADL - Adlib (OPL FM)<br />
AMI - Amiga MOD<br />
ROL - Roland MT-32<br />
GMD - General MIDI<br />
MAC - Macintosh (occurs in MI2, FOA)<br />
SPK - PC speaker<br />
<br />
Mac0 - Macintosh music type 0<br />
<br />
Mac1 \<br />
RIFF |<br />
TALK > Creative VOC file<br />
DIGI |<br />
Crea /<br />
<br />
HSHD - HE sound type without SOUN header<br />
<br />
FMUS - Used in 3DO versions of HE games</div>Jestar jokinhttps://wiki.scummvm.org/index.php?title=SCUMM/Technical_Reference/Index_File&diff=11593SCUMM/Technical Reference/Index File2009-08-01T10:43:23Z<p>Jestar jokin: /* MAXS */ V5 - guessing at some unknowns</p>
<hr />
<div>[[SCUMM/Technical Reference|SCUMM Technical Reference]] &rarr; ''SCUMM index file''<br />
<br />
<br />
= Introduction=<br />
<br />
Most of the information below are retrieved from the [http://scumm.mixnmojo.com/?page=specs&file=indexfiles.txt LucasHacks!] site and from the Pascal source code of the ''IndexFileReader 1.2'' (written by Ben Gorman (Bgbennyboy, http://quick.mixnmojo.com). In addition, ''ScummRevisited'' (written by Jimmi Thøgersen (Serge), http://www.mixnmojo.com/scumm/scummrev) turned out to be very useful in verifying the found offsets.<br />
<br />
The SCUMM index file contains special information to allow quick random access to the resources in the other game files. It also includes the room names and some max limits for the game. The following filenames are used:<br />
<br />
<br />
<table border="2" cellspacing="0" cellpadding="4"><br />
<tr><th width="100">filename</th><th>SCUMM version</th></tr><br />
<tr><td >00.lfl / 000.lfl</td><td>V3/4</td></tr><br />
<tr><td>.000</td><td>V5/6</td></tr><br />
<tr><td>.LA0</td><td>V7/8</td></tr><br />
</table><br />
<br />
<br />
Version 1 to 3 use hardcoded offsets and cannot be treated that easily. For the other games, the index file can be used to determine the [[SCUMM/Versions|SCUMM version]] because there have been slight changes in each version.<br />
<br />
* Version 4<br />
** the 5th and 6th byte match RN or OR<br />
* Version 5: <br />
** RNAM xor'ed with 0x69 at the beginning of the file<br />
** next 4 byte integer value xor'ed with 0x69 is &gt; 9<br />
* Version 6<br />
** RNAM xor'ed with 0x69 at the beginning<br />
** next 4 byte integer value xor'ed with 0x69 is 9 (actually it's the size of the chunk. In V6 games, no room names are stored so the size is 4 bytes (header) + 4 bytes (size) + 1 byte for the termination character).<br />
* Version 7<br />
** RNAM at the beginning of the file (not xor'ed this time)<br />
** next 4 bytes result in BE integer 9 (actually applies only to [[Full Throttle]])<br />
* Version 7 or 8<br />
** RNAM at the beginning of the file<br />
** next 4 bytes integer is &gt; 9<br />
<br />
<br />
How to distinguish between version 7 and 8? Not by looking at the first bytes, but the the size of the chunks is usually bigger because a 4 byte integer is used to store the number of objects.<br />
<br />
= Conventions =<br />
<br />
As usual, the [http://en.wikipedia.org/wiki/Endianness endianness (Wikipedia)] is important. Unless stated, little endianess (LE) is used. <br />
<br />
BE is used as abbreviation for big endianness. <br />
<br />
A '''Chunk''' is a named part of the file, e.g. RNAM. Each chunk has a header that contains at least the chunk name and its size. The following chunks are available:<br />
<br />
<br />
{| border="1" cellspacing="0" cellpadding="4"<br />
|RNAM Room Names<br />
|In V5+<br />
|-<br />
|MAXS Maximum Values<br />
|In V5+<br />
|-<br />
|DROO Directory of Rooms<br />
|In V5+<br />
|-<br />
|DRSC Direcory of Room Scripts<br />
|In V8<br />
|-<br />
|DSCR Directory of Scripts<br />
|In V5+<br />
|-<br />
|DSOU Directory of Sounds<br />
|In V5+<br />
|-<br />
|DCOS Directory of Costumes<br />
|In V5+<br />
|-<br />
|DCHR Directory of Charsets<br />
|In V5+<br />
|-<br />
|DOBJ Directory of Objects<br />
|In V5+<br />
|-<br />
|AARY List of Arrays<br />
|In V6+<br />
|-<br />
|ANAM Animation Names?<br />
|In V7<br />
|-<br />
|RM Room Names<br />
|In V3/4<br />
|-<br />
|0R Directory Of Rooms<br />
|In V3/4<br />
|-<br />
|0S Directory Of Scripts?<br />
|In V3/4<br />
|-<br />
|0N Directory Of Sounds?<br />
|In V3/4<br />
|-<br />
|0C Directory Of Costumes?<br />
|In V3/4<br />
|-<br />
|0O Directory Of Objects?<br />
|In V3/4<br />
|}<br />
<br />
<br />
= Scumm 3/4 =<br />
<br />
* File's aren't xor'ed<br />
<br />
To read in the data, the following pseudo-code can be used:<br />
<br />
Read Number of Items<br />
FROM 1 to "Number of Items" DO<br />
Read subvalue 1<br />
Read subvalue 2<br />
END<br />
<br />
<br />
==RN - Room names ==<br />
<br />
Block Size (4 bytes)<br />
Block Name (2 bytes)<br />
#Room No (1 byte)<br />
#Room Name (9 bytes) XOR'ed with FF<br />
Blank (00) byte (1 byte) Marks end of chunk<br />
<br />
<br />
==0R - Directory of Rooms==<br />
<br />
Block Size (4 bytes)<br />
Block Name (2 bytes)<br />
No of items (2 bytes)<br />
File Number (1 byte)<br />
Offset (4 bytes)<br />
<br />
''File Number'' is interesting if a game is splitted on multiple disks. 0 means ''not used''. <br />
<br />
For ''Offset'' only the value 0 seems to be used.<br />
<br />
==0S - Directory of Scripts ==<br />
<br />
Block Size (4 bytes)<br />
Block Name (2 bytes)<br />
No of items (2 bytes)<br />
Room Number (1 byte)<br />
Offset (4 bytes)<br />
<br />
The global scripts are stored in this directory. The offsets are relative to the room.<br />
<br />
==0N - Directory of Sounds ==<br />
<br />
Block Size (4 bytes)<br />
Block Name (2 bytes)<br />
No of items (2 bytes)<br />
Room Number (1 byte)<br />
Offset (4 bytes)<br />
<br />
Similar to scripts but holds indexes for sounds.<br />
<br />
==0C - Directory of Costumes ==<br />
<br />
Block Size (4 bytes)<br />
Block Name (2 bytes)<br />
No of items (2 bytes)<br />
Room Number (1 byte)<br />
Offset (4 bytes)<br />
<br />
Similar to scripts but holds indexes of customes. <br />
<br />
==0O - Directory of Objects==<br />
<br />
Block Size (4 bytes)<br />
Block Name (2 bytes)<br />
No of items (2 bytes)<br />
Owner+state (1 byte)<br />
<br />
The Object owner and state are encoded in one byte. Example:<br />
<br />
0xA2 &rarr; Owner = 0xA, State = 0x2<br />
<br />
The pseudo decode code would be:<br />
<br />
Owner = ( (Owner+state Byte) AND 0xF0) >> 4<br />
State = (Owner+state Byte) AND 0x0F<br />
<br />
= Scumm 5 =<br />
<br />
* The files are xor'ed with 0x69<br />
<br />
== RNAM - Room Names ==<br />
<br />
Block Name (4 bytes)<br />
Block Size (4 bytes BE)<br />
#Room No (1 byte)<br />
#Room Name (9 bytes) XOR'ed with FF<br />
Blank (00) byte (1 byte) Marks end of chunk<br />
<br />
<br />
== MAXS ==<br />
<br />
Block Name (4 bytes)<br />
Block Size (4 bytes BE)<br />
Variables (2 bytes)<br />
Unknown (2 bytes)<br />
Bit Variables (2 bytes)<br />
Local Objects (2 bytes)<br />
New Names? (2 bytes)<br />
Character Sets (2 bytes)<br />
Verbs? (2 bytes)<br />
Array? (2 bytes)<br />
Inventory Objects (2 bytes)<br />
<br />
== DROO - Directory of Rooms ==<br />
<br />
Block Name (4 bytes)<br />
Block Size (4 bytes BE)<br />
No of items (2 bytes)<br />
*Room Number (1 byte)<br />
*Offset (4 bytes)<br />
<br />
The flow how to read in this kind of information has changed slightly from V3/4.<br />
<br />
Read "No of items"<br />
FROM 1 TO "No of items" DO<br />
Read "Room Number"<br />
END<br />
<br />
FROM 1 TO "No of items" DO<br />
Read "Offset"<br />
END<br />
<br />
First read in all room numbers, then read in all room offsets. <br />
<br />
<br />
== DSCR - Directory of Scripts ==<br />
<br />
Block Name (4 bytes)<br />
Block Size (4 bytes BE)<br />
No of items (2 bytes)<br />
*Room Number (1 byte)<br />
*Offset (4 bytes)<br />
<br />
Indexes for global scripts, see pseudo code above on how to read in the data.<br />
<br />
<br />
== DSOU - Directory of Sound == <br />
<br />
Block Name (4 bytes)<br />
Block Size (4 bytes BE)<br />
No of items (2 bytes)<br />
*Room Number (1 byte)<br />
*Offset (4 bytes)<br />
<br />
Indexes for sound objects.<br />
<br />
<br />
== DCOS - Directory of Costumes ==<br />
<br />
Block Name (4 bytes)<br />
Block Size (4 bytes BE)<br />
No of items (2 bytes)<br />
*Room Number (1 byte)<br />
*Offset (4 bytes)<br />
<br />
Indexes for costumes<br />
<br />
<br />
== DCHR - Director of Charsets ==<br />
<br />
Block Name (4 bytes)<br />
Block Size (4 bytes BE)<br />
No of items (2 bytes)<br />
*Room Number (1 byte)<br />
*Offset (4 bytes)<br />
<br />
Indexes for charsets.<br />
<br />
<br />
== DOBJ - Directory of Objects ==<br />
<br />
Block Name (4 bytes)<br />
Block Size (4 bytes BE)<br />
No of items (2 bytes)<br />
*Owner+state (1 byte)<br />
<br />
Information about objects. See remarks in V3/4 section how the value should be interpreted.<br />
<br />
= Scumm 6 =<br />
<br />
* Files are xor'ed with 0x69<br />
<br />
<br />
== RNAM - Room Names ==<br />
<br />
Blank Byte(00) (1 byte)<br />
<br />
No room names are stored.<br />
<br />
<br />
== MAXS ==<br />
<br />
Block Name (4 bytes)<br />
Block Size (4 bytes BE)<br />
Variables (2 bytes)<br />
Unknown (2 bytes)<br />
Bit Variables (2 bytes)<br />
Local Objects (2 bytes)<br />
Arrays (2 bytes)<br />
Unknown (2 bytes)<br />
Verbs (2 bytes)<br />
Floating Objects (2 bytes)<br />
Inventory Objects (2 bytes)<br />
Rooms (2 bytes)<br />
Scripts (2 bytes)<br />
Sounds (2 bytes)<br />
Character Sets (2 bytes)<br />
Costumes (2 bytes)<br />
Global Objects (2 bytes)<br />
<br />
<br />
== DROO, DSCR, DSOU, DCOS, DCHR, DOBJ ==<br />
<br />
All as in V5<br />
<br />
<br />
== AARY - Array == <br />
<br />
Block Name (4 bytes)<br />
Block Size (4 bytes BE)<br />
#Stop (2 bytes) Stops if 0x0000<br />
#A (2 bytes)<br />
#B (2 bytes)<br />
#C (2 bytes)<br />
<br />
num=AARY no (itinerate through in loop)<br />
if c=1 then<br />
AARY=(num, 1, a, b)<br />
else<br />
AARY=(num, 1, a, b)<br />
<br />
If stop=0 you dont seek past the 6 bytes of A,B,C you just start the loop again.<br />
<br />
<br />
= Scumm 7 = <br />
<br />
* Files aren't xor'ed<br />
<br />
== RNAM - Room names ==<br />
<br />
* As in V6 ?!?!?!<br />
<br />
<br />
== MAXS ==<br />
<br />
Block Name (4 bytes)<br />
Block Size (4 bytes BE)<br />
Variables (2 bytes)<br />
Bit Variables (2 bytes)<br />
Unknown (2 bytes)<br />
Global Objects (2 bytes)<br />
Local Objects (2 bytes)<br />
New Names (2 bytes)<br />
Verbs (2 bytes)<br />
Floating Objects (2 bytes)<br />
Inventory Objects (2 bytes)<br />
Arrays (2 bytes)<br />
Rooms (2 bytes)<br />
Scripts (2 bytes)<br />
Sounds (2 bytes)<br />
Character Sets (2 bytes)<br />
Costumes (2 bytes)<br />
<br />
<br />
== DROO,DSCR,DSOU,DCOS,DCHR,DOBJ,AARY ==<br />
<br />
All as in V5<br />
<br />
<br />
== ANAM - Animation Names ==<br />
<br />
Block Name (4 bytes)<br />
Block Size (4 bytes BE)<br />
No of items (2 bytes<br />
#Name (8 bytes)<br />
#Blank (00) byte (1 byte)<br />
Blank (FF) byte (1 byte) Marks end of chunk<br />
<br />
<br />
= Scumm 8 =<br />
<br />
== RNAM - Room Names ==<br />
<br />
As in V6 ?<br />
<br />
<br />
== MAXS ==<br />
<br />
Block Name (4 bytes)<br />
Block Size (4 bytes BE)<br />
Variables (4 bytes)<br />
Bit Variables (4 bytes)<br />
Unknown (4 bytes)<br />
Scripts (4 bytes)<br />
Sounds (4 bytes)<br />
Character Sets (4 bytes)<br />
Costumes (4 bytes)<br />
Rooms (4 bytes)<br />
Unknown (4 bytes)<br />
Global Objects (4 bytes)<br />
Unknown (4 bytes)<br />
Local Objects (4 bytes)<br />
New Names (4 bytes)<br />
Floating Objects (4 bytes)<br />
Inventory Objects (4 bytes)<br />
Arrays (4 bytes)<br />
Verbs (4 bytes)<br />
<br />
<br />
== DROO - Directory of Rooms ==<br />
<br />
Block Name (4 bytes)<br />
Block Size (4 bytes BE)<br />
No of items (4 bytes)<br />
*Room Number (1 byte)<br />
*Offset (2 bytes)<br />
<br />
<br />
== DRSC - Directory of Room Scripts ==<br />
<br />
Block Name (4 bytes)<br />
Block Size (4 bytes BE)<br />
No of items (4 bytes)<br />
*Room Number (1 byte)<br />
*Offset (2 bytes)<br />
<br />
<br />
== DSCR - Directory of Scripts == <br />
<br />
Block Name (4 bytes)<br />
Block Size (4 bytes BE)<br />
No of items (4 bytes)<br />
*Room Number (1 byte)<br />
*Offset (2 bytes)<br />
<br />
<br />
== DSOU - Directory of Sound ==<br />
<br />
Block Name (4 bytes)<br />
Block Size (4 bytes BE)<br />
No of items (4 bytes)<br />
*Room Number (1 byte)<br />
*Offset (2 bytes)<br />
<br />
<br />
== DCOS - Directory of Costumes ==<br />
<br />
Block Name (4 bytes)<br />
Block Size (4 bytes BE)<br />
No of items (4 bytes)<br />
*Room Number (1 byte)<br />
*Offset (2 bytes)<br />
<br />
<br />
== DCHR - Directory of Charsets ==<br />
<br />
Block Name (4 bytes)<br />
Block Size (4 bytes BE)<br />
No of items (4 bytes)<br />
*Room Number (1 byte)<br />
*Offset (2 bytes)<br />
<br />
<br />
== DOBJ,AARY ==<br />
<br />
As in V7<br />
<br />
<br />
[[Category: SCUMM Technical Reference]]</div>Jestar jokinhttps://wiki.scummvm.org/index.php?title=SCUMM/Technical_Reference/Object_resources&diff=11541SCUMM/Technical Reference/Object resources2009-07-29T13:03:13Z<p>Jestar jokin: /* V6 Objects */</p>
<hr />
<div>=== V6 Objects ===<br />
<br />
In v6 objects are split in 2 chunks: OBIM and OBCD. OBIM store the images, zplanes, etc, while OBCD mostly store the scripts.<br />
<br />
==== OBIM ====<br />
<br />
* OBIM<br />
** IMHD : header<br />
** IMnn : images<br />
*** SMAP (or BMOP)<br />
*** ZPnn<br />
<br />
Note: In IMnn and ZPnn nn represent an hexadecimal number.<br />
<br />
===== IMHD =====<br />
<br />
<pre><br />
obj id : 16le<br />
num imnn : 16le<br />
num zpnn : 16le (per IMnn block)<br />
flags : 8<br />
unknown : 8<br />
x : 16le<br />
y : 16le<br />
width : 16le<br />
height : 16le<br />
num hotspots : 16le (usually one for each IMnn, but their is one even<br />
if no IMnn is present)<br />
hotspots<br />
x : 16le signed<br />
y : 16le signed<br />
</pre><br />
<br />
The hotspots indicate where the actors should stand when they walk to the object.<br />
<br />
Each IMnn contain an image for a state. As state 0 display nothing they start at 01. IMnn chunks contain a SMAP or BMOP chunk enventually followed by some ZPnn blocks. See [[Image resources]] for more details on these.<br />
<br />
==== OBCD ====<br />
<br />
* OBCD<br />
** CDHD : header<br />
** VERB : script<br />
** OBNA : name<br />
<br />
===== CDHD =====<br />
<br />
<pre><br />
obj id : 16le<br />
x : 16le<br />
y : 16le<br />
width : 16le<br />
height : 16le<br />
flags : 8<br />
parent : 8<br />
walk_x : 16le signed<br />
walk_y : 16le signed<br />
actor dir : 8 (direction the actor will look at when standing in front<br />
of the object)<br />
</pre><br />
<br />
Note that the size and position must match those in the IMHD.<br />
<br />
===== VERB =====<br />
<br />
The VERB chunk hold the scripts. It start with a table giving the offset of the entry point for each verb handled by the object code, followed by the code.<br />
<br />
<pre><br />
offset table : vlc<br />
verb : 8 (0xFF is default)<br />
offset : 16le<br />
table end : 8 (must be 0)<br />
code<br />
</pre><br />
<br />
The OBNA chunk simply contain a null terminated string.<br />
<br />
=== V5 Objects ===<br />
V5 objects are a lot like V6 Objects, with minor differences.<br />
<br />
===== IMHD =====<br />
<br />
<pre><br />
obj id : 16le<br />
num imnn : 16le<br />
num zpnn : 16le (per IMnn block)<br />
flags : 8<br />
unknown : 8<br />
x : 16le<br />
y : 16le<br />
width : 16le<br />
height : 16le<br />
</pre><br />
<br />
IMHD omits the hotspots.<br />
<br />
===== CDHD =====<br />
<br />
<pre><br />
obj id : 16le<br />
x : 8<br />
y : 8<br />
width : 8<br />
height : 8<br />
flags : 8<br />
parent : 8<br />
walk_x : 16le signed<br />
walk_y : 16le signed<br />
actor dir : 8 (direction the actor will look at when standing in front<br />
of the object)<br />
</pre><br />
<br />
x, y, width, and height are bytes. Their values should be multiplied by 8 (the size of an image strip).</div>Jestar jokinhttps://wiki.scummvm.org/index.php?title=SCUMM/Technical_Reference/Object_resources&diff=11540SCUMM/Technical Reference/Object resources2009-07-29T12:45:39Z<p>Jestar jokin: Add notes on V5 objects (not sure IMHD is correct)</p>
<hr />
<div>=== V6 Objects ===<br />
<br />
In v6 objects are splited in 2 chunks: OBIM and OBCD. OBIM store the images, zplanes, etc and OBCD mostly store the scripts.<br />
<br />
==== OBIM ====<br />
<br />
* OBIM<br />
** IMHD : header<br />
** IMnn : images<br />
*** SMAP (or BMOP)<br />
*** ZPnn<br />
<br />
Note: In IMnn and ZPnn nn represent an hexadecimal number.<br />
<br />
===== IMHD =====<br />
<br />
<pre><br />
obj id : 16le<br />
num imnn : 16le<br />
num zpnn : 16le (per IMnn block)<br />
flags : 8<br />
unknown : 8<br />
x : 16le<br />
y : 16le<br />
width : 16le<br />
height : 16le<br />
num hotspots : 16le (usually one for each IMnn, but their is one even<br />
if no IMnn is present)<br />
hotspots<br />
x : 16le signed<br />
y : 16le signed<br />
</pre><br />
<br />
The hotspots indicate where the actors should stand when they walk to the object.<br />
<br />
Each IMnn contain an image for a state. As state 0 display nothing they start at 01. IMnn chunks contain a SMAP or BMOP chunk enventually followed by some ZPnn blocks. See [[Image resources]] for more details on these.<br />
<br />
==== OBCD ====<br />
<br />
* OBCD<br />
** CDHD : header<br />
** VERB : script<br />
** OBNA : name<br />
<br />
===== CDHD =====<br />
<br />
<pre><br />
obj id : 16le<br />
x : 16le<br />
y : 16le<br />
width : 16le<br />
height : 16le<br />
flags : 8<br />
parent : 8<br />
walk_x : 16le signed<br />
walk_y : 16le signed<br />
actor dir : 8 (direction the actor will look at when standing in front<br />
of the object)<br />
</pre><br />
<br />
Note that the size and position must match those in the IMHD.<br />
<br />
===== VERB =====<br />
<br />
The VERB chunk hold the scripts. It start with a table giving the offset of the entry point for each verb handled by the object code, followed by the code.<br />
<br />
<pre><br />
offset table : vlc<br />
verb : 8 (0xFF is default)<br />
offset : 16le<br />
table end : 8 (must be 0)<br />
code<br />
</pre><br />
<br />
The OBNA chunk simply contain a null terminated string.<br />
<br />
=== V5 Objects ===<br />
V5 objects are a lot like V6 Objects, with minor differences.<br />
<br />
===== IMHD =====<br />
<br />
<pre><br />
obj id : 16le<br />
num imnn : 16le<br />
num zpnn : 16le (per IMnn block)<br />
flags : 8<br />
unknown : 8<br />
x : 16le<br />
y : 16le<br />
width : 16le<br />
height : 16le<br />
</pre><br />
<br />
IMHD omits the hotspots.<br />
<br />
===== CDHD =====<br />
<br />
<pre><br />
obj id : 16le<br />
x : 8<br />
y : 8<br />
width : 8<br />
height : 8<br />
flags : 8<br />
parent : 8<br />
walk_x : 16le signed<br />
walk_y : 16le signed<br />
actor dir : 8 (direction the actor will look at when standing in front<br />
of the object)<br />
</pre><br />
<br />
x, y, width, and height are bytes. Their values should be multiplied by 8 (the size of an image strip).</div>Jestar jokinhttps://wiki.scummvm.org/index.php?title=SCUMM/Technical_Reference/Object_resources&diff=11539SCUMM/Technical Reference/Object resources2009-07-29T12:28:23Z<p>Jestar jokin: /* CDHD */ add walk_x and walk_y based on object.h</p>
<hr />
<div>=== V6 Objects ===<br />
<br />
In v6 objects are splited in 2 chunks: OBIM and OBCD. OBIM store the images, zplanes, etc and OBCD mostly store the scripts.<br />
<br />
==== OBIM ====<br />
<br />
* OBIM<br />
** IMHD : header<br />
** IMnn : images<br />
*** SMAP (or BMOP)<br />
*** ZPnn<br />
<br />
Note: In IMnn and ZPnn nn represent an hexadecimal number.<br />
<br />
===== IMHD =====<br />
<br />
<pre><br />
obj id : 16le<br />
num imnn : 16le<br />
num zpnn : 16le (per IMnn block)<br />
flags : 8<br />
unknown : 8<br />
x : 16le<br />
y : 16le<br />
width : 16le<br />
height : 16le<br />
num hotspots : 16le (usually one for each IMnn, but their is one even<br />
if no IMnn is present)<br />
hotspots<br />
x : 16le signed<br />
y : 16le signed<br />
</pre><br />
<br />
The hotspots indicate where the actors should stand when they walk to the object.<br />
<br />
Each IMnn contain an image for a state. As state 0 display nothing they start at 01. IMnn chunks contain a SMAP or BMOP chunk enventually followed by some ZPnn blocks. See [[Image resources]] for more details on these.<br />
<br />
==== OBCD ====<br />
<br />
* OBCD<br />
** CDHD : header<br />
** VERB : script<br />
** OBNA : name<br />
<br />
===== CDHD =====<br />
<br />
<pre><br />
obj id : 16le<br />
x : 16le<br />
y : 16le<br />
width : 16le<br />
height : 16le<br />
flags : 8<br />
parent : 8<br />
walk_x : 16le signed<br />
walk_y : 16le signed<br />
actor dir : 8 (direction the actor will look at when standing in front<br />
of the object)<br />
</pre><br />
<br />
Note that the size and position must match those in the IMHD.<br />
<br />
===== VERB =====<br />
<br />
The VERB chunk hold the scripts. It start with a table giving the offset of the entry point for each verb handled by the object code, followed by the code.<br />
<br />
<pre><br />
offset table : vlc<br />
verb : 8 (0xFF is default)<br />
offset : 16le<br />
table end : 8 (must be 0)<br />
code<br />
</pre><br />
<br />
The OBNA chunk simply contain a null terminated string.</div>Jestar jokinhttps://wiki.scummvm.org/index.php?title=SCUMM/Technical_Reference/Object_resources&diff=11534SCUMM/Technical Reference/Object resources2009-07-28T12:26:00Z<p>Jestar jokin: /* IMHD */ add flags info according to object.h</p>
<hr />
<div>=== V6 Objects ===<br />
<br />
In v6 objects are splited in 2 chunks: OBIM and OBCD. OBIM store the images, zplanes, etc and OBCD mostly store the scripts.<br />
<br />
==== OBIM ====<br />
<br />
* OBIM<br />
** IMHD : header<br />
** IMnn : images<br />
*** SMAP (or BMOP)<br />
*** ZPnn<br />
<br />
Note: In IMnn and ZPnn nn represent an hexadecimal number.<br />
<br />
===== IMHD =====<br />
<br />
<pre><br />
obj id : 16le<br />
num imnn : 16le<br />
num zpnn : 16le (per IMnn block)<br />
flags : 8<br />
unknown : 8<br />
x : 16le<br />
y : 16le<br />
width : 16le<br />
height : 16le<br />
num hotspots : 16le (usually one for each IMnn, but their is one even<br />
if no IMnn is present)<br />
hotspots<br />
x : 16le signed<br />
y : 16le signed<br />
</pre><br />
<br />
The hotspots indicate where the actors should stand when they walk to the object.<br />
<br />
Each IMnn contain an image for a state. As state 0 display nothing they start at 01. IMnn chunks contain a SMAP or BMOP chunk enventually followed by some ZPnn blocks. See [[Image resources]] for more details on these.<br />
<br />
==== OBCD ====<br />
<br />
* OBCD<br />
** CDHD : header<br />
** VERB : script<br />
** OBNA : name<br />
<br />
===== CDHD =====<br />
<br />
<pre><br />
obj id : 16le<br />
x : 16le<br />
y : 16le<br />
width : 16le<br />
height : 16le<br />
flags : 8<br />
parent : 8<br />
unk : 2*16<br />
actor dir : 8 (direction the actor will look at when standing in front<br />
of the object)<br />
</pre><br />
<br />
Note that the size and position must match those in the IMHD.<br />
<br />
===== VERB =====<br />
<br />
The VERB chunk hold the scripts. It start with a table giving the offset of the entry point for each verb handled by the object code, followed by the code.<br />
<br />
<pre><br />
offset table : vlc<br />
verb : 8 (0xFF is default)<br />
offset : 16le<br />
table end : 8 (must be 0)<br />
code<br />
</pre><br />
<br />
The OBNA chunk simply contain a null terminated string.</div>Jestar jokinhttps://wiki.scummvm.org/index.php?title=SCUMM/Technical_Reference/Sound_resources&diff=11521SCUMM/Technical Reference/Sound resources2009-07-26T11:43:29Z<p>Jestar jokin: Some info on CD "SOU" blocks</p>
<hr />
<div>=Music=<br />
<br />
==Early v5==<br />
<br />
Going from Monkey Island 2 (MI2), music blocks are stored in LFLF blocks, outside of the ROOMs, so they can be accessed globally. The containing sound block looks like this:<br />
<br />
Block name 4 bytes ("SOUN")<br />
Block size 4 bytes<br />
Block name 4 bytes ("SOU ")<br />
Block size 4 bytes<br />
Music block variable<br />
<br />
The redundant header is possibly due to building on a legacy implementation, or for easier identification in the table stored in the .000 index file.<br />
<br />
The music block may contain any combination of ROL (Roland MT-32), ADL (Adlib/OPL FM), or SPK (PC speaker) blocks. They can also store a single SBL block for digitized sound (described in a later section). Aside from SBL, each of these blocks follow the same basic pattern.<br />
<br />
Block name 4 bytes ("ROL ", or "ADL ", or "SPK ")<br />
Block size 4 bytes<br />
MIDI data variable<br />
<br />
Every track is stored in MIDI format, in order to make use of the iMUSE technology through System Exclusive (SysEx) messages.<br />
<br />
Due to the predominance of the Sound Blaster and Adlib/OPL FM technology at the time, in at least MI2 every musical SOUN block contains an ADL block.<br />
<br />
==iMUSE==<br />
<br />
From SCUMM v5 onwards, LucasArts games used a dynamic music playback system called iMUSE. This basically consists of standard MIDI data, with embedded System Exclusive (SysEx) messages that act as markers in the song. iMUSE allows operations like conditional jumping & looping, adjusting the volume of parts, turning parts on and off, changing instruments, and detuning parts.<br />
<br />
You can find the original patent document [http://pat2pdf.org/pat2pdf/foo.pl?number=5315057 here], and some technical details can be found [http://alban.dotsec.net/15.html here].<br />
<br />
==Mac0==<br />
<br />
From Markus Magnuson (superqult) we got this information:<br />
<br />
4 bytes - 'SOUN'<br />
BE 4 bytes - block length<br />
<br />
4 bytes - 'Mac0'<br />
BE 4 bytes - (blockLength - 27)<br />
28 bytes - ???<br />
<br />
do this three times (once for each channel):<br />
4 bytes - 'Chan'<br />
BE 4 bytes - channel length<br />
4 bytes - instrument name (e.g. 'MARI')<br />
<br />
do this for ((chanLength-24)/4) times:<br />
2 bytes - note duration<br />
1 byte - note value<br />
1 byte - note velocity<br />
<br />
4 bytes - ???<br />
4 bytes - 'Loop'/'Done'<br />
4 bytes - ???<br />
1 byte - 0x09<br />
<br />
Instruments (and General Midi equivalent):<br />
"MARI" - Marimba (12)<br />
"PLUC" - Pizzicato Strings (45)<br />
"HARM" - Harmonica (22)<br />
"PIPE" - Church Organ? (19) or Flute? (73) or Bag Pipe (109)<br />
"TROM" - Trombone (57)<br />
"STRI" - String Ensemble (48 or 49)<br />
"HORN" - French Horn? (60) or English Horn? (69)<br />
"VIBE" - Vibraphone (11)<br />
"SHAK" - Shakuhachi? (77)<br />
"PANP" - Pan Flute (75)<br />
"WHIS" - Whistle (78) / Bottle (76)<br />
"ORGA" - Drawbar Organ (16; but could also be 17-20)<br />
"BONG" - Woodblock? (115)<br />
"BASS" - Bass (32-39)<br />
<br />
=Digitized Sounds=<br />
<br />
==Early v5 - SBL blocks==<br />
<br />
Digitized sounds first appeared in Monkey Island 1 & 2. They are contained in the .001 resource files, and are sub-blocks of "SOUN" blocks (see the music section above).<br />
<br />
Block name 4 bytes ("SBL ")<br />
Block size 4 bytes<br />
Sound header 4 bytes ("AUhd" or "WVhd")<br />
Unknown 3 bytes (always 00 00 80)<br />
Data header 4 bytes ("AUdt" or "WVdt")<br />
VOC data variable<br />
<br />
AUhd and AUdt are used in Monkey Island, while WVhd and WVdt are used in the non-interactive demo of Sam & Max. The actual sound data is stored in the Creative VOC format, without the identifying header.<br />
<br />
==Early v5 - CD tracks==<br />
<br />
Games that use CD tracks (Loom/CD, MI1/CD, Zak256/FM-TOWNS) are a bit different. For MI1/CD at least, the "SOU " block size is always 32 bytes and presumably points to the CD track to play.<br />
<br />
Here's some notes by cocomonk22:<br />
Values from offsets 0-23 (0x00-0x17) are all the same, so just copy data from an existing SOUN.<br />
At offset 24 (0x18) track number in hex format (for new music not in original start with track decimal 24 or hex 18).<br />
At offset 25 (0x19) seems to be loop, opening uses 01, scummbar uses ff.<br />
The six remaining values 26-31 (0x1a-0x1f) are all 00 if you want the music to start at the beginning of the track.<br />
<br />
An example of music not starting at the beginning:<br />
The scene at the lookout following the intro uses the same music as the opening, but starts at position 1 min 36 sec. Hex values are 01 23 30 00 00 00. 01 23 30 is equivalent to 1 35 48 in decimal.<br />
<br />
==v5-v6 - MONSTER.SOU==<br />
<br />
===Original===<br />
<br />
From Indy 4 onwards, sound effects and speech are stored in a separate resource file called "MONSTER.SOU". The format is:<br />
<br />
Block name 4 bytes ("SOU ")<br />
Block size 4 bytes<br />
One or more:<br />
Block name 4 bytes ("VCTL")<br />
Block size 4 bytes<br />
Lip-sync tags variable<br />
Sound data variable ("Crea" block / VOC file)<br />
<br />
The lip-sync tags provide timing information. In v5 the number of tags is stored in the calling text, according to the formula ((num_tags / 2) << 1) + 8. The "Crea" block is an entire Creative VOC file.<br />
<br />
===Compressed===<br />
<br />
ScummVM can use compressed monster.sou files created with the tool "compress_scumm_sou.exe". Aside from using either MP3, OGG, or FLAC formats for the sound data, they contain a mapping table followed by the sound data, like so:<br />
<br />
size_of_table : uint32<br />
size_of_table / 16 times {<br />
orig_offset : uint32<br />
actual_offset : uint32<br />
num_tags : uint32<br />
sound_size : unit32<br />
}<br />
size_of_table / 16 times {<br />
num_tags times {<br />
tag : uint8<br />
}<br />
sound : sound_size (sound file - MP3/OGG/FLAC)<br />
} <br />
<br />
Each entry in the table has 4 items, each item is 4 bytes, so a table with one entry has a size of 16.<br />
<br />
The original offset is what the game will try to play, the actual offset is taken from after the index table.<br />
<br />
Each sound is directly preceded by its lip-synch tags.<br />
<br />
=Sound block types=<br />
This information is gleaned from the ScummVM source code. Any block name with only three characters has a space at the end.<br />
MIDI \ Midi<br />
iMUS /<br />
<br />
SOU subtypes<br />
TOWS - FM Towns<br />
SBL - Sound Blaster digitized sound (Creative VOC file)<br />
ADL - Adlib (OPL FM)<br />
AMI - Amiga MOD<br />
ROL - Roland MT-32<br />
GMD - General MIDI<br />
MAC - Macintosh (occurs in MI2, FOA)<br />
SPK - PC speaker<br />
<br />
Mac0 - Macintosh music type 0<br />
<br />
Mac1 \<br />
RIFF |<br />
TALK > Creative VOC file<br />
DIGI |<br />
Crea /<br />
<br />
HSHD - HE sound type without SOUN header<br />
<br />
FMUS - Used in 3DO versions of HE games</div>Jestar jokinhttps://wiki.scummvm.org/index.php?title=User:Jestar_jokin&diff=11520User:Jestar jokin2009-07-26T11:28:13Z<p>Jestar jokin: Scummbler supports V3 and V4 scripts</p>
<hr />
<div>HI! Let's have a party, just you and me and everyone we know! WOOOOHOOOO<br />
<br />
I have been mucking around hacking SCUMM games, which is only possible thanks to the fantastic work done by the ScummVM team and all the other reverse engineers out there.<br />
<br />
I have developed a few tools that let you modify or create SCUMM ''V5'' resources:<br />
* Scummbler - compiles SCUMM V3, 4, and 5 scripts from the text scripts based on descumm's output. This makes it relatively easy to modify existing script resources in a game.<br />
* ScummPacker - extract & repack the resource files of SCUMM V5 games. You can add new content to games, such as scripts created with Scummbler, or backgrounds created with SCUMM Image Encoder.<br />
* ScummSpeaks - making use of ScummTr, allows you to map sounds in a MONSTER.SOU file (either compressed through ScummVM tools, or uncompressed original format) to lines of text. You can also use it to manipulate MONSTER.SOU files. Currently being used for a project to add speech to Monkey Island (which is really its only use).<br />
* SCUMM Image Encoder (mi2img) - convert between background resources extracted by ScummPacker and PNG files. It can only encode "lossless" backgrounds with a limited palette (around 160 colours).<br />
<br />
These are all made in Python. You can find them on [http://www.jestarjokin.net/ my website].<br />
<br />
Aside from plugging my toys on this wiki, I also hope to share the knowledge of SCUMM I've picked up in my adventures.<br />
<br />
(Also my name should be in lowercase, but MediaWiki is rubbish when it comes to rubbish names.)</div>Jestar jokinhttps://wiki.scummvm.org/index.php?title=SCUMM/V5_opcodes&diff=11080SCUMM/V5 opcodes2009-05-17T13:43:56Z<p>Jestar jokin: fix table</p>
<hr />
<div>=SCUMM V5 opcodes=<br />
The following conventions are used in the encoding descriptions.<br />
<br />
{| border="1" cellpadding="2" width=100%<br />
|- style="background:whitesmoke"<br />
|Term||Description<br />
|-<br />
|opcode||The instruction's opcode, with the appropriate bits set according to the parameters.<br />
|-<br />
|aux||An aux opcode that stores parameter bits and no other information. (the base aux opcode seems to always be $01)<br />
|-<br />
|sub-opcode||An aux opcode that indicates a specific function to perform (e.g. the "wait" instruction has sub-opcodes to "wait for message", "wait for actor" etc), as well as storing parameter bits if necessary.<br />
|-<br />
|result||A result pointer. (A standard word pointer, always a LE word.)<br />
|-<br />
|var||A variable pointer. Same as above, but is not written to. Because this is always a variable, the opcode is not affected like it would be with a normal parameter (described below).<br />
|-<br />
|value[8]||An 8-bit constant (a byte).<br />
|-<br />
|value[16]||A 16-bit constant (a word LE).<br />
|-<br />
|value[p8]||An 8-bit parameter. This may be encoded as a word LE if it's a pointer, or a byte if it's a constant.<br />
|-<br />
|value[p16]||A 16-bit parameter. This is always encoded as a word LE, and may be a pointer or constant.<br />
|-<br />
|value[v16]||A variable number of word LE parameters. These are encoded as a sequence of aux[8] param[p16]; param; aux contains the parameter bit to describe param (and is always $01, ignoring the parameter bits). A byte of $FF terminates the sequence. (actually always shown as "value[v16]...")<br />
|-<br />
|value[o]||The offset word for parameter value. This is only encoded if needed, but always at the position indicated. If not specified, the offset word occurs immediately after the parameter.<br />
|-<br />
|value[c]||An ASCII character. Because some instructions use null-terminated strings and some use $FF, the exact format of a string is described in the instruction. Almost always appears as "value[c]..."<br />
|-<br />
|term...||One or more terms.<br />
|}<br />
<br />
Of course, due to the non-orthogonality of the opcodes, there are lots of exceptions.<br />
<br />
<br />
==actorFollowCamera ($52)==<br />
<br />
===Encoding===<br />
opcode actor[p8]<br />
<br />
===Operation===<br />
Sets the camera to follow the given actor?<br />
<br />
<br />
==actorFromPos ($15)==<br />
<br />
===Encoding===<br />
opcode result x[p16] y[p16]<br />
<br />
===Operation===<br />
Returns the actor located at the given co-ordinates.<br />
<br />
<br />
==actorOps ($13)==<br />
parameters depend on auxiliary opcode; terminated by $FF<br />
<br />
===Encoding===<br />
opcode actor[p8] sub-opcode... $FF<br />
<br />
sub-opcodes:<br />
$00 arg1[p8]<br />
$01 costume[p8]<br />
$02 xspeed[p8] yspeed[p8]<br />
$03 sound[p8]<br />
$04 walkframe[p8]<br />
$05 starttalk[p8] endtalk[p8]<br />
$06 standframe[p8]<br />
$07 arg1[p8] arg2[p8] arg3[p8]<br />
$08<br />
$09 elevation[p16]<br />
$0A<br />
$0B index[p8] value[p8]<br />
$0C colour[p8]<br />
$0D name[c]... $00<br />
$0E initframe[p8]<br />
$10 width[p8]<br />
$11 xscale[p8] yscale[p8]<br />
$12<br />
$13 zplane[p8]<br />
$14<br />
$15 <br />
$16 animspeed[p8]<br />
$17 shadow[p8]<br />
<br />
===Operation===<br />
Miscellaneous actions on actors.<br />
<br />
{| border="1" cellpadding="2" width=100%<br />
|- style="background:whitesmoke"<br />
|Opcode||Meaning||Description<br />
|-<br />
|$00||dummy||A dummy case, does nothing (in ScummVM).<br />
|-<br />
|$01||SO_COSTUME||Sets the actor's costume.<br />
|-<br />
|$02||SO_STEP_DIST||Sets the actor's walking speed for x and y.<br />
|-<br />
|$03||SO_SOUND||Associates a sound with the actor (footsteps?)<br />
|-<br />
|$04||SO_WALK_ANIMATION||Sets the current frame of the walking animation.<br />
|-<br />
|$05||SO_TALK_ANIMATION||Sets the start and stop frames of the talking animation.<br />
|-<br />
|$06||SO_STAND_ANIMATION||Sets the current frame of the standing animation.<br />
|-<br />
|$07||SO_ANIMATION||Unknown; seems to be unused in ScummVM.<br />
|-<br />
|$08||SO_DEFAULT||Initializes actor.<br />
|-<br />
|$09||SO_ELEVATION||Sets the actor's elevation to the given value.<br />
|-<br />
|$0A||SO_ANIMATION_DEFAULT||Initializes the actor's animation frames.<br>Init frame = 1<br>Walk frame = 2<br>Stand frame = 3<br>Talk start frame = 4<br>Talk stop frame = 5<br />
|-<br />
|$0B||SO_PALETTE||Sets the colour at the given index to a new value (another entry in the colour lookup table/CLUT). Index must be between 0 and 31 (the number of colours in a costume).<br />
|-<br />
|$0C||SO_TALK_COLOR||Sets the actor's talk colour.<br />
|-<br />
|$0D||SO_ACTOR_NAME||Sets the actor's name to the given null-terminated string.<br />
|-<br />
|$0E||SO_INIT_ANIMATION||Sets the current frame of the initial animation.<br />
|-<br />
|$10||SO_ACTOR_WIDTH||Sets the actor's width.<br />
|-<br />
|$11||SO_ACTOR_SCALE||Sets the actor's X and Y scales.<br />
|-<br />
|$12||SO_NEVER_ZCLIP||Turns off all Z-clipping for the actor.<br />
|-<br />
|$13||SO_ALWAYS_ZCLIP||Forces the actor's Z-clipping for the given Z-plane?<br />
|-<br />
|$14||SO_IGNORE_BOXES||Ignores boxes, turns off Z-clipping, and puts actor somewhere if the actor is in the current room?<br />
|-<br />
|$15||SO_FOLLOW_BOXES||Follows boxes, turns off Z-clipping, and puts actor somewhere if the actor is in the current room?<br />
|-<br />
|$16||SO_ANIMATION_SPEED||Sets the animation speed.<br />
|-<br />
|$17||SO_SHADOW||Sets the shadow mode.<br />
|}<br />
<br />
===Variants===<br />
In SCUMM V3 and V4, the opcode values are slightly different.<br />
<br />
{| border="1" cellpadding="2" width=50%<br />
|- style="background:whitesmoke"<br />
|Opcode||Meaning<br />
|-<br />
|$00||dummy<br />
|-<br />
|$01||SO_COSTUME<br />
|-<br />
|$04||SO_STEP_DIST<br />
|-<br />
|$05||SO_SOUND<br />
|-<br />
|$06||SO_WALK_ANIMATION<br />
|-<br />
|$07||SO_TALK_ANIMATION<br />
|-<br />
|$08||SO_STAND_ANIMATION<br />
|-<br />
|$09||SO_ANIMATION<br />
|-<br />
|$0A||SO_DEFAULT<br />
|-<br />
|$0B||SO_ELEVATION<br />
|-<br />
|$0C||SO_ANIMATION_DEFAULT<br />
|-<br />
|$0D||SO_PALETTE<br />
|-<br />
|$0E||SO_TALK_COLOR<br />
|-<br />
|$0F||SO_ACTOR_NAME<br />
|-<br />
|$10||SO_INIT_ANIMATION<br />
|-<br />
|$12||SO_ACTOR_WIDTH<br />
|-<br />
|$13||SO_ACTOR_SCALE<br />
|-<br />
|$14||SO_IGNORE_BOXES<br />
|}<br />
<br />
Also in V3 and V4, sub-opcode $13 (SO_ACTOR_SCALE) only takes one parameter, so X and Y scaling is done at a 1:1 ratio.<br />
<br />
<br />
==actorSetClass ($5D)==<br />
<br />
===Encoding===<br />
opcode object[p16] classes[v16]...<br />
<br />
===Operation===<br />
Makes object inherit from all of the given classes. A class of "0" will clear all of the object's existing class data.<br />
<br />
<br />
==add ($5A)==<br />
<br />
===Encoding===<br />
opcode result value[p16]<br />
<br />
===Operation===<br />
result := result + value<br />
<br />
The variable pointed to by result is read, value is added to it, and the result written back.<br />
<br />
<br />
==and ($17)==<br />
one parameter, uses result<br />
<br />
===Encoding===<br />
opcode result value[p16]<br />
<br />
===Operation===<br />
result := result and value<br />
<br />
The variable pointed to by result is read, logically ANDed with value, and the result written back.<br />
<br />
<br />
==animateActor ($11)==<br />
<br />
===Encoding===<br />
opcode actor[p8] anim[p8]<br />
<br />
===Operation===<br />
Starts the given animation for the given actor.<br />
<br />
<br />
==breakHere ($80)==<br />
no parameters<br />
<br />
===Encoding===<br />
opcode<br />
<br />
===Operation===<br />
Deschedules the currently running thread. Execution continues at the next instruction when the thread's next timeslot comes around.<br />
<br />
<br />
==chainScript ($42)==<br />
one parameter plus varargs<br />
<br />
===Encoding===<br />
opcode script[p8] args[v16]...<br />
<br />
===Operation===<br />
Replaces the currently running script with another one. The current script is terminated immediately and the new script (determined by the given script ID), is executed in the same thread. The new script has its local variables initialised to the list args. Uninitialised variables have undefined values.<br />
<br />
<br />
==cursorCommand ($2C)==<br />
parameters depend on auxiliary opcode<br />
<br />
===Encoding===<br />
opcode sub-opcode<br />
<br />
sub-opcode can be any of the following:<br />
$01<br />
... $01 through $08 take the same arguments ...<br />
$08<br />
$0A cursornum[p8] charletter[p8]<br />
$0B index[p8] x[p8] y[p8]<br />
$0C cursor[p8]<br />
$0D charset[p8]<br />
$0E colours[v16]...<br />
<br />
===Operation===<br />
Miscellaneous actions on cursors & charsets.<br />
<br />
{| border="1" cellpadding="2" width=100%<br />
|- style="background:whitesmoke"<br />
|Opcode||Meaning||Description<br />
|-<br />
|$01||SO_CURSOR_ON||Turns the cursor on.<br />
|-<br />
|$02||SO_CURSOR_OFF||Turns the cursor off.<br />
|-<br />
|$03||SO_USERPUT_ON||Enables user input.<br />
|-<br />
|$04||SO_USERPUT_OFF||Disables user input.<br />
|-<br />
|$05||SO_CURSOR_SOFT_ON||Increments the cursor's state?<br />
|-<br />
|$06||SO_CURSOR_SOFT_OFF||Decrements the cursor's state?<br />
|-<br />
|$07||SO_USERPUT_SOFT_ON||Increments "user input" counter (when greater than 0, user input is enabled).<br />
|-<br />
|$08||SO_USERPUT_SOFT_OFF||Decrements "user input" counter (when 0 or less, user input is disabled).<br />
|-<br />
|$0A||SO_CURSOR_IMAGE||Changes the cursor image to a new one, based on image in a character set. Only used in Loom.<br />
|-<br />
|$0B||SO_CURSOR_HOTSPOT||Changes the hotspot of a cursor. Only used in Loom.<br />
|-<br />
|$0C||SO_CURSOR_SET||Changes the current cursor. Must be between 0 and 3 inclusive.<br />
|-<br />
|$0D||SO_CHARSET_SET||Initializes the given character set.<br />
|-<br />
|$0E||SO_CHARSET_COLORS||Initializes the character set data & colours to the given arguments? Must have 16 arguments?<br />
|}<br />
<br />
===Variants===<br />
In SCUMM V3, sub-opcode $0E performs a different function, to load/initialize a character set.<br />
<br />
opcode $0E arg1[p8] arg2[p8]<br />
<br />
<br />
==cutScene ($40)==<br />
<br />
===Encoding===<br />
opcode args[v16]...<br />
<br />
===Operation===<br />
??? If required, runs a script passing the given arguments. Cutscene data given by the first argument?<br />
<br />
<br />
==debug ($6B)==<br />
one parameter, no result<br />
<br />
===Encoding===<br />
opcode param[p16]<br />
<br />
===Operation===<br />
Passes the parameter to the interpreter's debugger. What this does is entirely platform-specific (and may do nothing).<br />
<br />
<br />
==decrement ($C6)==<br />
no parameters, uses result<br />
<br />
===Encoding===<br />
opcode result<br />
<br />
===Operation===<br />
result := result - 1<br />
<br />
Reads the variable pointed to by result, decrements it, and writes it back. <br />
<br />
<br />
==delay ($2E)==<br />
one constant parameter<br />
<br />
===Encoding===<br />
opcode param[24]<br />
<br />
===Operation===<br />
Suspends the current thread for the appropriate number of 1/60ths of a second. Yes, that really is a 24-bit LE constant.<br />
<br />
<br />
==delayVariable ($2B)==<br />
one constant parameter<br />
<br />
===Encoding===<br />
opcode var<br />
<br />
===Operation===<br />
var is dereferenced and the current thread suspended for that number of 1/60ths of a second.<br />
<br />
<br />
==divide ($5B)==<br />
one parameter, uses result<br />
<br />
===Encoding===<br />
opcode result value[p16]<br />
<br />
===Operation===<br />
result := result / value<br />
<br />
The variable pointed to by result is read, divided by value, and the result written back. If value is zero, the result is undefined (and the interpeter may halt with an error). <br />
<br />
<br />
==doSentence ($19)==<br />
<br />
===Encoding===<br />
opcode verb[p8] objectA[p16] objectB[p16]<br />
<br />
===Operation===<br />
Performs a verb sentence action, e.g. "Use monkey on hydrant". If verb is $FE, the current sentence script is stopped, status cleared etc.<br />
<br />
<br />
==drawBox ($3F)==<br />
two parameters, does not use result, supplementary opcode byte with three more subsequent parameters<br />
<br />
===Encoding===<br />
opcode left[p16] top[p16] auxopcode[8] right[p16] bottom[p16] colour[p8]<br />
<br />
===Operation===<br />
Draws a solid box on the backbuffer from (left, top) to (right, bottom) in the given colour.<br />
<br />
The only part of auxopcode that is relevant are the parameter bits. The rest of the opcode is ignored. <br />
<br />
<br />
==drawObject ($05)==<br />
<br />
===Encoding===<br />
opcode object[p16] sub-opcode<br />
<br />
sub-opcodes:<br />
$01 xpos[p16] ypos[p16]<br />
$02 state[p16]<br />
$1F<br />
<br />
===Operation===<br />
{| border="1" cellpadding="2" width=100%<br />
|- style="background:whitesmoke"<br />
|Opcode||Meaning||Description<br />
|-<br />
|$01||Draw At||Moves the given object to the given co-ordinates, and adds it to the drawing queue.<br />
|-<br />
|$02||Set State||Sets the state of the object, adds it to the drawing queue.<br />
|-<br />
|$1F||Draw||Does not change the object's position (or state?), still adds it to the drawing queue.<br />
|}<br />
<br />
===Variants===<br />
Small header games (v3 and v4) only support the parameters used with sub-opcode $01, e.g:<br />
opcode object[p16] xpos[p16] ypos[p16]<br />
Accordingly, they have three parameter bits, and hence more possible opcodes.<br />
<br />
<br />
==dummy ($A7)==<br />
<br />
===Encoding===<br />
opcode<br />
<br />
===Operation===<br />
V5 specific - The KIXX XL release of Monkey Island 2 (Amiga disk) used this opcode as a dummy, in order to remove copy protection and keep level selection.<br />
<br />
===Variants===<br />
In SCUMM V3 and V4, this opcode is used for the saveLoadVars instruction.<br />
<br />
<br />
==endCutScene ($C0)==<br />
<br />
===Encoding===<br />
opcode<br />
<br />
===Operation===<br />
Ends the cutscene, performing cleanup if necessary.<br />
<br />
<br />
==equalZero ($28)==<br />
jumps<br />
<br />
===Encoding===<br />
opcode var target[16]<br />
<br />
===Operation===<br />
unless (var == 0) goto target<br />
<br />
Target is a byte offset (measured from after this instruction), which will be added to the instruction pointer.<br />
<br />
<br />
==expression ($AC)==<br />
<br />
===Encoding===<br />
opcode result subopcode... $FF<br />
<br />
sub-opcodes:<br />
$01 value[p16]<br />
$02<br />
... $02 through $05 take the same arguments ...<br />
$05<br />
$06 nested-opcode<br />
<br />
===Operation===<br />
Expression mode operates on a stack. Values are pushed on, and operators are applied to the top two items on the stack.<br />
<br />
{| border="1" cellpadding="2" width=100%<br />
|- style="background:whitesmoke"<br />
|Opcode||Meaning||Description<br />
|-<br />
|$01||Value||Pushes a value onto the top of the stack.<br />
|-<br />
|$02||Add||stack[top - 1] + stack[top]<br />
|-<br />
|$03||Subtract||stack[top - 1] - stack[top]<br />
|-<br />
|$04||Multiply||stack[top - 1] * stack[top]<br />
|-<br />
|$05||Divide||stack[top - 1] / stack[top] (if stack[top] is 0 an error occurs)<br />
|-<br />
|$06||Nested Opcode||An entire instruction that returns a result, such as getActorScale. This is interpreted like a normal opcode, but the result is pushed onto the expression stack. (The opcode is passed the special "VAR_RESULT" parameter for "result")<br />
|}<br />
<br />
<br />
==faceActor ($09)==<br />
<br />
===Encoding===<br />
opcode actor[p8] object[p16]<br />
<br />
===Operation===<br />
Dereferences actor, tells actor to face object (presumably based on X/Y co-ordinates).<br />
<br />
<br />
==findInventory ($3D)==<br />
<br />
===Encoding===<br />
opcode result owner[p8] index[p8]<br />
<br />
===Operation===<br />
object := owner.inventory[index]<br />
Searches for all objects owned by owner (an actor or object), and returns the one at the given index (offset).<br />
<br />
<br />
==findObject ($35)==<br />
<br />
===Encoding===<br />
opcode result x[p8] y[p8]<br />
<br />
===Operation===<br />
Returns the first "touchable" local object at the given co-ordinates. Will not match on the bottom or right-hand edges of an object.<br />
<br />
<br />
==freezeScripts ($60)==<br />
<br />
===Encoding===<br />
opcode flag[p8]<br />
<br />
===Operation===<br />
Freezes all scripts (by setting the high bit on each script's status). If flag is >= $80, all freeze resistent scripts will also be frozen. If flag is 0, all scripts are unfrozen. Freezing effects are cumulative - i.e. if script A is frozen twice, and unfrozen once, it will still be frozen until it is unfrozen a second time. A script's frozen status is indicated by the high bit.<br />
<br />
<br />
==getActorCostume ($71)==<br />
<br />
===Encoding===<br />
opcode result actor[p8]<br />
<br />
===Operation===<br />
Returns the actor's current costume.<br />
<br />
<br />
==getActorElevation ($06)==<br />
<br />
===Encoding===<br />
opcode result actor[p8]<br />
<br />
===Operation===<br />
Returns the actor's current elevation.<br />
<br />
<br />
==getActorFacing ($63)==<br />
<br />
===Encoding===<br />
opcode result actor[p8]<br />
<br />
===Operation===<br />
Returns the current direction the actor is facing.<br />
<br />
<br />
==getActorMoving ($56)==<br />
<br />
===Encoding===<br />
opcode result actor[p8]<br />
<br />
===Operation===<br />
Returns the actor's moving status (0 or 1).<br />
<br />
<br />
==getActorRoom ($03)==<br />
<br />
===Encoding===<br />
opcode result actor[p8]<br />
<br />
===Operation===<br />
Returns the room the actor currently occupies?<br />
<br />
<br />
==getActorScale ($3B)==<br />
<br />
===Encoding===<br />
opcode result actor[p8]<br />
<br />
===Operation===<br />
Returns the actor's current scale.<br />
<br />
===Variants===<br />
In Indy3, this opcode is used for waitForActor.<br />
<br />
<br />
==getActorWalkBox ($7B)==<br />
<br />
===Encoding===<br />
opcode result actor[p8]<br />
<br />
===Operation===<br />
Returns the actor's walkbox.<br />
<br />
<br />
==getActorWidth ($6C)==<br />
<br />
===Encoding===<br />
opcode result actor[p8]<br />
<br />
===Operation===<br />
Returns the actor's width.<br />
<br />
<br />
==getActorX ($43)==<br />
<br />
===Encoding===<br />
opcode result actor[p16]<br />
<br />
===Operation===<br />
Returns the actor's current X co-ordinate.<br />
<br />
===Variants===<br />
In Indy3, actor is only one byte.<br />
opcode result actor[p8]<br />
<br />
<br />
==getActorY ($23)==<br />
<br />
===Encoding===<br />
opcode result actor[p16]<br />
<br />
===Operation===<br />
Returns the actor's current Y co-ordinate.<br />
<br />
===Variants===<br />
In Indy3, actor is only one byte.<br />
opcode result actor[p8]<br />
<br />
<br />
==getAnimCounter ($22)==<br />
<br />
===Encoding===<br />
opcode result actor[p8]<br />
<br />
===Operation===<br />
Returns the actor's animation counter.<br />
<br />
===Variants===<br />
This opcode is used for saveLoadGame in SCUMM V3.<br />
<br />
<br />
==getClosestObjActor ($66)==<br />
<br />
===Encoding===<br />
opcode result actor[p16]<br />
<br />
===Operation===<br />
Returns the object closest to the actor. Items that are more than 255 units (pixels in newer games, characters in older games) away from the actor will not be detected.<br />
<br />
<br />
==getDist ($34)==<br />
<br />
===Encoding===<br />
opcode result objA[p16] objB[p16]<br />
<br />
===Operation===<br />
Returns the distance between two actors/objects (objA and objB).<br />
<br />
<br />
==getInventoryCount ($31)==<br />
<br />
===Encoding===<br />
opcode result actor[p8]<br />
<br />
===Operation===<br />
Returns the number of items in an actor's inventory?<br />
<br />
<br />
==getObjectOwner ($10)==<br />
<br />
===Encoding===<br />
opcode result object[p16]<br />
<br />
===Operation===<br />
Returns the owner of an object.<br />
<br />
<br />
==getObjectState ($0F)==<br />
<br />
===Encoding===<br />
opcode result object[p16]<br />
<br />
===Operation===<br />
Returns the state of the object.<br />
<br />
===Variants===<br />
In small header games, this opcode is used for the "ifState" instruction.<br />
<br />
<br />
==getRandomNumber ($16)==<br />
<br />
===Encoding===<br />
opcode result seed[p8]<br />
<br />
===Operation===<br />
Returns a new random number based on the given seed.<br />
<br />
<br />
==getScriptRunning ($68)==<br />
<br />
===Encoding===<br />
opcode result script[p8]<br />
<br />
===Operation===<br />
Returns 1 if the given script is running, 0 if it's not.<br />
<br />
<br />
==getStringWidth ($67)==<br />
<br />
===Encoding===<br />
opcode result strptr[p8]<br />
<br />
===Operation===<br />
Gets the length of the string pointed to by strptr (either a variable or direct byte), stores the returned value in result.<br />
<br />
<br />
==getVerbEntryPoint ($0B)==<br />
<br />
===Encoding===<br />
opcode result object[p16] verb[p16]<br />
<br />
===Operation===<br />
Returns the entry point for the response code/script for when the given verb is applied to the given object? i.e. gets the start of the script to run for the specific user interaction.<br />
<br />
<br />
==ifClassOfIs ($1D)==<br />
jumps<br />
<br />
===Encoding===<br />
opcode value[p16] args[v16]... target[16]<br />
<br />
===Operation===<br />
unless (value.class is one of [args.class]) goto target<br />
<br />
Compares the value's class with all classes given in args.<br />
<br />
Target is a byte offset (measured from after this instruction), which will be added to the instruction pointer.<br />
<br />
<br />
==ifNotState ($2F) (V3-4)==<br />
This opcode is not present in SCUMM V5.<br />
<br />
===Encoding===<br />
opcode object[p16] state[p8] target[16]<br />
<br />
===Operation===<br />
unless (getState(object) != state) goto target<br />
<br />
<br />
==ifState ($0F) (V3-4)==<br />
This opcode is not present in SCUMM V5.<br />
<br />
===Encoding===<br />
opcode object[p16] state[p8] target[16]<br />
<br />
===Operation===<br />
unless (getState(object) == state) goto target<br />
<br />
<br />
==increment ($46)==<br />
no parameters, uses result<br />
<br />
===Encoding===<br />
opcode result<br />
<br />
===Operation===<br />
result := result + 1<br />
<br />
Reads the variable pointed to by result, increments it, and writes it back. <br />
<br />
<br />
==isActorInBox ($1F)==<br />
<br />
===Encoding===<br />
opcode actor[p8] box[p8] target[16]<br />
<br />
===Operation===<br />
Unless the actor's co-ordinates are within the bounds of the given box, jump to target.<br />
<br />
Target is a byte offset (measured from after this instruction), which will be added to the instruction pointer.<br />
<br />
<br />
==isEqual ($48)==<br />
<br />
===Encoding===<br />
opcode var value[p16] target[16]<br />
<br />
===Operation===<br />
unless (value == var) goto target<br />
<br />
Target is a byte offset (measured from after this instruction), which will be added to the instruction pointer.<br />
<br />
<br />
==isGreater ($78)==<br />
<br />
===Encoding===<br />
opcode var value[p16] target[16]<br />
<br />
===Operation===<br />
unless (value > var) goto target<br />
<br />
Target is a byte offset (measured from after this instruction), which will be added to the instruction pointer.<br />
<br />
<br />
==isGreaterEqual ($04)==<br />
<br />
===Encoding===<br />
opcode var value[p16] target[16]<br />
<br />
===Operation===<br />
unless (value >= var) goto target<br />
<br />
Target is a byte offset (measured from after this instruction), which will be added to the instruction pointer.<br />
<br />
<br />
==isLess ($44)==<br />
<br />
===Encoding===<br />
opcode var value[p16] target[16]<br />
<br />
===Operation===<br />
unless (value < var) goto target<br />
<br />
Target is a byte offset (measured from after this instruction), which will be added to the instruction pointer.<br />
<br />
<br />
==isNotEqual ($08)==<br />
<br />
===Encoding===<br />
opcode var value[p16] target[16]<br />
<br />
===Operation===<br />
unless (value != var) goto target<br />
<br />
Target is a byte offset (measured from after this instruction), which will be added to the instruction pointer.<br />
<br />
<br />
==isSoundRunning ($7C)==<br />
<br />
===Encoding===<br />
opcode result sound[p8]<br />
<br />
===Operation===<br />
Returns 1 if sound is running, returns 0 if sound is not running or if the given sound is 0.<br />
<br />
<br />
==jumpRelative ($18)==<br />
jumps<br />
<br />
===Encoding===<br />
opcode target[16]<br />
<br />
===Operation===<br />
PC := PC + target<br />
<br />
The inline constant target is read as a signed word and added to the program counter after the instruction has been read. Therefore, if target is zero, the instruction will do nothing; if target is -3, an infinite loop will result. <br />
<br />
<br />
==lessOrEqual ($38)==<br />
jumps<br />
<br />
===Encoding===<br />
opcode var value[p16] target[16]<br />
<br />
===Operation===<br />
unless (value <= var) goto target<br />
<br />
Target is a byte offset (measured from after this instruction), which will be added to the instruction pointer.<br />
<br />
<br />
==lights ($70)==<br />
<br />
===Encoding===<br />
opcode arg1[p8] arg2[8] arg3[8]<br />
<br />
===Operation===<br />
If arg3 is 0, the "current lights" variable is set to arg1.<br />
If arg3 is 1, the size of the "flashlight" light is determined by arg1 and arg2, for width and height in stripes (which are equivalent to 8 pixels each; see [[SCUMM/Technical Reference/Image resources]]).<br />
<br />
<br />
==loadRoom ($72)==<br />
<br />
===Encoding===<br />
opcode room[p8]<br />
<br />
===Operation===<br />
Loads the given room into memory.<br />
<br />
<br />
==loadRoomWithEgo ($24)==<br />
<br />
===Encoding===<br />
opcode object[p16] room[p8] x[16] y[16]<br />
<br />
===Operation===<br />
Places the Ego actor in room at object's position. If x is not -1, Ego will start moving towards the given x and y co-ordinates. If object is not in the given room an error will occur.<br />
(I think...)<br />
<br />
<br />
==matrixOp ($30)==<br />
<br />
===Encoding===<br />
opcode sub-opcode<br />
<br />
sub-opcodes:<br />
$01 box[p8] val[p8]<br />
$02 box[p8] val[p8]<br />
$03 box[p8] val[p8]<br />
$04<br />
<br />
===Operation===<br />
This instruction manipulates boxes.<br />
<br />
{| border="1" cellpadding="2" width=100%<br />
|- style="background:whitesmoke"<br />
|Opcode||Meaning||Description<br />
|-<br />
|$01||setBoxFlags||Sets the box's flags to the given value.<br />
|-<br />
|$02||setBoxScale||Sets the box's scale.<br />
|-<br />
|$03||setBoxScale||Sets the box's scale to ((val - 1) OR $8000).<br />
|-<br />
|$04||createBoxMatrix||Initializes the matrix of boxes, by determining the distances and shortest paths between boxes.<br />
|}<br />
<br />
===Variants===<br />
SCUMM V3 only has the one instruction, which behaves like setBoxFlags:<br />
opcode box[p8] val[8]<br />
<br />
<br />
==move ($1A)==<br />
<br />
===Encoding===<br />
opcode result value[p16]<br />
<br />
===Operation===<br />
result := value<br />
<br />
Value is moved into result.<br />
<br />
<br />
==multiply ($1B)==<br />
<br />
===Encoding===<br />
opcode result value[p16]<br />
<br />
===Operation===<br />
result := result * value<br />
<br />
The variable pointed to by result is read, multiplied by value, and written back.<br />
<br />
<br />
==notEqualZero ($A8)==<br />
<br />
===Encoding===<br />
opcode var target[16]<br />
<br />
===Operation===<br />
unless (var != 0) goto target<br />
<br />
Target is a byte offset (measured from after this instruction), which will be added to the instruction pointer.<br />
<br />
<br />
==oldRoomEffect ($5C) (V3-4)==<br />
This opcode/instruction not present in SCUMM V5.<br />
<br />
===Encoding===<br />
opcode sub-opcode<br />
<br />
sub-opcodes:<br />
$03 effect[p16]<br />
$?? effect[p16]<br />
<br />
===Operation===<br />
Performs like sub-opcode SO_ROOM_FADE of the roomOps instruction (fade in if effect != 0, otherwise fade out).<br />
<br />
This information may not be correct; descumm says if the sub-opcode is 3, to "set" the effect, but if the sub-opcode is anything else to fade in with the given effect.<br />
<br />
===Variants===<br />
FM-Towns SCUMM V3 performs a different effect, not fully implemented in ScummVM. At the moment ScummVM just forces a redraw of the screen background.<br />
<br />
<br />
==or ($57)==<br />
one parameter, uses result<br />
<br />
===Encoding===<br />
opcode result value[p16]<br />
<br />
===Operation===<br />
result := result or value<br />
<br />
The variable pointed to by result is read, logically ORed with value, and the result written back.<br />
<br />
<br />
==override ($58)==<br />
<br />
===Encoding===<br />
opcode sub-opcode<br />
<br />
sub-opcodes:<br />
$00<br />
$01 $18 target[16]<br />
<br />
===Operation===<br />
If the sub-opcode is 0, marks the end of an override section.<br><br />
If the sub-opcode is not 0, marks the beginning of an override section. The instruction is immediately followed by a "jumpRelative" instruction.<br><br />
Overrides are used by cutscenes; if a cutscene is skipped (if the user presses the ESC key), the script will jump by the given target (offset from the beginOverride instruction).<br />
<br />
<br />
==panCameraTo ($12)==<br />
<br />
===Encoding===<br />
opcode x[p16]<br />
<br />
===Operation===<br />
Starts the camera panning to the given x co-ordinate.<br />
<br />
<br />
==pickupObject ($25) (v5)==<br />
This instruction is only present in SCUMM V5.<br />
<br />
===Encoding===<br />
opcode object[p16] room[p8]<br />
<br />
===Operation===<br />
Adds the given object (located in the given room) to the Ego actor's inventory.<br />
<br />
===Variants===<br />
In SCUMM V3 and V4, this opcode is used for drawObject.<br />
<br />
<br />
==pickupObject ($50) (V3-4)==<br />
This opcode/instruction is not present in SCUMM V5.<br />
<br />
===Encoding===<br />
opcode object[p16]<br />
<br />
===Operation===<br />
Adds the given object (located in the given room) to the Ego actor's inventory. If object < 1, an error is raised. If the object is not found or the object is already in the inventory, this function ends gracefully.<br />
<br />
<br />
==print ($14)==<br />
<br />
===Encoding===<br />
opcode actor[p8] sub-opcode<br />
<br />
sub-opcodes<br />
$00 xpos[p16] ypos[p16]<br />
$01 colour[p8]<br />
$02 right[p16]<br />
$03 width[p16] height[p16]<br />
$04<br />
$06<br />
$07<br />
$08 offset[p16] delay[p16]<br />
$0F string[c]... $FF<br />
<br />
===Operation===<br />
Sets text properties and displays dialogue.<br />
<br />
{| border="1" cellpadding="2" width=100%<br />
|- style="background:whitesmoke"<br />
|Opcode||Meaning||Description<br />
|-<br />
|$00||SO_AT||Sets the position of the text that follows.<br />
|-<br />
|$01||SO_COLOR||Sets the colour of the text.<br />
|-<br />
|$02||SO_CLIPPED||Clips the text's right-hand side (for wrapping?).<br />
|-<br />
|$03||SO_ERASE||Erases characters (not used in ScummVM).<br />
|-<br />
|$04||SO_CENTER||Centres the text.<br />
|-<br />
|$06||SO_LEFT||Left-aligns the text.<br />
|-<br />
|$07||SO_OVERHEAD||Overhead-aligns the text.<br />
|-<br />
|$0F||SO_TEXTSTRING||Prints the text string that follows. Terminated by $FF.<br />
|}<br />
<br />
===Variants===<br />
In SCUMM V3, text function $06 sets the height of the text:<br />
$06 height[p16]<br />
<br />
In Loom CD (SCUMM V4), there is an additional text function $08 (SO_SAY_VOICE), which plays a portion of the CD audio track.<br />
$08 offset[p16] delay[p16]<br />
<br />
<br />
==printEgo ($D8)==<br />
<br />
===Encoding===<br />
opcode sub-opcode<br />
<br />
===Operation===<br />
Exactly the same as print, except the actor is implicitly Ego. See the entry for "print" for further explanation.<br />
<br />
<br />
==pseudoRoom ($CC)==<br />
<br />
===Encoding===<br />
opcode val[8] res[8]... $00<br />
<br />
===Operation===<br />
forall (res) {<br />
if (res >= $80) {<br />
_resourceMapper[res & $7F] := val<br />
}<br />
}<br />
<br />
What does this actually do? We may never know.<br />
<br />
It looks like res values always have the high bit set, e.g. 0x01 becomes 0x81.<br />
<br />
<br />
==putActor ($01)==<br />
<br />
===Encoding===<br />
opcode actor[p8] x[p16] y[p16]<br />
<br />
===Operation===<br />
Puts the actor at the given co-ordinates.<br />
<br />
<br />
==putActorAtObject ($0E)==<br />
<br />
===Encoding===<br />
opcode actor[p8] object[p16]<br />
<br />
===Operation===<br />
Puts the actor at the given object's position. If the object can not be found, a default position is returned (the centre of the screen in ScummVM).<br />
<br />
<br />
==putActorInRoom ($2D)==<br />
<br />
===Encoding===<br />
opcode actor[p8] room[p8]<br />
<br />
===Operation===<br />
Puts the actor in the given room.<br />
<br />
<br />
==resourceRoutines ($0C)==<br />
<br />
===Encoding===<br />
opcode sub-opcode<br />
<br />
sub-opcodes:<br />
$01 resID[p8]<br />
... $01 through $10 take the same arguments ...<br />
$10 resID[p8]<br />
$11<br />
$12 resID[p8]<br />
$13 resID[p8]<br />
$14 room[p8] object[p16]<br />
<br />
===Operation===<br />
resID is unique only within the resource type (e.g. script 11 will not conflict with sound 11).<br />
<br />
{| border="1" cellpadding="2" width=100%<br />
|- style="background:whitesmoke"<br />
|Opcode||Meaning||Description<br />
|-<br />
|$01||SO_LOAD_SCRIPT||Loads the given script into memory.<br />
|-<br />
|$02||SO_LOAD_SOUND||Loads the given sound into memory.<br />
|-<br />
|$03||SO_LOAD_COSTUME||Loads the given costume into memory.<br />
|-<br />
|$04||SO_LOAD_ROOM||Loads the given room into memory.<br />
|-<br />
|$05||SO_NUKE_SCRIPT||Obliterates the given script from memory.<br />
|-<br />
|$06||SO_NUKE_SOUND||Obliterates the given sound from memory.<br />
|-<br />
|$07||SO_NUKE_COSTUME||Obliterates the given costume from memory.<br />
|-<br />
|$08||SO_NUKE_ROOM||Obliterates the given room from memory.<br />
|-<br />
|$09||SO_LOCK_SCRIPT||Locks the given script.<br />
|-<br />
|$0A||SO_LOCK_SOUND||Locks the given sound.<br />
|-<br />
|$0B||SO_LOCK_COSTUME||Locks the given costume.<br />
|-<br />
|$0C||SO_LOCK_ROOM||Locks the given room.<br />
|-<br />
|$0D||SO_UNLOCK_SCRIPT||Unlocks the given script.<br />
|-<br />
|$0E||SO_UNLOCK_SOUND||Unlocks the given sound.<br />
|-<br />
|$0F||SO_UNLOCK_COSTUME||Unlocks the given costume.<br />
|-<br />
|$10||SO_UNLOCK_ROOM||Unlocks the given room.<br />
|-<br />
|$11||SO_CLEAR_HEAP||Clears the heap.<br />
|-<br />
|$12||SO_LOAD_CHARSET||Loads the given character set into memory.<br />
|-<br />
|$13||SO_NUKE_CHARSET||Obliterates the given character set from memory.<br />
|-<br />
|$14||SO_LOAD_OBJECT||Loads the given object from the given room resource.<br />
|}<br />
<br />
===Variants===<br />
FM-Towns games add the following sub-opcodes (these are not confirmed nor implemented in ScummVM):<br />
{| border="1" cellpadding="2" width=100%<br />
|- style="background:whitesmoke"<br />
|Opcode||Meaning||Description<br />
|-<br />
|$20||Unknown||Does nothing, not used in-game.<br />
|-<br />
|$21||Unknown||Does nothing, not used in-game.<br />
|-<br />
|$23||CD Volume||Possibly changes the volume of CD tracks (Loom CD). Takes 1 byte.<br />
|-<br />
|$24||Sound Volume||Sets the loudness of a sound resource. Used in Indy3 and Zak. Takes 2 bytes (left/right volumes?).<br />
|-<br />
|$25||Sound Pitch||Sets the pitch of a sound resource. Used in Indy3 and Zak. Takes 1 byte (pitch = "foo" - "center" semitones. Center is at $32 in the sound resource.)<br />
|}<br />
<br />
<br />
==roomOps ($33)==<br />
<br />
===Encoding===<br />
opcode sub-opcode<br />
<br />
sub-opcodes:<br />
$01 minX[p16] maxX[p16]<br />
$03 b[p16] h[p16]<br />
$04 red[p16] green[p16] blue[p16] aux index[p8]<br />
$05<br />
$06<br />
$07 scale1[p8] y1[p8] aux scale2[p8] y2[p8] aux slot[p8]<br />
$08 scale[p8] startcolour[p8] endcolour[p8]<br />
$09 loadflag[p8] loadslot[p8]<br />
$0A effect[p16]<br />
$0B redscale[p16] greenscale[p16] bluescale[p16] aux startcolour[p8] endcolour[p8]<br />
$0C redscale[p16] greenscale[p16] bluescale[p16] aux startcolour[p8] endcolour[p8]<br />
$0D resID[p8] filename[c]... $00<br />
$0E resID[p8] filename[c]... $00<br />
$0F resID[p8] aux start[p8] end[p8] aux time[p8]<br />
$10 colindex[p8] delay[p8]<br />
<br />
===Operation===<br />
{| border="1" cellpadding="2" width=100%<br />
|- style="background:whitesmoke"<br />
|Opcode||Meaning||Description<br />
|-<br />
|$01||SO_ROOM_SCROLL||Clamps the given arguments so scrolling does not extend past the width of the room or screen.<br />
|-<br />
|$03||SO_ROOM_SCREEN||Initialises a screen.<br />
|-<br />
|$04||SO_ROOM_PALETTE||Adjusts the room's palette.<br />
|-<br />
|$05||SO_ROOM_SHAKE_ON||Starts the room shaking.<br />
|-<br />
|$06||SO_ROOM_SHAKE_OFF||Ends the room shaking.<br />
|-<br />
|$07||SO_ROOM_SCALE||Sets the room's y scales? (slot is 1 greater than actual slot?)<br />
|-<br />
|$08||SO_ROOM_INTENSITY||Lightens/darkens the room's palette.<br />
|-<br />
|$09||SO_ROOM_SAVEGAME||Saves temporary state of the room/game?<br />
|-<br />
|$0A||SO_ROOM_FADE||If effect is 0, fades in the room. Otherwise, fades out with the given effect (taken from the high byte of effect).<br>1 = iris effect<br>2 = box wipe (upper-left to bottom-right)<br>3 = box wipe (upper-right to bottem-left)<br>4 = inverse box wipe.<br />
|-<br />
|$0B||SO_RGB_ROOM_INTENSITY||Lightens/darkens the room's palette, with different scales for red, green and blue.<br />
|-<br />
|$0C||SO_ROOM_SHADOW||Lightens/darkens the shadow palette, with different scales for red, green, and blue.<br />
|-<br />
|$0D||SO_SAVE_STRING||Saves a string resource to the given file?<br />
|-<br />
|$0E||SO_LOAD_STRING||Loads a string resource from a given file?<br />
|-<br />
|$0F||SO_ROOM_TRANSFORM||Manipulates palettes, strings?<br />
|-<br />
|$10||SO_CYCLE_SPEED||Starts colour cycling with delay? colIndex is between 0 and 16<br />
|}<br />
<br />
===Variants===<br />
SCUMM V3 (non-PC Engine) encodes the arguments before the sub-opcode:<br />
opcode arg1[p16] arg2[p16] sub-opcode<br />
<br />
Small header games (V3 and V4) include an extra sub-opcode, $02 (SO_ROOM_COLOR), which adjusts the room's palette:<br />
opcode $02 colour[p16] index[p16]<br />
... or for V3 games ...<br />
opcode colour[p16] index[p16] $02<br />
<br />
In small header games, sub-opcode $04 (SO_ROOM_PALETTE) affects the shadow palette, and only accepts two arguments, a "room colour slot" (palette entry? between 0 and 256) and an index:<br />
opcode $04 colour[p16] index[p16]<br />
... or for V3 games ...<br />
opcode colour[p16] index[p16] $04<br />
<br />
In FM-Towns games, sub-opcode $0A performs a different function and has its own sub-opcodes (some unknown and all not yet implemented in ScummVM):<br />
opcode $0A sub-opcode<br />
<br />
{| border="1" cellpadding="2" width=100%<br />
|- style="background:whitesmoke"<br />
|Opcode||Meaning||Description<br />
|-<br />
|$08||||compose kMainVirtScreen over a screen buffer<br />
|-<br />
|$09||||call 0x110:0x20 _ax=0x601 _edx=2<br />
|-<br />
|$0A||||call 0x110:0x20 _ax=0x601 _edx=3<br />
|-<br />
|$0B||||clear screen 0x1C:0x45000 sizeof(640 * 320)<br />
|-<br />
|$0C||||call 0x110:0x20 _ax=0x601 _edx=0<br />
|-<br />
|$0D||||call 0x110:0x20 _ax=0x601 _edx=1<br />
|-<br />
|$10||||enable clearing of a screen buffer in drawBitmap()<br />
|-<br />
|$11||||disable clearing of a screen buffer in drawBitmap()<br />
|-<br />
|$12||||clear a screen buffer<br />
|-<br />
|$13||||enable palette operations (palManipulate(), cyclePalette() etc.)<br />
|-<br />
|$14||||disable palette operations<br />
|-<br />
|$15||||disable clearing of screen 0x1C:0x5000 sizeof(640 * 320) in initScreens()<br />
|-<br />
|$16||||enable clearing of screen 0x1C:0x5000 sizeof(640 * 320) in initScreens()<br />
|-<br />
|$1E||||Unknown<br />
|}<br />
<br />
<br />
==saveLoadGame ($22) (V3-4)==<br />
This instruction is not present in SCUMM V5; its opcode is used for "getAnimCounter".<br />
<br />
===Encoding===<br />
opcode result arg1[p8]<br />
<br />
===Operation===<br />
The slot is determined by taking the lower 5 bits of arg1. The upper 3 bits determine an aux opcode, that performs an action described in the table below.<br />
<br />
{| border="1" cellpadding="2" width=100%<br />
|- style="background:whitesmoke"<br />
|Opcode||Meaning||Description<br />
|-<br />
|$00||Num. Available Slots||Returns the number of save slots available.<br />
|-<br />
|$20||Drive||In V3, returns the type of drive (0 = ???, 1 = A or B [floppy], 2 = hard drive).<br>In V4, sets the current drive (returns 1).<br />
|-<br />
|$40||Load Game||Loads a game from the given slot (returns 3 if successful, 5 otherwise).<br />
|-<br />
|$80||Save Game||Saves a game to the given slot (returns 0 if successful, 2 otherwise).<br />
|-<br />
|$C0||Test For Game||Tests if a save exists in the given slot (returns 6 if so, 7 otherwise).<br />
|}<br />
<br />
<br />
==saveLoadVars ($A7) (V3-4)==<br />
This instruction is not present in SCUMM V5; its opcode is used as a dummy.<br />
<br />
===Encoding===<br />
opcode sub-opcode<br />
<br />
sub-opcodes:<br />
$01 sub-sub-opcode... $00<br />
$02 sub-sub-opcode... $00<br />
<br />
$01 (save) sub-sub-opcodes:<br />
$01 resultA resultB<br />
$02 arg1[p8] arg2[p8]<br />
$03 filename[c]... $00<br />
$04<br />
$1F<br />
<br />
$02 (load) sub-sub-opcodes:<br />
$01 resultA resultB<br />
$02 arg1[p8] arg2[p8]<br />
$03 filename[c]... $00<br />
$04<br />
$1F<br />
<br />
===Operation===<br />
{| border="1" cellpadding="2" width=100%<br />
|- style="background:whitesmoke"<br />
|Opcode||Meaning||Description<br />
|-<br />
|$01||SO_SAVE_VARS||Saves variables (for saving games?)<br />
|-<br />
|$02?||SO_RESTORE_VERBS||Loads variables (for saving games?)<br>(I have not verified that restore vars is $02, as the ScummVM code only compares to $01.)<br />
|}<br />
<br />
{| border="1" cellpadding="2" width=100%<br />
|- style="background:whitesmoke"<br />
|Opcode||Meaning||Description<br />
|-<br />
|$01||Write Vars||Writes a range of variables.<br />
|-<br />
|$02||Write Strings||Writes a range of string variables.<br />
|-<br />
|$03||Open File||Opens a file for writing.<br />
|-<br />
|$04||Dummy||Does nothing.<br />
|-<br />
|$1F||Close File||Closes the last opened file.<br />
|}<br />
<br />
{| border="1" cellpadding="2" width=100%<br />
|- style="background:whitesmoke"<br />
|Opcode||Meaning||Description<br />
|-<br />
|$01||Read Vars||Reads a range of variables.<br />
|-<br />
|$02||Read Strings||Reads a range of string variables.<br />
|-<br />
|$03||Open File||Opens a file for reading.<br />
|-<br />
|$04||Dummy||Does nothing.<br />
|-<br />
|$1F||Close File||Closes the last opened file.<br />
|}<br />
<br />
<br />
==saveRestoreVerbs ($AB)==<br />
<br />
===Encoding=== <br />
opcode sub-opcode<br />
<br />
sub-opcodes: <br />
$01 start[p8] end[p8] mode[p8]<br />
$02 start[p8] end[p8] mode[p8]<br />
$03 start[p8] end[p8] mode[p8]<br />
<br />
===Operation===<br />
{| border="1" cellpadding="2" width=100%<br />
|- style="background:whitesmoke"<br />
|Opcode||Meaning||Description<br />
|-<br />
|$01||SO_SAVE_VERBS||For all verbs between start and end, sets the "saveid" to mode. <br />
|-<br />
|$02||SO_RESTORE_VERBS||For all verbs between start and end and matching mode, kills any existing verb, sets the saveid to 0 and generally inits the verb.<br />
|-<br />
|$03||SO_DELETE_VERBS||For all verbs between start and end and matching mode, kills any existing verb.<br />
|}<br />
<br />
<br />
==setCameraAt ($32)==<br />
<br />
===Encoding===<br />
opcode x[p16]<br />
<br />
===Operation===<br />
Sets the camera's x position.<br />
<br />
<br />
==setObjectName ($54)==<br />
<br />
===Encoding===<br />
opcode object[p16] name[c]... $00<br />
<br />
===Operation===<br />
Sets the given object's name.<br />
<br />
<br />
==setOwnerOf ($29)==<br />
<br />
===Encoding===<br />
opcode object[p16] owner[p8]<br />
<br />
===Operation===<br />
Sets the owner of the object.<br />
<br />
<br />
==setState ($07)==<br />
<br />
===Encoding===<br />
opcode object[p16] state[p8]<br />
<br />
===Operation===<br />
Sets the state of the object.<br />
<br />
<br />
==setVarRange ($26)==<br />
non-standard encoding<br />
<br />
===Encoding===<br />
opcode result number[8] values[8]...<br />
or<br />
opcode result number[8] values[16]...<br />
<br />
===Operation===<br />
for (i = 0; i < number; i++) {<br />
&#42;result + i := values[i];<br />
}<br />
<br />
This sets a number of variables to the given parameters. The starting variable is given as "result", and the number of variables to modify is given as "number". This is followed by the same number of values, which will be put into the variable locations. The values are constants, and can be either 16-bit, if the highest bit of the opcode is set, i.e. $A6; or 8-bit, if the highest bit of the opcode is not set, i.e. $26. Note that all values are affected by the opcode's high bit; you can't mix 8 and 16-bit values.<br />
<br />
descumm example:<br />
setVarRange(Var[178],9,[0,0,0,0,0,0,0,0,0]);<br />
<br />
This sets variables 178 to 186 (inclusive) to 0.<br />
<br />
<br />
==soundKludge ($4C)==<br />
<br />
===Encoding===<br />
opcode items[v16]...<br />
<br />
===Operation===<br />
If the first item is -1, the existing sound queue is processed. Otherwise, the list of items is added to the queue.<br />
<br />
===Variants===<br />
In SCUMM V3 and V4 (small header) games, this opcode is used for the WaitForSentence instruction.<br />
<br />
<br />
==startMusic ($02)==<br />
<br />
===Encoding===<br />
opcode music[p8]<br />
<br />
===Operation===<br />
Adds the music in to the queue to be played.<br />
<br />
===Variants===<br />
In FM-Towns (SCUMM V3) games, this instruction performs different functions (some kind of Audio CD status query function; some partially implemented in ScummVM):<br />
opcode result sub-opcode<br />
<br />
{| border="1" cellpadding="2" width=100%<br />
|- style="background:whitesmoke"<br />
|Opcode||Meaning||Description<br />
|-<br />
|$00||Is Playing||Returns true if a CD audio track is currently playing.<br />
|-<br />
|$FC||Unpause CD||Unpauses the CD audio track.<br />
|-<br />
|$FD||Pause CD||Pauses the CD audio track.<br />
|-<br />
|$FE||Get CD Sound||Returns the current CD sound.<br />
|-<br />
|$FF||CD Volume||Might return the the current CD volume in FM-Towns Loom.<br />
|-<br />
|other||Track Length||Returns the track length in seconds.<br />
|}<br />
<br />
<br />
==startObject ($37)==<br />
<br />
===Encoding===<br />
opcode object[p16] script[p8] args[v16]...<br />
<br />
===Operation===<br />
Starts the object's script (OBCD blocks), passing the given arguments.<br />
<br />
<br />
==startScript ($0A)==<br />
one parameter plus varargs, extra encoding in opcode<br />
<br />
===Encoding===<br />
opcode script[p8] args[v16]...<br />
<br />
===Operation===<br />
Spawns a new thread running the code in script script. The new script has its local variables initialised to the list args. Uninitialised variables have undefined values.<br />
<br />
The opcode carries extra information: <br />
<br />
{| border="1" cellpadding="2" width=10%<br />
|- style="background:whitesmoke"<br />
|7||6||5||4 0<br />
|-<br />
|P1||R||F||$0A<br />
|}<br />
<br />
P1 = standard parameter bit<br><br />
R = indicates that the script is recursive<br><br />
F = indicates that the script is freeze resistant (a call to freezeScripts will skip this script, unless the "force freeze" bit of the freezeScripts opcode is set).<br />
<br />
<br />
==startSound ($1C)==<br />
<br />
===Encoding===<br />
opcode sound[p8]<br />
<br />
===Operation===<br />
Adds the given sound to the sound queue to be played.<br />
<br />
<br />
==stopMusic ($20)==<br />
<br />
===Encoding===<br />
opcode<br />
<br />
===Operation===<br />
Stops all sounds.<br />
<br />
<br />
==stopObjectCode ($A0 or $00)==<br />
<br />
===Encoding===<br />
opcode<br />
<br />
===Operation===<br />
Marks the calling script as dead, to be later pruned from the thread pool. Cleans up residual arrays. Should always be the last instruction in a script.<br />
<br />
$A0 is used in local and global scripts (LSCR and SCRP blocks in the V5 resource files), $00 is used in room entry, room exit, and verb/object scripts (ENCD, EXCD, VERB blocks).<br />
<br />
<br />
==stopObjectScript ($6E)==<br />
<br />
===Encoding===<br />
opcode script[p16]<br />
<br />
===Operation===<br />
Marks the given object script as dead, to be later pruned from the thread pool. Cleans up residual arrays.<br />
<br />
<br />
==stopScript ($62)==<br />
<br />
===Encoding===<br />
opcode script[p8]<br />
<br />
===Operation===<br />
Marks the given script as dead, to be later pruned from the thread pool. Cleans up residual arrays.<br />
<br />
<br />
==stopSound ($3C)==<br />
<br />
===Encoding===<br />
opcode sound[p8]<br />
<br />
===Operation===<br />
Stops the given sound.<br />
<br />
<br />
==stringOps ($27)==<br />
parameters depend on sub-opcode<br />
<br />
===Encoding===<br />
opcode sub-opcode<br />
<br />
sub-opcodes:<br />
$01 stringID[p8] string[c]... $00<br />
$02 destID[p8] srcID[p8]<br />
$03 stringID[p8] index[p8] char[c]<br />
$04 result stringID[p8] index[p8]<br />
$05 stringID[p8] size[p8]<br />
<br />
===Operation===<br />
Miscellaneous actions on strings (Arrays, referred to by resource number).<br />
<br />
{| border="1" cellpadding="2" width=100%<br />
|- style="background:whitesmoke"<br />
|Opcode||Meaning||Description<br />
|-<br />
|$01||Load String||Loads the inline null-terminated string into the resource slot given by stringID.<br />
|-<br />
|$02||Copy String||Creates a duplicate of the string at resource slot srcID into destID. The old string at destID is lost.<br />
|-<br />
|$03||Write Character||Writes char at the given index (offset) of the string resource located at slot stringID. Out of bounds accesses cause undefined behaviour.<br />
|-<br />
|$04||Read Character||Reads a byte (character) at the given index (offset) of the string resource located at slot stringID, and writes it to result. Out of bounds accesses cause undefined behaviour.<br />
|-<br />
|$05||New String||Allocates or frees a string (Array), located at resource slot stringID. The string is initialised to size; if size is zero, the string is freed.<br />
|}<br />
<br />
<br />
==subtract ($3A)==<br />
<br />
===Encoding===<br />
opcode result value[p16]<br />
<br />
===Operation===<br />
result := result - value<br />
<br />
The variable pointed to by result is read, value is subtracted from it, and the result written back.<br />
<br />
<br />
==systemOps ($98)==<br />
<br />
===Encoding===<br />
opcode sub-opcode<br />
<br />
sub-opcodes:<br />
$01<br />
$02<br />
$03<br />
<br />
===Operation===<br />
{| border="1" cellpadding="2" width=100%<br />
|- style="background:whitesmoke"<br />
|Opcode||Meaning||Description<br />
|-<br />
|$01||SO_RESTART||Restarts the game.<br />
|-<br />
|$02||SO_PAUSE||Pauses/unpauses the game.<br />
|-<br />
|$03||SO_QUIT||Quits the game.<br />
|}<br />
<br />
<br />
==verbOps ($7A)==<br />
<br />
===Encoding===<br />
opcode verbID[p8] sub-opcode... $FF<br />
<br />
sub-opcodes:<br />
$01 object[p16]<br />
$02 name[c]... $00<br />
$03 colour[p8]<br />
$04 hicolour[p8]<br />
$05 left[p16] top[p16]<br />
$06<br />
$07<br />
$08<br />
$09<br />
$10 colour[p8]<br />
$11<br />
$12 key[p8]<br />
$13<br />
$14 stringID[p16]<br />
$16 object[p16] room[p8]<br />
$17 colour[p8]<br />
<br />
===Operation===<br />
{| border="1" cellpadding="2" width=100%<br />
|- style="background:whitesmoke"<br />
|Opcode||Meaning||Description<br />
|-<br />
|$01||SO_VERB_IMAGE||Assigns an object (image) to a verb.<br />
|-<br />
|$02||SO_VERB_NAME||Assigns the in-line name to the verb slot.<br />
|-<br />
|$03||SO_VERB_COLOR||Sets the colour of the verb.<br />
|-<br />
|$04||SO_VERB_HICOLOR||Sets the highlight colour of the verb.<br />
|-<br />
|$05||SO_VERB_AT||Sets the verb's top-left co-ordinates.<br />
|-<br />
|$06||SO_VERB_ON||Makes this verb active.<br />
|-<br />
|$07||SO_VERB_OFF||Makes this verb inactive.<br />
|-<br />
|$08||SO_VERB_DELETE||Kills this verb.<br />
|-<br />
|$09||SO_VERB_NEW||Creates a verb in the slot for the given verbID. If the slot is 0 (verb doesn't already exist), will add it to the next unusued slot; if this exceeds the global maximum number of verbs an error will be raised.<br />
|-<br />
|$10||SO_VERB_DIMCOLOR||Sets the dim colour of the verb.<br />
|-<br />
|$11||SO_VERB_DIM||Dims this verb.<br />
|-<br />
|$12||SO_VERB_KEY||Sets the key code (maybe ASCII char?) associated with this verb.<br />
|-<br />
|$13||SO_VERB_CENTER||Centres the verb?<br />
|-<br />
|$14||SO_VERB_NAME_STR||Loads the given string resource into the verb's slot. If either the string resource or verb slot is not found (0), the verb resource is nuked.<br />
|-<br />
|$16||Assign Object||Assigns an object from the given room to the verb (if the object's image index is not already assigned to the given object).<br />
|-<br />
|$17||Set Back Colour||Sets the background colour of the verb?<br />
|}<br />
<br />
<br />
==wait ($AE)==<br />
<br />
===Encoding===<br />
opcode sub-opcode<br />
<br />
sub-opcodes:<br />
$01 actor[p8]<br />
$02 <br />
$03<br />
$04<br />
<br />
===Operation===<br />
{| border="1" cellpadding="2" width=100%<br />
|- style="background:whitesmoke"<br />
|Opcode||Meaning||Description<br />
|-<br />
|$01||SO_WAIT_FOR_ACTOR||If the given actor is moving, breaks and resumes at this instruction again.<br />
|-<br />
|$02||SO_WAIT_FOR_MESSAGE||If the global variable VAR_HAVE_MSG (Var[3]) is not zero, breaks and resumes at this instruction again.<br />
|-<br />
|$03||SO_WAIT_FOR_CAMERA||If the camera has not reached its destination x position, breaks and resumes at this instruction again.<br />
|-<br />
|$04||SO_WAIT_FOR_SENTENCE||If there is a sentence present?, breaks and resumes at this instruction again<br />
|}<br />
<br />
===Variants===<br />
In Indy3 (non-Macintosh), this opcode only acts as SO_WAIT_FOR_MESSAGE and omits the sub-opcode.<br />
opcode<br />
<br />
<br />
==walkActorTo ($1E)==<br />
<br />
===Encoding===<br />
opcode actor[p8] x[p16] y[p16]<br />
<br />
===Operation===<br />
Sets the actor to begin walking to the given position.<br />
<br />
<br />
==walkActorToActor ($0D)==<br />
<br />
===Encoding===<br />
opcode walker[p8] walkee[p8] distance[8]<br />
<br />
===Operation===<br />
Walks walker towards walkee's position by the given distance. Walker and walkee are both actors.<br />
<br />
<br />
==walkActorToObject ($36)==<br />
<br />
===Encoding===<br />
opcode actor[p8] object[p16]<br />
<br />
===Operation===<br />
Sets the actor to begin walking to the given object's position.<br />
<br />
=Variables=<br />
<br />
A number of variables are reserved for use by the SPUTM/SCUMM engine. Here is a list of known variables and their corresponding numbers, taken from the ScummVM source code.<br />
<br />
VAR_RESULT = 0; // descumm claims var 0 is the result var (for expressions)<br />
VAR_KEYPRESS = 0; // script_v5_.cpp claims var 0 is for keypresses...<br />
VAR_EGO = 1;<br />
VAR_CAMERA_POS_X = 2;<br />
VAR_HAVE_MSG = 3;<br />
VAR_ROOM = 4;<br />
VAR_OVERRIDE = 5;<br />
VAR_MACHINE_SPEED = 6;<br />
VAR_ME = 7;<br />
VAR_NUM_ACTOR = 8;<br />
VAR_CURRENT_LIGHTS = 9;<br />
VAR_CURRENTDRIVE = 10;<br />
VAR_TMR_1 = 11;<br />
VAR_TMR_2 = 12;<br />
VAR_TMR_3 = 13;<br />
VAR_MUSIC_TIMER = 14;<br />
VAR_ACTOR_RANGE_MIN = 15;<br />
VAR_ACTOR_RANGE_MAX = 16;<br />
VAR_CAMERA_MIN_X = 17;<br />
VAR_CAMERA_MAX_X = 18;<br />
VAR_TIMER_NEXT = 19;<br />
VAR_VIRT_MOUSE_X = 20;<br />
VAR_VIRT_MOUSE_Y = 21;<br />
VAR_ROOM_RESOURCE = 22;<br />
VAR_LAST_SOUND = 23;<br />
VAR_CUTSCENEEXIT_KEY = 24;<br />
VAR_TALK_ACTOR = 25;<br />
VAR_CAMERA_FAST_X = 26;<br />
VAR_SCROLL_SCRIPT = 27;<br />
VAR_ENTRY_SCRIPT = 28;<br />
VAR_ENTRY_SCRIPT2 = 29;<br />
VAR_EXIT_SCRIPT = 30;<br />
VAR_EXIT_SCRIPT2 = 31;<br />
VAR_VERB_SCRIPT = 32;<br />
VAR_SENTENCE_SCRIPT = 33;<br />
VAR_INVENTORY_SCRIPT = 34;<br />
VAR_CUTSCENE_START_SCRIPT = 35;<br />
VAR_CUTSCENE_END_SCRIPT = 36;<br />
VAR_CHARINC = 37;<br />
VAR_WALKTO_OBJ = 38;<br />
VAR_DEBUGMODE = 39;<br />
VAR_HEAPSPACE = 40;<br />
VAR_RESTART_KEY = 42;<br />
VAR_PAUSE_KEY = 43;<br />
VAR_MOUSE_X = 44;<br />
VAR_MOUSE_Y = 45;<br />
VAR_TIMER = 46;<br />
VAR_TIMER_TOTAL = 47;<br />
VAR_SOUNDCARD = 48;<br />
VAR_VIDEOMODE = 49;<br />
VAR_MAINMENU_KEY = 50;<br />
VAR_FIXEDDISK = 51;<br />
VAR_CURSORSTATE = 52;<br />
VAR_USERPUT = 53;<br />
VAR_V5_TALK_STRING_Y = 54;<br />
VAR_SOUNDRESULT = 56;<br />
VAR_TALKSTOP_KEY = 57;<br />
VAR_FADE_DELAY = 59;<br />
VAR_NOSUBTITLES = 60;<br />
VAR_SOUNDPARAM = 64;<br />
VAR_SOUNDPARAM2 = 65;<br />
VAR_SOUNDPARAM3 = 66;<br />
VAR_INPUTMODE = 67; // 1 is keyboard, 2 is joystick, 3 is mouse<br />
VAR_MEMORY_PERFORMANCE = 68;<br />
VAR_VIDEO_PERFORMANCE = 69;<br />
VAR_ROOM_FLAG = 70;<br />
VAR_GAME_LOADED = 71;<br />
VAR_NEW_ROOM = 72;<br />
<br />
<br />
=Table of Parameters=<br />
Please see the wiki page [[SCUMM/V5_opcodes/Table]] for a concise rendition of the above information (with a few omissions dues to the complexity of the instructions).</div>Jestar jokinhttps://wiki.scummvm.org/index.php?title=SCUMM/V5_opcodes&diff=11079SCUMM/V5 opcodes2009-05-17T13:43:00Z<p>Jestar jokin: actorOps - differences in V3-4. stopObjectCode - explained when $00 is used.</p>
<hr />
<div>=SCUMM V5 opcodes=<br />
The following conventions are used in the encoding descriptions.<br />
<br />
{| border="1" cellpadding="2" width=100%<br />
|- style="background:whitesmoke"<br />
|Term||Description<br />
|-<br />
|opcode||The instruction's opcode, with the appropriate bits set according to the parameters.<br />
|-<br />
|aux||An aux opcode that stores parameter bits and no other information. (the base aux opcode seems to always be $01)<br />
|-<br />
|sub-opcode||An aux opcode that indicates a specific function to perform (e.g. the "wait" instruction has sub-opcodes to "wait for message", "wait for actor" etc), as well as storing parameter bits if necessary.<br />
|-<br />
|result||A result pointer. (A standard word pointer, always a LE word.)<br />
|-<br />
|var||A variable pointer. Same as above, but is not written to. Because this is always a variable, the opcode is not affected like it would be with a normal parameter (described below).<br />
|-<br />
|value[8]||An 8-bit constant (a byte).<br />
|-<br />
|value[16]||A 16-bit constant (a word LE).<br />
|-<br />
|value[p8]||An 8-bit parameter. This may be encoded as a word LE if it's a pointer, or a byte if it's a constant.<br />
|-<br />
|value[p16]||A 16-bit parameter. This is always encoded as a word LE, and may be a pointer or constant.<br />
|-<br />
|value[v16]||A variable number of word LE parameters. These are encoded as a sequence of aux[8] param[p16]; param; aux contains the parameter bit to describe param (and is always $01, ignoring the parameter bits). A byte of $FF terminates the sequence. (actually always shown as "value[v16]...")<br />
|-<br />
|value[o]||The offset word for parameter value. This is only encoded if needed, but always at the position indicated. If not specified, the offset word occurs immediately after the parameter.<br />
|-<br />
|value[c]||An ASCII character. Because some instructions use null-terminated strings and some use $FF, the exact format of a string is described in the instruction. Almost always appears as "value[c]..."<br />
|-<br />
|term...||One or more terms.<br />
|}<br />
<br />
Of course, due to the non-orthogonality of the opcodes, there are lots of exceptions.<br />
<br />
<br />
==actorFollowCamera ($52)==<br />
<br />
===Encoding===<br />
opcode actor[p8]<br />
<br />
===Operation===<br />
Sets the camera to follow the given actor?<br />
<br />
<br />
==actorFromPos ($15)==<br />
<br />
===Encoding===<br />
opcode result x[p16] y[p16]<br />
<br />
===Operation===<br />
Returns the actor located at the given co-ordinates.<br />
<br />
<br />
==actorOps ($13)==<br />
parameters depend on auxiliary opcode; terminated by $FF<br />
<br />
===Encoding===<br />
opcode actor[p8] sub-opcode... $FF<br />
<br />
sub-opcodes:<br />
$00 arg1[p8]<br />
$01 costume[p8]<br />
$02 xspeed[p8] yspeed[p8]<br />
$03 sound[p8]<br />
$04 walkframe[p8]<br />
$05 starttalk[p8] endtalk[p8]<br />
$06 standframe[p8]<br />
$07 arg1[p8] arg2[p8] arg3[p8]<br />
$08<br />
$09 elevation[p16]<br />
$0A<br />
$0B index[p8] value[p8]<br />
$0C colour[p8]<br />
$0D name[c]... $00<br />
$0E initframe[p8]<br />
$10 width[p8]<br />
$11 xscale[p8] yscale[p8]<br />
$12<br />
$13 zplane[p8]<br />
$14<br />
$15 <br />
$16 animspeed[p8]<br />
$17 shadow[p8]<br />
<br />
===Operation===<br />
Miscellaneous actions on actors.<br />
<br />
{| border="1" cellpadding="2" width=100%<br />
|- style="background:whitesmoke"<br />
|Opcode||Meaning||Description<br />
|-<br />
|$00||dummy||A dummy case, does nothing (in ScummVM).<br />
|-<br />
|$01||SO_COSTUME||Sets the actor's costume.<br />
|-<br />
|$02||SO_STEP_DIST||Sets the actor's walking speed for x and y.<br />
|-<br />
|$03||SO_SOUND||Associates a sound with the actor (footsteps?)<br />
|-<br />
|$04||SO_WALK_ANIMATION||Sets the current frame of the walking animation.<br />
|-<br />
|$05||SO_TALK_ANIMATION||Sets the start and stop frames of the talking animation.<br />
|-<br />
|$06||SO_STAND_ANIMATION||Sets the current frame of the standing animation.<br />
|-<br />
|$07||SO_ANIMATION||Unknown; seems to be unused in ScummVM.<br />
|-<br />
|$08||SO_DEFAULT||Initializes actor.<br />
|-<br />
|$09||SO_ELEVATION||Sets the actor's elevation to the given value.<br />
|-<br />
|$0A||SO_ANIMATION_DEFAULT||Initializes the actor's animation frames.<br>Init frame = 1<br>Walk frame = 2<br>Stand frame = 3<br>Talk start frame = 4<br>Talk stop frame = 5<br />
|-<br />
|$0B||SO_PALETTE||Sets the colour at the given index to a new value (another entry in the colour lookup table/CLUT). Index must be between 0 and 31 (the number of colours in a costume).<br />
|-<br />
|$0C||SO_TALK_COLOR||Sets the actor's talk colour.<br />
|-<br />
|$0D||SO_ACTOR_NAME||Sets the actor's name to the given null-terminated string.<br />
|-<br />
|$0E||SO_INIT_ANIMATION||Sets the current frame of the initial animation.<br />
|-<br />
|$10||SO_ACTOR_WIDTH||Sets the actor's width.<br />
|-<br />
|$11||SO_ACTOR_SCALE||Sets the actor's X and Y scales.<br />
|-<br />
|$12||SO_NEVER_ZCLIP||Turns off all Z-clipping for the actor.<br />
|-<br />
|$13||SO_ALWAYS_ZCLIP||Forces the actor's Z-clipping for the given Z-plane?<br />
|-<br />
|$14||SO_IGNORE_BOXES||Ignores boxes, turns off Z-clipping, and puts actor somewhere if the actor is in the current room?<br />
|-<br />
|$15||SO_FOLLOW_BOXES||Follows boxes, turns off Z-clipping, and puts actor somewhere if the actor is in the current room?<br />
|-<br />
|$16||SO_ANIMATION_SPEED||Sets the animation speed.<br />
|-<br />
|$17||SO_SHADOW||Sets the shadow mode.<br />
|}<br />
<br />
===Variants===<br />
In SCUMM V3 and V4, the opcode values are slightly different.<br />
<br />
{| border="1" cellpadding="2" width=100%<br />
|- style="background:whitesmoke"<br />
|Opcode||Meaning||Description<br />
|-<br />
|$00||dummy<br />
|-<br />
|$01||SO_COSTUME<br />
|-<br />
|$04||SO_STEP_DIST<br />
|-<br />
|$05||SO_SOUND<br />
|-<br />
|$06||SO_WALK_ANIMATION<br />
|-<br />
|$07||SO_TALK_ANIMATION<br />
|-<br />
|$08||SO_STAND_ANIMATION<br />
|-<br />
|$09||SO_ANIMATION<br />
|-<br />
|$0A||SO_DEFAULT<br />
|-<br />
|$0B||SO_ELEVATION<br />
|-<br />
|$0C||SO_ANIMATION_DEFAULT<br />
|-<br />
|$0D||SO_PALETTE<br />
|-<br />
|$0E||SO_TALK_COLOR<br />
|-<br />
|$0F||SO_ACTOR_NAME<br />
|-<br />
|$10||SO_INIT_ANIMATION<br />
|-<br />
|$12||SO_ACTOR_WIDTH<br />
|-<br />
|$13||SO_ACTOR_SCALE<br />
|-<br />
|$14||SO_IGNORE_BOXES<br />
|}<br />
<br />
Also in V3 and V4, sub-opcode $13 (SO_ACTOR_SCALE) only takes one parameter, so X and Y scaling is done at a 1:1 ratio.<br />
<br />
<br />
==actorSetClass ($5D)==<br />
<br />
===Encoding===<br />
opcode object[p16] classes[v16]...<br />
<br />
===Operation===<br />
Makes object inherit from all of the given classes. A class of "0" will clear all of the object's existing class data.<br />
<br />
<br />
==add ($5A)==<br />
<br />
===Encoding===<br />
opcode result value[p16]<br />
<br />
===Operation===<br />
result := result + value<br />
<br />
The variable pointed to by result is read, value is added to it, and the result written back.<br />
<br />
<br />
==and ($17)==<br />
one parameter, uses result<br />
<br />
===Encoding===<br />
opcode result value[p16]<br />
<br />
===Operation===<br />
result := result and value<br />
<br />
The variable pointed to by result is read, logically ANDed with value, and the result written back.<br />
<br />
<br />
==animateActor ($11)==<br />
<br />
===Encoding===<br />
opcode actor[p8] anim[p8]<br />
<br />
===Operation===<br />
Starts the given animation for the given actor.<br />
<br />
<br />
==breakHere ($80)==<br />
no parameters<br />
<br />
===Encoding===<br />
opcode<br />
<br />
===Operation===<br />
Deschedules the currently running thread. Execution continues at the next instruction when the thread's next timeslot comes around.<br />
<br />
<br />
==chainScript ($42)==<br />
one parameter plus varargs<br />
<br />
===Encoding===<br />
opcode script[p8] args[v16]...<br />
<br />
===Operation===<br />
Replaces the currently running script with another one. The current script is terminated immediately and the new script (determined by the given script ID), is executed in the same thread. The new script has its local variables initialised to the list args. Uninitialised variables have undefined values.<br />
<br />
<br />
==cursorCommand ($2C)==<br />
parameters depend on auxiliary opcode<br />
<br />
===Encoding===<br />
opcode sub-opcode<br />
<br />
sub-opcode can be any of the following:<br />
$01<br />
... $01 through $08 take the same arguments ...<br />
$08<br />
$0A cursornum[p8] charletter[p8]<br />
$0B index[p8] x[p8] y[p8]<br />
$0C cursor[p8]<br />
$0D charset[p8]<br />
$0E colours[v16]...<br />
<br />
===Operation===<br />
Miscellaneous actions on cursors & charsets.<br />
<br />
{| border="1" cellpadding="2" width=100%<br />
|- style="background:whitesmoke"<br />
|Opcode||Meaning||Description<br />
|-<br />
|$01||SO_CURSOR_ON||Turns the cursor on.<br />
|-<br />
|$02||SO_CURSOR_OFF||Turns the cursor off.<br />
|-<br />
|$03||SO_USERPUT_ON||Enables user input.<br />
|-<br />
|$04||SO_USERPUT_OFF||Disables user input.<br />
|-<br />
|$05||SO_CURSOR_SOFT_ON||Increments the cursor's state?<br />
|-<br />
|$06||SO_CURSOR_SOFT_OFF||Decrements the cursor's state?<br />
|-<br />
|$07||SO_USERPUT_SOFT_ON||Increments "user input" counter (when greater than 0, user input is enabled).<br />
|-<br />
|$08||SO_USERPUT_SOFT_OFF||Decrements "user input" counter (when 0 or less, user input is disabled).<br />
|-<br />
|$0A||SO_CURSOR_IMAGE||Changes the cursor image to a new one, based on image in a character set. Only used in Loom.<br />
|-<br />
|$0B||SO_CURSOR_HOTSPOT||Changes the hotspot of a cursor. Only used in Loom.<br />
|-<br />
|$0C||SO_CURSOR_SET||Changes the current cursor. Must be between 0 and 3 inclusive.<br />
|-<br />
|$0D||SO_CHARSET_SET||Initializes the given character set.<br />
|-<br />
|$0E||SO_CHARSET_COLORS||Initializes the character set data & colours to the given arguments? Must have 16 arguments?<br />
|}<br />
<br />
===Variants===<br />
In SCUMM V3, sub-opcode $0E performs a different function, to load/initialize a character set.<br />
<br />
opcode $0E arg1[p8] arg2[p8]<br />
<br />
<br />
==cutScene ($40)==<br />
<br />
===Encoding===<br />
opcode args[v16]...<br />
<br />
===Operation===<br />
??? If required, runs a script passing the given arguments. Cutscene data given by the first argument?<br />
<br />
<br />
==debug ($6B)==<br />
one parameter, no result<br />
<br />
===Encoding===<br />
opcode param[p16]<br />
<br />
===Operation===<br />
Passes the parameter to the interpreter's debugger. What this does is entirely platform-specific (and may do nothing).<br />
<br />
<br />
==decrement ($C6)==<br />
no parameters, uses result<br />
<br />
===Encoding===<br />
opcode result<br />
<br />
===Operation===<br />
result := result - 1<br />
<br />
Reads the variable pointed to by result, decrements it, and writes it back. <br />
<br />
<br />
==delay ($2E)==<br />
one constant parameter<br />
<br />
===Encoding===<br />
opcode param[24]<br />
<br />
===Operation===<br />
Suspends the current thread for the appropriate number of 1/60ths of a second. Yes, that really is a 24-bit LE constant.<br />
<br />
<br />
==delayVariable ($2B)==<br />
one constant parameter<br />
<br />
===Encoding===<br />
opcode var<br />
<br />
===Operation===<br />
var is dereferenced and the current thread suspended for that number of 1/60ths of a second.<br />
<br />
<br />
==divide ($5B)==<br />
one parameter, uses result<br />
<br />
===Encoding===<br />
opcode result value[p16]<br />
<br />
===Operation===<br />
result := result / value<br />
<br />
The variable pointed to by result is read, divided by value, and the result written back. If value is zero, the result is undefined (and the interpeter may halt with an error). <br />
<br />
<br />
==doSentence ($19)==<br />
<br />
===Encoding===<br />
opcode verb[p8] objectA[p16] objectB[p16]<br />
<br />
===Operation===<br />
Performs a verb sentence action, e.g. "Use monkey on hydrant". If verb is $FE, the current sentence script is stopped, status cleared etc.<br />
<br />
<br />
==drawBox ($3F)==<br />
two parameters, does not use result, supplementary opcode byte with three more subsequent parameters<br />
<br />
===Encoding===<br />
opcode left[p16] top[p16] auxopcode[8] right[p16] bottom[p16] colour[p8]<br />
<br />
===Operation===<br />
Draws a solid box on the backbuffer from (left, top) to (right, bottom) in the given colour.<br />
<br />
The only part of auxopcode that is relevant are the parameter bits. The rest of the opcode is ignored. <br />
<br />
<br />
==drawObject ($05)==<br />
<br />
===Encoding===<br />
opcode object[p16] sub-opcode<br />
<br />
sub-opcodes:<br />
$01 xpos[p16] ypos[p16]<br />
$02 state[p16]<br />
$1F<br />
<br />
===Operation===<br />
{| border="1" cellpadding="2" width=100%<br />
|- style="background:whitesmoke"<br />
|Opcode||Meaning||Description<br />
|-<br />
|$01||Draw At||Moves the given object to the given co-ordinates, and adds it to the drawing queue.<br />
|-<br />
|$02||Set State||Sets the state of the object, adds it to the drawing queue.<br />
|-<br />
|$1F||Draw||Does not change the object's position (or state?), still adds it to the drawing queue.<br />
|}<br />
<br />
===Variants===<br />
Small header games (v3 and v4) only support the parameters used with sub-opcode $01, e.g:<br />
opcode object[p16] xpos[p16] ypos[p16]<br />
Accordingly, they have three parameter bits, and hence more possible opcodes.<br />
<br />
<br />
==dummy ($A7)==<br />
<br />
===Encoding===<br />
opcode<br />
<br />
===Operation===<br />
V5 specific - The KIXX XL release of Monkey Island 2 (Amiga disk) used this opcode as a dummy, in order to remove copy protection and keep level selection.<br />
<br />
===Variants===<br />
In SCUMM V3 and V4, this opcode is used for the saveLoadVars instruction.<br />
<br />
<br />
==endCutScene ($C0)==<br />
<br />
===Encoding===<br />
opcode<br />
<br />
===Operation===<br />
Ends the cutscene, performing cleanup if necessary.<br />
<br />
<br />
==equalZero ($28)==<br />
jumps<br />
<br />
===Encoding===<br />
opcode var target[16]<br />
<br />
===Operation===<br />
unless (var == 0) goto target<br />
<br />
Target is a byte offset (measured from after this instruction), which will be added to the instruction pointer.<br />
<br />
<br />
==expression ($AC)==<br />
<br />
===Encoding===<br />
opcode result subopcode... $FF<br />
<br />
sub-opcodes:<br />
$01 value[p16]<br />
$02<br />
... $02 through $05 take the same arguments ...<br />
$05<br />
$06 nested-opcode<br />
<br />
===Operation===<br />
Expression mode operates on a stack. Values are pushed on, and operators are applied to the top two items on the stack.<br />
<br />
{| border="1" cellpadding="2" width=100%<br />
|- style="background:whitesmoke"<br />
|Opcode||Meaning||Description<br />
|-<br />
|$01||Value||Pushes a value onto the top of the stack.<br />
|-<br />
|$02||Add||stack[top - 1] + stack[top]<br />
|-<br />
|$03||Subtract||stack[top - 1] - stack[top]<br />
|-<br />
|$04||Multiply||stack[top - 1] * stack[top]<br />
|-<br />
|$05||Divide||stack[top - 1] / stack[top] (if stack[top] is 0 an error occurs)<br />
|-<br />
|$06||Nested Opcode||An entire instruction that returns a result, such as getActorScale. This is interpreted like a normal opcode, but the result is pushed onto the expression stack. (The opcode is passed the special "VAR_RESULT" parameter for "result")<br />
|}<br />
<br />
<br />
==faceActor ($09)==<br />
<br />
===Encoding===<br />
opcode actor[p8] object[p16]<br />
<br />
===Operation===<br />
Dereferences actor, tells actor to face object (presumably based on X/Y co-ordinates).<br />
<br />
<br />
==findInventory ($3D)==<br />
<br />
===Encoding===<br />
opcode result owner[p8] index[p8]<br />
<br />
===Operation===<br />
object := owner.inventory[index]<br />
Searches for all objects owned by owner (an actor or object), and returns the one at the given index (offset).<br />
<br />
<br />
==findObject ($35)==<br />
<br />
===Encoding===<br />
opcode result x[p8] y[p8]<br />
<br />
===Operation===<br />
Returns the first "touchable" local object at the given co-ordinates. Will not match on the bottom or right-hand edges of an object.<br />
<br />
<br />
==freezeScripts ($60)==<br />
<br />
===Encoding===<br />
opcode flag[p8]<br />
<br />
===Operation===<br />
Freezes all scripts (by setting the high bit on each script's status). If flag is >= $80, all freeze resistent scripts will also be frozen. If flag is 0, all scripts are unfrozen. Freezing effects are cumulative - i.e. if script A is frozen twice, and unfrozen once, it will still be frozen until it is unfrozen a second time. A script's frozen status is indicated by the high bit.<br />
<br />
<br />
==getActorCostume ($71)==<br />
<br />
===Encoding===<br />
opcode result actor[p8]<br />
<br />
===Operation===<br />
Returns the actor's current costume.<br />
<br />
<br />
==getActorElevation ($06)==<br />
<br />
===Encoding===<br />
opcode result actor[p8]<br />
<br />
===Operation===<br />
Returns the actor's current elevation.<br />
<br />
<br />
==getActorFacing ($63)==<br />
<br />
===Encoding===<br />
opcode result actor[p8]<br />
<br />
===Operation===<br />
Returns the current direction the actor is facing.<br />
<br />
<br />
==getActorMoving ($56)==<br />
<br />
===Encoding===<br />
opcode result actor[p8]<br />
<br />
===Operation===<br />
Returns the actor's moving status (0 or 1).<br />
<br />
<br />
==getActorRoom ($03)==<br />
<br />
===Encoding===<br />
opcode result actor[p8]<br />
<br />
===Operation===<br />
Returns the room the actor currently occupies?<br />
<br />
<br />
==getActorScale ($3B)==<br />
<br />
===Encoding===<br />
opcode result actor[p8]<br />
<br />
===Operation===<br />
Returns the actor's current scale.<br />
<br />
===Variants===<br />
In Indy3, this opcode is used for waitForActor.<br />
<br />
<br />
==getActorWalkBox ($7B)==<br />
<br />
===Encoding===<br />
opcode result actor[p8]<br />
<br />
===Operation===<br />
Returns the actor's walkbox.<br />
<br />
<br />
==getActorWidth ($6C)==<br />
<br />
===Encoding===<br />
opcode result actor[p8]<br />
<br />
===Operation===<br />
Returns the actor's width.<br />
<br />
<br />
==getActorX ($43)==<br />
<br />
===Encoding===<br />
opcode result actor[p16]<br />
<br />
===Operation===<br />
Returns the actor's current X co-ordinate.<br />
<br />
===Variants===<br />
In Indy3, actor is only one byte.<br />
opcode result actor[p8]<br />
<br />
<br />
==getActorY ($23)==<br />
<br />
===Encoding===<br />
opcode result actor[p16]<br />
<br />
===Operation===<br />
Returns the actor's current Y co-ordinate.<br />
<br />
===Variants===<br />
In Indy3, actor is only one byte.<br />
opcode result actor[p8]<br />
<br />
<br />
==getAnimCounter ($22)==<br />
<br />
===Encoding===<br />
opcode result actor[p8]<br />
<br />
===Operation===<br />
Returns the actor's animation counter.<br />
<br />
===Variants===<br />
This opcode is used for saveLoadGame in SCUMM V3.<br />
<br />
<br />
==getClosestObjActor ($66)==<br />
<br />
===Encoding===<br />
opcode result actor[p16]<br />
<br />
===Operation===<br />
Returns the object closest to the actor. Items that are more than 255 units (pixels in newer games, characters in older games) away from the actor will not be detected.<br />
<br />
<br />
==getDist ($34)==<br />
<br />
===Encoding===<br />
opcode result objA[p16] objB[p16]<br />
<br />
===Operation===<br />
Returns the distance between two actors/objects (objA and objB).<br />
<br />
<br />
==getInventoryCount ($31)==<br />
<br />
===Encoding===<br />
opcode result actor[p8]<br />
<br />
===Operation===<br />
Returns the number of items in an actor's inventory?<br />
<br />
<br />
==getObjectOwner ($10)==<br />
<br />
===Encoding===<br />
opcode result object[p16]<br />
<br />
===Operation===<br />
Returns the owner of an object.<br />
<br />
<br />
==getObjectState ($0F)==<br />
<br />
===Encoding===<br />
opcode result object[p16]<br />
<br />
===Operation===<br />
Returns the state of the object.<br />
<br />
===Variants===<br />
In small header games, this opcode is used for the "ifState" instruction.<br />
<br />
<br />
==getRandomNumber ($16)==<br />
<br />
===Encoding===<br />
opcode result seed[p8]<br />
<br />
===Operation===<br />
Returns a new random number based on the given seed.<br />
<br />
<br />
==getScriptRunning ($68)==<br />
<br />
===Encoding===<br />
opcode result script[p8]<br />
<br />
===Operation===<br />
Returns 1 if the given script is running, 0 if it's not.<br />
<br />
<br />
==getStringWidth ($67)==<br />
<br />
===Encoding===<br />
opcode result strptr[p8]<br />
<br />
===Operation===<br />
Gets the length of the string pointed to by strptr (either a variable or direct byte), stores the returned value in result.<br />
<br />
<br />
==getVerbEntryPoint ($0B)==<br />
<br />
===Encoding===<br />
opcode result object[p16] verb[p16]<br />
<br />
===Operation===<br />
Returns the entry point for the response code/script for when the given verb is applied to the given object? i.e. gets the start of the script to run for the specific user interaction.<br />
<br />
<br />
==ifClassOfIs ($1D)==<br />
jumps<br />
<br />
===Encoding===<br />
opcode value[p16] args[v16]... target[16]<br />
<br />
===Operation===<br />
unless (value.class is one of [args.class]) goto target<br />
<br />
Compares the value's class with all classes given in args.<br />
<br />
Target is a byte offset (measured from after this instruction), which will be added to the instruction pointer.<br />
<br />
<br />
==ifNotState ($2F) (V3-4)==<br />
This opcode is not present in SCUMM V5.<br />
<br />
===Encoding===<br />
opcode object[p16] state[p8] target[16]<br />
<br />
===Operation===<br />
unless (getState(object) != state) goto target<br />
<br />
<br />
==ifState ($0F) (V3-4)==<br />
This opcode is not present in SCUMM V5.<br />
<br />
===Encoding===<br />
opcode object[p16] state[p8] target[16]<br />
<br />
===Operation===<br />
unless (getState(object) == state) goto target<br />
<br />
<br />
==increment ($46)==<br />
no parameters, uses result<br />
<br />
===Encoding===<br />
opcode result<br />
<br />
===Operation===<br />
result := result + 1<br />
<br />
Reads the variable pointed to by result, increments it, and writes it back. <br />
<br />
<br />
==isActorInBox ($1F)==<br />
<br />
===Encoding===<br />
opcode actor[p8] box[p8] target[16]<br />
<br />
===Operation===<br />
Unless the actor's co-ordinates are within the bounds of the given box, jump to target.<br />
<br />
Target is a byte offset (measured from after this instruction), which will be added to the instruction pointer.<br />
<br />
<br />
==isEqual ($48)==<br />
<br />
===Encoding===<br />
opcode var value[p16] target[16]<br />
<br />
===Operation===<br />
unless (value == var) goto target<br />
<br />
Target is a byte offset (measured from after this instruction), which will be added to the instruction pointer.<br />
<br />
<br />
==isGreater ($78)==<br />
<br />
===Encoding===<br />
opcode var value[p16] target[16]<br />
<br />
===Operation===<br />
unless (value > var) goto target<br />
<br />
Target is a byte offset (measured from after this instruction), which will be added to the instruction pointer.<br />
<br />
<br />
==isGreaterEqual ($04)==<br />
<br />
===Encoding===<br />
opcode var value[p16] target[16]<br />
<br />
===Operation===<br />
unless (value >= var) goto target<br />
<br />
Target is a byte offset (measured from after this instruction), which will be added to the instruction pointer.<br />
<br />
<br />
==isLess ($44)==<br />
<br />
===Encoding===<br />
opcode var value[p16] target[16]<br />
<br />
===Operation===<br />
unless (value < var) goto target<br />
<br />
Target is a byte offset (measured from after this instruction), which will be added to the instruction pointer.<br />
<br />
<br />
==isNotEqual ($08)==<br />
<br />
===Encoding===<br />
opcode var value[p16] target[16]<br />
<br />
===Operation===<br />
unless (value != var) goto target<br />
<br />
Target is a byte offset (measured from after this instruction), which will be added to the instruction pointer.<br />
<br />
<br />
==isSoundRunning ($7C)==<br />
<br />
===Encoding===<br />
opcode result sound[p8]<br />
<br />
===Operation===<br />
Returns 1 if sound is running, returns 0 if sound is not running or if the given sound is 0.<br />
<br />
<br />
==jumpRelative ($18)==<br />
jumps<br />
<br />
===Encoding===<br />
opcode target[16]<br />
<br />
===Operation===<br />
PC := PC + target<br />
<br />
The inline constant target is read as a signed word and added to the program counter after the instruction has been read. Therefore, if target is zero, the instruction will do nothing; if target is -3, an infinite loop will result. <br />
<br />
<br />
==lessOrEqual ($38)==<br />
jumps<br />
<br />
===Encoding===<br />
opcode var value[p16] target[16]<br />
<br />
===Operation===<br />
unless (value <= var) goto target<br />
<br />
Target is a byte offset (measured from after this instruction), which will be added to the instruction pointer.<br />
<br />
<br />
==lights ($70)==<br />
<br />
===Encoding===<br />
opcode arg1[p8] arg2[8] arg3[8]<br />
<br />
===Operation===<br />
If arg3 is 0, the "current lights" variable is set to arg1.<br />
If arg3 is 1, the size of the "flashlight" light is determined by arg1 and arg2, for width and height in stripes (which are equivalent to 8 pixels each; see [[SCUMM/Technical Reference/Image resources]]).<br />
<br />
<br />
==loadRoom ($72)==<br />
<br />
===Encoding===<br />
opcode room[p8]<br />
<br />
===Operation===<br />
Loads the given room into memory.<br />
<br />
<br />
==loadRoomWithEgo ($24)==<br />
<br />
===Encoding===<br />
opcode object[p16] room[p8] x[16] y[16]<br />
<br />
===Operation===<br />
Places the Ego actor in room at object's position. If x is not -1, Ego will start moving towards the given x and y co-ordinates. If object is not in the given room an error will occur.<br />
(I think...)<br />
<br />
<br />
==matrixOp ($30)==<br />
<br />
===Encoding===<br />
opcode sub-opcode<br />
<br />
sub-opcodes:<br />
$01 box[p8] val[p8]<br />
$02 box[p8] val[p8]<br />
$03 box[p8] val[p8]<br />
$04<br />
<br />
===Operation===<br />
This instruction manipulates boxes.<br />
<br />
{| border="1" cellpadding="2" width=100%<br />
|- style="background:whitesmoke"<br />
|Opcode||Meaning||Description<br />
|-<br />
|$01||setBoxFlags||Sets the box's flags to the given value.<br />
|-<br />
|$02||setBoxScale||Sets the box's scale.<br />
|-<br />
|$03||setBoxScale||Sets the box's scale to ((val - 1) OR $8000).<br />
|-<br />
|$04||createBoxMatrix||Initializes the matrix of boxes, by determining the distances and shortest paths between boxes.<br />
|}<br />
<br />
===Variants===<br />
SCUMM V3 only has the one instruction, which behaves like setBoxFlags:<br />
opcode box[p8] val[8]<br />
<br />
<br />
==move ($1A)==<br />
<br />
===Encoding===<br />
opcode result value[p16]<br />
<br />
===Operation===<br />
result := value<br />
<br />
Value is moved into result.<br />
<br />
<br />
==multiply ($1B)==<br />
<br />
===Encoding===<br />
opcode result value[p16]<br />
<br />
===Operation===<br />
result := result * value<br />
<br />
The variable pointed to by result is read, multiplied by value, and written back.<br />
<br />
<br />
==notEqualZero ($A8)==<br />
<br />
===Encoding===<br />
opcode var target[16]<br />
<br />
===Operation===<br />
unless (var != 0) goto target<br />
<br />
Target is a byte offset (measured from after this instruction), which will be added to the instruction pointer.<br />
<br />
<br />
==oldRoomEffect ($5C) (V3-4)==<br />
This opcode/instruction not present in SCUMM V5.<br />
<br />
===Encoding===<br />
opcode sub-opcode<br />
<br />
sub-opcodes:<br />
$03 effect[p16]<br />
$?? effect[p16]<br />
<br />
===Operation===<br />
Performs like sub-opcode SO_ROOM_FADE of the roomOps instruction (fade in if effect != 0, otherwise fade out).<br />
<br />
This information may not be correct; descumm says if the sub-opcode is 3, to "set" the effect, but if the sub-opcode is anything else to fade in with the given effect.<br />
<br />
===Variants===<br />
FM-Towns SCUMM V3 performs a different effect, not fully implemented in ScummVM. At the moment ScummVM just forces a redraw of the screen background.<br />
<br />
<br />
==or ($57)==<br />
one parameter, uses result<br />
<br />
===Encoding===<br />
opcode result value[p16]<br />
<br />
===Operation===<br />
result := result or value<br />
<br />
The variable pointed to by result is read, logically ORed with value, and the result written back.<br />
<br />
<br />
==override ($58)==<br />
<br />
===Encoding===<br />
opcode sub-opcode<br />
<br />
sub-opcodes:<br />
$00<br />
$01 $18 target[16]<br />
<br />
===Operation===<br />
If the sub-opcode is 0, marks the end of an override section.<br><br />
If the sub-opcode is not 0, marks the beginning of an override section. The instruction is immediately followed by a "jumpRelative" instruction.<br><br />
Overrides are used by cutscenes; if a cutscene is skipped (if the user presses the ESC key), the script will jump by the given target (offset from the beginOverride instruction).<br />
<br />
<br />
==panCameraTo ($12)==<br />
<br />
===Encoding===<br />
opcode x[p16]<br />
<br />
===Operation===<br />
Starts the camera panning to the given x co-ordinate.<br />
<br />
<br />
==pickupObject ($25) (v5)==<br />
This instruction is only present in SCUMM V5.<br />
<br />
===Encoding===<br />
opcode object[p16] room[p8]<br />
<br />
===Operation===<br />
Adds the given object (located in the given room) to the Ego actor's inventory.<br />
<br />
===Variants===<br />
In SCUMM V3 and V4, this opcode is used for drawObject.<br />
<br />
<br />
==pickupObject ($50) (V3-4)==<br />
This opcode/instruction is not present in SCUMM V5.<br />
<br />
===Encoding===<br />
opcode object[p16]<br />
<br />
===Operation===<br />
Adds the given object (located in the given room) to the Ego actor's inventory. If object < 1, an error is raised. If the object is not found or the object is already in the inventory, this function ends gracefully.<br />
<br />
<br />
==print ($14)==<br />
<br />
===Encoding===<br />
opcode actor[p8] sub-opcode<br />
<br />
sub-opcodes<br />
$00 xpos[p16] ypos[p16]<br />
$01 colour[p8]<br />
$02 right[p16]<br />
$03 width[p16] height[p16]<br />
$04<br />
$06<br />
$07<br />
$08 offset[p16] delay[p16]<br />
$0F string[c]... $FF<br />
<br />
===Operation===<br />
Sets text properties and displays dialogue.<br />
<br />
{| border="1" cellpadding="2" width=100%<br />
|- style="background:whitesmoke"<br />
|Opcode||Meaning||Description<br />
|-<br />
|$00||SO_AT||Sets the position of the text that follows.<br />
|-<br />
|$01||SO_COLOR||Sets the colour of the text.<br />
|-<br />
|$02||SO_CLIPPED||Clips the text's right-hand side (for wrapping?).<br />
|-<br />
|$03||SO_ERASE||Erases characters (not used in ScummVM).<br />
|-<br />
|$04||SO_CENTER||Centres the text.<br />
|-<br />
|$06||SO_LEFT||Left-aligns the text.<br />
|-<br />
|$07||SO_OVERHEAD||Overhead-aligns the text.<br />
|-<br />
|$0F||SO_TEXTSTRING||Prints the text string that follows. Terminated by $FF.<br />
|}<br />
<br />
===Variants===<br />
In SCUMM V3, text function $06 sets the height of the text:<br />
$06 height[p16]<br />
<br />
In Loom CD (SCUMM V4), there is an additional text function $08 (SO_SAY_VOICE), which plays a portion of the CD audio track.<br />
$08 offset[p16] delay[p16]<br />
<br />
<br />
==printEgo ($D8)==<br />
<br />
===Encoding===<br />
opcode sub-opcode<br />
<br />
===Operation===<br />
Exactly the same as print, except the actor is implicitly Ego. See the entry for "print" for further explanation.<br />
<br />
<br />
==pseudoRoom ($CC)==<br />
<br />
===Encoding===<br />
opcode val[8] res[8]... $00<br />
<br />
===Operation===<br />
forall (res) {<br />
if (res >= $80) {<br />
_resourceMapper[res & $7F] := val<br />
}<br />
}<br />
<br />
What does this actually do? We may never know.<br />
<br />
It looks like res values always have the high bit set, e.g. 0x01 becomes 0x81.<br />
<br />
<br />
==putActor ($01)==<br />
<br />
===Encoding===<br />
opcode actor[p8] x[p16] y[p16]<br />
<br />
===Operation===<br />
Puts the actor at the given co-ordinates.<br />
<br />
<br />
==putActorAtObject ($0E)==<br />
<br />
===Encoding===<br />
opcode actor[p8] object[p16]<br />
<br />
===Operation===<br />
Puts the actor at the given object's position. If the object can not be found, a default position is returned (the centre of the screen in ScummVM).<br />
<br />
<br />
==putActorInRoom ($2D)==<br />
<br />
===Encoding===<br />
opcode actor[p8] room[p8]<br />
<br />
===Operation===<br />
Puts the actor in the given room.<br />
<br />
<br />
==resourceRoutines ($0C)==<br />
<br />
===Encoding===<br />
opcode sub-opcode<br />
<br />
sub-opcodes:<br />
$01 resID[p8]<br />
... $01 through $10 take the same arguments ...<br />
$10 resID[p8]<br />
$11<br />
$12 resID[p8]<br />
$13 resID[p8]<br />
$14 room[p8] object[p16]<br />
<br />
===Operation===<br />
resID is unique only within the resource type (e.g. script 11 will not conflict with sound 11).<br />
<br />
{| border="1" cellpadding="2" width=100%<br />
|- style="background:whitesmoke"<br />
|Opcode||Meaning||Description<br />
|-<br />
|$01||SO_LOAD_SCRIPT||Loads the given script into memory.<br />
|-<br />
|$02||SO_LOAD_SOUND||Loads the given sound into memory.<br />
|-<br />
|$03||SO_LOAD_COSTUME||Loads the given costume into memory.<br />
|-<br />
|$04||SO_LOAD_ROOM||Loads the given room into memory.<br />
|-<br />
|$05||SO_NUKE_SCRIPT||Obliterates the given script from memory.<br />
|-<br />
|$06||SO_NUKE_SOUND||Obliterates the given sound from memory.<br />
|-<br />
|$07||SO_NUKE_COSTUME||Obliterates the given costume from memory.<br />
|-<br />
|$08||SO_NUKE_ROOM||Obliterates the given room from memory.<br />
|-<br />
|$09||SO_LOCK_SCRIPT||Locks the given script.<br />
|-<br />
|$0A||SO_LOCK_SOUND||Locks the given sound.<br />
|-<br />
|$0B||SO_LOCK_COSTUME||Locks the given costume.<br />
|-<br />
|$0C||SO_LOCK_ROOM||Locks the given room.<br />
|-<br />
|$0D||SO_UNLOCK_SCRIPT||Unlocks the given script.<br />
|-<br />
|$0E||SO_UNLOCK_SOUND||Unlocks the given sound.<br />
|-<br />
|$0F||SO_UNLOCK_COSTUME||Unlocks the given costume.<br />
|-<br />
|$10||SO_UNLOCK_ROOM||Unlocks the given room.<br />
|-<br />
|$11||SO_CLEAR_HEAP||Clears the heap.<br />
|-<br />
|$12||SO_LOAD_CHARSET||Loads the given character set into memory.<br />
|-<br />
|$13||SO_NUKE_CHARSET||Obliterates the given character set from memory.<br />
|-<br />
|$14||SO_LOAD_OBJECT||Loads the given object from the given room resource.<br />
|}<br />
<br />
===Variants===<br />
FM-Towns games add the following sub-opcodes (these are not confirmed nor implemented in ScummVM):<br />
{| border="1" cellpadding="2" width=100%<br />
|- style="background:whitesmoke"<br />
|Opcode||Meaning||Description<br />
|-<br />
|$20||Unknown||Does nothing, not used in-game.<br />
|-<br />
|$21||Unknown||Does nothing, not used in-game.<br />
|-<br />
|$23||CD Volume||Possibly changes the volume of CD tracks (Loom CD). Takes 1 byte.<br />
|-<br />
|$24||Sound Volume||Sets the loudness of a sound resource. Used in Indy3 and Zak. Takes 2 bytes (left/right volumes?).<br />
|-<br />
|$25||Sound Pitch||Sets the pitch of a sound resource. Used in Indy3 and Zak. Takes 1 byte (pitch = "foo" - "center" semitones. Center is at $32 in the sound resource.)<br />
|}<br />
<br />
<br />
==roomOps ($33)==<br />
<br />
===Encoding===<br />
opcode sub-opcode<br />
<br />
sub-opcodes:<br />
$01 minX[p16] maxX[p16]<br />
$03 b[p16] h[p16]<br />
$04 red[p16] green[p16] blue[p16] aux index[p8]<br />
$05<br />
$06<br />
$07 scale1[p8] y1[p8] aux scale2[p8] y2[p8] aux slot[p8]<br />
$08 scale[p8] startcolour[p8] endcolour[p8]<br />
$09 loadflag[p8] loadslot[p8]<br />
$0A effect[p16]<br />
$0B redscale[p16] greenscale[p16] bluescale[p16] aux startcolour[p8] endcolour[p8]<br />
$0C redscale[p16] greenscale[p16] bluescale[p16] aux startcolour[p8] endcolour[p8]<br />
$0D resID[p8] filename[c]... $00<br />
$0E resID[p8] filename[c]... $00<br />
$0F resID[p8] aux start[p8] end[p8] aux time[p8]<br />
$10 colindex[p8] delay[p8]<br />
<br />
===Operation===<br />
{| border="1" cellpadding="2" width=100%<br />
|- style="background:whitesmoke"<br />
|Opcode||Meaning||Description<br />
|-<br />
|$01||SO_ROOM_SCROLL||Clamps the given arguments so scrolling does not extend past the width of the room or screen.<br />
|-<br />
|$03||SO_ROOM_SCREEN||Initialises a screen.<br />
|-<br />
|$04||SO_ROOM_PALETTE||Adjusts the room's palette.<br />
|-<br />
|$05||SO_ROOM_SHAKE_ON||Starts the room shaking.<br />
|-<br />
|$06||SO_ROOM_SHAKE_OFF||Ends the room shaking.<br />
|-<br />
|$07||SO_ROOM_SCALE||Sets the room's y scales? (slot is 1 greater than actual slot?)<br />
|-<br />
|$08||SO_ROOM_INTENSITY||Lightens/darkens the room's palette.<br />
|-<br />
|$09||SO_ROOM_SAVEGAME||Saves temporary state of the room/game?<br />
|-<br />
|$0A||SO_ROOM_FADE||If effect is 0, fades in the room. Otherwise, fades out with the given effect (taken from the high byte of effect).<br>1 = iris effect<br>2 = box wipe (upper-left to bottom-right)<br>3 = box wipe (upper-right to bottem-left)<br>4 = inverse box wipe.<br />
|-<br />
|$0B||SO_RGB_ROOM_INTENSITY||Lightens/darkens the room's palette, with different scales for red, green and blue.<br />
|-<br />
|$0C||SO_ROOM_SHADOW||Lightens/darkens the shadow palette, with different scales for red, green, and blue.<br />
|-<br />
|$0D||SO_SAVE_STRING||Saves a string resource to the given file?<br />
|-<br />
|$0E||SO_LOAD_STRING||Loads a string resource from a given file?<br />
|-<br />
|$0F||SO_ROOM_TRANSFORM||Manipulates palettes, strings?<br />
|-<br />
|$10||SO_CYCLE_SPEED||Starts colour cycling with delay? colIndex is between 0 and 16<br />
|}<br />
<br />
===Variants===<br />
SCUMM V3 (non-PC Engine) encodes the arguments before the sub-opcode:<br />
opcode arg1[p16] arg2[p16] sub-opcode<br />
<br />
Small header games (V3 and V4) include an extra sub-opcode, $02 (SO_ROOM_COLOR), which adjusts the room's palette:<br />
opcode $02 colour[p16] index[p16]<br />
... or for V3 games ...<br />
opcode colour[p16] index[p16] $02<br />
<br />
In small header games, sub-opcode $04 (SO_ROOM_PALETTE) affects the shadow palette, and only accepts two arguments, a "room colour slot" (palette entry? between 0 and 256) and an index:<br />
opcode $04 colour[p16] index[p16]<br />
... or for V3 games ...<br />
opcode colour[p16] index[p16] $04<br />
<br />
In FM-Towns games, sub-opcode $0A performs a different function and has its own sub-opcodes (some unknown and all not yet implemented in ScummVM):<br />
opcode $0A sub-opcode<br />
<br />
{| border="1" cellpadding="2" width=100%<br />
|- style="background:whitesmoke"<br />
|Opcode||Meaning||Description<br />
|-<br />
|$08||||compose kMainVirtScreen over a screen buffer<br />
|-<br />
|$09||||call 0x110:0x20 _ax=0x601 _edx=2<br />
|-<br />
|$0A||||call 0x110:0x20 _ax=0x601 _edx=3<br />
|-<br />
|$0B||||clear screen 0x1C:0x45000 sizeof(640 * 320)<br />
|-<br />
|$0C||||call 0x110:0x20 _ax=0x601 _edx=0<br />
|-<br />
|$0D||||call 0x110:0x20 _ax=0x601 _edx=1<br />
|-<br />
|$10||||enable clearing of a screen buffer in drawBitmap()<br />
|-<br />
|$11||||disable clearing of a screen buffer in drawBitmap()<br />
|-<br />
|$12||||clear a screen buffer<br />
|-<br />
|$13||||enable palette operations (palManipulate(), cyclePalette() etc.)<br />
|-<br />
|$14||||disable palette operations<br />
|-<br />
|$15||||disable clearing of screen 0x1C:0x5000 sizeof(640 * 320) in initScreens()<br />
|-<br />
|$16||||enable clearing of screen 0x1C:0x5000 sizeof(640 * 320) in initScreens()<br />
|-<br />
|$1E||||Unknown<br />
|}<br />
<br />
<br />
==saveLoadGame ($22) (V3-4)==<br />
This instruction is not present in SCUMM V5; its opcode is used for "getAnimCounter".<br />
<br />
===Encoding===<br />
opcode result arg1[p8]<br />
<br />
===Operation===<br />
The slot is determined by taking the lower 5 bits of arg1. The upper 3 bits determine an aux opcode, that performs an action described in the table below.<br />
<br />
{| border="1" cellpadding="2" width=100%<br />
|- style="background:whitesmoke"<br />
|Opcode||Meaning||Description<br />
|-<br />
|$00||Num. Available Slots||Returns the number of save slots available.<br />
|-<br />
|$20||Drive||In V3, returns the type of drive (0 = ???, 1 = A or B [floppy], 2 = hard drive).<br>In V4, sets the current drive (returns 1).<br />
|-<br />
|$40||Load Game||Loads a game from the given slot (returns 3 if successful, 5 otherwise).<br />
|-<br />
|$80||Save Game||Saves a game to the given slot (returns 0 if successful, 2 otherwise).<br />
|-<br />
|$C0||Test For Game||Tests if a save exists in the given slot (returns 6 if so, 7 otherwise).<br />
|}<br />
<br />
<br />
==saveLoadVars ($A7) (V3-4)==<br />
This instruction is not present in SCUMM V5; its opcode is used as a dummy.<br />
<br />
===Encoding===<br />
opcode sub-opcode<br />
<br />
sub-opcodes:<br />
$01 sub-sub-opcode... $00<br />
$02 sub-sub-opcode... $00<br />
<br />
$01 (save) sub-sub-opcodes:<br />
$01 resultA resultB<br />
$02 arg1[p8] arg2[p8]<br />
$03 filename[c]... $00<br />
$04<br />
$1F<br />
<br />
$02 (load) sub-sub-opcodes:<br />
$01 resultA resultB<br />
$02 arg1[p8] arg2[p8]<br />
$03 filename[c]... $00<br />
$04<br />
$1F<br />
<br />
===Operation===<br />
{| border="1" cellpadding="2" width=100%<br />
|- style="background:whitesmoke"<br />
|Opcode||Meaning||Description<br />
|-<br />
|$01||SO_SAVE_VARS||Saves variables (for saving games?)<br />
|-<br />
|$02?||SO_RESTORE_VERBS||Loads variables (for saving games?)<br>(I have not verified that restore vars is $02, as the ScummVM code only compares to $01.)<br />
|}<br />
<br />
{| border="1" cellpadding="2" width=100%<br />
|- style="background:whitesmoke"<br />
|Opcode||Meaning||Description<br />
|-<br />
|$01||Write Vars||Writes a range of variables.<br />
|-<br />
|$02||Write Strings||Writes a range of string variables.<br />
|-<br />
|$03||Open File||Opens a file for writing.<br />
|-<br />
|$04||Dummy||Does nothing.<br />
|-<br />
|$1F||Close File||Closes the last opened file.<br />
|}<br />
<br />
{| border="1" cellpadding="2" width=100%<br />
|- style="background:whitesmoke"<br />
|Opcode||Meaning||Description<br />
|-<br />
|$01||Read Vars||Reads a range of variables.<br />
|-<br />
|$02||Read Strings||Reads a range of string variables.<br />
|-<br />
|$03||Open File||Opens a file for reading.<br />
|-<br />
|$04||Dummy||Does nothing.<br />
|-<br />
|$1F||Close File||Closes the last opened file.<br />
|}<br />
<br />
<br />
==saveRestoreVerbs ($AB)==<br />
<br />
===Encoding=== <br />
opcode sub-opcode<br />
<br />
sub-opcodes: <br />
$01 start[p8] end[p8] mode[p8]<br />
$02 start[p8] end[p8] mode[p8]<br />
$03 start[p8] end[p8] mode[p8]<br />
<br />
===Operation===<br />
{| border="1" cellpadding="2" width=100%<br />
|- style="background:whitesmoke"<br />
|Opcode||Meaning||Description<br />
|-<br />
|$01||SO_SAVE_VERBS||For all verbs between start and end, sets the "saveid" to mode. <br />
|-<br />
|$02||SO_RESTORE_VERBS||For all verbs between start and end and matching mode, kills any existing verb, sets the saveid to 0 and generally inits the verb.<br />
|-<br />
|$03||SO_DELETE_VERBS||For all verbs between start and end and matching mode, kills any existing verb.<br />
|}<br />
<br />
<br />
==setCameraAt ($32)==<br />
<br />
===Encoding===<br />
opcode x[p16]<br />
<br />
===Operation===<br />
Sets the camera's x position.<br />
<br />
<br />
==setObjectName ($54)==<br />
<br />
===Encoding===<br />
opcode object[p16] name[c]... $00<br />
<br />
===Operation===<br />
Sets the given object's name.<br />
<br />
<br />
==setOwnerOf ($29)==<br />
<br />
===Encoding===<br />
opcode object[p16] owner[p8]<br />
<br />
===Operation===<br />
Sets the owner of the object.<br />
<br />
<br />
==setState ($07)==<br />
<br />
===Encoding===<br />
opcode object[p16] state[p8]<br />
<br />
===Operation===<br />
Sets the state of the object.<br />
<br />
<br />
==setVarRange ($26)==<br />
non-standard encoding<br />
<br />
===Encoding===<br />
opcode result number[8] values[8]...<br />
or<br />
opcode result number[8] values[16]...<br />
<br />
===Operation===<br />
for (i = 0; i < number; i++) {<br />
&#42;result + i := values[i];<br />
}<br />
<br />
This sets a number of variables to the given parameters. The starting variable is given as "result", and the number of variables to modify is given as "number". This is followed by the same number of values, which will be put into the variable locations. The values are constants, and can be either 16-bit, if the highest bit of the opcode is set, i.e. $A6; or 8-bit, if the highest bit of the opcode is not set, i.e. $26. Note that all values are affected by the opcode's high bit; you can't mix 8 and 16-bit values.<br />
<br />
descumm example:<br />
setVarRange(Var[178],9,[0,0,0,0,0,0,0,0,0]);<br />
<br />
This sets variables 178 to 186 (inclusive) to 0.<br />
<br />
<br />
==soundKludge ($4C)==<br />
<br />
===Encoding===<br />
opcode items[v16]...<br />
<br />
===Operation===<br />
If the first item is -1, the existing sound queue is processed. Otherwise, the list of items is added to the queue.<br />
<br />
===Variants===<br />
In SCUMM V3 and V4 (small header) games, this opcode is used for the WaitForSentence instruction.<br />
<br />
<br />
==startMusic ($02)==<br />
<br />
===Encoding===<br />
opcode music[p8]<br />
<br />
===Operation===<br />
Adds the music in to the queue to be played.<br />
<br />
===Variants===<br />
In FM-Towns (SCUMM V3) games, this instruction performs different functions (some kind of Audio CD status query function; some partially implemented in ScummVM):<br />
opcode result sub-opcode<br />
<br />
{| border="1" cellpadding="2" width=100%<br />
|- style="background:whitesmoke"<br />
|Opcode||Meaning||Description<br />
|-<br />
|$00||Is Playing||Returns true if a CD audio track is currently playing.<br />
|-<br />
|$FC||Unpause CD||Unpauses the CD audio track.<br />
|-<br />
|$FD||Pause CD||Pauses the CD audio track.<br />
|-<br />
|$FE||Get CD Sound||Returns the current CD sound.<br />
|-<br />
|$FF||CD Volume||Might return the the current CD volume in FM-Towns Loom.<br />
|-<br />
|other||Track Length||Returns the track length in seconds.<br />
|}<br />
<br />
<br />
==startObject ($37)==<br />
<br />
===Encoding===<br />
opcode object[p16] script[p8] args[v16]...<br />
<br />
===Operation===<br />
Starts the object's script (OBCD blocks), passing the given arguments.<br />
<br />
<br />
==startScript ($0A)==<br />
one parameter plus varargs, extra encoding in opcode<br />
<br />
===Encoding===<br />
opcode script[p8] args[v16]...<br />
<br />
===Operation===<br />
Spawns a new thread running the code in script script. The new script has its local variables initialised to the list args. Uninitialised variables have undefined values.<br />
<br />
The opcode carries extra information: <br />
<br />
{| border="1" cellpadding="2" width=10%<br />
|- style="background:whitesmoke"<br />
|7||6||5||4 0<br />
|-<br />
|P1||R||F||$0A<br />
|}<br />
<br />
P1 = standard parameter bit<br><br />
R = indicates that the script is recursive<br><br />
F = indicates that the script is freeze resistant (a call to freezeScripts will skip this script, unless the "force freeze" bit of the freezeScripts opcode is set).<br />
<br />
<br />
==startSound ($1C)==<br />
<br />
===Encoding===<br />
opcode sound[p8]<br />
<br />
===Operation===<br />
Adds the given sound to the sound queue to be played.<br />
<br />
<br />
==stopMusic ($20)==<br />
<br />
===Encoding===<br />
opcode<br />
<br />
===Operation===<br />
Stops all sounds.<br />
<br />
<br />
==stopObjectCode ($A0 or $00)==<br />
<br />
===Encoding===<br />
opcode<br />
<br />
===Operation===<br />
Marks the calling script as dead, to be later pruned from the thread pool. Cleans up residual arrays. Should always be the last instruction in a script.<br />
<br />
$A0 is used in local and global scripts (LSCR and SCRP blocks in the V5 resource files), $00 is used in room entry, room exit, and verb/object scripts (ENCD, EXCD, VERB blocks).<br />
<br />
<br />
==stopObjectScript ($6E)==<br />
<br />
===Encoding===<br />
opcode script[p16]<br />
<br />
===Operation===<br />
Marks the given object script as dead, to be later pruned from the thread pool. Cleans up residual arrays.<br />
<br />
<br />
==stopScript ($62)==<br />
<br />
===Encoding===<br />
opcode script[p8]<br />
<br />
===Operation===<br />
Marks the given script as dead, to be later pruned from the thread pool. Cleans up residual arrays.<br />
<br />
<br />
==stopSound ($3C)==<br />
<br />
===Encoding===<br />
opcode sound[p8]<br />
<br />
===Operation===<br />
Stops the given sound.<br />
<br />
<br />
==stringOps ($27)==<br />
parameters depend on sub-opcode<br />
<br />
===Encoding===<br />
opcode sub-opcode<br />
<br />
sub-opcodes:<br />
$01 stringID[p8] string[c]... $00<br />
$02 destID[p8] srcID[p8]<br />
$03 stringID[p8] index[p8] char[c]<br />
$04 result stringID[p8] index[p8]<br />
$05 stringID[p8] size[p8]<br />
<br />
===Operation===<br />
Miscellaneous actions on strings (Arrays, referred to by resource number).<br />
<br />
{| border="1" cellpadding="2" width=100%<br />
|- style="background:whitesmoke"<br />
|Opcode||Meaning||Description<br />
|-<br />
|$01||Load String||Loads the inline null-terminated string into the resource slot given by stringID.<br />
|-<br />
|$02||Copy String||Creates a duplicate of the string at resource slot srcID into destID. The old string at destID is lost.<br />
|-<br />
|$03||Write Character||Writes char at the given index (offset) of the string resource located at slot stringID. Out of bounds accesses cause undefined behaviour.<br />
|-<br />
|$04||Read Character||Reads a byte (character) at the given index (offset) of the string resource located at slot stringID, and writes it to result. Out of bounds accesses cause undefined behaviour.<br />
|-<br />
|$05||New String||Allocates or frees a string (Array), located at resource slot stringID. The string is initialised to size; if size is zero, the string is freed.<br />
|}<br />
<br />
<br />
==subtract ($3A)==<br />
<br />
===Encoding===<br />
opcode result value[p16]<br />
<br />
===Operation===<br />
result := result - value<br />
<br />
The variable pointed to by result is read, value is subtracted from it, and the result written back.<br />
<br />
<br />
==systemOps ($98)==<br />
<br />
===Encoding===<br />
opcode sub-opcode<br />
<br />
sub-opcodes:<br />
$01<br />
$02<br />
$03<br />
<br />
===Operation===<br />
{| border="1" cellpadding="2" width=100%<br />
|- style="background:whitesmoke"<br />
|Opcode||Meaning||Description<br />
|-<br />
|$01||SO_RESTART||Restarts the game.<br />
|-<br />
|$02||SO_PAUSE||Pauses/unpauses the game.<br />
|-<br />
|$03||SO_QUIT||Quits the game.<br />
|}<br />
<br />
<br />
==verbOps ($7A)==<br />
<br />
===Encoding===<br />
opcode verbID[p8] sub-opcode... $FF<br />
<br />
sub-opcodes:<br />
$01 object[p16]<br />
$02 name[c]... $00<br />
$03 colour[p8]<br />
$04 hicolour[p8]<br />
$05 left[p16] top[p16]<br />
$06<br />
$07<br />
$08<br />
$09<br />
$10 colour[p8]<br />
$11<br />
$12 key[p8]<br />
$13<br />
$14 stringID[p16]<br />
$16 object[p16] room[p8]<br />
$17 colour[p8]<br />
<br />
===Operation===<br />
{| border="1" cellpadding="2" width=100%<br />
|- style="background:whitesmoke"<br />
|Opcode||Meaning||Description<br />
|-<br />
|$01||SO_VERB_IMAGE||Assigns an object (image) to a verb.<br />
|-<br />
|$02||SO_VERB_NAME||Assigns the in-line name to the verb slot.<br />
|-<br />
|$03||SO_VERB_COLOR||Sets the colour of the verb.<br />
|-<br />
|$04||SO_VERB_HICOLOR||Sets the highlight colour of the verb.<br />
|-<br />
|$05||SO_VERB_AT||Sets the verb's top-left co-ordinates.<br />
|-<br />
|$06||SO_VERB_ON||Makes this verb active.<br />
|-<br />
|$07||SO_VERB_OFF||Makes this verb inactive.<br />
|-<br />
|$08||SO_VERB_DELETE||Kills this verb.<br />
|-<br />
|$09||SO_VERB_NEW||Creates a verb in the slot for the given verbID. If the slot is 0 (verb doesn't already exist), will add it to the next unusued slot; if this exceeds the global maximum number of verbs an error will be raised.<br />
|-<br />
|$10||SO_VERB_DIMCOLOR||Sets the dim colour of the verb.<br />
|-<br />
|$11||SO_VERB_DIM||Dims this verb.<br />
|-<br />
|$12||SO_VERB_KEY||Sets the key code (maybe ASCII char?) associated with this verb.<br />
|-<br />
|$13||SO_VERB_CENTER||Centres the verb?<br />
|-<br />
|$14||SO_VERB_NAME_STR||Loads the given string resource into the verb's slot. If either the string resource or verb slot is not found (0), the verb resource is nuked.<br />
|-<br />
|$16||Assign Object||Assigns an object from the given room to the verb (if the object's image index is not already assigned to the given object).<br />
|-<br />
|$17||Set Back Colour||Sets the background colour of the verb?<br />
|}<br />
<br />
<br />
==wait ($AE)==<br />
<br />
===Encoding===<br />
opcode sub-opcode<br />
<br />
sub-opcodes:<br />
$01 actor[p8]<br />
$02 <br />
$03<br />
$04<br />
<br />
===Operation===<br />
{| border="1" cellpadding="2" width=100%<br />
|- style="background:whitesmoke"<br />
|Opcode||Meaning||Description<br />
|-<br />
|$01||SO_WAIT_FOR_ACTOR||If the given actor is moving, breaks and resumes at this instruction again.<br />
|-<br />
|$02||SO_WAIT_FOR_MESSAGE||If the global variable VAR_HAVE_MSG (Var[3]) is not zero, breaks and resumes at this instruction again.<br />
|-<br />
|$03||SO_WAIT_FOR_CAMERA||If the camera has not reached its destination x position, breaks and resumes at this instruction again.<br />
|-<br />
|$04||SO_WAIT_FOR_SENTENCE||If there is a sentence present?, breaks and resumes at this instruction again<br />
|}<br />
<br />
===Variants===<br />
In Indy3 (non-Macintosh), this opcode only acts as SO_WAIT_FOR_MESSAGE and omits the sub-opcode.<br />
opcode<br />
<br />
<br />
==walkActorTo ($1E)==<br />
<br />
===Encoding===<br />
opcode actor[p8] x[p16] y[p16]<br />
<br />
===Operation===<br />
Sets the actor to begin walking to the given position.<br />
<br />
<br />
==walkActorToActor ($0D)==<br />
<br />
===Encoding===<br />
opcode walker[p8] walkee[p8] distance[8]<br />
<br />
===Operation===<br />
Walks walker towards walkee's position by the given distance. Walker and walkee are both actors.<br />
<br />
<br />
==walkActorToObject ($36)==<br />
<br />
===Encoding===<br />
opcode actor[p8] object[p16]<br />
<br />
===Operation===<br />
Sets the actor to begin walking to the given object's position.<br />
<br />
=Variables=<br />
<br />
A number of variables are reserved for use by the SPUTM/SCUMM engine. Here is a list of known variables and their corresponding numbers, taken from the ScummVM source code.<br />
<br />
VAR_RESULT = 0; // descumm claims var 0 is the result var (for expressions)<br />
VAR_KEYPRESS = 0; // script_v5_.cpp claims var 0 is for keypresses...<br />
VAR_EGO = 1;<br />
VAR_CAMERA_POS_X = 2;<br />
VAR_HAVE_MSG = 3;<br />
VAR_ROOM = 4;<br />
VAR_OVERRIDE = 5;<br />
VAR_MACHINE_SPEED = 6;<br />
VAR_ME = 7;<br />
VAR_NUM_ACTOR = 8;<br />
VAR_CURRENT_LIGHTS = 9;<br />
VAR_CURRENTDRIVE = 10;<br />
VAR_TMR_1 = 11;<br />
VAR_TMR_2 = 12;<br />
VAR_TMR_3 = 13;<br />
VAR_MUSIC_TIMER = 14;<br />
VAR_ACTOR_RANGE_MIN = 15;<br />
VAR_ACTOR_RANGE_MAX = 16;<br />
VAR_CAMERA_MIN_X = 17;<br />
VAR_CAMERA_MAX_X = 18;<br />
VAR_TIMER_NEXT = 19;<br />
VAR_VIRT_MOUSE_X = 20;<br />
VAR_VIRT_MOUSE_Y = 21;<br />
VAR_ROOM_RESOURCE = 22;<br />
VAR_LAST_SOUND = 23;<br />
VAR_CUTSCENEEXIT_KEY = 24;<br />
VAR_TALK_ACTOR = 25;<br />
VAR_CAMERA_FAST_X = 26;<br />
VAR_SCROLL_SCRIPT = 27;<br />
VAR_ENTRY_SCRIPT = 28;<br />
VAR_ENTRY_SCRIPT2 = 29;<br />
VAR_EXIT_SCRIPT = 30;<br />
VAR_EXIT_SCRIPT2 = 31;<br />
VAR_VERB_SCRIPT = 32;<br />
VAR_SENTENCE_SCRIPT = 33;<br />
VAR_INVENTORY_SCRIPT = 34;<br />
VAR_CUTSCENE_START_SCRIPT = 35;<br />
VAR_CUTSCENE_END_SCRIPT = 36;<br />
VAR_CHARINC = 37;<br />
VAR_WALKTO_OBJ = 38;<br />
VAR_DEBUGMODE = 39;<br />
VAR_HEAPSPACE = 40;<br />
VAR_RESTART_KEY = 42;<br />
VAR_PAUSE_KEY = 43;<br />
VAR_MOUSE_X = 44;<br />
VAR_MOUSE_Y = 45;<br />
VAR_TIMER = 46;<br />
VAR_TIMER_TOTAL = 47;<br />
VAR_SOUNDCARD = 48;<br />
VAR_VIDEOMODE = 49;<br />
VAR_MAINMENU_KEY = 50;<br />
VAR_FIXEDDISK = 51;<br />
VAR_CURSORSTATE = 52;<br />
VAR_USERPUT = 53;<br />
VAR_V5_TALK_STRING_Y = 54;<br />
VAR_SOUNDRESULT = 56;<br />
VAR_TALKSTOP_KEY = 57;<br />
VAR_FADE_DELAY = 59;<br />
VAR_NOSUBTITLES = 60;<br />
VAR_SOUNDPARAM = 64;<br />
VAR_SOUNDPARAM2 = 65;<br />
VAR_SOUNDPARAM3 = 66;<br />
VAR_INPUTMODE = 67; // 1 is keyboard, 2 is joystick, 3 is mouse<br />
VAR_MEMORY_PERFORMANCE = 68;<br />
VAR_VIDEO_PERFORMANCE = 69;<br />
VAR_ROOM_FLAG = 70;<br />
VAR_GAME_LOADED = 71;<br />
VAR_NEW_ROOM = 72;<br />
<br />
<br />
=Table of Parameters=<br />
Please see the wiki page [[SCUMM/V5_opcodes/Table]] for a concise rendition of the above information (with a few omissions dues to the complexity of the instructions).</div>Jestar jokinhttps://wiki.scummvm.org/index.php?title=SCUMM/Technical_Reference/Script_resources&diff=11074SCUMM/Technical Reference/Script resources2009-05-16T02:18:56Z<p>Jestar jokin: /* Object Scripts in V3/4 (OC) */ Filled out unknowns based on object.cpp/ScummEngine_v4::resetRoomObject</p>
<hr />
<div>[[SCUMM/Technical Reference]] &rarr; ''Script resources''<br />
<br />
<br />
Scripts control the internal logic of the games. They exist in different flavours:<br />
<br />
* global scripts<br />
* local scripts<br />
* room entry scripts<br />
* room exit scripts<br />
* object scripts <br />
<br />
Starting with Scumm V5, the blockname contains 4 bytes and the block size is BE including the 8 bytes for the header. Older games just have a 2 bytes blockname and the block size is in LE without the 6 bytes for the header.<br />
<br />
<br><br />
<br />
== Global Scripts (SC or SCRP) ==<br />
<br />
Global scripts are limited to 200 and stored in the '''LF''' or '''LFLF''' container. The id and the offset is stored in the ''directory of scripts'' in the game [[SCUMM/Index File|index file]].<br />
<br />
Block name 2 ("SC") or 4 ("SCRP") bytes<br />
Block size 4 bytes <br />
Script code variable<br />
<br />
== Local Scripts (LS or LSCR) ==<br />
<br />
Local scripts are stored within a room. For games until version 6, the first byte after the blockname contains the id of the script. IDs for local scripts always start at 200.<br />
<br />
Block name 2 ("LS") or 4 ("LSCR") bytes<br />
Block size 4 bytes<br />
ID 1 byte<br />
Script code variable<br />
<br />
For v7 and v8 games the script id is stored in 2 bytes and starts with 2000.<br />
<br />
Block name 4 bytes ("LSCR")<br />
Block size 4 bytes<br />
ID 2 bytes<br />
Script code variable<br />
<br />
== Room Entry Scripts (EN or ENCD) ==<br />
<br />
This block contains special code when a room is entered. <br />
<br />
Block name 2 ("EN") or 4 ("ENCD") bytes<br />
Block size 4 bytes<br />
Script code variable<br />
<br />
<br />
== Room Exit Scripts (EX or EXCD) ==<br />
<br />
This block contains special code when the player leaves a room <br />
<br />
Block name 2 ("EX") or 4 ("EXCD") bytes<br />
Block size 4 bytes<br />
Script code variable<br />
<br />
<br />
== Object Scripts V5+ (OBCD) ==<br />
<br />
These are scripts that correspond to VERB actions. VERBs are predefined activities at the bottom of the screen, e.g. "Open", "Look", "Give" etc. For each named object in a room, the game designer could define responses to the players actions. A single VERB block contains the code for all possible player actions on the object. Starting with version 5, the whole code can be found in an [[Object resources|Object Resource]]. <br />
<br />
OBCD <br />
Block name 4 bytes ("OBCD")<br />
Block size 4 bytes<br />
<br />
CDHD<br />
Block name 4 bytes ("CDHD")<br />
Block size 4 bytes (25)<br />
obj id 2 bytes<br />
... see [[Object resources|Object Resource]]<br />
<br />
VERB<br />
Block name 4 bytes ("VERB")<br />
Block size 4 bytes<br />
offset table variable {<br />
verb 1 byte (0xFF is default)<br />
offset 2 bytes<br />
}<br />
table end 1 byte (must be 0x00)<br />
object code variable<br />
<br />
OBNA<br />
Block name 4 bytes ("OBNA")<br />
Block size 4 bytes<br />
object name null-terminated string<br />
<br />
<br />
== Object Scripts in V3/4 (OC) ==<br />
<br />
In Version 3 and 4 the code can be found in the '''OC''' block:<br />
<br />
OC<br />
Block size 4 bytes (LE)<br />
Block name 2 bytes ("OC")<br />
Object ID 2 bytes (LE)<br />
unknown 1 byte<br />
x pos 1 byte<br />
y pos, par. state 1 byte<br />
image width / 8 1 byte<br />
parent 1 byte<br />
walk_x 2 bytes (LE)<br />
walk_y 2 bytes (LE)<br />
height, actor dir 1 byte<br />
name offset 1 byte<br />
offset table variable {<br />
verb 1 byte (0xFF is default)<br />
offset 2 bytes<br />
}<br />
table end 1 byte (must be 0x00)<br />
object name null-terminated string<br />
object code variable<br />
<br />
<br />
This block contains all object data except for the actual image bitmap. Compare this to V5+ objects, where metadata is split into seperate CDHD and OBNA blocks.<br />
<br />
Image width is given in strips, which are 8 pixels wide. The high bit of y pos is used to store the parent's state (0 or 1). Both x pos and y pos will be multiplied by 8 by the interpreter. The lower three bits (mask 0x07) of height are used to store actor dir. Name offset is the absolute offset of object name (or, if you prefer, the position after table end). <br />
<br />
The offset table is a variable block like that used in the VERB block in later games, which contains the verb identifier (1 byte) and the absolute offset (2 bytes). The table end is marked with 0x00. Next is the object's name, which is a standard null-terminated string. After this follows the actual object code. Note that unlike other script types, because there are multiple entry points (one for each supported verb), there are also multiple exit points (or "stopObjectCode" instructions).</div>Jestar jokinhttps://wiki.scummvm.org/index.php?title=SCUMM/Technical_Reference/Script_resources&diff=11067SCUMM/Technical Reference/Script resources2009-05-15T14:40:24Z<p>Jestar jokin: Added info to v3/4 script blocks, clarified table entries & other bits.</p>
<hr />
<div>[[SCUMM/Technical Reference]] &rarr; ''Script resources''<br />
<br />
<br />
Scripts control the internal logic of the games. They exist in different flavours:<br />
<br />
* global scripts<br />
* local scripts<br />
* room entry scripts<br />
* room exit scripts<br />
* object scripts <br />
<br />
Starting with Scumm V5, the blockname contains 4 bytes and the block size is BE including the 8 bytes for the header. Older games just have a 2 bytes blockname and the block size is in LE without the 6 bytes for the header.<br />
<br />
<br><br />
<br />
== Global Scripts (SC or SCRP) ==<br />
<br />
Global scripts are limited to 200 and stored in the '''LF''' or '''LFLF''' container. The id and the offset is stored in the ''directory of scripts'' in the game [[SCUMM/Index File|index file]].<br />
<br />
Block name 2 ("SC") or 4 ("SCRP") bytes<br />
Block size 4 bytes <br />
Script code variable<br />
<br />
== Local Scripts (LS or LSCR) ==<br />
<br />
Local scripts are stored within a room. For games until version 6, the first byte after the blockname contains the id of the script. IDs for local scripts always start at 200.<br />
<br />
Block name 2 ("LS") or 4 ("LSCR") bytes<br />
Block size 4 bytes<br />
ID 1 byte<br />
Script code variable<br />
<br />
For v7 and v8 games the script id is stored in 2 bytes and starts with 2000.<br />
<br />
Block name 4 bytes ("LSCR")<br />
Block size 4 bytes<br />
ID 2 bytes<br />
Script code variable<br />
<br />
== Room Entry Scripts (EN or ENCD) ==<br />
<br />
This block contains special code when a room is entered. <br />
<br />
Block name 2 ("EN") or 4 ("ENCD") bytes<br />
Block size 4 bytes<br />
Script code variable<br />
<br />
<br />
== Room Exit Scripts (EX or EXCD) ==<br />
<br />
This block contains special code when the player leaves a room <br />
<br />
Block name 2 ("EX") or 4 ("EXCD") bytes<br />
Block size 4 bytes<br />
Script code variable<br />
<br />
<br />
== Object Scripts V5+ (OBCD) ==<br />
<br />
These are scripts that correspond to VERB actions. VERBs are predefined activities at the bottom of the screen, e.g. "Open", "Look", "Give" etc. For each named object in a room, the game designer could define responses to the players actions. A single VERB block contains the code for all possible player actions on the object. Starting with version 5, the whole code can be found in an [[Object resources|Object Resource]]. <br />
<br />
OBCD <br />
Block name 4 bytes ("OBCD")<br />
Block size 4 bytes<br />
<br />
CDHD<br />
Block name 4 bytes ("CDHD")<br />
Block size 4 bytes (25)<br />
obj id 2 bytes<br />
... see [[Object resources|Object Resource]]<br />
<br />
VERB<br />
Block name 4 bytes ("VERB")<br />
Block size 4 bytes<br />
offset table variable {<br />
verb 1 byte (0xFF is default)<br />
offset 2 bytes<br />
}<br />
table end 1 byte (must be 0x00)<br />
object code variable<br />
<br />
OBNA<br />
Block name 4 bytes ("OBNA")<br />
Block size 4 bytes<br />
object name null-terminated string<br />
<br />
<br />
== Object Scripts in V3/4 (OC) ==<br />
<br />
In Version 3 and 4 the code can be found in the '''OC''' block:<br />
<br />
OC<br />
Block size 4 bytes (LE)<br />
Block name 2 bytes ("OC")<br />
Object ID 2 bytes (LE)<br />
unknown 3 bytes<br />
image width / 8 1 byte<br />
unknown 5 bytes<br />
height & 0xF8 1 byte<br />
name offset 1 byte<br />
offset table variable {<br />
verb 1 byte (0xFF is default)<br />
offset 2 bytes<br />
}<br />
table end 1 byte (must be 0x00)<br />
object name null-terminated string<br />
object code variable<br />
<br />
<br />
This block contains all object data except for the actual image bitmap. Compare this to V5+ objects, where metadata is split into seperate CDHD and OBNA blocks.<br />
<br />
Image width is given in strips, which are 8 pixels wide. Name offset is the absolute offset of object name (or, if you prefer, the position after table end). <br />
<br />
The offset table is a variable block like that used in the VERB block in later games, which contains the verb identifier (1 byte) and the absolute offset (2 bytes). The table end is marked with 0x00. Next is the object's name, which is a standard null-terminated string. After this follows the actual object code. Note that unlike other script types, because there are multiple entry points (one for each supported verb), there are also multiple exit points (or "stopObjectCode" instructions).</div>Jestar jokinhttps://wiki.scummvm.org/index.php?title=SCUMM/Technical_Reference/Sound_resources&diff=11053SCUMM/Technical Reference/Sound resources2009-05-11T04:35:47Z<p>Jestar jokin: /* iMUSE */</p>
<hr />
<div>=Music=<br />
<br />
==Early v5==<br />
<br />
Going from Monkey Island 2 (MI2), music blocks are stored in LFLF blocks, outside of the ROOMs, so they can be accessed globally. The containing sound block looks like this:<br />
<br />
Block name 4 bytes ("SOUN")<br />
Block size 4 bytes<br />
Block name 4 bytes ("SOU ")<br />
Block size 4 bytes<br />
Music block variable<br />
<br />
The redundant header is possibly due to building on a legacy implementation, or for easier identification in the table stored in the .000 index file.<br />
<br />
The music block may contain any combination of ROL (Roland MT-32), ADL (Adlib/OPL FM), or SPK (PC speaker) blocks. They can also store a single SBL block for digitized sound (described in a later section). Aside from SBL, each of these blocks follow the same basic pattern.<br />
<br />
Block name 4 bytes ("ROL ", or "ADL ", or "SPK ")<br />
Block size 4 bytes<br />
MIDI data variable<br />
<br />
Every track is stored in MIDI format, in order to make use of the iMUSE technology through System Exclusive (SysEx) messages.<br />
<br />
Due to the predominance of the Sound Blaster and Adlib/OPL FM technology at the time, in at least MI2 every musical SOUN block contains an ADL block.<br />
<br />
==iMUSE==<br />
<br />
From SCUMM v5 onwards, LucasArts games used a dynamic music playback system called iMUSE. This basically consists of standard MIDI data, with embedded System Exclusive (SysEx) messages that act as markers in the song. iMUSE allows operations like conditional jumping & looping, adjusting the volume of parts, turning parts on and off, changing instruments, and detuning parts.<br />
<br />
You can find the original patent document [http://pat2pdf.org/pat2pdf/foo.pl?number=5315057 here], and some technical details can be found [http://alban.dotsec.net/15.html here].<br />
<br />
==Mac0==<br />
<br />
From Markus Magnuson (superqult) we got this information:<br />
<br />
4 bytes - 'SOUN'<br />
BE 4 bytes - block length<br />
<br />
4 bytes - 'Mac0'<br />
BE 4 bytes - (blockLength - 27)<br />
28 bytes - ???<br />
<br />
do this three times (once for each channel):<br />
4 bytes - 'Chan'<br />
BE 4 bytes - channel length<br />
4 bytes - instrument name (e.g. 'MARI')<br />
<br />
do this for ((chanLength-24)/4) times:<br />
2 bytes - note duration<br />
1 byte - note value<br />
1 byte - note velocity<br />
<br />
4 bytes - ???<br />
4 bytes - 'Loop'/'Done'<br />
4 bytes - ???<br />
1 byte - 0x09<br />
<br />
Instruments (and General Midi equivalent):<br />
"MARI" - Marimba (12)<br />
"PLUC" - Pizzicato Strings (45)<br />
"HARM" - Harmonica (22)<br />
"PIPE" - Church Organ? (19) or Flute? (73) or Bag Pipe (109)<br />
"TROM" - Trombone (57)<br />
"STRI" - String Ensemble (48 or 49)<br />
"HORN" - French Horn? (60) or English Horn? (69)<br />
"VIBE" - Vibraphone (11)<br />
"SHAK" - Shakuhachi? (77)<br />
"PANP" - Pan Flute (75)<br />
"WHIS" - Whistle (78) / Bottle (76)<br />
"ORGA" - Drawbar Organ (16; but could also be 17-20)<br />
"BONG" - Woodblock? (115)<br />
"BASS" - Bass (32-39)<br />
<br />
=Digitized Sounds=<br />
<br />
==Early v5 - SBL blocks==<br />
<br />
Digitized sounds first appeared in Monkey Island 1 & 2. They are contained in the .001 resource files, and are sub-blocks of "SOUN" blocks (see the music section above).<br />
<br />
Block name 4 bytes ("SBL ")<br />
Block size 4 bytes<br />
Sound header 4 bytes ("AUhd" or "WVhd")<br />
Unknown 3 bytes (always 00 00 80)<br />
Data header 4 bytes ("AUdt" or "WVdt")<br />
VOC data variable<br />
<br />
AUhd and AUdt are used in Monkey Island, while WVhd and WVdt are used in the non-interactive demo of Sam & Max. The actual sound data is stored in the Creative VOC format, without the identifying header.<br />
<br />
==Early v5 - CD tracks==<br />
<br />
Games that use CD tracks (Loom/CD, MI1/CD, Zak256/FM-TOWNS) are a bit different. For MI1/CD at least, the "SOU " block size is always 32 bytes and presumably points to the CD track to play.<br />
<br />
==v5-v6 - MONSTER.SOU==<br />
<br />
===Original===<br />
<br />
From Indy 4 onwards, sound effects and speech are stored in a separate resource file called "MONSTER.SOU". The format is:<br />
<br />
Block name 4 bytes ("SOU ")<br />
Block size 4 bytes<br />
One or more:<br />
Block name 4 bytes ("VCTL")<br />
Block size 4 bytes<br />
Lip-sync tags variable<br />
Sound data variable ("Crea" block / VOC file)<br />
<br />
The lip-sync tags provide timing information. In v5 the number of tags is stored in the calling text, according to the formula ((num_tags / 2) << 1) + 8. The "Crea" block is an entire Creative VOC file.<br />
<br />
===Compressed===<br />
<br />
ScummVM can use compressed monster.sou files created with the tool "compress_scumm_sou.exe". Aside from using either MP3, OGG, or FLAC formats for the sound data, they contain a mapping table followed by the sound data, like so:<br />
<br />
size_of_table : uint32<br />
size_of_table / 16 times {<br />
orig_offset : uint32<br />
actual_offset : uint32<br />
num_tags : uint32<br />
sound_size : unit32<br />
}<br />
size_of_table / 16 times {<br />
num_tags times {<br />
tag : uint8<br />
}<br />
sound : sound_size (sound file - MP3/OGG/FLAC)<br />
} <br />
<br />
Each entry in the table has 4 items, each item is 4 bytes, so a table with one entry has a size of 16.<br />
<br />
The original offset is what the game will try to play, the actual offset is taken from after the index table.<br />
<br />
Each sound is directly preceded by its lip-synch tags.<br />
<br />
=Sound block types=<br />
This information is gleaned from the ScummVM source code. Any block name with only three characters has a space at the end.<br />
MIDI \ Midi<br />
iMUS /<br />
<br />
SOU subtypes<br />
TOWS - FM Towns<br />
SBL - Sound Blaster digitized sound (Creative VOC file)<br />
ADL - Adlib (OPL FM)<br />
AMI - Amiga MOD<br />
ROL - Roland MT-32<br />
GMD - General MIDI<br />
MAC - Macintosh (occurs in MI2, FOA)<br />
SPK - PC speaker<br />
<br />
Mac0 - Macintosh music type 0<br />
<br />
Mac1 \<br />
RIFF |<br />
TALK > Creative VOC file<br />
DIGI |<br />
Crea /<br />
<br />
HSHD - HE sound type without SOUN header<br />
<br />
FMUS - Used in 3DO versions of HE games</div>Jestar jokinhttps://wiki.scummvm.org/index.php?title=SCUMM/Technical_Reference/Sound_resources&diff=11052SCUMM/Technical Reference/Sound resources2009-05-11T04:32:09Z<p>Jestar jokin: /* Music */ remove todo</p>
<hr />
<div>=Music=<br />
<br />
==Early v5==<br />
<br />
Going from Monkey Island 2 (MI2), music blocks are stored in LFLF blocks, outside of the ROOMs, so they can be accessed globally. The containing sound block looks like this:<br />
<br />
Block name 4 bytes ("SOUN")<br />
Block size 4 bytes<br />
Block name 4 bytes ("SOU ")<br />
Block size 4 bytes<br />
Music block variable<br />
<br />
The redundant header is possibly due to building on a legacy implementation, or for easier identification in the table stored in the .000 index file.<br />
<br />
The music block may contain any combination of ROL (Roland MT-32), ADL (Adlib/OPL FM), or SPK (PC speaker) blocks. They can also store a single SBL block for digitized sound (described in a later section). Aside from SBL, each of these blocks follow the same basic pattern.<br />
<br />
Block name 4 bytes ("ROL ", or "ADL ", or "SPK ")<br />
Block size 4 bytes<br />
MIDI data variable<br />
<br />
Every track is stored in MIDI format, in order to make use of the iMUSE technology through System Exclusive (SysEx) messages.<br />
<br />
Due to the predominance of the Sound Blaster and Adlib/OPL FM technology at the time, in at least MI2 every musical SOUN block contains an ADL block.<br />
<br />
==iMUSE==<br />
<br />
From SCUMM v5 onwards, LucasArts games used a dynamic music playback system called iMUSE. This basically consists of standard MIDI data, with embedded System Exclusive (SysEx) messages that act as markers in the song. This allows operations like jumping, looping, adjust the volume of parts, turning on/off parts, changing instruments, and pitch detuning.<br />
<br />
You can find the original patent document here: [[http://pat2pdf.org/pat2pdf/foo.pl?number=5315057]], and some technical details can be found here: [[http://alban.dotsec.net/15.html]].<br />
<br />
==Mac0==<br />
<br />
From Markus Magnuson (superqult) we got this information:<br />
<br />
4 bytes - 'SOUN'<br />
BE 4 bytes - block length<br />
<br />
4 bytes - 'Mac0'<br />
BE 4 bytes - (blockLength - 27)<br />
28 bytes - ???<br />
<br />
do this three times (once for each channel):<br />
4 bytes - 'Chan'<br />
BE 4 bytes - channel length<br />
4 bytes - instrument name (e.g. 'MARI')<br />
<br />
do this for ((chanLength-24)/4) times:<br />
2 bytes - note duration<br />
1 byte - note value<br />
1 byte - note velocity<br />
<br />
4 bytes - ???<br />
4 bytes - 'Loop'/'Done'<br />
4 bytes - ???<br />
1 byte - 0x09<br />
<br />
Instruments (and General Midi equivalent):<br />
"MARI" - Marimba (12)<br />
"PLUC" - Pizzicato Strings (45)<br />
"HARM" - Harmonica (22)<br />
"PIPE" - Church Organ? (19) or Flute? (73) or Bag Pipe (109)<br />
"TROM" - Trombone (57)<br />
"STRI" - String Ensemble (48 or 49)<br />
"HORN" - French Horn? (60) or English Horn? (69)<br />
"VIBE" - Vibraphone (11)<br />
"SHAK" - Shakuhachi? (77)<br />
"PANP" - Pan Flute (75)<br />
"WHIS" - Whistle (78) / Bottle (76)<br />
"ORGA" - Drawbar Organ (16; but could also be 17-20)<br />
"BONG" - Woodblock? (115)<br />
"BASS" - Bass (32-39)<br />
<br />
=Digitized Sounds=<br />
<br />
==Early v5 - SBL blocks==<br />
<br />
Digitized sounds first appeared in Monkey Island 1 & 2. They are contained in the .001 resource files, and are sub-blocks of "SOUN" blocks (see the music section above).<br />
<br />
Block name 4 bytes ("SBL ")<br />
Block size 4 bytes<br />
Sound header 4 bytes ("AUhd" or "WVhd")<br />
Unknown 3 bytes (always 00 00 80)<br />
Data header 4 bytes ("AUdt" or "WVdt")<br />
VOC data variable<br />
<br />
AUhd and AUdt are used in Monkey Island, while WVhd and WVdt are used in the non-interactive demo of Sam & Max. The actual sound data is stored in the Creative VOC format, without the identifying header.<br />
<br />
==Early v5 - CD tracks==<br />
<br />
Games that use CD tracks (Loom/CD, MI1/CD, Zak256/FM-TOWNS) are a bit different. For MI1/CD at least, the "SOU " block size is always 32 bytes and presumably points to the CD track to play.<br />
<br />
==v5-v6 - MONSTER.SOU==<br />
<br />
===Original===<br />
<br />
From Indy 4 onwards, sound effects and speech are stored in a separate resource file called "MONSTER.SOU". The format is:<br />
<br />
Block name 4 bytes ("SOU ")<br />
Block size 4 bytes<br />
One or more:<br />
Block name 4 bytes ("VCTL")<br />
Block size 4 bytes<br />
Lip-sync tags variable<br />
Sound data variable ("Crea" block / VOC file)<br />
<br />
The lip-sync tags provide timing information. In v5 the number of tags is stored in the calling text, according to the formula ((num_tags / 2) << 1) + 8. The "Crea" block is an entire Creative VOC file.<br />
<br />
===Compressed===<br />
<br />
ScummVM can use compressed monster.sou files created with the tool "compress_scumm_sou.exe". Aside from using either MP3, OGG, or FLAC formats for the sound data, they contain a mapping table followed by the sound data, like so:<br />
<br />
size_of_table : uint32<br />
size_of_table / 16 times {<br />
orig_offset : uint32<br />
actual_offset : uint32<br />
num_tags : uint32<br />
sound_size : unit32<br />
}<br />
size_of_table / 16 times {<br />
num_tags times {<br />
tag : uint8<br />
}<br />
sound : sound_size (sound file - MP3/OGG/FLAC)<br />
} <br />
<br />
Each entry in the table has 4 items, each item is 4 bytes, so a table with one entry has a size of 16.<br />
<br />
The original offset is what the game will try to play, the actual offset is taken from after the index table.<br />
<br />
Each sound is directly preceded by its lip-synch tags.<br />
<br />
=Sound block types=<br />
This information is gleaned from the ScummVM source code. Any block name with only three characters has a space at the end.<br />
MIDI \ Midi<br />
iMUS /<br />
<br />
SOU subtypes<br />
TOWS - FM Towns<br />
SBL - Sound Blaster digitized sound (Creative VOC file)<br />
ADL - Adlib (OPL FM)<br />
AMI - Amiga MOD<br />
ROL - Roland MT-32<br />
GMD - General MIDI<br />
MAC - Macintosh (occurs in MI2, FOA)<br />
SPK - PC speaker<br />
<br />
Mac0 - Macintosh music type 0<br />
<br />
Mac1 \<br />
RIFF |<br />
TALK > Creative VOC file<br />
DIGI |<br />
Crea /<br />
<br />
HSHD - HE sound type without SOUN header<br />
<br />
FMUS - Used in 3DO versions of HE games</div>Jestar jokinhttps://wiki.scummvm.org/index.php?title=SCUMM/Technical_Reference/Sound_resources&diff=11051SCUMM/Technical Reference/Sound resources2009-05-11T04:31:40Z<p>Jestar jokin: brief note on iMUSE</p>
<hr />
<div>=Music=<br />
<br />
Todo:<br />
* Adlib, GM, MT-32 etc formats<br />
* Digital<br />
* iMUSE (separate tracks and specific markers in each song format)<br />
<br />
==Early v5==<br />
<br />
Going from Monkey Island 2 (MI2), music blocks are stored in LFLF blocks, outside of the ROOMs, so they can be accessed globally. The containing sound block looks like this:<br />
<br />
Block name 4 bytes ("SOUN")<br />
Block size 4 bytes<br />
Block name 4 bytes ("SOU ")<br />
Block size 4 bytes<br />
Music block variable<br />
<br />
The redundant header is possibly due to building on a legacy implementation, or for easier identification in the table stored in the .000 index file.<br />
<br />
The music block may contain any combination of ROL (Roland MT-32), ADL (Adlib/OPL FM), or SPK (PC speaker) blocks. They can also store a single SBL block for digitized sound (described in a later section). Aside from SBL, each of these blocks follow the same basic pattern.<br />
<br />
Block name 4 bytes ("ROL ", or "ADL ", or "SPK ")<br />
Block size 4 bytes<br />
MIDI data variable<br />
<br />
Every track is stored in MIDI format, in order to make use of the iMUSE technology through System Exclusive (SysEx) messages.<br />
<br />
Due to the predominance of the Sound Blaster and Adlib/OPL FM technology at the time, in at least MI2 every musical SOUN block contains an ADL block.<br />
<br />
==iMUSE==<br />
<br />
From SCUMM v5 onwards, LucasArts games used a dynamic music playback system called iMUSE. This basically consists of standard MIDI data, with embedded System Exclusive (SysEx) messages that act as markers in the song. This allows operations like jumping, looping, adjust the volume of parts, turning on/off parts, changing instruments, and pitch detuning.<br />
<br />
You can find the original patent document here: [[http://pat2pdf.org/pat2pdf/foo.pl?number=5315057]], and some technical details can be found here: [[http://alban.dotsec.net/15.html]].<br />
<br />
==Mac0==<br />
<br />
From Markus Magnuson (superqult) we got this information:<br />
<br />
4 bytes - 'SOUN'<br />
BE 4 bytes - block length<br />
<br />
4 bytes - 'Mac0'<br />
BE 4 bytes - (blockLength - 27)<br />
28 bytes - ???<br />
<br />
do this three times (once for each channel):<br />
4 bytes - 'Chan'<br />
BE 4 bytes - channel length<br />
4 bytes - instrument name (e.g. 'MARI')<br />
<br />
do this for ((chanLength-24)/4) times:<br />
2 bytes - note duration<br />
1 byte - note value<br />
1 byte - note velocity<br />
<br />
4 bytes - ???<br />
4 bytes - 'Loop'/'Done'<br />
4 bytes - ???<br />
1 byte - 0x09<br />
<br />
Instruments (and General Midi equivalent):<br />
"MARI" - Marimba (12)<br />
"PLUC" - Pizzicato Strings (45)<br />
"HARM" - Harmonica (22)<br />
"PIPE" - Church Organ? (19) or Flute? (73) or Bag Pipe (109)<br />
"TROM" - Trombone (57)<br />
"STRI" - String Ensemble (48 or 49)<br />
"HORN" - French Horn? (60) or English Horn? (69)<br />
"VIBE" - Vibraphone (11)<br />
"SHAK" - Shakuhachi? (77)<br />
"PANP" - Pan Flute (75)<br />
"WHIS" - Whistle (78) / Bottle (76)<br />
"ORGA" - Drawbar Organ (16; but could also be 17-20)<br />
"BONG" - Woodblock? (115)<br />
"BASS" - Bass (32-39)<br />
<br />
=Digitized Sounds=<br />
<br />
==Early v5 - SBL blocks==<br />
<br />
Digitized sounds first appeared in Monkey Island 1 & 2. They are contained in the .001 resource files, and are sub-blocks of "SOUN" blocks (see the music section above).<br />
<br />
Block name 4 bytes ("SBL ")<br />
Block size 4 bytes<br />
Sound header 4 bytes ("AUhd" or "WVhd")<br />
Unknown 3 bytes (always 00 00 80)<br />
Data header 4 bytes ("AUdt" or "WVdt")<br />
VOC data variable<br />
<br />
AUhd and AUdt are used in Monkey Island, while WVhd and WVdt are used in the non-interactive demo of Sam & Max. The actual sound data is stored in the Creative VOC format, without the identifying header.<br />
<br />
==Early v5 - CD tracks==<br />
<br />
Games that use CD tracks (Loom/CD, MI1/CD, Zak256/FM-TOWNS) are a bit different. For MI1/CD at least, the "SOU " block size is always 32 bytes and presumably points to the CD track to play.<br />
<br />
==v5-v6 - MONSTER.SOU==<br />
<br />
===Original===<br />
<br />
From Indy 4 onwards, sound effects and speech are stored in a separate resource file called "MONSTER.SOU". The format is:<br />
<br />
Block name 4 bytes ("SOU ")<br />
Block size 4 bytes<br />
One or more:<br />
Block name 4 bytes ("VCTL")<br />
Block size 4 bytes<br />
Lip-sync tags variable<br />
Sound data variable ("Crea" block / VOC file)<br />
<br />
The lip-sync tags provide timing information. In v5 the number of tags is stored in the calling text, according to the formula ((num_tags / 2) << 1) + 8. The "Crea" block is an entire Creative VOC file.<br />
<br />
===Compressed===<br />
<br />
ScummVM can use compressed monster.sou files created with the tool "compress_scumm_sou.exe". Aside from using either MP3, OGG, or FLAC formats for the sound data, they contain a mapping table followed by the sound data, like so:<br />
<br />
size_of_table : uint32<br />
size_of_table / 16 times {<br />
orig_offset : uint32<br />
actual_offset : uint32<br />
num_tags : uint32<br />
sound_size : unit32<br />
}<br />
size_of_table / 16 times {<br />
num_tags times {<br />
tag : uint8<br />
}<br />
sound : sound_size (sound file - MP3/OGG/FLAC)<br />
} <br />
<br />
Each entry in the table has 4 items, each item is 4 bytes, so a table with one entry has a size of 16.<br />
<br />
The original offset is what the game will try to play, the actual offset is taken from after the index table.<br />
<br />
Each sound is directly preceded by its lip-synch tags.<br />
<br />
=Sound block types=<br />
This information is gleaned from the ScummVM source code. Any block name with only three characters has a space at the end.<br />
MIDI \ Midi<br />
iMUS /<br />
<br />
SOU subtypes<br />
TOWS - FM Towns<br />
SBL - Sound Blaster digitized sound (Creative VOC file)<br />
ADL - Adlib (OPL FM)<br />
AMI - Amiga MOD<br />
ROL - Roland MT-32<br />
GMD - General MIDI<br />
MAC - Macintosh (occurs in MI2, FOA)<br />
SPK - PC speaker<br />
<br />
Mac0 - Macintosh music type 0<br />
<br />
Mac1 \<br />
RIFF |<br />
TALK > Creative VOC file<br />
DIGI |<br />
Crea /<br />
<br />
HSHD - HE sound type without SOUN header<br />
<br />
FMUS - Used in 3DO versions of HE games</div>Jestar jokinhttps://wiki.scummvm.org/index.php?title=SCUMM/Technical_Reference/Index_File&diff=11042SCUMM/Technical Reference/Index File2009-04-29T06:18:03Z<p>Jestar jokin: Fix mangled ø</p>
<hr />
<div>[[SCUMM/Technical Reference|SCUMM Technical Reference]] &rarr; ''SCUMM index file''<br />
<br />
<br />
= Introduction=<br />
<br />
Most of the information below are retrieved from the [http://scumm.mixnmojo.com/?page=specs&file=indexfiles.txt LucasHacks!] site and from the Pascal source code of the ''IndexFileReader 1.2'' (written by Ben Gorman (Bgbennyboy, http://quick.mixnmojo.com). In addition, ''ScummRevisited'' (written by Jimmi Thøgersen (Serge), http://www.mixnmojo.com/scumm/scummrev) turned out to be very useful in verifying the found offsets.<br />
<br />
The SCUMM index file contains special information to allow quick random access to the resources in the other game files. It also includes the room names and some max limits for the game. The following filenames are used:<br />
<br />
<br />
<table border="2" cellspacing="0" cellpadding="4"><br />
<tr><th width="100">filename</th><th>SCUMM version</th></tr><br />
<tr><td >00.lfl / 000.lfl</td><td>V3/4</td></tr><br />
<tr><td>.000</td><td>V5/6</td></tr><br />
<tr><td>.LA0</td><td>V7/8</td></tr><br />
</table><br />
<br />
<br />
Version 1 to 3 use hardcoded offsets and cannot be treated that easily. For the other games, the index file can be used to determine the [[SCUMM/Versions|SCUMM version]] because there have been slight changes in each version.<br />
<br />
* Version 4<br />
** the 5th and 6th byte match RN or OR<br />
* Version 5: <br />
** RNAM xor'ed with 0x69 at the beginning of the file<br />
** next 4 byte integer value xor'ed with 0x69 is &gt; 9<br />
* Version 6<br />
** RNAM xor'ed with 0x69 at the beginning<br />
** next 4 byte integer value xor'ed with 0x69 is 9 (actually it's the size of the chunk. In V6 games, no room names are stored so the size is 4 bytes (header) + 4 bytes (size) + 1 byte for the termination character).<br />
* Version 7<br />
** RNAM at the beginning of the file (not xor'ed this time)<br />
** next 4 bytes result in BE integer 9 (actually applies only to [[Full Throttle]])<br />
* Version 7 or 8<br />
** RNAM at the beginning of the file<br />
** next 4 bytes integer is &gt; 9<br />
<br />
<br />
How to distinguish between version 7 and 8? Not by looking at the first bytes, but the the size of the chunks is usually bigger because a 4 byte integer is used to store the number of objects.<br />
<br />
= Conventions =<br />
<br />
As usual, the [http://en.wikipedia.org/wiki/Endianness endianness (Wikipedia)] is important. Unless stated, little endianess (LE) is used. <br />
<br />
BE is used as abbreviation for big endianness. <br />
<br />
A '''Chunk''' is a named part of the file, e.g. RNAM. Each chunk has a header that contains at least the chunk name and its size. The following chunks are available:<br />
<br />
<br />
{| border="1" cellspacing="0" cellpadding="4"<br />
|RNAM Room Names<br />
|In V5+<br />
|-<br />
|MAXS Maximum Values<br />
|In V5+<br />
|-<br />
|DROO Directory of Rooms<br />
|In V5+<br />
|-<br />
|DRSC Direcory of Room Scripts<br />
|In V8<br />
|-<br />
|DSCR Directory of Scripts<br />
|In V5+<br />
|-<br />
|DSOU Directory of Sounds<br />
|In V5+<br />
|-<br />
|DCOS Directory of Costumes<br />
|In V5+<br />
|-<br />
|DCHR Directory of Charsets<br />
|In V5+<br />
|-<br />
|DOBJ Directory of Objects<br />
|In V5+<br />
|-<br />
|AARY List of Arrays<br />
|In V6+<br />
|-<br />
|ANAM Animation Names?<br />
|In V7<br />
|-<br />
|RM Room Names<br />
|In V3/4<br />
|-<br />
|0R Directory Of Rooms<br />
|In V3/4<br />
|-<br />
|0S Directory Of Scripts?<br />
|In V3/4<br />
|-<br />
|0N Directory Of Sounds?<br />
|In V3/4<br />
|-<br />
|0C Directory Of Costumes?<br />
|In V3/4<br />
|-<br />
|0O Directory Of Objects?<br />
|In V3/4<br />
|}<br />
<br />
<br />
= Scumm 3/4 =<br />
<br />
* File's aren't xor'ed<br />
<br />
To read in the data, the following pseudo-code can be used:<br />
<br />
Read Number of Items<br />
FROM 1 to "Number of Items" DO<br />
Read subvalue 1<br />
Read subvalue 2<br />
END<br />
<br />
<br />
==RN - Room names ==<br />
<br />
Block Size (4 bytes)<br />
Block Name (2 bytes)<br />
#Room No (1 byte)<br />
#Room Name (9 bytes) XOR'ed with FF<br />
Blank (00) byte (1 byte) Marks end of chunk<br />
<br />
<br />
==0R - Directory of Rooms==<br />
<br />
Block Size (4 bytes)<br />
Block Name (2 bytes)<br />
No of items (2 bytes)<br />
File Number (1 byte)<br />
Offset (4 bytes)<br />
<br />
''File Number'' is interesting if a game is splitted on multiple disks. 0 means ''not used''. <br />
<br />
For ''Offset'' only the value 0 seems to be used.<br />
<br />
==0S - Directory of Scripts ==<br />
<br />
Block Size (4 bytes)<br />
Block Name (2 bytes)<br />
No of items (2 bytes)<br />
Room Number (1 byte)<br />
Offset (4 bytes)<br />
<br />
The global scripts are stored in this directory. The offsets are relative to the room.<br />
<br />
==0N - Directory of Sounds ==<br />
<br />
Block Size (4 bytes)<br />
Block Name (2 bytes)<br />
No of items (2 bytes)<br />
Room Number (1 byte)<br />
Offset (4 bytes)<br />
<br />
Similar to scripts but holds indexes for sounds.<br />
<br />
==0C - Directory of Costumes ==<br />
<br />
Block Size (4 bytes)<br />
Block Name (2 bytes)<br />
No of items (2 bytes)<br />
Room Number (1 byte)<br />
Offset (4 bytes)<br />
<br />
Similar to scripts but holds indexes of customes. <br />
<br />
==0O - Directory of Objects==<br />
<br />
Block Size (4 bytes)<br />
Block Name (2 bytes)<br />
No of items (2 bytes)<br />
Owner+state (1 byte)<br />
<br />
The Object owner and state are encoded in one byte. Example:<br />
<br />
0xA2 &rarr; Owner = 0xA, State = 0x2<br />
<br />
The pseudo decode code would be:<br />
<br />
Owner = ( (Owner+state Byte) AND 0xF0) >> 4<br />
State = (Owner+state Byte) AND 0x0F<br />
<br />
= Scumm 5 =<br />
<br />
* The files are xor'ed with 0x69<br />
<br />
== RNAM - Room Names ==<br />
<br />
Block Name (4 bytes)<br />
Block Size (4 bytes BE)<br />
#Room No (1 byte)<br />
#Room Name (9 bytes) XOR'ed with FF<br />
Blank (00) byte (1 byte) Marks end of chunk<br />
<br />
<br />
== MAXS ==<br />
<br />
Block Name (4 bytes)<br />
Block Size (4 bytes BE)<br />
Variables (2 bytes)<br />
Unknown (2 bytes)<br />
Bit Variables (2 bytes)<br />
Local Objects (2 bytes)<br />
Unknown (2 bytes)<br />
Character Sets (2 bytes)<br />
Unknown (2 bytes)<br />
Unknown (2 bytes)<br />
Inventory Objects (2 bytes)<br />
<br />
== DROO - Directory of Rooms ==<br />
<br />
Block Name (4 bytes)<br />
Block Size (4 bytes BE)<br />
No of items (2 bytes)<br />
*Room Number (1 byte)<br />
*Offset (4 bytes)<br />
<br />
The flow how to read in this kind of information has changed slightly from V3/4.<br />
<br />
Read "No of items"<br />
FROM 1 TO "No of items" DO<br />
Read "Room Number"<br />
END<br />
<br />
FROM 1 TO "No of items" DO<br />
Read "Offset"<br />
END<br />
<br />
First read in all room numbers, then read in all room offsets. <br />
<br />
<br />
== DSCR - Directory of Scripts ==<br />
<br />
Block Name (4 bytes)<br />
Block Size (4 bytes BE)<br />
No of items (2 bytes)<br />
*Room Number (1 byte)<br />
*Offset (4 bytes)<br />
<br />
Indexes for global scripts, see pseudo code above on how to read in the data.<br />
<br />
<br />
== DSOU - Directory of Sound == <br />
<br />
Block Name (4 bytes)<br />
Block Size (4 bytes BE)<br />
No of items (2 bytes)<br />
*Room Number (1 byte)<br />
*Offset (4 bytes)<br />
<br />
Indexes for sound objects.<br />
<br />
<br />
== DCOS - Directory of Costumes ==<br />
<br />
Block Name (4 bytes)<br />
Block Size (4 bytes BE)<br />
No of items (2 bytes)<br />
*Room Number (1 byte)<br />
*Offset (4 bytes)<br />
<br />
Indexes for costumes<br />
<br />
<br />
== DCHR - Director of Charsets ==<br />
<br />
Block Name (4 bytes)<br />
Block Size (4 bytes BE)<br />
No of items (2 bytes)<br />
*Room Number (1 byte)<br />
*Offset (4 bytes)<br />
<br />
Indexes for charsets.<br />
<br />
<br />
== DOBJ - Directory of Objects ==<br />
<br />
Block Name (4 bytes)<br />
Block Size (4 bytes BE)<br />
No of items (2 bytes)<br />
*Owner+state (1 byte)<br />
<br />
Information about objects. See remarks in V3/4 section how the value should be interpreted.<br />
<br />
= Scumm 6 =<br />
<br />
* Files are xor'ed with 0x69<br />
<br />
<br />
== RNAM - Room Names ==<br />
<br />
Blank Byte(00) (1 byte)<br />
<br />
No room names are stored.<br />
<br />
<br />
== MAXS ==<br />
<br />
Block Name (4 bytes)<br />
Block Size (4 bytes BE)<br />
Variables (2 bytes)<br />
Unknown (2 bytes)<br />
Bit Variables (2 bytes)<br />
Local Objects (2 bytes)<br />
Arrays (2 bytes)<br />
Unknown (2 bytes)<br />
Verbs (2 bytes)<br />
Floating Objects (2 bytes)<br />
Inventory Objects (2 bytes)<br />
Rooms (2 bytes)<br />
Scripts (2 bytes)<br />
Sounds (2 bytes)<br />
Character Sets (2 bytes)<br />
Costumes (2 bytes)<br />
Global Objects (2 bytes)<br />
<br />
<br />
== DROO, DSCR, DSOU, DCOS, DCHR, DOBJ ==<br />
<br />
All as in V5<br />
<br />
<br />
== AARY - Array == <br />
<br />
Block Name (4 bytes)<br />
Block Size (4 bytes BE)<br />
#Stop (2 bytes) Stops if 0x0000<br />
#A (2 bytes)<br />
#B (2 bytes)<br />
#C (2 bytes)<br />
<br />
num=AARY no (itinerate through in loop)<br />
if c=1 then<br />
AARY=(num, 1, a, b)<br />
else<br />
AARY=(num, 1, a, b)<br />
<br />
If stop=0 you dont seek past the 6 bytes of A,B,C you just start the loop again.<br />
<br />
<br />
= Scumm 7 = <br />
<br />
* Files aren't xor'ed<br />
<br />
== RNAM - Room names ==<br />
<br />
* As in V6 ?!?!?!<br />
<br />
<br />
== MAXS ==<br />
<br />
Block Name (4 bytes)<br />
Block Size (4 bytes BE)<br />
Variables (2 bytes)<br />
Bit Variables (2 bytes)<br />
Unknown (2 bytes)<br />
Global Objects (2 bytes)<br />
Local Objects (2 bytes)<br />
New Names (2 bytes)<br />
Verbs (2 bytes)<br />
Floating Objects (2 bytes)<br />
Inventory Objects (2 bytes)<br />
Arrays (2 bytes)<br />
Rooms (2 bytes)<br />
Scripts (2 bytes)<br />
Sounds (2 bytes)<br />
Character Sets (2 bytes)<br />
Costumes (2 bytes)<br />
<br />
<br />
== DROO,DSCR,DSOU,DCOS,DCHR,DOBJ,AARY ==<br />
<br />
All as in V5<br />
<br />
<br />
== ANAM - Animation Names ==<br />
<br />
Block Name (4 bytes)<br />
Block Size (4 bytes BE)<br />
No of items (2 bytes<br />
#Name (8 bytes)<br />
#Blank (00) byte (1 byte)<br />
Blank (FF) byte (1 byte) Marks end of chunk<br />
<br />
<br />
= Scumm 8 =<br />
<br />
== RNAM - Room Names ==<br />
<br />
As in V6 ?<br />
<br />
<br />
== MAXS ==<br />
<br />
Block Name (4 bytes)<br />
Block Size (4 bytes BE)<br />
Variables (4 bytes)<br />
Bit Variables (4 bytes)<br />
Unknown (4 bytes)<br />
Scripts (4 bytes)<br />
Sounds (4 bytes)<br />
Character Sets (4 bytes)<br />
Costumes (4 bytes)<br />
Rooms (4 bytes)<br />
Unknown (4 bytes)<br />
Global Objects (4 bytes)<br />
Unknown (4 bytes)<br />
Local Objects (4 bytes)<br />
New Names (4 bytes)<br />
Floating Objects (4 bytes)<br />
Inventory Objects (4 bytes)<br />
Arrays (4 bytes)<br />
Verbs (4 bytes)<br />
<br />
<br />
== DROO - Directory of Rooms ==<br />
<br />
Block Name (4 bytes)<br />
Block Size (4 bytes BE)<br />
No of items (4 bytes)<br />
*Room Number (1 byte)<br />
*Offset (2 bytes)<br />
<br />
<br />
== DRSC - Directory of Room Scripts ==<br />
<br />
Block Name (4 bytes)<br />
Block Size (4 bytes BE)<br />
No of items (4 bytes)<br />
*Room Number (1 byte)<br />
*Offset (2 bytes)<br />
<br />
<br />
== DSCR - Directory of Scripts == <br />
<br />
Block Name (4 bytes)<br />
Block Size (4 bytes BE)<br />
No of items (4 bytes)<br />
*Room Number (1 byte)<br />
*Offset (2 bytes)<br />
<br />
<br />
== DSOU - Directory of Sound ==<br />
<br />
Block Name (4 bytes)<br />
Block Size (4 bytes BE)<br />
No of items (4 bytes)<br />
*Room Number (1 byte)<br />
*Offset (2 bytes)<br />
<br />
<br />
== DCOS - Directory of Costumes ==<br />
<br />
Block Name (4 bytes)<br />
Block Size (4 bytes BE)<br />
No of items (4 bytes)<br />
*Room Number (1 byte)<br />
*Offset (2 bytes)<br />
<br />
<br />
== DCHR - Directory of Charsets ==<br />
<br />
Block Name (4 bytes)<br />
Block Size (4 bytes BE)<br />
No of items (4 bytes)<br />
*Room Number (1 byte)<br />
*Offset (2 bytes)<br />
<br />
<br />
== DOBJ,AARY ==<br />
<br />
As in V7<br />
<br />
<br />
[[Category: SCUMM Technical Reference]]</div>Jestar jokinhttps://wiki.scummvm.org/index.php?title=User:Jestar_jokin&diff=11030User:Jestar jokin2009-04-26T07:03:47Z<p>Jestar jokin: Scummbler v2 is out and not so shoddy</p>
<hr />
<div>HI! Let's have a party, just you and me and everyone we know! WOOOOHOOOO<br />
<br />
I have been mucking around hacking SCUMM games, which is only possible thanks to the fantastic work done by the ScummVM team and all the other reverse engineers out there.<br />
<br />
I have developed a few tools that let you modify or create SCUMM ''V5'' resources:<br />
* Scummbler - compiles SCUMM V5 scripts from the text scripts based on descumm's output. This makes it relatively easy to modify existing script resources in a game.<br />
* ScummPacker - extract & repack the resource files of SCUMM V5 games. You can add new content to games, such as scripts created with Scummbler, or backgrounds created with SCUMM Image Encoder.<br />
* ScummSpeaks - making use of ScummTr, allows you to map sounds in a MONSTER.SOU file (either compressed through ScummVM tools, or uncompressed original format) to lines of text. You can also use it to manipulate MONSTER.SOU files. Currently being used for a project to add speech to Monkey Island (which is really its only use).<br />
* SCUMM Image Encoder (mi2img) - convert between background resources extracted by ScummPacker and PNG files. It can only encode lossless backgrounds with a limited palette (around 160 colours).<br />
<br />
These are all made in Python. You can find them on [http://www.jestarjokin.net/ my website].<br />
<br />
Aside from plugging my toys on this wiki, I also hope to share the knowledge of SCUMM I've picked up in my adventures.<br />
<br />
(Also my name should be in lowercase, but MediaWiki is rubbish when it comes to rubbish names.)</div>Jestar jokinhttps://wiki.scummvm.org/index.php?title=SCUMM/V5_opcodes&diff=11029SCUMM/V5 opcodes2009-04-26T05:28:58Z<p>Jestar jokin: Fix some v3, v4 variant info</p>
<hr />
<div>=SCUMM V5 opcodes=<br />
The following conventions are used in the encoding descriptions.<br />
<br />
{| border="1" cellpadding="2" width=100%<br />
|- style="background:whitesmoke"<br />
|Term||Description<br />
|-<br />
|opcode||The instruction's opcode, with the appropriate bits set according to the parameters.<br />
|-<br />
|aux||An aux opcode that stores parameter bits and no other information. (the base aux opcode seems to always be $01)<br />
|-<br />
|sub-opcode||An aux opcode that indicates a specific function to perform (e.g. the "wait" instruction has sub-opcodes to "wait for message", "wait for actor" etc), as well as storing parameter bits if necessary.<br />
|-<br />
|result||A result pointer. (A standard word pointer, always a LE word.)<br />
|-<br />
|var||A variable pointer. Same as above, but is not written to. Because this is always a variable, the opcode is not affected like it would be with a normal parameter (described below).<br />
|-<br />
|value[8]||An 8-bit constant (a byte).<br />
|-<br />
|value[16]||A 16-bit constant (a word LE).<br />
|-<br />
|value[p8]||An 8-bit parameter. This may be encoded as a word LE if it's a pointer, or a byte if it's a constant.<br />
|-<br />
|value[p16]||A 16-bit parameter. This is always encoded as a word LE, and may be a pointer or constant.<br />
|-<br />
|value[v16]||A variable number of word LE parameters. These are encoded as a sequence of aux[8] param[p16]; param; aux contains the parameter bit to describe param (and is always $01, ignoring the parameter bits). A byte of $FF terminates the sequence. (actually always shown as "value[v16]...")<br />
|-<br />
|value[o]||The offset word for parameter value. This is only encoded if needed, but always at the position indicated. If not specified, the offset word occurs immediately after the parameter.<br />
|-<br />
|value[c]||An ASCII character. Because some instructions use null-terminated strings and some use $FF, the exact format of a string is described in the instruction. Almost always appears as "value[c]..."<br />
|-<br />
|term...||One or more terms.<br />
|}<br />
<br />
Of course, due to the non-orthogonality of the opcodes, there are lots of exceptions.<br />
<br />
<br />
==actorFollowCamera ($52)==<br />
<br />
===Encoding===<br />
opcode actor[p8]<br />
<br />
===Operation===<br />
Sets the camera to follow the given actor?<br />
<br />
<br />
==actorFromPos ($15)==<br />
<br />
===Encoding===<br />
opcode result x[p16] y[p16]<br />
<br />
===Operation===<br />
Returns the actor located at the given co-ordinates.<br />
<br />
<br />
==actorOps ($13)==<br />
parameters depend on auxiliary opcode; terminated by $FF<br />
<br />
===Encoding===<br />
opcode actor[p8] sub-opcode... $FF<br />
<br />
sub-opcodes:<br />
$00 arg1[p8]<br />
$01 costume[p8]<br />
$02 xspeed[p8] yspeed[p8]<br />
$03 sound[p8]<br />
$04 walkframe[p8]<br />
$05 starttalk[p8] endtalk[p8]<br />
$06 standframe[p8]<br />
$07 arg1[p8] arg2[p8] arg3[p8]<br />
$08<br />
$09 elevation[p16]<br />
$0A<br />
$0B index[p8] value[p8]<br />
$0C colour[p8]<br />
$0D name[c]... $00<br />
$0E initframe[p8]<br />
$10 width[p8]<br />
$11 xscale[p8] yscale[p8]<br />
$12<br />
$13 zplane[p8]<br />
$14<br />
$15 <br />
$16 animspeed[p8]<br />
$17 shadow[p8]<br />
<br />
===Operation===<br />
Miscellaneous actions on actors.<br />
<br />
{| border="1" cellpadding="2" width=100%<br />
|- style="background:whitesmoke"<br />
|Opcode||Meaning||Description<br />
|-<br />
|$00||dummy||A dummy case, does nothing (in ScummVM).<br />
|-<br />
|$01||SO_COSTUME||Sets the actor's costume.<br />
|-<br />
|$02||SO_STEP_DIST||Sets the actor's walking speed for x and y.<br />
|-<br />
|$03||SO_SOUND||Associates a sound with the actor (footsteps?)<br />
|-<br />
|$04||SO_WALK_ANIMATION||Sets the current frame of the walking animation.<br />
|-<br />
|$05||SO_TALK_ANIMATION||Sets the start and stop frames of the talking animation.<br />
|-<br />
|$06||SO_STAND_ANIMATION||Sets the current frame of the standing animation.<br />
|-<br />
|$07||SO_ANIMATION||Unknown; seems to be unused in ScummVM.<br />
|-<br />
|$08||SO_DEFAULT||Initializes actor.<br />
|-<br />
|$09||SO_ELEVATION||Sets the actor's elevation to the given value.<br />
|-<br />
|$0A||SO_ANIMATION_DEFAULT||Initializes the actor's animation frames.<br>Init frame = 1<br>Walk frame = 2<br>Stand frame = 3<br>Talk start frame = 4<br>Talk stop frame = 5<br />
|-<br />
|$0B||SO_PALETTE||Sets the colour at the given index to a new value (another entry in the colour lookup table/CLUT). Index must be between 0 and 31 (the number of colours in a costume).<br />
|-<br />
|$0C||SO_TALK_COLOR||Sets the actor's talk colour.<br />
|-<br />
|$0D||SO_ACTOR_NAME||Sets the actor's name to the given null-terminated string.<br />
|-<br />
|$0E||SO_INIT_ANIMATION||Sets the current frame of the initial animation.<br />
|-<br />
|$10||SO_ACTOR_WIDTH||Sets the actor's width.<br />
|-<br />
|$11||SO_ACTOR_SCALE||Sets the actor's X and Y scales.<br />
|-<br />
|$12||SO_NEVER_ZCLIP||Turns off all Z-clipping for the actor.<br />
|-<br />
|$13||SO_ALWAYS_ZCLIP||Forces the actor's Z-clipping for the given Z-plane?<br />
|-<br />
|$14||SO_IGNORE_BOXES||Ignores boxes, turns off Z-clipping, and puts actor somewhere if the actor is in the current room?<br />
|-<br />
|$15||SO_FOLLOW_BOXES||Follows boxes, turns off Z-clipping, and puts actor somewhere if the actor is in the current room?<br />
|-<br />
|$16||SO_ANIMATION_SPEED||Sets the animation speed.<br />
|-<br />
|$17||SO_SHADOW||Sets the shadow mode.<br />
|}<br />
<br />
===Variants===<br />
In SCUMM V3 and V4, sub-opcode $11 (SO_ACTOR_SCALE) only takes one parameter, so X and Y scaling is done at a 1:1 ratio.<br />
<br />
<br />
==actorSetClass ($5D)==<br />
<br />
===Encoding===<br />
opcode object[p16] classes[v16]...<br />
<br />
===Operation===<br />
Makes object inherit from all of the given classes. A class of "0" will clear all of the object's existing class data.<br />
<br />
<br />
==add ($5A)==<br />
<br />
===Encoding===<br />
opcode result value[p16]<br />
<br />
===Operation===<br />
result := result + value<br />
<br />
The variable pointed to by result is read, value is added to it, and the result written back.<br />
<br />
<br />
==and ($17)==<br />
one parameter, uses result<br />
<br />
===Encoding===<br />
opcode result value[p16]<br />
<br />
===Operation===<br />
result := result and value<br />
<br />
The variable pointed to by result is read, logically ANDed with value, and the result written back.<br />
<br />
<br />
==animateActor ($11)==<br />
<br />
===Encoding===<br />
opcode actor[p8] anim[p8]<br />
<br />
===Operation===<br />
Starts the given animation for the given actor.<br />
<br />
<br />
==breakHere ($80)==<br />
no parameters<br />
<br />
===Encoding===<br />
opcode<br />
<br />
===Operation===<br />
Deschedules the currently running thread. Execution continues at the next instruction when the thread's next timeslot comes around.<br />
<br />
<br />
==chainScript ($42)==<br />
one parameter plus varargs<br />
<br />
===Encoding===<br />
opcode script[p8] args[v16]...<br />
<br />
===Operation===<br />
Replaces the currently running script with another one. The current script is terminated immediately and the new script (determined by the given script ID), is executed in the same thread. The new script has its local variables initialised to the list args. Uninitialised variables have undefined values.<br />
<br />
<br />
==cursorCommand ($2C)==<br />
parameters depend on auxiliary opcode<br />
<br />
===Encoding===<br />
opcode sub-opcode<br />
<br />
sub-opcode can be any of the following:<br />
$01<br />
... $01 through $08 take the same arguments ...<br />
$08<br />
$0A cursornum[p8] charletter[p8]<br />
$0B index[p8] x[p8] y[p8]<br />
$0C cursor[p8]<br />
$0D charset[p8]<br />
$0E colours[v16]...<br />
<br />
===Operation===<br />
Miscellaneous actions on cursors & charsets.<br />
<br />
{| border="1" cellpadding="2" width=100%<br />
|- style="background:whitesmoke"<br />
|Opcode||Meaning||Description<br />
|-<br />
|$01||SO_CURSOR_ON||Turns the cursor on.<br />
|-<br />
|$02||SO_CURSOR_OFF||Turns the cursor off.<br />
|-<br />
|$03||SO_USERPUT_ON||Enables user input.<br />
|-<br />
|$04||SO_USERPUT_OFF||Disables user input.<br />
|-<br />
|$05||SO_CURSOR_SOFT_ON||Increments the cursor's state?<br />
|-<br />
|$06||SO_CURSOR_SOFT_OFF||Decrements the cursor's state?<br />
|-<br />
|$07||SO_USERPUT_SOFT_ON||Increments "user input" counter (when greater than 0, user input is enabled).<br />
|-<br />
|$08||SO_USERPUT_SOFT_OFF||Decrements "user input" counter (when 0 or less, user input is disabled).<br />
|-<br />
|$0A||SO_CURSOR_IMAGE||Changes the cursor image to a new one, based on image in a character set. Only used in Loom.<br />
|-<br />
|$0B||SO_CURSOR_HOTSPOT||Changes the hotspot of a cursor. Only used in Loom.<br />
|-<br />
|$0C||SO_CURSOR_SET||Changes the current cursor. Must be between 0 and 3 inclusive.<br />
|-<br />
|$0D||SO_CHARSET_SET||Initializes the given character set.<br />
|-<br />
|$0E||SO_CHARSET_COLORS||Initializes the character set data & colours to the given arguments? Must have 16 arguments?<br />
|}<br />
<br />
===Variants===<br />
In SCUMM V3, sub-opcode $0E performs a different function, to load/initialize a character set.<br />
<br />
opcode $0E arg1[p8] arg2[p8]<br />
<br />
<br />
==cutScene ($40)==<br />
<br />
===Encoding===<br />
opcode args[v16]...<br />
<br />
===Operation===<br />
??? If required, runs a script passing the given arguments. Cutscene data given by the first argument?<br />
<br />
<br />
==debug ($6B)==<br />
one parameter, no result<br />
<br />
===Encoding===<br />
opcode param[p16]<br />
<br />
===Operation===<br />
Passes the parameter to the interpreter's debugger. What this does is entirely platform-specific (and may do nothing).<br />
<br />
<br />
==decrement ($C6)==<br />
no parameters, uses result<br />
<br />
===Encoding===<br />
opcode result<br />
<br />
===Operation===<br />
result := result - 1<br />
<br />
Reads the variable pointed to by result, decrements it, and writes it back. <br />
<br />
<br />
==delay ($2E)==<br />
one constant parameter<br />
<br />
===Encoding===<br />
opcode param[24]<br />
<br />
===Operation===<br />
Suspends the current thread for the appropriate number of 1/60ths of a second. Yes, that really is a 24-bit LE constant.<br />
<br />
<br />
==delayVariable ($2B)==<br />
one constant parameter<br />
<br />
===Encoding===<br />
opcode var<br />
<br />
===Operation===<br />
var is dereferenced and the current thread suspended for that number of 1/60ths of a second.<br />
<br />
<br />
==divide ($5B)==<br />
one parameter, uses result<br />
<br />
===Encoding===<br />
opcode result value[p16]<br />
<br />
===Operation===<br />
result := result / value<br />
<br />
The variable pointed to by result is read, divided by value, and the result written back. If value is zero, the result is undefined (and the interpeter may halt with an error). <br />
<br />
<br />
==doSentence ($19)==<br />
<br />
===Encoding===<br />
opcode verb[p8] objectA[p16] objectB[p16]<br />
<br />
===Operation===<br />
Performs a verb sentence action, e.g. "Use monkey on hydrant". If verb is $FE, the current sentence script is stopped, status cleared etc.<br />
<br />
<br />
==drawBox ($3F)==<br />
two parameters, does not use result, supplementary opcode byte with three more subsequent parameters<br />
<br />
===Encoding===<br />
opcode left[p16] top[p16] auxopcode[8] right[p16] bottom[p16] colour[p8]<br />
<br />
===Operation===<br />
Draws a solid box on the backbuffer from (left, top) to (right, bottom) in the given colour.<br />
<br />
The only part of auxopcode that is relevant are the parameter bits. The rest of the opcode is ignored. <br />
<br />
<br />
==drawObject ($05)==<br />
<br />
===Encoding===<br />
opcode object[p16] sub-opcode<br />
<br />
sub-opcodes:<br />
$01 xpos[p16] ypos[p16]<br />
$02 state[p16]<br />
$1F<br />
<br />
===Operation===<br />
{| border="1" cellpadding="2" width=100%<br />
|- style="background:whitesmoke"<br />
|Opcode||Meaning||Description<br />
|-<br />
|$01||Draw At||Moves the given object to the given co-ordinates, and adds it to the drawing queue.<br />
|-<br />
|$02||Set State||Sets the state of the object, adds it to the drawing queue.<br />
|-<br />
|$1F||Draw||Does not change the object's position (or state?), still adds it to the drawing queue.<br />
|}<br />
<br />
===Variants===<br />
Small header games (v3 and v4) only support the parameters used with sub-opcode $01, e.g:<br />
opcode object[p16] xpos[p16] ypos[p16]<br />
Accordingly, they have three parameter bits, and hence more possible opcodes.<br />
<br />
<br />
==dummy ($A7)==<br />
<br />
===Encoding===<br />
opcode<br />
<br />
===Operation===<br />
V5 specific - The KIXX XL release of Monkey Island 2 (Amiga disk) used this opcode as a dummy, in order to remove copy protection and keep level selection.<br />
<br />
===Variants===<br />
In SCUMM V3 and V4, this opcode is used for the saveLoadVars instruction.<br />
<br />
<br />
==endCutScene ($C0)==<br />
<br />
===Encoding===<br />
opcode<br />
<br />
===Operation===<br />
Ends the cutscene, performing cleanup if necessary.<br />
<br />
<br />
==equalZero ($28)==<br />
jumps<br />
<br />
===Encoding===<br />
opcode var target[16]<br />
<br />
===Operation===<br />
unless (var == 0) goto target<br />
<br />
Target is a byte offset (measured from after this instruction), which will be added to the instruction pointer.<br />
<br />
<br />
==expression ($AC)==<br />
<br />
===Encoding===<br />
opcode result subopcode... $FF<br />
<br />
sub-opcodes:<br />
$01 value[p16]<br />
$02<br />
... $02 through $05 take the same arguments ...<br />
$05<br />
$06 nested-opcode<br />
<br />
===Operation===<br />
Expression mode operates on a stack. Values are pushed on, and operators are applied to the top two items on the stack.<br />
<br />
{| border="1" cellpadding="2" width=100%<br />
|- style="background:whitesmoke"<br />
|Opcode||Meaning||Description<br />
|-<br />
|$01||Value||Pushes a value onto the top of the stack.<br />
|-<br />
|$02||Add||stack[top - 1] + stack[top]<br />
|-<br />
|$03||Subtract||stack[top - 1] - stack[top]<br />
|-<br />
|$04||Multiply||stack[top - 1] * stack[top]<br />
|-<br />
|$05||Divide||stack[top - 1] / stack[top] (if stack[top] is 0 an error occurs)<br />
|-<br />
|$06||Nested Opcode||An entire instruction that returns a result, such as getActorScale. This is interpreted like a normal opcode, but the result is pushed onto the expression stack. (The opcode is passed the special "VAR_RESULT" parameter for "result")<br />
|}<br />
<br />
<br />
==faceActor ($09)==<br />
<br />
===Encoding===<br />
opcode actor[p8] object[p16]<br />
<br />
===Operation===<br />
Dereferences actor, tells actor to face object (presumably based on X/Y co-ordinates).<br />
<br />
<br />
==findInventory ($3D)==<br />
<br />
===Encoding===<br />
opcode result owner[p8] index[p8]<br />
<br />
===Operation===<br />
object := owner.inventory[index]<br />
Searches for all objects owned by owner (an actor or object), and returns the one at the given index (offset).<br />
<br />
<br />
==findObject ($35)==<br />
<br />
===Encoding===<br />
opcode result x[p8] y[p8]<br />
<br />
===Operation===<br />
Returns the first "touchable" local object at the given co-ordinates. Will not match on the bottom or right-hand edges of an object.<br />
<br />
<br />
==freezeScripts ($60)==<br />
<br />
===Encoding===<br />
opcode flag[p8]<br />
<br />
===Operation===<br />
Freezes all scripts (by setting the high bit on each script's status). If flag is >= $80, all freeze resistent scripts will also be frozen. If flag is 0, all scripts are unfrozen. Freezing effects are cumulative - i.e. if script A is frozen twice, and unfrozen once, it will still be frozen until it is unfrozen a second time. A script's frozen status is indicated by the high bit.<br />
<br />
<br />
==getActorCostume ($71)==<br />
<br />
===Encoding===<br />
opcode result actor[p8]<br />
<br />
===Operation===<br />
Returns the actor's current costume.<br />
<br />
<br />
==getActorElevation ($06)==<br />
<br />
===Encoding===<br />
opcode result actor[p8]<br />
<br />
===Operation===<br />
Returns the actor's current elevation.<br />
<br />
<br />
==getActorFacing ($63)==<br />
<br />
===Encoding===<br />
opcode result actor[p8]<br />
<br />
===Operation===<br />
Returns the current direction the actor is facing.<br />
<br />
<br />
==getActorMoving ($56)==<br />
<br />
===Encoding===<br />
opcode result actor[p8]<br />
<br />
===Operation===<br />
Returns the actor's moving status (0 or 1).<br />
<br />
<br />
==getActorRoom ($03)==<br />
<br />
===Encoding===<br />
opcode result actor[p8]<br />
<br />
===Operation===<br />
Returns the room the actor currently occupies?<br />
<br />
<br />
==getActorScale ($3B)==<br />
<br />
===Encoding===<br />
opcode result actor[p8]<br />
<br />
===Operation===<br />
Returns the actor's current scale.<br />
<br />
===Variants===<br />
In Indy3, this opcode is used for waitForActor.<br />
<br />
<br />
==getActorWalkBox ($7B)==<br />
<br />
===Encoding===<br />
opcode result actor[p8]<br />
<br />
===Operation===<br />
Returns the actor's walkbox.<br />
<br />
<br />
==getActorWidth ($6C)==<br />
<br />
===Encoding===<br />
opcode result actor[p8]<br />
<br />
===Operation===<br />
Returns the actor's width.<br />
<br />
<br />
==getActorX ($43)==<br />
<br />
===Encoding===<br />
opcode result actor[p16]<br />
<br />
===Operation===<br />
Returns the actor's current X co-ordinate.<br />
<br />
===Variants===<br />
In Indy3, actor is only one byte.<br />
opcode result actor[p8]<br />
<br />
<br />
==getActorY ($23)==<br />
<br />
===Encoding===<br />
opcode result actor[p16]<br />
<br />
===Operation===<br />
Returns the actor's current Y co-ordinate.<br />
<br />
===Variants===<br />
In Indy3, actor is only one byte.<br />
opcode result actor[p8]<br />
<br />
<br />
==getAnimCounter ($22)==<br />
<br />
===Encoding===<br />
opcode result actor[p8]<br />
<br />
===Operation===<br />
Returns the actor's animation counter.<br />
<br />
===Variants===<br />
This opcode is used for saveLoadGame in SCUMM V3.<br />
<br />
<br />
==getClosestObjActor ($66)==<br />
<br />
===Encoding===<br />
opcode result actor[p16]<br />
<br />
===Operation===<br />
Returns the object closest to the actor. Items that are more than 255 units (pixels in newer games, characters in older games) away from the actor will not be detected.<br />
<br />
<br />
==getDist ($34)==<br />
<br />
===Encoding===<br />
opcode result objA[p16] objB[p16]<br />
<br />
===Operation===<br />
Returns the distance between two actors/objects (objA and objB).<br />
<br />
<br />
==getInventoryCount ($31)==<br />
<br />
===Encoding===<br />
opcode result actor[p8]<br />
<br />
===Operation===<br />
Returns the number of items in an actor's inventory?<br />
<br />
<br />
==getObjectOwner ($10)==<br />
<br />
===Encoding===<br />
opcode result object[p16]<br />
<br />
===Operation===<br />
Returns the owner of an object.<br />
<br />
<br />
==getObjectState ($0F)==<br />
<br />
===Encoding===<br />
opcode result object[p16]<br />
<br />
===Operation===<br />
Returns the state of the object.<br />
<br />
===Variants===<br />
In small header games, this opcode is used for the "ifState" instruction.<br />
<br />
<br />
==getRandomNumber ($16)==<br />
<br />
===Encoding===<br />
opcode result seed[p8]<br />
<br />
===Operation===<br />
Returns a new random number based on the given seed.<br />
<br />
<br />
==getScriptRunning ($68)==<br />
<br />
===Encoding===<br />
opcode result script[p8]<br />
<br />
===Operation===<br />
Returns 1 if the given script is running, 0 if it's not.<br />
<br />
<br />
==getStringWidth ($67)==<br />
<br />
===Encoding===<br />
opcode result strptr[p8]<br />
<br />
===Operation===<br />
Gets the length of the string pointed to by strptr (either a variable or direct byte), stores the returned value in result.<br />
<br />
<br />
==getVerbEntryPoint ($0B)==<br />
<br />
===Encoding===<br />
opcode result object[p16] verb[p16]<br />
<br />
===Operation===<br />
Returns the entry point for the response code/script for when the given verb is applied to the given object? i.e. gets the start of the script to run for the specific user interaction.<br />
<br />
<br />
==ifClassOfIs ($1D)==<br />
jumps<br />
<br />
===Encoding===<br />
opcode value[p16] args[v16]... target[16]<br />
<br />
===Operation===<br />
unless (value.class is one of [args.class]) goto target<br />
<br />
Compares the value's class with all classes given in args.<br />
<br />
Target is a byte offset (measured from after this instruction), which will be added to the instruction pointer.<br />
<br />
<br />
==ifNotState ($2F) (V3-4)==<br />
This opcode is not present in SCUMM V5.<br />
<br />
===Encoding===<br />
opcode object[p16] state[p8] target[16]<br />
<br />
===Operation===<br />
unless (getState(object) != state) goto target<br />
<br />
<br />
==ifState ($0F) (V3-4)==<br />
This opcode is not present in SCUMM V5.<br />
<br />
===Encoding===<br />
opcode object[p16] state[p8] target[16]<br />
<br />
===Operation===<br />
unless (getState(object) == state) goto target<br />
<br />
<br />
==increment ($46)==<br />
no parameters, uses result<br />
<br />
===Encoding===<br />
opcode result<br />
<br />
===Operation===<br />
result := result + 1<br />
<br />
Reads the variable pointed to by result, increments it, and writes it back. <br />
<br />
<br />
==isActorInBox ($1F)==<br />
<br />
===Encoding===<br />
opcode actor[p8] box[p8] target[16]<br />
<br />
===Operation===<br />
Unless the actor's co-ordinates are within the bounds of the given box, jump to target.<br />
<br />
Target is a byte offset (measured from after this instruction), which will be added to the instruction pointer.<br />
<br />
<br />
==isEqual ($48)==<br />
<br />
===Encoding===<br />
opcode var value[p16] target[16]<br />
<br />
===Operation===<br />
unless (value == var) goto target<br />
<br />
Target is a byte offset (measured from after this instruction), which will be added to the instruction pointer.<br />
<br />
<br />
==isGreater ($78)==<br />
<br />
===Encoding===<br />
opcode var value[p16] target[16]<br />
<br />
===Operation===<br />
unless (value > var) goto target<br />
<br />
Target is a byte offset (measured from after this instruction), which will be added to the instruction pointer.<br />
<br />
<br />
==isGreaterEqual ($04)==<br />
<br />
===Encoding===<br />
opcode var value[p16] target[16]<br />
<br />
===Operation===<br />
unless (value >= var) goto target<br />
<br />
Target is a byte offset (measured from after this instruction), which will be added to the instruction pointer.<br />
<br />
<br />
==isLess ($44)==<br />
<br />
===Encoding===<br />
opcode var value[p16] target[16]<br />
<br />
===Operation===<br />
unless (value < var) goto target<br />
<br />
Target is a byte offset (measured from after this instruction), which will be added to the instruction pointer.<br />
<br />
<br />
==isNotEqual ($08)==<br />
<br />
===Encoding===<br />
opcode var value[p16] target[16]<br />
<br />
===Operation===<br />
unless (value != var) goto target<br />
<br />
Target is a byte offset (measured from after this instruction), which will be added to the instruction pointer.<br />
<br />
<br />
==isSoundRunning ($7C)==<br />
<br />
===Encoding===<br />
opcode result sound[p8]<br />
<br />
===Operation===<br />
Returns 1 if sound is running, returns 0 if sound is not running or if the given sound is 0.<br />
<br />
<br />
==jumpRelative ($18)==<br />
jumps<br />
<br />
===Encoding===<br />
opcode target[16]<br />
<br />
===Operation===<br />
PC := PC + target<br />
<br />
The inline constant target is read as a signed word and added to the program counter after the instruction has been read. Therefore, if target is zero, the instruction will do nothing; if target is -3, an infinite loop will result. <br />
<br />
<br />
==lessOrEqual ($38)==<br />
jumps<br />
<br />
===Encoding===<br />
opcode var value[p16] target[16]<br />
<br />
===Operation===<br />
unless (value <= var) goto target<br />
<br />
Target is a byte offset (measured from after this instruction), which will be added to the instruction pointer.<br />
<br />
<br />
==lights ($70)==<br />
<br />
===Encoding===<br />
opcode arg1[p8] arg2[8] arg3[8]<br />
<br />
===Operation===<br />
If arg3 is 0, the "current lights" variable is set to arg1.<br />
If arg3 is 1, the size of the "flashlight" light is determined by arg1 and arg2, for width and height in stripes (which are equivalent to 8 pixels each; see [[SCUMM/Technical Reference/Image resources]]).<br />
<br />
<br />
==loadRoom ($72)==<br />
<br />
===Encoding===<br />
opcode room[p8]<br />
<br />
===Operation===<br />
Loads the given room into memory.<br />
<br />
<br />
==loadRoomWithEgo ($24)==<br />
<br />
===Encoding===<br />
opcode object[p16] room[p8] x[16] y[16]<br />
<br />
===Operation===<br />
Places the Ego actor in room at object's position. If x is not -1, Ego will start moving towards the given x and y co-ordinates. If object is not in the given room an error will occur.<br />
(I think...)<br />
<br />
<br />
==matrixOp ($30)==<br />
<br />
===Encoding===<br />
opcode sub-opcode<br />
<br />
sub-opcodes:<br />
$01 box[p8] val[p8]<br />
$02 box[p8] val[p8]<br />
$03 box[p8] val[p8]<br />
$04<br />
<br />
===Operation===<br />
This instruction manipulates boxes.<br />
<br />
{| border="1" cellpadding="2" width=100%<br />
|- style="background:whitesmoke"<br />
|Opcode||Meaning||Description<br />
|-<br />
|$01||setBoxFlags||Sets the box's flags to the given value.<br />
|-<br />
|$02||setBoxScale||Sets the box's scale.<br />
|-<br />
|$03||setBoxScale||Sets the box's scale to ((val - 1) OR $8000).<br />
|-<br />
|$04||createBoxMatrix||Initializes the matrix of boxes, by determining the distances and shortest paths between boxes.<br />
|}<br />
<br />
===Variants===<br />
SCUMM V3 only has the one instruction, which behaves like setBoxFlags:<br />
opcode box[p8] val[8]<br />
<br />
<br />
==move ($1A)==<br />
<br />
===Encoding===<br />
opcode result value[p16]<br />
<br />
===Operation===<br />
result := value<br />
<br />
Value is moved into result.<br />
<br />
<br />
==multiply ($1B)==<br />
<br />
===Encoding===<br />
opcode result value[p16]<br />
<br />
===Operation===<br />
result := result * value<br />
<br />
The variable pointed to by result is read, multiplied by value, and written back.<br />
<br />
<br />
==notEqualZero ($A8)==<br />
<br />
===Encoding===<br />
opcode var target[16]<br />
<br />
===Operation===<br />
unless (var != 0) goto target<br />
<br />
Target is a byte offset (measured from after this instruction), which will be added to the instruction pointer.<br />
<br />
<br />
==oldRoomEffect ($5C) (V3-4)==<br />
This opcode/instruction not present in SCUMM V5.<br />
<br />
===Encoding===<br />
opcode sub-opcode<br />
<br />
sub-opcodes:<br />
$03 effect[p16]<br />
$?? effect[p16]<br />
<br />
===Operation===<br />
Performs like sub-opcode SO_ROOM_FADE of the roomOps instruction (fade in if effect != 0, otherwise fade out).<br />
<br />
This information may not be correct; descumm says if the sub-opcode is 3, to "set" the effect, but if the sub-opcode is anything else to fade in with the given effect.<br />
<br />
===Variants===<br />
FM-Towns SCUMM V3 performs a different effect, not fully implemented in ScummVM. At the moment ScummVM just forces a redraw of the screen background.<br />
<br />
<br />
==or ($57)==<br />
one parameter, uses result<br />
<br />
===Encoding===<br />
opcode result value[p16]<br />
<br />
===Operation===<br />
result := result or value<br />
<br />
The variable pointed to by result is read, logically ORed with value, and the result written back.<br />
<br />
<br />
==override ($58)==<br />
<br />
===Encoding===<br />
opcode sub-opcode<br />
<br />
sub-opcodes:<br />
$00<br />
$01 $18 target[16]<br />
<br />
===Operation===<br />
If the sub-opcode is 0, marks the end of an override section.<br><br />
If the sub-opcode is not 0, marks the beginning of an override section. The instruction is immediately followed by a "jumpRelative" instruction.<br><br />
Overrides are used by cutscenes; if a cutscene is skipped (if the user presses the ESC key), the script will jump by the given target (offset from the beginOverride instruction).<br />
<br />
<br />
==panCameraTo ($12)==<br />
<br />
===Encoding===<br />
opcode x[p16]<br />
<br />
===Operation===<br />
Starts the camera panning to the given x co-ordinate.<br />
<br />
<br />
==pickupObject ($25) (v5)==<br />
This instruction is only present in SCUMM V5.<br />
<br />
===Encoding===<br />
opcode object[p16] room[p8]<br />
<br />
===Operation===<br />
Adds the given object (located in the given room) to the Ego actor's inventory.<br />
<br />
===Variants===<br />
In SCUMM V3 and V4, this opcode is used for drawObject.<br />
<br />
<br />
==pickupObject ($50) (V3-4)==<br />
This opcode/instruction is not present in SCUMM V5.<br />
<br />
===Encoding===<br />
opcode object[p16]<br />
<br />
===Operation===<br />
Adds the given object (located in the given room) to the Ego actor's inventory. If object < 1, an error is raised. If the object is not found or the object is already in the inventory, this function ends gracefully.<br />
<br />
<br />
==print ($14)==<br />
<br />
===Encoding===<br />
opcode actor[p8] sub-opcode<br />
<br />
sub-opcodes<br />
$00 xpos[p16] ypos[p16]<br />
$01 colour[p8]<br />
$02 right[p16]<br />
$03 width[p16] height[p16]<br />
$04<br />
$06<br />
$07<br />
$08 offset[p16] delay[p16]<br />
$0F string[c]... $FF<br />
<br />
===Operation===<br />
Sets text properties and displays dialogue.<br />
<br />
{| border="1" cellpadding="2" width=100%<br />
|- style="background:whitesmoke"<br />
|Opcode||Meaning||Description<br />
|-<br />
|$00||SO_AT||Sets the position of the text that follows.<br />
|-<br />
|$01||SO_COLOR||Sets the colour of the text.<br />
|-<br />
|$02||SO_CLIPPED||Clips the text's right-hand side (for wrapping?).<br />
|-<br />
|$03||SO_ERASE||Erases characters (not used in ScummVM).<br />
|-<br />
|$04||SO_CENTER||Centres the text.<br />
|-<br />
|$06||SO_LEFT||Left-aligns the text.<br />
|-<br />
|$07||SO_OVERHEAD||Overhead-aligns the text.<br />
|-<br />
|$0F||SO_TEXTSTRING||Prints the text string that follows. Terminated by $FF.<br />
|}<br />
<br />
===Variants===<br />
In SCUMM V3, text function $06 sets the height of the text:<br />
$06 height[p16]<br />
<br />
In Loom CD (SCUMM V4), there is an additional text function $08 (SO_SAY_VOICE), which plays a portion of the CD audio track.<br />
$08 offset[p16] delay[p16]<br />
<br />
<br />
==printEgo ($D8)==<br />
<br />
===Encoding===<br />
opcode sub-opcode<br />
<br />
===Operation===<br />
Exactly the same as print, except the actor is implicitly Ego. See the entry for "print" for further explanation.<br />
<br />
<br />
==pseudoRoom ($CC)==<br />
<br />
===Encoding===<br />
opcode val[8] res[8]... $00<br />
<br />
===Operation===<br />
forall (res) {<br />
if (res >= $80) {<br />
_resourceMapper[res & $7F] := val<br />
}<br />
}<br />
<br />
What does this actually do? We may never know.<br />
<br />
It looks like res values always have the high bit set, e.g. 0x01 becomes 0x81.<br />
<br />
<br />
==putActor ($01)==<br />
<br />
===Encoding===<br />
opcode actor[p8] x[p16] y[p16]<br />
<br />
===Operation===<br />
Puts the actor at the given co-ordinates.<br />
<br />
<br />
==putActorAtObject ($0E)==<br />
<br />
===Encoding===<br />
opcode actor[p8] object[p16]<br />
<br />
===Operation===<br />
Puts the actor at the given object's position. If the object can not be found, a default position is returned (the centre of the screen in ScummVM).<br />
<br />
<br />
==putActorInRoom ($2D)==<br />
<br />
===Encoding===<br />
opcode actor[p8] room[p8]<br />
<br />
===Operation===<br />
Puts the actor in the given room.<br />
<br />
<br />
==resourceRoutines ($0C)==<br />
<br />
===Encoding===<br />
opcode sub-opcode<br />
<br />
sub-opcodes:<br />
$01 resID[p8]<br />
... $01 through $10 take the same arguments ...<br />
$10 resID[p8]<br />
$11<br />
$12 resID[p8]<br />
$13 resID[p8]<br />
$14 room[p8] object[p16]<br />
<br />
===Operation===<br />
resID is unique only within the resource type (e.g. script 11 will not conflict with sound 11).<br />
<br />
{| border="1" cellpadding="2" width=100%<br />
|- style="background:whitesmoke"<br />
|Opcode||Meaning||Description<br />
|-<br />
|$01||SO_LOAD_SCRIPT||Loads the given script into memory.<br />
|-<br />
|$02||SO_LOAD_SOUND||Loads the given sound into memory.<br />
|-<br />
|$03||SO_LOAD_COSTUME||Loads the given costume into memory.<br />
|-<br />
|$04||SO_LOAD_ROOM||Loads the given room into memory.<br />
|-<br />
|$05||SO_NUKE_SCRIPT||Obliterates the given script from memory.<br />
|-<br />
|$06||SO_NUKE_SOUND||Obliterates the given sound from memory.<br />
|-<br />
|$07||SO_NUKE_COSTUME||Obliterates the given costume from memory.<br />
|-<br />
|$08||SO_NUKE_ROOM||Obliterates the given room from memory.<br />
|-<br />
|$09||SO_LOCK_SCRIPT||Locks the given script.<br />
|-<br />
|$0A||SO_LOCK_SOUND||Locks the given sound.<br />
|-<br />
|$0B||SO_LOCK_COSTUME||Locks the given costume.<br />
|-<br />
|$0C||SO_LOCK_ROOM||Locks the given room.<br />
|-<br />
|$0D||SO_UNLOCK_SCRIPT||Unlocks the given script.<br />
|-<br />
|$0E||SO_UNLOCK_SOUND||Unlocks the given sound.<br />
|-<br />
|$0F||SO_UNLOCK_COSTUME||Unlocks the given costume.<br />
|-<br />
|$10||SO_UNLOCK_ROOM||Unlocks the given room.<br />
|-<br />
|$11||SO_CLEAR_HEAP||Clears the heap.<br />
|-<br />
|$12||SO_LOAD_CHARSET||Loads the given character set into memory.<br />
|-<br />
|$13||SO_NUKE_CHARSET||Obliterates the given character set from memory.<br />
|-<br />
|$14||SO_LOAD_OBJECT||Loads the given object from the given room resource.<br />
|}<br />
<br />
===Variants===<br />
FM-Towns games add the following sub-opcodes (these are not confirmed nor implemented in ScummVM):<br />
{| border="1" cellpadding="2" width=100%<br />
|- style="background:whitesmoke"<br />
|Opcode||Meaning||Description<br />
|-<br />
|$20||Unknown||Does nothing, not used in-game.<br />
|-<br />
|$21||Unknown||Does nothing, not used in-game.<br />
|-<br />
|$23||CD Volume||Possibly changes the volume of CD tracks (Loom CD). Takes 1 byte.<br />
|-<br />
|$24||Sound Volume||Sets the loudness of a sound resource. Used in Indy3 and Zak. Takes 2 bytes (left/right volumes?).<br />
|-<br />
|$25||Sound Pitch||Sets the pitch of a sound resource. Used in Indy3 and Zak. Takes 1 byte (pitch = "foo" - "center" semitones. Center is at $32 in the sound resource.)<br />
|}<br />
<br />
<br />
==roomOps ($33)==<br />
<br />
===Encoding===<br />
opcode sub-opcode<br />
<br />
sub-opcodes:<br />
$01 minX[p16] maxX[p16]<br />
$03 b[p16] h[p16]<br />
$04 red[p16] green[p16] blue[p16] aux index[p8]<br />
$05<br />
$06<br />
$07 scale1[p8] y1[p8] aux scale2[p8] y2[p8] aux slot[p8]<br />
$08 scale[p8] startcolour[p8] endcolour[p8]<br />
$09 loadflag[p8] loadslot[p8]<br />
$0A effect[p16]<br />
$0B redscale[p16] greenscale[p16] bluescale[p16] aux startcolour[p8] endcolour[p8]<br />
$0C redscale[p16] greenscale[p16] bluescale[p16] aux startcolour[p8] endcolour[p8]<br />
$0D resID[p8] filename[c]... $00<br />
$0E resID[p8] filename[c]... $00<br />
$0F resID[p8] aux start[p8] end[p8] aux time[p8]<br />
$10 colindex[p8] delay[p8]<br />
<br />
===Operation===<br />
{| border="1" cellpadding="2" width=100%<br />
|- style="background:whitesmoke"<br />
|Opcode||Meaning||Description<br />
|-<br />
|$01||SO_ROOM_SCROLL||Clamps the given arguments so scrolling does not extend past the width of the room or screen.<br />
|-<br />
|$03||SO_ROOM_SCREEN||Initialises a screen.<br />
|-<br />
|$04||SO_ROOM_PALETTE||Adjusts the room's palette.<br />
|-<br />
|$05||SO_ROOM_SHAKE_ON||Starts the room shaking.<br />
|-<br />
|$06||SO_ROOM_SHAKE_OFF||Ends the room shaking.<br />
|-<br />
|$07||SO_ROOM_SCALE||Sets the room's y scales? (slot is 1 greater than actual slot?)<br />
|-<br />
|$08||SO_ROOM_INTENSITY||Lightens/darkens the room's palette.<br />
|-<br />
|$09||SO_ROOM_SAVEGAME||Saves temporary state of the room/game?<br />
|-<br />
|$0A||SO_ROOM_FADE||If effect is 0, fades in the room. Otherwise, fades out with the given effect (taken from the high byte of effect).<br>1 = iris effect<br>2 = box wipe (upper-left to bottom-right)<br>3 = box wipe (upper-right to bottem-left)<br>4 = inverse box wipe.<br />
|-<br />
|$0B||SO_RGB_ROOM_INTENSITY||Lightens/darkens the room's palette, with different scales for red, green and blue.<br />
|-<br />
|$0C||SO_ROOM_SHADOW||Lightens/darkens the shadow palette, with different scales for red, green, and blue.<br />
|-<br />
|$0D||SO_SAVE_STRING||Saves a string resource to the given file?<br />
|-<br />
|$0E||SO_LOAD_STRING||Loads a string resource from a given file?<br />
|-<br />
|$0F||SO_ROOM_TRANSFORM||Manipulates palettes, strings?<br />
|-<br />
|$10||SO_CYCLE_SPEED||Starts colour cycling with delay? colIndex is between 0 and 16<br />
|}<br />
<br />
===Variants===<br />
SCUMM V3 (non-PC Engine) encodes the arguments before the sub-opcode:<br />
opcode arg1[p16] arg2[p16] sub-opcode<br />
<br />
Small header games (V3 and V4) include an extra sub-opcode, $02 (SO_ROOM_COLOR), which adjusts the room's palette:<br />
opcode $02 colour[p16] index[p16]<br />
... or for V3 games ...<br />
opcode colour[p16] index[p16] $02<br />
<br />
In small header games, sub-opcode $04 (SO_ROOM_PALETTE) affects the shadow palette, and only accepts two arguments, a "room colour slot" (palette entry? between 0 and 256) and an index:<br />
opcode $04 colour[p16] index[p16]<br />
... or for V3 games ...<br />
opcode colour[p16] index[p16] $04<br />
<br />
In FM-Towns games, sub-opcode $0A performs a different function and has its own sub-opcodes (some unknown and all not yet implemented in ScummVM):<br />
opcode $0A sub-opcode<br />
<br />
{| border="1" cellpadding="2" width=100%<br />
|- style="background:whitesmoke"<br />
|Opcode||Meaning||Description<br />
|-<br />
|$08||||compose kMainVirtScreen over a screen buffer<br />
|-<br />
|$09||||call 0x110:0x20 _ax=0x601 _edx=2<br />
|-<br />
|$0A||||call 0x110:0x20 _ax=0x601 _edx=3<br />
|-<br />
|$0B||||clear screen 0x1C:0x45000 sizeof(640 * 320)<br />
|-<br />
|$0C||||call 0x110:0x20 _ax=0x601 _edx=0<br />
|-<br />
|$0D||||call 0x110:0x20 _ax=0x601 _edx=1<br />
|-<br />
|$10||||enable clearing of a screen buffer in drawBitmap()<br />
|-<br />
|$11||||disable clearing of a screen buffer in drawBitmap()<br />
|-<br />
|$12||||clear a screen buffer<br />
|-<br />
|$13||||enable palette operations (palManipulate(), cyclePalette() etc.)<br />
|-<br />
|$14||||disable palette operations<br />
|-<br />
|$15||||disable clearing of screen 0x1C:0x5000 sizeof(640 * 320) in initScreens()<br />
|-<br />
|$16||||enable clearing of screen 0x1C:0x5000 sizeof(640 * 320) in initScreens()<br />
|-<br />
|$1E||||Unknown<br />
|}<br />
<br />
<br />
==saveLoadGame ($22) (V3-4)==<br />
This instruction is not present in SCUMM V5; its opcode is used for "getAnimCounter".<br />
<br />
===Encoding===<br />
opcode result arg1[p8]<br />
<br />
===Operation===<br />
The slot is determined by taking the lower 5 bits of arg1. The upper 3 bits determine an aux opcode, that performs an action described in the table below.<br />
<br />
{| border="1" cellpadding="2" width=100%<br />
|- style="background:whitesmoke"<br />
|Opcode||Meaning||Description<br />
|-<br />
|$00||Num. Available Slots||Returns the number of save slots available.<br />
|-<br />
|$20||Drive||In V3, returns the type of drive (0 = ???, 1 = A or B [floppy], 2 = hard drive).<br>In V4, sets the current drive (returns 1).<br />
|-<br />
|$40||Load Game||Loads a game from the given slot (returns 3 if successful, 5 otherwise).<br />
|-<br />
|$80||Save Game||Saves a game to the given slot (returns 0 if successful, 2 otherwise).<br />
|-<br />
|$C0||Test For Game||Tests if a save exists in the given slot (returns 6 if so, 7 otherwise).<br />
|}<br />
<br />
<br />
==saveLoadVars ($A7) (V3-4)==<br />
This instruction is not present in SCUMM V5; its opcode is used as a dummy.<br />
<br />
===Encoding===<br />
opcode sub-opcode<br />
<br />
sub-opcodes:<br />
$01 sub-sub-opcode... $00<br />
$02 sub-sub-opcode... $00<br />
<br />
$01 (save) sub-sub-opcodes:<br />
$01 resultA resultB<br />
$02 arg1[p8] arg2[p8]<br />
$03 filename[c]... $00<br />
$04<br />
$1F<br />
<br />
$02 (load) sub-sub-opcodes:<br />
$01 resultA resultB<br />
$02 arg1[p8] arg2[p8]<br />
$03 filename[c]... $00<br />
$04<br />
$1F<br />
<br />
===Operation===<br />
{| border="1" cellpadding="2" width=100%<br />
|- style="background:whitesmoke"<br />
|Opcode||Meaning||Description<br />
|-<br />
|$01||SO_SAVE_VARS||Saves variables (for saving games?)<br />
|-<br />
|$02?||SO_RESTORE_VERBS||Loads variables (for saving games?)<br>(I have not verified that restore vars is $02, as the ScummVM code only compares to $01.)<br />
|}<br />
<br />
{| border="1" cellpadding="2" width=100%<br />
|- style="background:whitesmoke"<br />
|Opcode||Meaning||Description<br />
|-<br />
|$01||Write Vars||Writes a range of variables.<br />
|-<br />
|$02||Write Strings||Writes a range of string variables.<br />
|-<br />
|$03||Open File||Opens a file for writing.<br />
|-<br />
|$04||Dummy||Does nothing.<br />
|-<br />
|$1F||Close File||Closes the last opened file.<br />
|}<br />
<br />
{| border="1" cellpadding="2" width=100%<br />
|- style="background:whitesmoke"<br />
|Opcode||Meaning||Description<br />
|-<br />
|$01||Read Vars||Reads a range of variables.<br />
|-<br />
|$02||Read Strings||Reads a range of string variables.<br />
|-<br />
|$03||Open File||Opens a file for reading.<br />
|-<br />
|$04||Dummy||Does nothing.<br />
|-<br />
|$1F||Close File||Closes the last opened file.<br />
|}<br />
<br />
<br />
==saveRestoreVerbs ($AB)==<br />
<br />
===Encoding=== <br />
opcode sub-opcode<br />
<br />
sub-opcodes: <br />
$01 start[p8] end[p8] mode[p8]<br />
$02 start[p8] end[p8] mode[p8]<br />
$03 start[p8] end[p8] mode[p8]<br />
<br />
===Operation===<br />
{| border="1" cellpadding="2" width=100%<br />
|- style="background:whitesmoke"<br />
|Opcode||Meaning||Description<br />
|-<br />
|$01||SO_SAVE_VERBS||For all verbs between start and end, sets the "saveid" to mode. <br />
|-<br />
|$02||SO_RESTORE_VERBS||For all verbs between start and end and matching mode, kills any existing verb, sets the saveid to 0 and generally inits the verb.<br />
|-<br />
|$03||SO_DELETE_VERBS||For all verbs between start and end and matching mode, kills any existing verb.<br />
|}<br />
<br />
<br />
==setCameraAt ($32)==<br />
<br />
===Encoding===<br />
opcode x[p16]<br />
<br />
===Operation===<br />
Sets the camera's x position.<br />
<br />
<br />
==setObjectName ($54)==<br />
<br />
===Encoding===<br />
opcode object[p16] name[c]... $00<br />
<br />
===Operation===<br />
Sets the given object's name.<br />
<br />
<br />
==setOwnerOf ($29)==<br />
<br />
===Encoding===<br />
opcode object[p16] owner[p8]<br />
<br />
===Operation===<br />
Sets the owner of the object.<br />
<br />
<br />
==setState ($07)==<br />
<br />
===Encoding===<br />
opcode object[p16] state[p8]<br />
<br />
===Operation===<br />
Sets the state of the object.<br />
<br />
<br />
==setVarRange ($26)==<br />
non-standard encoding<br />
<br />
===Encoding===<br />
opcode result number[8] values[8]...<br />
or<br />
opcode result number[8] values[16]...<br />
<br />
===Operation===<br />
for (i = 0; i < number; i++) {<br />
&#42;result + i := values[i];<br />
}<br />
<br />
This sets a number of variables to the given parameters. The starting variable is given as "result", and the number of variables to modify is given as "number". This is followed by the same number of values, which will be put into the variable locations. The values are constants, and can be either 16-bit, if the highest bit of the opcode is set, i.e. $A6; or 8-bit, if the highest bit of the opcode is not set, i.e. $26. Note that all values are affected by the opcode's high bit; you can't mix 8 and 16-bit values.<br />
<br />
descumm example:<br />
setVarRange(Var[178],9,[0,0,0,0,0,0,0,0,0]);<br />
<br />
This sets variables 178 to 186 (inclusive) to 0.<br />
<br />
<br />
==soundKludge ($4C)==<br />
<br />
===Encoding===<br />
opcode items[v16]...<br />
<br />
===Operation===<br />
If the first item is -1, the existing sound queue is processed. Otherwise, the list of items is added to the queue.<br />
<br />
===Variants===<br />
In SCUMM V3 and V4 (small header) games, this opcode is used for the WaitForSentence instruction.<br />
<br />
<br />
==startMusic ($02)==<br />
<br />
===Encoding===<br />
opcode music[p8]<br />
<br />
===Operation===<br />
Adds the music in to the queue to be played.<br />
<br />
===Variants===<br />
In FM-Towns (SCUMM V3) games, this instruction performs different functions (some kind of Audio CD status query function; some partially implemented in ScummVM):<br />
opcode result sub-opcode<br />
<br />
{| border="1" cellpadding="2" width=100%<br />
|- style="background:whitesmoke"<br />
|Opcode||Meaning||Description<br />
|-<br />
|$00||Is Playing||Returns true if a CD audio track is currently playing.<br />
|-<br />
|$FC||Unpause CD||Unpauses the CD audio track.<br />
|-<br />
|$FD||Pause CD||Pauses the CD audio track.<br />
|-<br />
|$FE||Get CD Sound||Returns the current CD sound.<br />
|-<br />
|$FF||CD Volume||Might return the the current CD volume in FM-Towns Loom.<br />
|-<br />
|other||Track Length||Returns the track length in seconds.<br />
|}<br />
<br />
<br />
==startObject ($37)==<br />
<br />
===Encoding===<br />
opcode object[p16] script[p8] args[v16]...<br />
<br />
===Operation===<br />
Starts the object's script (OBCD blocks), passing the given arguments.<br />
<br />
<br />
==startScript ($0A)==<br />
one parameter plus varargs, extra encoding in opcode<br />
<br />
===Encoding===<br />
opcode script[p8] args[v16]...<br />
<br />
===Operation===<br />
Spawns a new thread running the code in script script. The new script has its local variables initialised to the list args. Uninitialised variables have undefined values.<br />
<br />
The opcode carries extra information: <br />
<br />
{| border="1" cellpadding="2" width=10%<br />
|- style="background:whitesmoke"<br />
|7||6||5||4 0<br />
|-<br />
|P1||R||F||$0A<br />
|}<br />
<br />
P1 = standard parameter bit<br><br />
R = indicates that the script is recursive<br><br />
F = indicates that the script is freeze resistant (a call to freezeScripts will skip this script, unless the "force freeze" bit of the freezeScripts opcode is set).<br />
<br />
<br />
==startSound ($1C)==<br />
<br />
===Encoding===<br />
opcode sound[p8]<br />
<br />
===Operation===<br />
Adds the given sound to the sound queue to be played.<br />
<br />
<br />
==stopMusic ($20)==<br />
<br />
===Encoding===<br />
opcode<br />
<br />
===Operation===<br />
Stops all sounds.<br />
<br />
<br />
==stopObjectCode ($A0 or $00)==<br />
<br />
===Encoding===<br />
opcode<br />
<br />
===Operation===<br />
Marks the calling script as dead, to be later pruned from the thread pool. Cleans up residual arrays. Should always be the last instruction in a script.<br />
<br />
$A0 is present in LSCR and SCRP files... when does $00 occur?<br />
<br />
<br />
==stopObjectScript ($6E)==<br />
<br />
===Encoding===<br />
opcode script[p16]<br />
<br />
===Operation===<br />
Marks the given object script as dead, to be later pruned from the thread pool. Cleans up residual arrays.<br />
<br />
<br />
==stopScript ($62)==<br />
<br />
===Encoding===<br />
opcode script[p8]<br />
<br />
===Operation===<br />
Marks the given script as dead, to be later pruned from the thread pool. Cleans up residual arrays.<br />
<br />
<br />
==stopSound ($3C)==<br />
<br />
===Encoding===<br />
opcode sound[p8]<br />
<br />
===Operation===<br />
Stops the given sound.<br />
<br />
<br />
==stringOps ($27)==<br />
parameters depend on sub-opcode<br />
<br />
===Encoding===<br />
opcode sub-opcode<br />
<br />
sub-opcodes:<br />
$01 stringID[p8] string[c]... $00<br />
$02 destID[p8] srcID[p8]<br />
$03 stringID[p8] index[p8] char[c]<br />
$04 result stringID[p8] index[p8]<br />
$05 stringID[p8] size[p8]<br />
<br />
===Operation===<br />
Miscellaneous actions on strings (Arrays, referred to by resource number).<br />
<br />
{| border="1" cellpadding="2" width=100%<br />
|- style="background:whitesmoke"<br />
|Opcode||Meaning||Description<br />
|-<br />
|$01||Load String||Loads the inline null-terminated string into the resource slot given by stringID.<br />
|-<br />
|$02||Copy String||Creates a duplicate of the string at resource slot srcID into destID. The old string at destID is lost.<br />
|-<br />
|$03||Write Character||Writes char at the given index (offset) of the string resource located at slot stringID. Out of bounds accesses cause undefined behaviour.<br />
|-<br />
|$04||Read Character||Reads a byte (character) at the given index (offset) of the string resource located at slot stringID, and writes it to result. Out of bounds accesses cause undefined behaviour.<br />
|-<br />
|$05||New String||Allocates or frees a string (Array), located at resource slot stringID. The string is initialised to size; if size is zero, the string is freed.<br />
|}<br />
<br />
<br />
==subtract ($3A)==<br />
<br />
===Encoding===<br />
opcode result value[p16]<br />
<br />
===Operation===<br />
result := result - value<br />
<br />
The variable pointed to by result is read, value is subtracted from it, and the result written back.<br />
<br />
<br />
==systemOps ($98)==<br />
<br />
===Encoding===<br />
opcode sub-opcode<br />
<br />
sub-opcodes:<br />
$01<br />
$02<br />
$03<br />
<br />
===Operation===<br />
{| border="1" cellpadding="2" width=100%<br />
|- style="background:whitesmoke"<br />
|Opcode||Meaning||Description<br />
|-<br />
|$01||SO_RESTART||Restarts the game.<br />
|-<br />
|$02||SO_PAUSE||Pauses/unpauses the game.<br />
|-<br />
|$03||SO_QUIT||Quits the game.<br />
|}<br />
<br />
<br />
==verbOps ($7A)==<br />
<br />
===Encoding===<br />
opcode verbID[p8] sub-opcode... $FF<br />
<br />
sub-opcodes:<br />
$01 object[p16]<br />
$02 name[c]... $00<br />
$03 colour[p8]<br />
$04 hicolour[p8]<br />
$05 left[p16] top[p16]<br />
$06<br />
$07<br />
$08<br />
$09<br />
$10 colour[p8]<br />
$11<br />
$12 key[p8]<br />
$13<br />
$14 stringID[p16]<br />
$16 object[p16] room[p8]<br />
$17 colour[p8]<br />
<br />
===Operation===<br />
{| border="1" cellpadding="2" width=100%<br />
|- style="background:whitesmoke"<br />
|Opcode||Meaning||Description<br />
|-<br />
|$01||SO_VERB_IMAGE||Assigns an object (image) to a verb.<br />
|-<br />
|$02||SO_VERB_NAME||Assigns the in-line name to the verb slot.<br />
|-<br />
|$03||SO_VERB_COLOR||Sets the colour of the verb.<br />
|-<br />
|$04||SO_VERB_HICOLOR||Sets the highlight colour of the verb.<br />
|-<br />
|$05||SO_VERB_AT||Sets the verb's top-left co-ordinates.<br />
|-<br />
|$06||SO_VERB_ON||Makes this verb active.<br />
|-<br />
|$07||SO_VERB_OFF||Makes this verb inactive.<br />
|-<br />
|$08||SO_VERB_DELETE||Kills this verb.<br />
|-<br />
|$09||SO_VERB_NEW||Creates a verb in the slot for the given verbID. If the slot is 0 (verb doesn't already exist), will add it to the next unusued slot; if this exceeds the global maximum number of verbs an error will be raised.<br />
|-<br />
|$10||SO_VERB_DIMCOLOR||Sets the dim colour of the verb.<br />
|-<br />
|$11||SO_VERB_DIM||Dims this verb.<br />
|-<br />
|$12||SO_VERB_KEY||Sets the key code (maybe ASCII char?) associated with this verb.<br />
|-<br />
|$13||SO_VERB_CENTER||Centres the verb?<br />
|-<br />
|$14||SO_VERB_NAME_STR||Loads the given string resource into the verb's slot. If either the string resource or verb slot is not found (0), the verb resource is nuked.<br />
|-<br />
|$16||Assign Object||Assigns an object from the given room to the verb (if the object's image index is not already assigned to the given object).<br />
|-<br />
|$17||Set Back Colour||Sets the background colour of the verb?<br />
|}<br />
<br />
<br />
==wait ($AE)==<br />
<br />
===Encoding===<br />
opcode sub-opcode<br />
<br />
sub-opcodes:<br />
$01 actor[p8]<br />
$02 <br />
$03<br />
$04<br />
<br />
===Operation===<br />
{| border="1" cellpadding="2" width=100%<br />
|- style="background:whitesmoke"<br />
|Opcode||Meaning||Description<br />
|-<br />
|$01||SO_WAIT_FOR_ACTOR||If the given actor is moving, breaks and resumes at this instruction again.<br />
|-<br />
|$02||SO_WAIT_FOR_MESSAGE||If the global variable VAR_HAVE_MSG (Var[3]) is not zero, breaks and resumes at this instruction again.<br />
|-<br />
|$03||SO_WAIT_FOR_CAMERA||If the camera has not reached its destination x position, breaks and resumes at this instruction again.<br />
|-<br />
|$04||SO_WAIT_FOR_SENTENCE||If there is a sentence present?, breaks and resumes at this instruction again<br />
|}<br />
<br />
===Variants===<br />
In Indy3 (non-Macintosh), this opcode only acts as SO_WAIT_FOR_MESSAGE and omits the sub-opcode.<br />
opcode<br />
<br />
<br />
==walkActorTo ($1E)==<br />
<br />
===Encoding===<br />
opcode actor[p8] x[p16] y[p16]<br />
<br />
===Operation===<br />
Sets the actor to begin walking to the given position.<br />
<br />
<br />
==walkActorToActor ($0D)==<br />
<br />
===Encoding===<br />
opcode walker[p8] walkee[p8] distance[8]<br />
<br />
===Operation===<br />
Walks walker towards walkee's position by the given distance. Walker and walkee are both actors.<br />
<br />
<br />
==walkActorToObject ($36)==<br />
<br />
===Encoding===<br />
opcode actor[p8] object[p16]<br />
<br />
===Operation===<br />
Sets the actor to begin walking to the given object's position.<br />
<br />
<br />
=Variables=<br />
<br />
A number of variables are reserved for use by the SPUTM/SCUMM engine. Here is a list of known variables and their corresponding numbers, taken from the ScummVM source code.<br />
<br />
VAR_RESULT = 0; // descumm claims var 0 is the result var (for expressions)<br />
VAR_KEYPRESS = 0; // script_v5_.cpp claims var 0 is for keypresses...<br />
VAR_EGO = 1;<br />
VAR_CAMERA_POS_X = 2;<br />
VAR_HAVE_MSG = 3;<br />
VAR_ROOM = 4;<br />
VAR_OVERRIDE = 5;<br />
VAR_MACHINE_SPEED = 6;<br />
VAR_ME = 7;<br />
VAR_NUM_ACTOR = 8;<br />
VAR_CURRENT_LIGHTS = 9;<br />
VAR_CURRENTDRIVE = 10;<br />
VAR_TMR_1 = 11;<br />
VAR_TMR_2 = 12;<br />
VAR_TMR_3 = 13;<br />
VAR_MUSIC_TIMER = 14;<br />
VAR_ACTOR_RANGE_MIN = 15;<br />
VAR_ACTOR_RANGE_MAX = 16;<br />
VAR_CAMERA_MIN_X = 17;<br />
VAR_CAMERA_MAX_X = 18;<br />
VAR_TIMER_NEXT = 19;<br />
VAR_VIRT_MOUSE_X = 20;<br />
VAR_VIRT_MOUSE_Y = 21;<br />
VAR_ROOM_RESOURCE = 22;<br />
VAR_LAST_SOUND = 23;<br />
VAR_CUTSCENEEXIT_KEY = 24;<br />
VAR_TALK_ACTOR = 25;<br />
VAR_CAMERA_FAST_X = 26;<br />
VAR_SCROLL_SCRIPT = 27;<br />
VAR_ENTRY_SCRIPT = 28;<br />
VAR_ENTRY_SCRIPT2 = 29;<br />
VAR_EXIT_SCRIPT = 30;<br />
VAR_EXIT_SCRIPT2 = 31;<br />
VAR_VERB_SCRIPT = 32;<br />
VAR_SENTENCE_SCRIPT = 33;<br />
VAR_INVENTORY_SCRIPT = 34;<br />
VAR_CUTSCENE_START_SCRIPT = 35;<br />
VAR_CUTSCENE_END_SCRIPT = 36;<br />
VAR_CHARINC = 37;<br />
VAR_WALKTO_OBJ = 38;<br />
VAR_DEBUGMODE = 39;<br />
VAR_HEAPSPACE = 40;<br />
VAR_RESTART_KEY = 42;<br />
VAR_PAUSE_KEY = 43;<br />
VAR_MOUSE_X = 44;<br />
VAR_MOUSE_Y = 45;<br />
VAR_TIMER = 46;<br />
VAR_TIMER_TOTAL = 47;<br />
VAR_SOUNDCARD = 48;<br />
VAR_VIDEOMODE = 49;<br />
VAR_MAINMENU_KEY = 50;<br />
VAR_FIXEDDISK = 51;<br />
VAR_CURSORSTATE = 52;<br />
VAR_USERPUT = 53;<br />
VAR_V5_TALK_STRING_Y = 54;<br />
VAR_SOUNDRESULT = 56;<br />
VAR_TALKSTOP_KEY = 57;<br />
VAR_FADE_DELAY = 59;<br />
VAR_NOSUBTITLES = 60;<br />
VAR_SOUNDPARAM = 64;<br />
VAR_SOUNDPARAM2 = 65;<br />
VAR_SOUNDPARAM3 = 66;<br />
VAR_INPUTMODE = 67; // 1 is keyboard, 2 is joystick, 3 is mouse<br />
VAR_MEMORY_PERFORMANCE = 68;<br />
VAR_VIDEO_PERFORMANCE = 69;<br />
VAR_ROOM_FLAG = 70;<br />
VAR_GAME_LOADED = 71;<br />
VAR_NEW_ROOM = 72;<br />
<br />
<br />
=Table of Parameters=<br />
Please see the wiki page [[SCUMM/V5_opcodes/Table]] for a concise rendition of the above information (with a few omissions dues to the complexity of the instructions).</div>Jestar jokinhttps://wiki.scummvm.org/index.php?title=SCUMM/V5_opcodes&diff=11028SCUMM/V5 opcodes2009-04-26T04:40:47Z<p>Jestar jokin: </p>
<hr />
<div>=SCUMM V5 opcodes=<br />
The following conventions are used in the encoding descriptions.<br />
<br />
{| border="1" cellpadding="2" width=100%<br />
|- style="background:whitesmoke"<br />
|Term||Description<br />
|-<br />
|opcode||The instruction's opcode, with the appropriate bits set according to the parameters.<br />
|-<br />
|aux||An aux opcode that stores parameter bits and no other information. (the base aux opcode seems to always be $01)<br />
|-<br />
|sub-opcode||An aux opcode that indicates a specific function to perform (e.g. the "wait" instruction has sub-opcodes to "wait for message", "wait for actor" etc), as well as storing parameter bits if necessary.<br />
|-<br />
|result||A result pointer. (A standard word pointer, always a LE word.)<br />
|-<br />
|var||A variable pointer. Same as above, but is not written to. Because this is always a variable, the opcode is not affected like it would be with a normal parameter (described below).<br />
|-<br />
|value[8]||An 8-bit constant (a byte).<br />
|-<br />
|value[16]||A 16-bit constant (a word LE).<br />
|-<br />
|value[p8]||An 8-bit parameter. This may be encoded as a word LE if it's a pointer, or a byte if it's a constant.<br />
|-<br />
|value[p16]||A 16-bit parameter. This is always encoded as a word LE, and may be a pointer or constant.<br />
|-<br />
|value[v16]||A variable number of word LE parameters. These are encoded as a sequence of aux[8] param[p16]; param; aux contains the parameter bit to describe param (and is always $01, ignoring the parameter bits). A byte of $FF terminates the sequence. (actually always shown as "value[v16]...")<br />
|-<br />
|value[o]||The offset word for parameter value. This is only encoded if needed, but always at the position indicated. If not specified, the offset word occurs immediately after the parameter.<br />
|-<br />
|value[c]||An ASCII character. Because some instructions use null-terminated strings and some use $FF, the exact format of a string is described in the instruction. Almost always appears as "value[c]..."<br />
|-<br />
|term...||One or more terms.<br />
|}<br />
<br />
Of course, due to the non-orthogonality of the opcodes, there are lots of exceptions.<br />
<br />
<br />
==actorFollowCamera ($52)==<br />
<br />
===Encoding===<br />
opcode actor[p8]<br />
<br />
===Operation===<br />
Sets the camera to follow the given actor?<br />
<br />
<br />
==actorFromPos ($15)==<br />
<br />
===Encoding===<br />
opcode result x[p16] y[p16]<br />
<br />
===Operation===<br />
Returns the actor located at the given co-ordinates.<br />
<br />
<br />
==actorOps ($13)==<br />
parameters depend on auxiliary opcode; terminated by $FF<br />
<br />
===Encoding===<br />
opcode actor[p8] sub-opcode... $FF<br />
<br />
sub-opcodes:<br />
$00 arg1[p8]<br />
$01 costume[p8]<br />
$02 xspeed[p8] yspeed[p8]<br />
$03 sound[p8]<br />
$04 walkframe[p8]<br />
$05 starttalk[p8] endtalk[p8]<br />
$06 standframe[p8]<br />
$07 arg1[p8] arg2[p8] arg3[p8]<br />
$08<br />
$09 elevation[p16]<br />
$0A<br />
$0B index[p8] value[p8]<br />
$0C colour[p8]<br />
$0D name[c]... $00<br />
$0E initframe[p8]<br />
$10 width[p8]<br />
$11 xscale[p8] yscale[p8]<br />
$12<br />
$13 zplane[p8]<br />
$14<br />
$15 <br />
$16 animspeed[p8]<br />
$17 shadow[p8]<br />
<br />
===Operation===<br />
Miscellaneous actions on actors.<br />
<br />
{| border="1" cellpadding="2" width=100%<br />
|- style="background:whitesmoke"<br />
|Opcode||Meaning||Description<br />
|-<br />
|$00||dummy||A dummy case, does nothing (in ScummVM).<br />
|-<br />
|$01||SO_COSTUME||Sets the actor's costume.<br />
|-<br />
|$02||SO_STEP_DIST||Sets the actor's walking speed for x and y.<br />
|-<br />
|$03||SO_SOUND||Associates a sound with the actor (footsteps?)<br />
|-<br />
|$04||SO_WALK_ANIMATION||Sets the current frame of the walking animation.<br />
|-<br />
|$05||SO_TALK_ANIMATION||Sets the start and stop frames of the talking animation.<br />
|-<br />
|$06||SO_STAND_ANIMATION||Sets the current frame of the standing animation.<br />
|-<br />
|$07||SO_ANIMATION||Unknown; seems to be unused in ScummVM.<br />
|-<br />
|$08||SO_DEFAULT||Initializes actor.<br />
|-<br />
|$09||SO_ELEVATION||Sets the actor's elevation to the given value.<br />
|-<br />
|$0A||SO_ANIMATION_DEFAULT||Initializes the actor's animation frames.<br>Init frame = 1<br>Walk frame = 2<br>Stand frame = 3<br>Talk start frame = 4<br>Talk stop frame = 5<br />
|-<br />
|$0B||SO_PALETTE||Sets the colour at the given index to a new value (another entry in the colour lookup table/CLUT). Index must be between 0 and 31 (the number of colours in a costume).<br />
|-<br />
|$0C||SO_TALK_COLOR||Sets the actor's talk colour.<br />
|-<br />
|$0D||SO_ACTOR_NAME||Sets the actor's name to the given null-terminated string.<br />
|-<br />
|$0E||SO_INIT_ANIMATION||Sets the current frame of the initial animation.<br />
|-<br />
|$10||SO_ACTOR_WIDTH||Sets the actor's width.<br />
|-<br />
|$11||SO_ACTOR_SCALE||Sets the actor's X and Y scales.<br />
|-<br />
|$12||SO_NEVER_ZCLIP||Turns off all Z-clipping for the actor.<br />
|-<br />
|$13||SO_ALWAYS_ZCLIP||Forces the actor's Z-clipping for the given Z-plane?<br />
|-<br />
|$14||SO_IGNORE_BOXES||Ignores boxes, turns off Z-clipping, and puts actor somewhere if the actor is in the current room?<br />
|-<br />
|$15||SO_FOLLOW_BOXES||Follows boxes, turns off Z-clipping, and puts actor somewhere if the actor is in the current room?<br />
|-<br />
|$16||SO_ANIMATION_SPEED||Sets the animation speed.<br />
|-<br />
|$17||SO_SHADOW||Sets the shadow mode.<br />
|}<br />
<br />
===Variants===<br />
In SCUMM V3 and V4, sub-opcode $11 (SO_ACTOR_SCALE) only takes one parameter, so X and Y scaling is done at a 1:1 ratio.<br />
<br />
<br />
==actorSetClass ($5D)==<br />
<br />
===Encoding===<br />
opcode object[p16] classes[v16]...<br />
<br />
===Operation===<br />
Makes object inherit from all of the given classes. A class of "0" will clear all of the object's existing class data.<br />
<br />
<br />
==add ($5A)==<br />
<br />
===Encoding===<br />
opcode result value[p16]<br />
<br />
===Operation===<br />
result := result + value<br />
<br />
The variable pointed to by result is read, value is added to it, and the result written back.<br />
<br />
<br />
==and ($17)==<br />
one parameter, uses result<br />
<br />
===Encoding===<br />
opcode result value[p16]<br />
<br />
===Operation===<br />
result := result and value<br />
<br />
The variable pointed to by result is read, logically ANDed with value, and the result written back.<br />
<br />
<br />
==animateActor ($11)==<br />
<br />
===Encoding===<br />
opcode actor[p8] anim[p8]<br />
<br />
===Operation===<br />
Starts the given animation for the given actor.<br />
<br />
<br />
==breakHere ($80)==<br />
no parameters<br />
<br />
===Encoding===<br />
opcode<br />
<br />
===Operation===<br />
Deschedules the currently running thread. Execution continues at the next instruction when the thread's next timeslot comes around.<br />
<br />
<br />
==chainScript ($42)==<br />
one parameter plus varargs<br />
<br />
===Encoding===<br />
opcode script[p8] args[v16]...<br />
<br />
===Operation===<br />
Replaces the currently running script with another one. The current script is terminated immediately and the new script (determined by the given script ID), is executed in the same thread. The new script has its local variables initialised to the list args. Uninitialised variables have undefined values.<br />
<br />
<br />
==cursorCommand ($2C)==<br />
parameters depend on auxiliary opcode<br />
<br />
===Encoding===<br />
opcode sub-opcode<br />
<br />
sub-opcode can be any of the following:<br />
$01<br />
... $01 through $08 take the same arguments ...<br />
$08<br />
$0A cursornum[p8] charletter[p8]<br />
$0B index[p8] x[p8] y[p8]<br />
$0C cursor[p8]<br />
$0D charset[p8]<br />
$0E colours[v16]...<br />
<br />
===Operation===<br />
Miscellaneous actions on cursors & charsets.<br />
<br />
{| border="1" cellpadding="2" width=100%<br />
|- style="background:whitesmoke"<br />
|Opcode||Meaning||Description<br />
|-<br />
|$01||SO_CURSOR_ON||Turns the cursor on.<br />
|-<br />
|$02||SO_CURSOR_OFF||Turns the cursor off.<br />
|-<br />
|$03||SO_USERPUT_ON||Enables user input.<br />
|-<br />
|$04||SO_USERPUT_OFF||Disables user input.<br />
|-<br />
|$05||SO_CURSOR_SOFT_ON||Increments the cursor's state?<br />
|-<br />
|$06||SO_CURSOR_SOFT_OFF||Decrements the cursor's state?<br />
|-<br />
|$07||SO_USERPUT_SOFT_ON||Increments "user input" counter (when greater than 0, user input is enabled).<br />
|-<br />
|$08||SO_USERPUT_SOFT_OFF||Decrements "user input" counter (when 0 or less, user input is disabled).<br />
|-<br />
|$0A||SO_CURSOR_IMAGE||Changes the cursor image to a new one, based on image in a character set. Only used in Loom.<br />
|-<br />
|$0B||SO_CURSOR_HOTSPOT||Changes the hotspot of a cursor. Only used in Loom.<br />
|-<br />
|$0C||SO_CURSOR_SET||Changes the current cursor. Must be between 0 and 3 inclusive.<br />
|-<br />
|$0D||SO_CHARSET_SET||Initializes the given character set.<br />
|-<br />
|$0E||SO_CHARSET_COLORS||Initializes the character set data & colours to the given arguments? Must have 16 arguments?<br />
|}<br />
<br />
===Variants===<br />
In SCUMM V3, sub-opcode $0E performs a different function, to load/initialize a character set.<br />
<br />
opcode $0E arg1[p8] arg2[p8]<br />
<br />
<br />
==cutScene ($40)==<br />
<br />
===Encoding===<br />
opcode args[v16]...<br />
<br />
===Operation===<br />
??? If required, runs a script passing the given arguments. Cutscene data given by the first argument?<br />
<br />
<br />
==debug ($6B)==<br />
one parameter, no result<br />
<br />
===Encoding===<br />
opcode param[p16]<br />
<br />
===Operation===<br />
Passes the parameter to the interpreter's debugger. What this does is entirely platform-specific (and may do nothing).<br />
<br />
<br />
==decrement ($C6)==<br />
no parameters, uses result<br />
<br />
===Encoding===<br />
opcode result<br />
<br />
===Operation===<br />
result := result - 1<br />
<br />
Reads the variable pointed to by result, decrements it, and writes it back. <br />
<br />
<br />
==delay ($2E)==<br />
one constant parameter<br />
<br />
===Encoding===<br />
opcode param[24]<br />
<br />
===Operation===<br />
Suspends the current thread for the appropriate number of 1/60ths of a second. Yes, that really is a 24-bit LE constant.<br />
<br />
<br />
==delayVariable ($2B)==<br />
one constant parameter<br />
<br />
===Encoding===<br />
opcode var<br />
<br />
===Operation===<br />
var is dereferenced and the current thread suspended for that number of 1/60ths of a second.<br />
<br />
<br />
==divide ($5B)==<br />
one parameter, uses result<br />
<br />
===Encoding===<br />
opcode result value[p16]<br />
<br />
===Operation===<br />
result := result / value<br />
<br />
The variable pointed to by result is read, divided by value, and the result written back. If value is zero, the result is undefined (and the interpeter may halt with an error). <br />
<br />
<br />
==doSentence ($19)==<br />
<br />
===Encoding===<br />
opcode verb[p8] objectA[p16] objectB[p16]<br />
<br />
===Operation===<br />
Performs a verb sentence action, e.g. "Use monkey on hydrant". If verb is $FE, the current sentence script is stopped, status cleared etc.<br />
<br />
<br />
==drawBox ($3F)==<br />
two parameters, does not use result, supplementary opcode byte with three more subsequent parameters<br />
<br />
===Encoding===<br />
opcode left[p16] top[p16] auxopcode[8] right[p16] bottom[p16] colour[p8]<br />
<br />
===Operation===<br />
Draws a solid box on the backbuffer from (left, top) to (right, bottom) in the given colour.<br />
<br />
The only part of auxopcode that is relevant are the parameter bits. The rest of the opcode is ignored. <br />
<br />
<br />
==drawObject ($05)==<br />
<br />
===Encoding===<br />
opcode object[p16] sub-opcode<br />
<br />
sub-opcodes:<br />
$01 xpos[p16] ypos[p16]<br />
$02 state[p16]<br />
$1F<br />
<br />
===Operation===<br />
{| border="1" cellpadding="2" width=100%<br />
|- style="background:whitesmoke"<br />
|Opcode||Meaning||Description<br />
|-<br />
|$01||Draw At||Moves the given object to the given co-ordinates, and adds it to the drawing queue.<br />
|-<br />
|$02||Set State||Sets the state of the object, adds it to the drawing queue.<br />
|-<br />
|$1F||Draw||Does not change the object's position (or state?), still adds it to the drawing queue.<br />
|}<br />
<br />
===Variants===<br />
Small header games only support the parameters used with sub-opcode $01, e.g:<br />
opcode object[p16] xpos[p16] ypos[p16]<br />
Accordingly, they have three parameter bits, and hence more possible opcodes.<br />
<br />
<br />
==dummy ($A7)==<br />
<br />
===Encoding===<br />
opcode<br />
<br />
===Operation===<br />
V5 specific - The KIXX XL release of Monkey Island 2 (Amiga disk) used this opcode as a dummy, in order to remove copy protection and keep level selection.<br />
<br />
===Variants===<br />
In SCUMM V3 and V4, this opcode is used for the saveLoadVars instruction.<br />
<br />
<br />
==endCutScene ($C0)==<br />
<br />
===Encoding===<br />
opcode<br />
<br />
===Operation===<br />
Ends the cutscene, performing cleanup if necessary.<br />
<br />
<br />
==equalZero ($28)==<br />
jumps<br />
<br />
===Encoding===<br />
opcode var target[16]<br />
<br />
===Operation===<br />
unless (var == 0) goto target<br />
<br />
Target is a byte offset (measured from after this instruction), which will be added to the instruction pointer.<br />
<br />
<br />
==expression ($AC)==<br />
<br />
===Encoding===<br />
opcode result subopcode... $FF<br />
<br />
sub-opcodes:<br />
$01 value[p16]<br />
$02<br />
... $02 through $05 take the same arguments ...<br />
$05<br />
$06 nested-opcode<br />
<br />
===Operation===<br />
Expression mode operates on a stack. Values are pushed on, and operators are applied to the top two items on the stack.<br />
<br />
{| border="1" cellpadding="2" width=100%<br />
|- style="background:whitesmoke"<br />
|Opcode||Meaning||Description<br />
|-<br />
|$01||Value||Pushes a value onto the top of the stack.<br />
|-<br />
|$02||Add||stack[top - 1] + stack[top]<br />
|-<br />
|$03||Subtract||stack[top - 1] - stack[top]<br />
|-<br />
|$04||Multiply||stack[top - 1] * stack[top]<br />
|-<br />
|$05||Divide||stack[top - 1] / stack[top] (if stack[top] is 0 an error occurs)<br />
|-<br />
|$06||Nested Opcode||An entire instruction that returns a result, such as getActorScale. This is interpreted like a normal opcode, but the result is pushed onto the expression stack. (The opcode is passed the special "VAR_RESULT" parameter for "result")<br />
|}<br />
<br />
<br />
==faceActor ($09)==<br />
<br />
===Encoding===<br />
opcode actor[p8] object[p16]<br />
<br />
===Operation===<br />
Dereferences actor, tells actor to face object (presumably based on X/Y co-ordinates).<br />
<br />
<br />
==findInventory ($3D)==<br />
<br />
===Encoding===<br />
opcode result owner[p8] index[p8]<br />
<br />
===Operation===<br />
object := owner.inventory[index]<br />
Searches for all objects owned by owner (an actor or object), and returns the one at the given index (offset).<br />
<br />
<br />
==findObject ($35)==<br />
<br />
===Encoding===<br />
opcode result x[p8] y[p8]<br />
<br />
===Operation===<br />
Returns the first "touchable" local object at the given co-ordinates. Will not match on the bottom or right-hand edges of an object.<br />
<br />
<br />
==freezeScripts ($60)==<br />
<br />
===Encoding===<br />
opcode flag[p8]<br />
<br />
===Operation===<br />
Freezes all scripts (by setting the high bit on each script's status). If flag is >= $80, all freeze resistent scripts will also be frozen. If flag is 0, all scripts are unfrozen. Freezing effects are cumulative - i.e. if script A is frozen twice, and unfrozen once, it will still be frozen until it is unfrozen a second time. A script's frozen status is indicated by the high bit.<br />
<br />
<br />
==getActorCostume ($71)==<br />
<br />
===Encoding===<br />
opcode result actor[p8]<br />
<br />
===Operation===<br />
Returns the actor's current costume.<br />
<br />
<br />
==getActorElevation ($06)==<br />
<br />
===Encoding===<br />
opcode result actor[p8]<br />
<br />
===Operation===<br />
Returns the actor's current elevation.<br />
<br />
<br />
==getActorFacing ($63)==<br />
<br />
===Encoding===<br />
opcode result actor[p8]<br />
<br />
===Operation===<br />
Returns the current direction the actor is facing.<br />
<br />
<br />
==getActorMoving ($56)==<br />
<br />
===Encoding===<br />
opcode result actor[p8]<br />
<br />
===Operation===<br />
Returns the actor's moving status (0 or 1).<br />
<br />
<br />
==getActorRoom ($03)==<br />
<br />
===Encoding===<br />
opcode result actor[p8]<br />
<br />
===Operation===<br />
Returns the room the actor currently occupies?<br />
<br />
<br />
==getActorScale ($3B)==<br />
<br />
===Encoding===<br />
opcode result actor[p8]<br />
<br />
===Operation===<br />
Returns the actor's current scale.<br />
<br />
===Variants===<br />
In Indy3, this opcode is used for waitForActor.<br />
<br />
<br />
==getActorWalkBox ($7B)==<br />
<br />
===Encoding===<br />
opcode result actor[p8]<br />
<br />
===Operation===<br />
Returns the actor's walkbox.<br />
<br />
<br />
==getActorWidth ($6C)==<br />
<br />
===Encoding===<br />
opcode result actor[p8]<br />
<br />
===Operation===<br />
Returns the actor's width.<br />
<br />
<br />
==getActorX ($43)==<br />
<br />
===Encoding===<br />
opcode result actor[p16]<br />
<br />
===Operation===<br />
Returns the actor's current X co-ordinate.<br />
<br />
===Variants===<br />
In Indy3, actor is only one byte.<br />
opcode result actor[p8]<br />
<br />
<br />
==getActorY ($23)==<br />
<br />
===Encoding===<br />
opcode result actor[p16]<br />
<br />
===Operation===<br />
Returns the actor's current Y co-ordinate.<br />
<br />
===Variants===<br />
In Indy3, actor is only one byte.<br />
opcode result actor[p8]<br />
<br />
<br />
==getAnimCounter ($22)==<br />
<br />
===Encoding===<br />
opcode result actor[p8]<br />
<br />
===Operation===<br />
Returns the actor's animation counter.<br />
<br />
===Variants===<br />
This opcode is used for saveLoadGame in SCUMM V3.<br />
<br />
<br />
==getClosestObjActor ($66)==<br />
<br />
===Encoding===<br />
opcode result actor[p16]<br />
<br />
===Operation===<br />
Returns the object closest to the actor. Items that are more than 255 units (pixels in newer games, characters in older games) away from the actor will not be detected.<br />
<br />
<br />
==getDist ($34)==<br />
<br />
===Encoding===<br />
opcode result objA[p16] objB[p16]<br />
<br />
===Operation===<br />
Returns the distance between two actors/objects (objA and objB).<br />
<br />
<br />
==getInventoryCount ($31)==<br />
<br />
===Encoding===<br />
opcode result actor[p8]<br />
<br />
===Operation===<br />
Returns the number of items in an actor's inventory?<br />
<br />
<br />
==getObjectOwner ($10)==<br />
<br />
===Encoding===<br />
opcode result object[p16]<br />
<br />
===Operation===<br />
Returns the owner of an object.<br />
<br />
<br />
==getObjectState ($0F)==<br />
<br />
===Encoding===<br />
opcode result object[p16]<br />
<br />
===Operation===<br />
Returns the state of the object.<br />
<br />
===Variants===<br />
In small header games, the encoding becomes:<br />
opcode object[p16] state[p8] target[16]<br />
operation becomes<br />
unless (getState(object) == state) goto target<br />
<br />
<br />
==getRandomNumber ($16)==<br />
<br />
===Encoding===<br />
opcode result seed[p8]<br />
<br />
===Operation===<br />
Returns a new random number based on the given seed.<br />
<br />
<br />
==getScriptRunning ($68)==<br />
<br />
===Encoding===<br />
opcode result script[p8]<br />
<br />
===Operation===<br />
Returns 1 if the given script is running, 0 if it's not.<br />
<br />
<br />
==getStringWidth ($67)==<br />
<br />
===Encoding===<br />
opcode result strptr[p8]<br />
<br />
===Operation===<br />
Gets the length of the string pointed to by strptr (either a variable or direct byte), stores the returned value in result.<br />
<br />
<br />
==getVerbEntryPoint ($0B)==<br />
<br />
===Encoding===<br />
opcode result object[p16] verb[p16]<br />
<br />
===Operation===<br />
Returns the entry point for the response code/script for when the given verb is applied to the given object? i.e. gets the start of the script to run for the specific user interaction.<br />
<br />
<br />
==ifClassOfIs ($1D)==<br />
jumps<br />
<br />
===Encoding===<br />
opcode value[p16] args[v16]... target[16]<br />
<br />
===Operation===<br />
unless (value.class is one of [args.class]) goto target<br />
<br />
Compares the value's class with all classes given in args.<br />
<br />
Target is a byte offset (measured from after this instruction), which will be added to the instruction pointer.<br />
<br />
<br />
==ifNotState ($2F) (V3-4)==<br />
This opcode is not present in SCUMM V5.<br />
<br />
===Encoding===<br />
opcode object[p16] state[p8] target[16]<br />
<br />
===Operation===<br />
unless (stateOf(object) != state) goto target<br />
<br />
<br />
==ifState ($4F) (V3-4)==<br />
This opcode is not present in SCUMM V5.<br />
<br />
===Encoding===<br />
opcode object[p16] state[p8] target[16]<br />
<br />
===Operation===<br />
unless (stateOf(object) == state) goto target<br />
<br />
<br />
==increment ($46)==<br />
no parameters, uses result<br />
<br />
===Encoding===<br />
opcode result<br />
<br />
===Operation===<br />
result := result + 1<br />
<br />
Reads the variable pointed to by result, increments it, and writes it back. <br />
<br />
<br />
==isActorInBox ($1F)==<br />
<br />
===Encoding===<br />
opcode actor[p8] box[p8] target[16]<br />
<br />
===Operation===<br />
Unless the actor's co-ordinates are within the bounds of the given box, jump to target.<br />
<br />
Target is a byte offset (measured from after this instruction), which will be added to the instruction pointer.<br />
<br />
<br />
==isEqual ($48)==<br />
<br />
===Encoding===<br />
opcode var value[p16] target[16]<br />
<br />
===Operation===<br />
unless (value == var) goto target<br />
<br />
Target is a byte offset (measured from after this instruction), which will be added to the instruction pointer.<br />
<br />
<br />
==isGreater ($78)==<br />
<br />
===Encoding===<br />
opcode var value[p16] target[16]<br />
<br />
===Operation===<br />
unless (value > var) goto target<br />
<br />
Target is a byte offset (measured from after this instruction), which will be added to the instruction pointer.<br />
<br />
<br />
==isGreaterEqual ($04)==<br />
<br />
===Encoding===<br />
opcode var value[p16] target[16]<br />
<br />
===Operation===<br />
unless (value >= var) goto target<br />
<br />
Target is a byte offset (measured from after this instruction), which will be added to the instruction pointer.<br />
<br />
<br />
==isLess ($44)==<br />
<br />
===Encoding===<br />
opcode var value[p16] target[16]<br />
<br />
===Operation===<br />
unless (value < var) goto target<br />
<br />
Target is a byte offset (measured from after this instruction), which will be added to the instruction pointer.<br />
<br />
<br />
==isNotEqual ($08)==<br />
<br />
===Encoding===<br />
opcode var value[p16] target[16]<br />
<br />
===Operation===<br />
unless (value != var) goto target<br />
<br />
Target is a byte offset (measured from after this instruction), which will be added to the instruction pointer.<br />
<br />
<br />
==isSoundRunning ($7C)==<br />
<br />
===Encoding===<br />
opcode result sound[p8]<br />
<br />
===Operation===<br />
Returns 1 if sound is running, returns 0 if sound is not running or if the given sound is 0.<br />
<br />
<br />
==jumpRelative ($18)==<br />
jumps<br />
<br />
===Encoding===<br />
opcode target[16]<br />
<br />
===Operation===<br />
PC := PC + target<br />
<br />
The inline constant target is read as a signed word and added to the program counter after the instruction has been read. Therefore, if target is zero, the instruction will do nothing; if target is -3, an infinite loop will result. <br />
<br />
<br />
==lessOrEqual ($38)==<br />
jumps<br />
<br />
===Encoding===<br />
opcode var value[p16] target[16]<br />
<br />
===Operation===<br />
unless (value <= var) goto target<br />
<br />
Target is a byte offset (measured from after this instruction), which will be added to the instruction pointer.<br />
<br />
<br />
==lights ($70)==<br />
<br />
===Encoding===<br />
opcode arg1[p8] arg2[8] arg3[8]<br />
<br />
===Operation===<br />
If arg3 is 0, the "current lights" variable is set to arg1.<br />
If arg3 is 1, the size of the "flashlight" light is determined by arg1 and arg2, for width and height in stripes (which are equivalent to 8 pixels each; see [[SCUMM/Technical Reference/Image resources]]).<br />
<br />
<br />
==loadRoom ($72)==<br />
<br />
===Encoding===<br />
opcode room[p8]<br />
<br />
===Operation===<br />
Loads the given room into memory.<br />
<br />
<br />
==loadRoomWithEgo ($24)==<br />
<br />
===Encoding===<br />
opcode object[p16] room[p8] x[16] y[16]<br />
<br />
===Operation===<br />
Places the Ego actor in room at object's position. If x is not -1, Ego will start moving towards the given x and y co-ordinates. If object is not in the given room an error will occur.<br />
(I think...)<br />
<br />
<br />
==matrixOp ($30)==<br />
<br />
===Encoding===<br />
opcode sub-opcode<br />
<br />
sub-opcodes:<br />
$01 box[p8] val[p8]<br />
$02 box[p8] val[p8]<br />
$03 box[p8] val[p8]<br />
$04<br />
<br />
===Operation===<br />
This instruction manipulates boxes.<br />
<br />
{| border="1" cellpadding="2" width=100%<br />
|- style="background:whitesmoke"<br />
|Opcode||Meaning||Description<br />
|-<br />
|$01||setBoxFlags||Sets the box's flags to the given value.<br />
|-<br />
|$02||setBoxScale||Sets the box's scale.<br />
|-<br />
|$03||setBoxScale||Sets the box's scale to ((val - 1) OR $8000).<br />
|-<br />
|$04||createBoxMatrix||Initializes the matrix of boxes, by determining the distances and shortest paths between boxes.<br />
|}<br />
<br />
===Variants===<br />
SCUMM V3 only has the one instruction, which behaves like setBoxFlags:<br />
opcode box[p8] val[8]<br />
<br />
<br />
==move ($1A)==<br />
<br />
===Encoding===<br />
opcode result value[p16]<br />
<br />
===Operation===<br />
result := value<br />
<br />
Value is moved into result.<br />
<br />
<br />
==multiply ($1B)==<br />
<br />
===Encoding===<br />
opcode result value[p16]<br />
<br />
===Operation===<br />
result := result * value<br />
<br />
The variable pointed to by result is read, multiplied by value, and written back.<br />
<br />
<br />
==notEqualZero ($A8)==<br />
<br />
===Encoding===<br />
opcode var target[16]<br />
<br />
===Operation===<br />
unless (var != 0) goto target<br />
<br />
Target is a byte offset (measured from after this instruction), which will be added to the instruction pointer.<br />
<br />
<br />
==oldRoomEffect ($5C) (V4)==<br />
This opcode/instruction is only present in SCUMM V4.<br />
<br />
===Encoding===<br />
opcode sub-opcode<br />
<br />
sub-opcodes:<br />
$03 effect[p16]<br />
<br />
===Operation===<br />
Performs like sub-opcode SO_ROOM_FADE of the roomOps instruction (fade in if effect != 0, otherwise fade out).<br />
<br />
This information may not be correct; descumm says if the sub-opcode is 3, to "set" the effect, but if the sub-opcode is anything else to fade in with the given effect.<br />
<br />
===Variants===<br />
FM-Towns SCUMM V3 performs a different effect, not fully implemented in ScummVM. At the moment ScummVM just forces a redraw of the screen background.<br />
<br />
<br />
==or ($57)==<br />
one parameter, uses result<br />
<br />
===Encoding===<br />
opcode result value[p16]<br />
<br />
===Operation===<br />
result := result or value<br />
<br />
The variable pointed to by result is read, logically ORed with value, and the result written back.<br />
<br />
<br />
==override ($58)==<br />
<br />
===Encoding===<br />
opcode sub-opcode<br />
<br />
sub-opcodes:<br />
$00<br />
$01 $18 target[16]<br />
<br />
===Operation===<br />
If the sub-opcode is 0, marks the end of an override section.<br><br />
If the sub-opcode is not 0, marks the beginning of an override section. The instruction is immediately followed by a "jumpRelative" instruction.<br><br />
Overrides are used by cutscenes; if a cutscene is skipped (if the user presses the ESC key), the script will jump by the given target (offset from the beginOverride instruction).<br />
<br />
<br />
==panCameraTo ($12)==<br />
<br />
===Encoding===<br />
opcode x[p16]<br />
<br />
===Operation===<br />
Starts the camera panning to the given x co-ordinate.<br />
<br />
<br />
==pickupObject ($25)==<br />
<br />
===Encoding===<br />
opcode object[p16] room[p8]<br />
<br />
===Operation===<br />
Adds the given object (located in the given room) to the Ego actor's inventory.<br />
<br />
===Variants===<br />
In SCUMM V3 and V4, this opcode is used for drawObject.<br />
<br />
<br />
==pickupObjectOld ($50) (V4)==<br />
This opcode is not present in SCUMM V5.<br />
<br />
===Encoding===<br />
opcode object[p16]<br />
<br />
===Operation===<br />
Adds the given object (located in the given room) to the Ego actor's inventory. If object < 1, an error is raised. If the object is not found or the object is already in the inventory, this function ends gracefully.<br />
<br />
<br />
==print ($14)==<br />
<br />
===Encoding===<br />
opcode actor[p8] sub-opcode<br />
<br />
sub-opcodes<br />
$00 xpos[p16] ypos[p16]<br />
$01 colour[p8]<br />
$02 right[p16]<br />
$03 width[p16] height[p16]<br />
$04<br />
$06<br />
$07<br />
$08 offset[p16] delay[p16]<br />
$0F string[c]... $FF<br />
<br />
===Operation===<br />
Sets text properties and displays dialogue.<br />
<br />
{| border="1" cellpadding="2" width=100%<br />
|- style="background:whitesmoke"<br />
|Opcode||Meaning||Description<br />
|-<br />
|$00||SO_AT||Sets the position of the text that follows.<br />
|-<br />
|$01||SO_COLOR||Sets the colour of the text.<br />
|-<br />
|$02||SO_CLIPPED||Clips the text's right-hand side (for wrapping?).<br />
|-<br />
|$03||SO_ERASE||Erases characters (not used in ScummVM).<br />
|-<br />
|$04||SO_CENTER||Centres the text.<br />
|-<br />
|$06||SO_LEFT||Left-aligns the text.<br />
|-<br />
|$07||SO_OVERHEAD||Overhead-aligns the text.<br />
|-<br />
|$0F||SO_TEXTSTRING||Prints the text string that follows. Terminated by $FF.<br />
|}<br />
<br />
===Variants===<br />
In SCUMM V3, text function $06 sets the height of the text:<br />
$06 height[p16]<br />
<br />
In Loom CD (SCUMM V4), there is an additional text function $08 (SO_SAY_VOICE), which plays a portion of the CD audio track.<br />
$08 offset[p16] delay[p16]<br />
<br />
<br />
==printEgo ($D8)==<br />
<br />
===Encoding===<br />
opcode sub-opcode<br />
<br />
===Operation===<br />
Exactly the same as print, except the actor is implicitly Ego. See the entry for "print" for further explanation.<br />
<br />
<br />
==pseudoRoom ($CC)==<br />
<br />
===Encoding===<br />
opcode val[8] res[8]... $00<br />
<br />
===Operation===<br />
forall (res) {<br />
if (res >= $80) {<br />
_resourceMapper[res & $7F] := val<br />
}<br />
}<br />
<br />
What does this actually do? We may never know.<br />
<br />
It looks like res values always have the high bit set, e.g. 0x01 becomes 0x81.<br />
<br />
<br />
==putActor ($01)==<br />
<br />
===Encoding===<br />
opcode actor[p8] x[p16] y[p16]<br />
<br />
===Operation===<br />
Puts the actor at the given co-ordinates.<br />
<br />
<br />
==putActorAtObject ($0E)==<br />
<br />
===Encoding===<br />
opcode actor[p8] object[p16]<br />
<br />
===Operation===<br />
Puts the actor at the given object's position. If the object can not be found, a default position is returned (the centre of the screen in ScummVM).<br />
<br />
<br />
==putActorInRoom ($2D)==<br />
<br />
===Encoding===<br />
opcode actor[p8] room[p8]<br />
<br />
===Operation===<br />
Puts the actor in the given room.<br />
<br />
<br />
==resourceRoutines ($0C)==<br />
<br />
===Encoding===<br />
opcode sub-opcode<br />
<br />
sub-opcodes:<br />
$01 resID[p8]<br />
... $01 through $10 take the same arguments ...<br />
$10 resID[p8]<br />
$11<br />
$12 resID[p8]<br />
$13 resID[p8]<br />
$14 room[p8] object[p16]<br />
<br />
===Operation===<br />
resID is unique only within the resource type (e.g. script 11 will not conflict with sound 11).<br />
<br />
{| border="1" cellpadding="2" width=100%<br />
|- style="background:whitesmoke"<br />
|Opcode||Meaning||Description<br />
|-<br />
|$01||SO_LOAD_SCRIPT||Loads the given script into memory.<br />
|-<br />
|$02||SO_LOAD_SOUND||Loads the given sound into memory.<br />
|-<br />
|$03||SO_LOAD_COSTUME||Loads the given costume into memory.<br />
|-<br />
|$04||SO_LOAD_ROOM||Loads the given room into memory.<br />
|-<br />
|$05||SO_NUKE_SCRIPT||Obliterates the given script from memory.<br />
|-<br />
|$06||SO_NUKE_SOUND||Obliterates the given sound from memory.<br />
|-<br />
|$07||SO_NUKE_COSTUME||Obliterates the given costume from memory.<br />
|-<br />
|$08||SO_NUKE_ROOM||Obliterates the given room from memory.<br />
|-<br />
|$09||SO_LOCK_SCRIPT||Locks the given script.<br />
|-<br />
|$0A||SO_LOCK_SOUND||Locks the given sound.<br />
|-<br />
|$0B||SO_LOCK_COSTUME||Locks the given costume.<br />
|-<br />
|$0C||SO_LOCK_ROOM||Locks the given room.<br />
|-<br />
|$0D||SO_UNLOCK_SCRIPT||Unlocks the given script.<br />
|-<br />
|$0E||SO_UNLOCK_SOUND||Unlocks the given sound.<br />
|-<br />
|$0F||SO_UNLOCK_COSTUME||Unlocks the given costume.<br />
|-<br />
|$10||SO_UNLOCK_ROOM||Unlocks the given room.<br />
|-<br />
|$11||SO_CLEAR_HEAP||Clears the heap.<br />
|-<br />
|$12||SO_LOAD_CHARSET||Loads the given character set into memory.<br />
|-<br />
|$13||SO_NUKE_CHARSET||Obliterates the given character set from memory.<br />
|-<br />
|$14||SO_LOAD_OBJECT||Loads the given object from the given room resource.<br />
|}<br />
<br />
===Variants===<br />
FM-Towns games add the following sub-opcodes (these are not confirmed nor implemented in ScummVM):<br />
{| border="1" cellpadding="2" width=100%<br />
|- style="background:whitesmoke"<br />
|Opcode||Meaning||Description<br />
|-<br />
|$20||Unknown||Does nothing, not used in-game.<br />
|-<br />
|$21||Unknown||Does nothing, not used in-game.<br />
|-<br />
|$23||CD Volume||Possibly changes the volume of CD tracks (Loom CD). Takes 1 byte.<br />
|-<br />
|$24||Sound Volume||Sets the loudness of a sound resource. Used in Indy3 and Zak. Takes 2 bytes (left/right volumes?).<br />
|-<br />
|$25||Sound Pitch||Sets the pitch of a sound resource. Used in Indy3 and Zak. Takes 1 byte (pitch = "foo" - "center" semitones. Center is at $32 in the sound resource.)<br />
|}<br />
<br />
<br />
==roomOps ($33)==<br />
<br />
===Encoding===<br />
opcode sub-opcode<br />
<br />
sub-opcodes:<br />
$01 minX[p16] maxX[p16]<br />
$03 b[p16] h[p16]<br />
$04 red[p16] green[p16] blue[p16] aux index[p8]<br />
$05<br />
$06<br />
$07 scale1[p8] y1[p8] aux scale2[p8] y2[p8] aux slot[p8]<br />
$08 scale[p8] startcolour[p8] endcolour[p8]<br />
$09 loadflag[p8] loadslot[p8]<br />
$0A effect[p16]<br />
$0B redscale[p16] greenscale[p16] bluescale[p16] aux startcolour[p8] endcolour[p8]<br />
$0C redscale[p16] greenscale[p16] bluescale[p16] aux startcolour[p8] endcolour[p8]<br />
$0D resID[p8] filename[c]... $00<br />
$0E resID[p8] filename[c]... $00<br />
$0F resID[p8] aux start[p8] end[p8] aux time[p8]<br />
$10 colindex[p8] delay[p8]<br />
<br />
===Operation===<br />
{| border="1" cellpadding="2" width=100%<br />
|- style="background:whitesmoke"<br />
|Opcode||Meaning||Description<br />
|-<br />
|$01||SO_ROOM_SCROLL||Clamps the given arguments so scrolling does not extend past the width of the room or screen.<br />
|-<br />
|$03||SO_ROOM_SCREEN||Initialises a screen.<br />
|-<br />
|$04||SO_ROOM_PALETTE||Adjusts the room's palette.<br />
|-<br />
|$05||SO_ROOM_SHAKE_ON||Starts the room shaking.<br />
|-<br />
|$06||SO_ROOM_SHAKE_OFF||Ends the room shaking.<br />
|-<br />
|$07||SO_ROOM_SCALE||Sets the room's y scales? (slot is 1 greater than actual slot?)<br />
|-<br />
|$08||SO_ROOM_INTENSITY||Lightens/darkens the room's palette.<br />
|-<br />
|$09||SO_ROOM_SAVEGAME||Saves temporary state of the room/game?<br />
|-<br />
|$0A||SO_ROOM_FADE||If effect is 0, fades in the room. Otherwise, fades out with the given effect (taken from the high byte of effect).<br>1 = iris effect<br>2 = box wipe (upper-left to bottom-right)<br>3 = box wipe (upper-right to bottem-left)<br>4 = inverse box wipe.<br />
|-<br />
|$0B||SO_RGB_ROOM_INTENSITY||Lightens/darkens the room's palette, with different scales for red, green and blue.<br />
|-<br />
|$0C||SO_ROOM_SHADOW||Lightens/darkens the shadow palette, with different scales for red, green, and blue.<br />
|-<br />
|$0D||SO_SAVE_STRING||Saves a string resource to the given file?<br />
|-<br />
|$0E||SO_LOAD_STRING||Loads a string resource from a given file?<br />
|-<br />
|$0F||SO_ROOM_TRANSFORM||Manipulates palettes, strings?<br />
|-<br />
|$10||SO_CYCLE_SPEED||Starts colour cycling with delay? colIndex is between 0 and 16<br />
|}<br />
<br />
===Variants===<br />
SCUMM V3 (non-PC Engine) encodes the arguments before the sub-opcode:<br />
opcode arg1[p16] arg2[p16] sub-opcode<br />
<br />
Small header games include an extra sub-opcode, $02 (SO_ROOM_COLOR), which adjusts the room's palette:<br />
opcode $02 colour[p16] index[p16]<br />
... or for V3 games ...<br />
opcode colour[p16] index[p16] $02<br />
<br />
In small header games, sub-opcode $04 (SO_ROOM_PALETTE) affects the shadow palette, and only accepts two arguments, a "room colour slot" (palette entry? between 0 and 256) and an index:<br />
opcode $04 colour[p16] index[p16]<br />
... or for V3 games ...<br />
opcode colour[p16] index[p16] $04<br />
<br />
In FM-Towns games, sub-opcode $0A performs a different function and has its own sub-opcodes (some unknown and all not yet implemented in ScummVM):<br />
opcode $0A sub-opcode<br />
<br />
{| border="1" cellpadding="2" width=100%<br />
|- style="background:whitesmoke"<br />
|Opcode||Meaning||Description<br />
|-<br />
|$08||||compose kMainVirtScreen over a screen buffer<br />
|-<br />
|$09||||call 0x110:0x20 _ax=0x601 _edx=2<br />
|-<br />
|$0A||||call 0x110:0x20 _ax=0x601 _edx=3<br />
|-<br />
|$0B||||clear screen 0x1C:0x45000 sizeof(640 * 320)<br />
|-<br />
|$0C||||call 0x110:0x20 _ax=0x601 _edx=0<br />
|-<br />
|$0D||||call 0x110:0x20 _ax=0x601 _edx=1<br />
|-<br />
|$10||||enable clearing of a screen buffer in drawBitmap()<br />
|-<br />
|$11||||disable clearing of a screen buffer in drawBitmap()<br />
|-<br />
|$12||||clear a screen buffer<br />
|-<br />
|$13||||enable palette operations (palManipulate(), cyclePalette() etc.)<br />
|-<br />
|$14||||disable palette operations<br />
|-<br />
|$15||||disable clearing of screen 0x1C:0x5000 sizeof(640 * 320) in initScreens()<br />
|-<br />
|$16||||enable clearing of screen 0x1C:0x5000 sizeof(640 * 320) in initScreens()<br />
|-<br />
|$1E||||Unknown<br />
|}<br />
<br />
<br />
==saveLoadGame ($22) (V3-4)==<br />
This instruction is not present in SCUMM V5; its opcode is used for "getAnimCounter".<br />
<br />
===Encoding===<br />
opcode result arg1[p8]<br />
<br />
===Operation===<br />
The slot is determined by taking the lower 5 bits of arg1. The upper 3 bits determine an aux opcode, that performs an action described in the table below.<br />
<br />
{| border="1" cellpadding="2" width=100%<br />
|- style="background:whitesmoke"<br />
|Opcode||Meaning||Description<br />
|-<br />
|$00||Num. Available Slots||Returns the number of save slots available.<br />
|-<br />
|$20||Drive||In V3, returns the type of drive (0 = ???, 1 = A or B [floppy], 2 = hard drive).<br>In V4, sets the current drive (returns 1).<br />
|-<br />
|$40||Load Game||Loads a game from the given slot (returns 3 if successful, 5 otherwise).<br />
|-<br />
|$80||Save Game||Saves a game to the given slot (returns 0 if successful, 2 otherwise).<br />
|-<br />
|$C0||Test For Game||Tests if a save exists in the given slot (returns 6 if so, 7 otherwise).<br />
|}<br />
<br />
<br />
==saveLoadVars ($A7) (V3-4)==<br />
This instruction is not present in SCUMM V5; its opcode is used as a dummy.<br />
<br />
===Encoding===<br />
opcode sub-opcode<br />
<br />
sub-opcodes:<br />
$01 sub-sub-opcode... $00<br />
$02 sub-sub-opcode... $00<br />
<br />
$01 (save) sub-sub-opcodes:<br />
$01 resultA resultB<br />
$02 arg1[p8] arg2[p8]<br />
$03 filename[c]... $00<br />
$04<br />
$1F<br />
<br />
$02 (load) sub-sub-opcodes:<br />
$01 resultA resultB<br />
$02 arg1[p8] arg2[p8]<br />
$03 filename[c]... $00<br />
$04<br />
$1F<br />
<br />
===Operation===<br />
{| border="1" cellpadding="2" width=100%<br />
|- style="background:whitesmoke"<br />
|Opcode||Meaning||Description<br />
|-<br />
|$01||SO_SAVE_VARS||Saves variables (for saving games?)<br />
|-<br />
|$02?||SO_RESTORE_VERBS||Loads variables (for saving games?)<br>(I have not verified that restore vars is $02, as the ScummVM code only compares to $01.)<br />
|}<br />
<br />
{| border="1" cellpadding="2" width=100%<br />
|- style="background:whitesmoke"<br />
|Opcode||Meaning||Description<br />
|-<br />
|$01||Write Vars||Writes a range of variables.<br />
|-<br />
|$02||Write Strings||Writes a range of string variables.<br />
|-<br />
|$03||Open File||Opens a file for writing.<br />
|-<br />
|$04||Dummy||Does nothing.<br />
|-<br />
|$1F||Close File||Closes the last opened file.<br />
|}<br />
<br />
{| border="1" cellpadding="2" width=100%<br />
|- style="background:whitesmoke"<br />
|Opcode||Meaning||Description<br />
|-<br />
|$01||Read Vars||Reads a range of variables.<br />
|-<br />
|$02||Read Strings||Reads a range of string variables.<br />
|-<br />
|$03||Open File||Opens a file for reading.<br />
|-<br />
|$04||Dummy||Does nothing.<br />
|-<br />
|$1F||Close File||Closes the last opened file.<br />
|}<br />
<br />
<br />
==saveRestoreVerbs ($AB)==<br />
<br />
===Encoding=== <br />
opcode sub-opcode<br />
<br />
sub-opcodes: <br />
$01 start[p8] end[p8] mode[p8]<br />
$02 start[p8] end[p8] mode[p8]<br />
$03 start[p8] end[p8] mode[p8]<br />
<br />
===Operation===<br />
{| border="1" cellpadding="2" width=100%<br />
|- style="background:whitesmoke"<br />
|Opcode||Meaning||Description<br />
|-<br />
|$01||SO_SAVE_VERBS||For all verbs between start and end, sets the "saveid" to mode. <br />
|-<br />
|$02||SO_RESTORE_VERBS||For all verbs between start and end and matching mode, kills any existing verb, sets the saveid to 0 and generally inits the verb.<br />
|-<br />
|$03||SO_DELETE_VERBS||For all verbs between start and end and matching mode, kills any existing verb.<br />
|}<br />
<br />
<br />
==setCameraAt ($32)==<br />
<br />
===Encoding===<br />
opcode x[p16]<br />
<br />
===Operation===<br />
Sets the camera's x position.<br />
<br />
<br />
==setObjectName ($54)==<br />
<br />
===Encoding===<br />
opcode object[p16] name[c]... $00<br />
<br />
===Operation===<br />
Sets the given object's name.<br />
<br />
<br />
==setOwnerOf ($29)==<br />
<br />
===Encoding===<br />
opcode object[p16] owner[p8]<br />
<br />
===Operation===<br />
Sets the owner of the object.<br />
<br />
<br />
==setState ($07)==<br />
<br />
===Encoding===<br />
opcode object[p16] state[p8]<br />
<br />
===Operation===<br />
Sets the state of the object.<br />
<br />
<br />
==setVarRange ($26)==<br />
non-standard encoding<br />
<br />
===Encoding===<br />
opcode result number[8] values[8]...<br />
or<br />
opcode result number[8] values[16]...<br />
<br />
===Operation===<br />
for (i = 0; i < number; i++) {<br />
&#42;result + i := values[i];<br />
}<br />
<br />
This sets a number of variables to the given parameters. The starting variable is given as "result", and the number of variables to modify is given as "number". This is followed by the same number of values, which will be put into the variable locations. The values are constants, and can be either 16-bit, if the highest bit of the opcode is set, i.e. $A6; or 8-bit, if the highest bit of the opcode is not set, i.e. $26. Note that all values are affected by the opcode's high bit; you can't mix 8 and 16-bit values.<br />
<br />
descumm example:<br />
setVarRange(Var[178],9,[0,0,0,0,0,0,0,0,0]);<br />
<br />
This sets variables 178 to 186 (inclusive) to 0.<br />
<br />
<br />
==soundKludge ($4C)==<br />
<br />
===Encoding===<br />
opcode items[v16]...<br />
<br />
===Operation===<br />
If the first item is -1, the existing sound queue is processed. Otherwise, the list of items is added to the queue.<br />
<br />
===Variants===<br />
In SCUMM V3 (small header) games, this opcode is used for the WaitForSentence instruction.<br />
<br />
<br />
==startMusic ($02)==<br />
<br />
===Encoding===<br />
opcode music[p8]<br />
<br />
===Operation===<br />
Adds the music in to the queue to be played.<br />
<br />
===Variants===<br />
In FM-Towns (SCUMM V3) games, this instruction performs different functions (some kind of Audio CD status query function; some partially implemented in ScummVM):<br />
opcode result sub-opcode<br />
<br />
{| border="1" cellpadding="2" width=100%<br />
|- style="background:whitesmoke"<br />
|Opcode||Meaning||Description<br />
|-<br />
|$00||Is Playing||Returns true if a CD audio track is currently playing.<br />
|-<br />
|$FC||Unpause CD||Unpauses the CD audio track.<br />
|-<br />
|$FD||Pause CD||Pauses the CD audio track.<br />
|-<br />
|$FE||Get CD Sound||Returns the current CD sound.<br />
|-<br />
|$FF||CD Volume||Might return the the current CD volume in FM-Towns Loom.<br />
|-<br />
|other||Track Length||Returns the track length in seconds.<br />
|}<br />
<br />
<br />
==startObject ($37)==<br />
<br />
===Encoding===<br />
opcode object[p16] script[p8] args[v16]...<br />
<br />
===Operation===<br />
Starts the object's script (OBCD blocks), passing the given arguments.<br />
<br />
<br />
==startScript ($0A)==<br />
one parameter plus varargs, extra encoding in opcode<br />
<br />
===Encoding===<br />
opcode script[p8] args[v16]...<br />
<br />
===Operation===<br />
Spawns a new thread running the code in script script. The new script has its local variables initialised to the list args. Uninitialised variables have undefined values.<br />
<br />
The opcode carries extra information: <br />
<br />
{| border="1" cellpadding="2" width=10%<br />
|- style="background:whitesmoke"<br />
|7||6||5||4 0<br />
|-<br />
|P1||R||F||$0A<br />
|}<br />
<br />
P1 = standard parameter bit<br><br />
R = indicates that the script is recursive<br><br />
F = indicates that the script is freeze resistant (a call to freezeScripts will skip this script, unless the "force freeze" bit of the freezeScripts opcode is set).<br />
<br />
<br />
==startSound ($1C)==<br />
<br />
===Encoding===<br />
opcode sound[p8]<br />
<br />
===Operation===<br />
Adds the given sound to the sound queue to be played.<br />
<br />
<br />
==stopMusic ($20)==<br />
<br />
===Encoding===<br />
opcode<br />
<br />
===Operation===<br />
Stops all sounds.<br />
<br />
<br />
==stopObjectCode ($A0 or $00)==<br />
<br />
===Encoding===<br />
opcode<br />
<br />
===Operation===<br />
Marks the calling script as dead, to be later pruned from the thread pool. Cleans up residual arrays. Should always be the last instruction in a script.<br />
<br />
$A0 is present in LSCR and SCRP files... when does $00 occur?<br />
<br />
<br />
==stopObjectScript ($6E)==<br />
<br />
===Encoding===<br />
opcode script[p16]<br />
<br />
===Operation===<br />
Marks the given object script as dead, to be later pruned from the thread pool. Cleans up residual arrays.<br />
<br />
<br />
==stopScript ($62)==<br />
<br />
===Encoding===<br />
opcode script[p8]<br />
<br />
===Operation===<br />
Marks the given script as dead, to be later pruned from the thread pool. Cleans up residual arrays.<br />
<br />
<br />
==stopSound ($3C)==<br />
<br />
===Encoding===<br />
opcode sound[p8]<br />
<br />
===Operation===<br />
Stops the given sound.<br />
<br />
<br />
==stringOps ($27)==<br />
parameters depend on sub-opcode<br />
<br />
===Encoding===<br />
opcode sub-opcode<br />
<br />
sub-opcodes:<br />
$01 stringID[p8] string[c]... $00<br />
$02 destID[p8] srcID[p8]<br />
$03 stringID[p8] index[p8] char[c]<br />
$04 result stringID[p8] index[p8]<br />
$05 stringID[p8] size[p8]<br />
<br />
===Operation===<br />
Miscellaneous actions on strings (Arrays, referred to by resource number).<br />
<br />
{| border="1" cellpadding="2" width=100%<br />
|- style="background:whitesmoke"<br />
|Opcode||Meaning||Description<br />
|-<br />
|$01||Load String||Loads the inline null-terminated string into the resource slot given by stringID.<br />
|-<br />
|$02||Copy String||Creates a duplicate of the string at resource slot srcID into destID. The old string at destID is lost.<br />
|-<br />
|$03||Write Character||Writes char at the given index (offset) of the string resource located at slot stringID. Out of bounds accesses cause undefined behaviour.<br />
|-<br />
|$04||Read Character||Reads a byte (character) at the given index (offset) of the string resource located at slot stringID, and writes it to result. Out of bounds accesses cause undefined behaviour.<br />
|-<br />
|$05||New String||Allocates or frees a string (Array), located at resource slot stringID. The string is initialised to size; if size is zero, the string is freed.<br />
|}<br />
<br />
<br />
==subtract ($3A)==<br />
<br />
===Encoding===<br />
opcode result value[p16]<br />
<br />
===Operation===<br />
result := result - value<br />
<br />
The variable pointed to by result is read, value is subtracted from it, and the result written back.<br />
<br />
<br />
==systemOps ($98)==<br />
<br />
===Encoding===<br />
opcode sub-opcode<br />
<br />
sub-opcodes:<br />
$01<br />
$02<br />
$03<br />
<br />
===Operation===<br />
{| border="1" cellpadding="2" width=100%<br />
|- style="background:whitesmoke"<br />
|Opcode||Meaning||Description<br />
|-<br />
|$01||SO_RESTART||Restarts the game.<br />
|-<br />
|$02||SO_PAUSE||Pauses/unpauses the game.<br />
|-<br />
|$03||SO_QUIT||Quits the game.<br />
|}<br />
<br />
<br />
==verbOps ($7A)==<br />
<br />
===Encoding===<br />
opcode verbID[p8] sub-opcode... $FF<br />
<br />
sub-opcodes:<br />
$01 object[p16]<br />
$02 name[c]... $00<br />
$03 colour[p8]<br />
$04 hicolour[p8]<br />
$05 left[p16] top[p16]<br />
$06<br />
$07<br />
$08<br />
$09<br />
$10 colour[p8]<br />
$11<br />
$12 key[p8]<br />
$13<br />
$14 stringID[p16]<br />
$16 object[p16] room[p8]<br />
$17 colour[p8]<br />
<br />
===Operation===<br />
{| border="1" cellpadding="2" width=100%<br />
|- style="background:whitesmoke"<br />
|Opcode||Meaning||Description<br />
|-<br />
|$01||SO_VERB_IMAGE||Assigns an object (image) to a verb.<br />
|-<br />
|$02||SO_VERB_NAME||Assigns the in-line name to the verb slot.<br />
|-<br />
|$03||SO_VERB_COLOR||Sets the colour of the verb.<br />
|-<br />
|$04||SO_VERB_HICOLOR||Sets the highlight colour of the verb.<br />
|-<br />
|$05||SO_VERB_AT||Sets the verb's top-left co-ordinates.<br />
|-<br />
|$06||SO_VERB_ON||Makes this verb active.<br />
|-<br />
|$07||SO_VERB_OFF||Makes this verb inactive.<br />
|-<br />
|$08||SO_VERB_DELETE||Kills this verb.<br />
|-<br />
|$09||SO_VERB_NEW||Creates a verb in the slot for the given verbID. If the slot is 0 (verb doesn't already exist), will add it to the next unusued slot; if this exceeds the global maximum number of verbs an error will be raised.<br />
|-<br />
|$10||SO_VERB_DIMCOLOR||Sets the dim colour of the verb.<br />
|-<br />
|$11||SO_VERB_DIM||Dims this verb.<br />
|-<br />
|$12||SO_VERB_KEY||Sets the key code (maybe ASCII char?) associated with this verb.<br />
|-<br />
|$13||SO_VERB_CENTER||Centres the verb?<br />
|-<br />
|$14||SO_VERB_NAME_STR||Loads the given string resource into the verb's slot. If either the string resource or verb slot is not found (0), the verb resource is nuked.<br />
|-<br />
|$16||Assign Object||Assigns an object from the given room to the verb (if the object's image index is not already assigned to the given object).<br />
|-<br />
|$17||Set Back Colour||Sets the background colour of the verb?<br />
|}<br />
<br />
<br />
==wait ($AE)==<br />
<br />
===Encoding===<br />
opcode sub-opcode<br />
<br />
sub-opcodes:<br />
$01 actor[p8]<br />
$02 <br />
$03<br />
$04<br />
<br />
===Operation===<br />
{| border="1" cellpadding="2" width=100%<br />
|- style="background:whitesmoke"<br />
|Opcode||Meaning||Description<br />
|-<br />
|$01||SO_WAIT_FOR_ACTOR||If the given actor is moving, breaks and resumes at this instruction again.<br />
|-<br />
|$02||SO_WAIT_FOR_MESSAGE||If the global variable VAR_HAVE_MSG (Var[3]) is not zero, breaks and resumes at this instruction again.<br />
|-<br />
|$03||SO_WAIT_FOR_CAMERA||If the camera has not reached its destination x position, breaks and resumes at this instruction again.<br />
|-<br />
|$04||SO_WAIT_FOR_SENTENCE||If there is a sentence present?, breaks and resumes at this instruction again<br />
|}<br />
<br />
===Variants===<br />
In Indy3 (non-Macintosh), this opcode only acts as SO_WAIT_FOR_MESSAGE and omits the sub-opcode.<br />
opcode<br />
<br />
<br />
==walkActorTo ($1E)==<br />
<br />
===Encoding===<br />
opcode actor[p8] x[p16] y[p16]<br />
<br />
===Operation===<br />
Sets the actor to begin walking to the given position.<br />
<br />
<br />
==walkActorToActor ($0D)==<br />
<br />
===Encoding===<br />
opcode walker[p8] walkee[p8] distance[8]<br />
<br />
===Operation===<br />
Walks walker towards walkee's position by the given distance. Walker and walkee are both actors.<br />
<br />
<br />
==walkActorToObject ($36)==<br />
<br />
===Encoding===<br />
opcode actor[p8] object[p16]<br />
<br />
===Operation===<br />
Sets the actor to begin walking to the given object's position.<br />
<br />
=Variables=<br />
<br />
A number of variables are reserved for use by the SPUTM/SCUMM engine. Here is a list of known variables and their corresponding numbers, taken from the ScummVM source code.<br />
<br />
VAR_RESULT = 0; // descumm claims var 0 is the result var (for expressions)<br />
VAR_KEYPRESS = 0; // script_v5_.cpp claims var 0 is for keypresses...<br />
VAR_EGO = 1;<br />
VAR_CAMERA_POS_X = 2;<br />
VAR_HAVE_MSG = 3;<br />
VAR_ROOM = 4;<br />
VAR_OVERRIDE = 5;<br />
VAR_MACHINE_SPEED = 6;<br />
VAR_ME = 7;<br />
VAR_NUM_ACTOR = 8;<br />
VAR_CURRENT_LIGHTS = 9;<br />
VAR_CURRENTDRIVE = 10;<br />
VAR_TMR_1 = 11;<br />
VAR_TMR_2 = 12;<br />
VAR_TMR_3 = 13;<br />
VAR_MUSIC_TIMER = 14;<br />
VAR_ACTOR_RANGE_MIN = 15;<br />
VAR_ACTOR_RANGE_MAX = 16;<br />
VAR_CAMERA_MIN_X = 17;<br />
VAR_CAMERA_MAX_X = 18;<br />
VAR_TIMER_NEXT = 19;<br />
VAR_VIRT_MOUSE_X = 20;<br />
VAR_VIRT_MOUSE_Y = 21;<br />
VAR_ROOM_RESOURCE = 22;<br />
VAR_LAST_SOUND = 23;<br />
VAR_CUTSCENEEXIT_KEY = 24;<br />
VAR_TALK_ACTOR = 25;<br />
VAR_CAMERA_FAST_X = 26;<br />
VAR_SCROLL_SCRIPT = 27;<br />
VAR_ENTRY_SCRIPT = 28;<br />
VAR_ENTRY_SCRIPT2 = 29;<br />
VAR_EXIT_SCRIPT = 30;<br />
VAR_EXIT_SCRIPT2 = 31;<br />
VAR_VERB_SCRIPT = 32;<br />
VAR_SENTENCE_SCRIPT = 33;<br />
VAR_INVENTORY_SCRIPT = 34;<br />
VAR_CUTSCENE_START_SCRIPT = 35;<br />
VAR_CUTSCENE_END_SCRIPT = 36;<br />
VAR_CHARINC = 37;<br />
VAR_WALKTO_OBJ = 38;<br />
VAR_DEBUGMODE = 39;<br />
VAR_HEAPSPACE = 40;<br />
VAR_RESTART_KEY = 42;<br />
VAR_PAUSE_KEY = 43;<br />
VAR_MOUSE_X = 44;<br />
VAR_MOUSE_Y = 45;<br />
VAR_TIMER = 46;<br />
VAR_TIMER_TOTAL = 47;<br />
VAR_SOUNDCARD = 48;<br />
VAR_VIDEOMODE = 49;<br />
VAR_MAINMENU_KEY = 50;<br />
VAR_FIXEDDISK = 51;<br />
VAR_CURSORSTATE = 52;<br />
VAR_USERPUT = 53;<br />
VAR_V5_TALK_STRING_Y = 54;<br />
VAR_SOUNDRESULT = 56;<br />
VAR_TALKSTOP_KEY = 57;<br />
VAR_FADE_DELAY = 59;<br />
VAR_NOSUBTITLES = 60;<br />
VAR_SOUNDPARAM = 64;<br />
VAR_SOUNDPARAM2 = 65;<br />
VAR_SOUNDPARAM3 = 66;<br />
VAR_INPUTMODE = 67; // 1 is keyboard, 2 is joystick, 3 is mouse<br />
VAR_MEMORY_PERFORMANCE = 68;<br />
VAR_VIDEO_PERFORMANCE = 69;<br />
VAR_ROOM_FLAG = 70;<br />
VAR_GAME_LOADED = 71;<br />
VAR_NEW_ROOM = 72;<br />
<br />
<br />
=Table of Parameters=<br />
Please see the wiki page [[SCUMM/V5_opcodes/Table]] for a concise rendition of the above information (with a few omissions dues to the complexity of the instructions).</div>Jestar jokinhttps://wiki.scummvm.org/index.php?title=SCUMM/V2_opcodes&diff=11019SCUMM/V2 opcodes2009-04-24T01:43:23Z<p>Jestar jokin: Added stubs for v2 specific opcodes</p>
<hr />
<div>=SCUMM V2 opcodes=<br />
<br />
==actorFollowCamera ($52)==<br />
<br />
==actorFromPos ($15)==<br />
<br />
==actorOps ($13)==<br />
<br />
==add ($5A)==<br />
<br />
==addIndirect ($2A)==<br />
<br />
==assignVarByte ($2C)==<br />
<br />
==assignVarWordIndirect ($0A)==<br />
<br />
==beginOverride ($58)==<br />
<br />
==chainScript ($4A)==<br />
<br />
==clearState01 ($77)==<br />
<br />
==clearState02 ($17)==<br />
<br />
==clearState04 ($67)==<br />
<br />
==clearState08 ($47)==<br />
<br />
==cursorCommand ($60)==<br />
<br />
==cutscene ($40)==<br />
<br />
==delay ($2E)==<br />
<br />
==doSentence ($19)==<br />
<br />
==drawObject ($05)==<br />
<br />
==drawSentence ($AC)==<br />
<br />
==dummy ($5C)==<br />
<br />
==endCutscene ($C0)==<br />
<br />
==faceActor ($09)==<br />
<br />
==findObject ($35)==<br />
<br />
==getActorRoom ($03)==<br />
<br />
==isGreaterEqual ($04)==<br />
<br />
==isNotEqual ($08)==<br />
<br />
==getActorElevation ($06)==<br />
<br />
==getActorWalkBox ($7B)==<br />
<br />
==getActorX ($43)==<br />
<br />
==getActorY ($23)==<br />
<br />
==getBitVar ($31)==<br />
<br />
==getObjPreposition ($6C)==<br />
<br />
==ifClassOfIs ($1D)==<br />
<br />
==ifNotState01 ($3F)==<br />
<br />
==ifNotState02 ($5F)==<br />
<br />
==ifNotState04 ($2F)==<br />
<br />
==ifNotState08 ($0F)==<br />
<br />
==ifState01 ($7F)==<br />
<br />
==ifState02 ($1F)==<br />
<br />
==ifState04 ($6F)==<br />
<br />
==ifState08 ($4F)==<br />
<br />
==isGreater ($78)==<br />
<br />
==isGreaterEqual ($04)==<br />
<br />
==isLess ($44)==<br />
<br />
==isLessEqual ($38)==<br />
<br />
==lights ($70)==<br />
<br />
==loadRoomWithEgo ($24)==<br />
<br />
==panCameraTo ($12)==<br />
<br />
==pickupObject ($50)==<br />
<br />
==putActor ($01)==<br />
<br />
==putActorAtObject ($0E)==<br />
<br />
==putActorInRoom ($2D)==<br />
<br />
==resourceRoutines ($0C)==<br />
<br />
==restart ($98)==<br />
<br />
==roomOps ($33)==<br />
<br />
==setActorElevation ($3D)==<br />
<br />
==setBitVar ($1B)==<br />
<br />
==setCameraAt ($32)==<br />
<br />
==setObjPreposition ($0B)==<br />
<br />
==setOwnerOf ($29)==<br />
<br />
==setState01 ($37)==<br />
<br />
==setState02 ($57)==<br />
<br />
==setState04 ($27)==<br />
<br />
==setState08 ($07)==<br />
<br />
==startMusic ($02)==<br />
<br />
==startScript ($42)==<br />
<br />
==stopScript ($62)==<br />
<br />
==stopObjectCode ($00)==<br />
<br />
==subIndirect ($6A)==<br />
<br />
==subtract ($3A)==<br />
<br />
==switchCostumeSet ($AB)==<br />
<br />
==verbOps ($7A)==<br />
<br />
==waitForActor ($3B)==<br />
<br />
==waitForMessage ($AE)==<br />
<br />
==waitForSentence ($4C)==<br />
<br />
==walkActorTo ($1E)==<br />
<br />
==walkActorToObject ($36)==</div>Jestar jokinhttps://wiki.scummvm.org/index.php?title=SCUMM/V5_opcodes&diff=11018SCUMM/V5 opcodes2009-04-23T13:28:54Z<p>Jestar jokin: A few minor fixes, hopefully the last from me</p>
<hr />
<div>=SCUMM V5 opcodes=<br />
The following conventions are used in the encoding descriptions.<br />
<br />
{| border="1" cellpadding="2" width=100%<br />
|- style="background:whitesmoke"<br />
|Term||Description<br />
|-<br />
|opcode||The instruction's opcode, with the appropriate bits set according to the parameters.<br />
|-<br />
|aux||An aux opcode that stores parameter bits and no other information. (the base aux opcode seems to always be $01)<br />
|-<br />
|sub-opcode||An aux opcode that indicates a specific function to perform (e.g. the "wait" instruction has sub-opcodes to "wait for message", "wait for actor" etc), as well as storing parameter bits if necessary.<br />
|-<br />
|result||A result pointer. (A standard word pointer, always a LE word.)<br />
|-<br />
|var||A variable pointer. Same as above, but is not written to. Because this is always a variable, the opcode is not affected like it would be with a normal parameter (described below).<br />
|-<br />
|value[8]||An 8-bit constant (a byte).<br />
|-<br />
|value[16]||A 16-bit constant (a word LE).<br />
|-<br />
|value[p8]||An 8-bit parameter. This may be encoded as a word LE if it's a pointer, or a byte if it's a constant.<br />
|-<br />
|value[p16]||A 16-bit parameter. This is always encoded as a word LE, and may be a pointer or constant.<br />
|-<br />
|value[v16]||A variable number of word LE parameters. These are encoded as a sequence of aux[8] param[p16]; param; aux contains the parameter bit to describe param (and is always $01, ignoring the parameter bits). A byte of $FF terminates the sequence. (actually always shown as "value[v16]...")<br />
|-<br />
|value[o]||The offset word for parameter value. This is only encoded if needed, but always at the position indicated. If not specified, the offset word occurs immediately after the parameter.<br />
|-<br />
|value[c]||An ASCII character. Because some instructions use null-terminated strings and some use $FF, the exact format of a string is described in the instruction. Almost always appears as "value[c]..."<br />
|-<br />
|term...||One or more terms.<br />
|}<br />
<br />
Of course, due to the non-orthogonality of the opcodes, there are lots of exceptions.<br />
<br />
<br />
==actorFollowCamera ($52)==<br />
<br />
===Encoding===<br />
opcode actor[p8]<br />
<br />
===Operation===<br />
Sets the camera to follow the given actor?<br />
<br />
<br />
==actorFromPos ($15)==<br />
<br />
===Encoding===<br />
opcode result x[p16] y[p16]<br />
<br />
===Operation===<br />
Returns the actor located at the given co-ordinates.<br />
<br />
<br />
==actorOps ($13)==<br />
parameters depend on auxiliary opcode; terminated by $FF<br />
<br />
===Encoding===<br />
opcode actor[p8] sub-opcode... $FF<br />
<br />
sub-opcodes:<br />
$00 arg1[p8]<br />
$01 costume[p8]<br />
$02 xspeed[p8] yspeed[p8]<br />
$03 sound[p8]<br />
$04 walkframe[p8]<br />
$05 starttalk[p8] endtalk[p8]<br />
$06 standframe[p8]<br />
$07 arg1[p8] arg2[p8] arg3[p8]<br />
$08<br />
$09 elevation[p16]<br />
$0A<br />
$0B index[p8] value[p8]<br />
$0C colour[p8]<br />
$0D name[c]... $00<br />
$0E initframe[p8]<br />
$10 width[p8]<br />
$11 xscale[p8] yscale[p8]<br />
$12<br />
$13 zplane[p8]<br />
$14<br />
$15 <br />
$16 animspeed[p8]<br />
$17 shadow[p8]<br />
<br />
===Operation===<br />
Miscellaneous actions on actors.<br />
<br />
{| border="1" cellpadding="2" width=100%<br />
|- style="background:whitesmoke"<br />
|Opcode||Meaning||Description<br />
|-<br />
|$00||dummy||A dummy case, does nothing (in ScummVM).<br />
|-<br />
|$01||SO_COSTUME||Sets the actor's costume.<br />
|-<br />
|$02||SO_STEP_DIST||Sets the actor's walking speed for x and y.<br />
|-<br />
|$03||SO_SOUND||Associates a sound with the actor (footsteps?)<br />
|-<br />
|$04||SO_WALK_ANIMATION||Sets the current frame of the walking animation.<br />
|-<br />
|$05||SO_TALK_ANIMATION||Sets the start and stop frames of the talking animation.<br />
|-<br />
|$06||SO_STAND_ANIMATION||Sets the current frame of the standing animation.<br />
|-<br />
|$07||SO_ANIMATION||Unknown; seems to be unused in ScummVM.<br />
|-<br />
|$08||SO_DEFAULT||Initializes actor.<br />
|-<br />
|$09||SO_ELEVATION||Sets the actor's elevation to the given value.<br />
|-<br />
|$0A||SO_ANIMATION_DEFAULT||Initializes the actor's animation frames.<br>Init frame = 1<br>Walk frame = 2<br>Stand frame = 3<br>Talk start frame = 4<br>Talk stop frame = 5<br />
|-<br />
|$0B||SO_PALETTE||Sets the colour at the given index to a new value (another entry in the colour lookup table/CLUT). Index must be between 0 and 31 (the number of colours in a costume).<br />
|-<br />
|$0C||SO_TALK_COLOR||Sets the actor's talk colour.<br />
|-<br />
|$0D||SO_ACTOR_NAME||Sets the actor's name to the given null-terminated string.<br />
|-<br />
|$0E||SO_INIT_ANIMATION||Sets the current frame of the initial animation.<br />
|-<br />
|$10||SO_ACTOR_WIDTH||Sets the actor's width.<br />
|-<br />
|$11||SO_ACTOR_SCALE||Sets the actor's X and Y scales.<br />
|-<br />
|$12||SO_NEVER_ZCLIP||Turns off all Z-clipping for the actor.<br />
|-<br />
|$13||SO_ALWAYS_ZCLIP||Forces the actor's Z-clipping for the given Z-plane?<br />
|-<br />
|$14||SO_IGNORE_BOXES||Ignores boxes, turns off Z-clipping, and puts actor somewhere if the actor is in the current room?<br />
|-<br />
|$15||SO_FOLLOW_BOXES||Follows boxes, turns off Z-clipping, and puts actor somewhere if the actor is in the current room?<br />
|-<br />
|$16||SO_ANIMATION_SPEED||Sets the animation speed.<br />
|-<br />
|$17||SO_SHADOW||Sets the shadow mode.<br />
|}<br />
<br />
===Variants===<br />
In SCUMM V4, sub-opcode $11 (SO_ACTOR_SCALE) only takes one parameter, so X and Y scaling is done at a 1:1 ratio.<br />
<br />
<br />
==actorSetClass ($5D)==<br />
<br />
===Encoding===<br />
opcode object[p16] classes[v16]...<br />
<br />
===Operation===<br />
Makes object inherit from all of the given classes. A class of "0" will clear all of the object's existing class data.<br />
<br />
<br />
==add ($5A)==<br />
<br />
===Encoding===<br />
opcode result value[p16]<br />
<br />
===Operation===<br />
result := result + value<br />
<br />
The variable pointed to by result is read, value is added to it, and the result written back.<br />
<br />
<br />
==and ($17)==<br />
one parameter, uses result<br />
<br />
===Encoding===<br />
opcode result value[p16]<br />
<br />
===Operation===<br />
result := result and value<br />
<br />
The variable pointed to by result is read, logically ANDed with value, and the result written back.<br />
<br />
<br />
==animateActor ($11)==<br />
<br />
===Encoding===<br />
opcode actor[p8] anim[p8]<br />
<br />
===Operation===<br />
Starts the given animation for the given actor.<br />
<br />
<br />
==breakHere ($80)==<br />
no parameters<br />
<br />
===Encoding===<br />
opcode<br />
<br />
===Operation===<br />
Deschedules the currently running thread. Execution continues at the next instruction when the thread's next timeslot comes around.<br />
<br />
<br />
==chainScript ($42)==<br />
one parameter plus varargs<br />
<br />
===Encoding===<br />
opcode script[p8] args[v16]...<br />
<br />
===Operation===<br />
Replaces the currently running script with another one. The current script is terminated immediately and the new script (determined by the given script ID), is executed in the same thread. The new script has its local variables initialised to the list args. Uninitialised variables have undefined values.<br />
<br />
<br />
==cursorCommand ($2C)==<br />
parameters depend on auxiliary opcode<br />
<br />
===Encoding===<br />
opcode sub-opcode<br />
<br />
sub-opcode can be any of the following:<br />
$01<br />
... $01 through $08 take the same arguments ...<br />
$08<br />
$0A cursornum[p8] charletter[p8]<br />
$0B index[p8] x[p8] y[p8]<br />
$0C cursor[p8]<br />
$0D charset[p8]<br />
$0E colours[v16]...<br />
<br />
===Operation===<br />
Miscellaneous actions on cursors & charsets.<br />
<br />
{| border="1" cellpadding="2" width=100%<br />
|- style="background:whitesmoke"<br />
|Opcode||Meaning||Description<br />
|-<br />
|$01||SO_CURSOR_ON||Turns the cursor on.<br />
|-<br />
|$02||SO_CURSOR_OFF||Turns the cursor off.<br />
|-<br />
|$03||SO_USERPUT_ON||Enables user input.<br />
|-<br />
|$04||SO_USERPUT_OFF||Disables user input.<br />
|-<br />
|$05||SO_CURSOR_SOFT_ON||Increments the cursor's state?<br />
|-<br />
|$06||SO_CURSOR_SOFT_OFF||Decrements the cursor's state?<br />
|-<br />
|$07||SO_USERPUT_SOFT_ON||Increments "user input" counter (when greater than 0, user input is enabled).<br />
|-<br />
|$08||SO_USERPUT_SOFT_OFF||Decrements "user input" counter (when 0 or less, user input is disabled).<br />
|-<br />
|$0A||SO_CURSOR_IMAGE||Changes the cursor image to a new one, based on image in a character set. Only used in Loom.<br />
|-<br />
|$0B||SO_CURSOR_HOTSPOT||Changes the hotspot of a cursor. Only used in Loom.<br />
|-<br />
|$0C||SO_CURSOR_SET||Changes the current cursor. Must be between 0 and 3 inclusive.<br />
|-<br />
|$0D||SO_CHARSET_SET||Initializes the given character set.<br />
|-<br />
|$0E||SO_CHARSET_COLORS||Initializes the character set data & colours to the given arguments? Must have 16 arguments?<br />
|}<br />
<br />
===Variants===<br />
In SCUMM V3, sub-opcode $0E performs a different function, to load/initialize a character set.<br />
<br />
opcode $0E arg1[p8] arg2[p8]<br />
<br />
<br />
==cutScene ($40)==<br />
<br />
===Encoding===<br />
opcode args[v16]...<br />
<br />
===Operation===<br />
??? If required, runs a script passing the given arguments. Cutscene data given by the first argument?<br />
<br />
<br />
==debug ($6B)==<br />
one parameter, no result<br />
<br />
===Encoding===<br />
opcode param[p16]<br />
<br />
===Operation===<br />
Passes the parameter to the interpreter's debugger. What this does is entirely platform-specific (and may do nothing).<br />
<br />
<br />
==decrement ($C6)==<br />
no parameters, uses result<br />
<br />
===Encoding===<br />
opcode result<br />
<br />
===Operation===<br />
result := result - 1<br />
<br />
Reads the variable pointed to by result, decrements it, and writes it back. <br />
<br />
<br />
==delay ($2E)==<br />
one constant parameter<br />
<br />
===Encoding===<br />
opcode param[24]<br />
<br />
===Operation===<br />
Suspends the current thread for the appropriate number of 1/60ths of a second. Yes, that really is a 24-bit LE constant.<br />
<br />
<br />
==delayVariable ($2B)==<br />
one constant parameter<br />
<br />
===Encoding===<br />
opcode var<br />
<br />
===Operation===<br />
var is dereferenced and the current thread suspended for that number of 1/60ths of a second.<br />
<br />
<br />
==divide ($5B)==<br />
one parameter, uses result<br />
<br />
===Encoding===<br />
opcode result value[p16]<br />
<br />
===Operation===<br />
result := result / value<br />
<br />
The variable pointed to by result is read, divided by value, and the result written back. If value is zero, the result is undefined (and the interpeter may halt with an error). <br />
<br />
<br />
==doSentence ($19)==<br />
<br />
===Encoding===<br />
opcode verb[p8] objectA[p16] objectB[p16]<br />
<br />
===Operation===<br />
Performs a verb sentence action, e.g. "Use monkey on hydrant". If verb is $FE, the current sentence script is stopped, status cleared etc.<br />
<br />
<br />
==drawBox ($3F)==<br />
two parameters, does not use result, supplementary opcode byte with three more subsequent parameters<br />
<br />
===Encoding===<br />
opcode left[p16] top[p16] auxopcode[8] right[p16] bottom[p16] colour[p8]<br />
<br />
===Operation===<br />
Draws a solid box on the backbuffer from (left, top) to (right, bottom) in the given colour.<br />
<br />
The only part of auxopcode that is relevant are the parameter bits. The rest of the opcode is ignored. <br />
<br />
<br />
==drawObject ($05)==<br />
<br />
===Encoding===<br />
opcode object[p16] sub-opcode<br />
<br />
sub-opcodes:<br />
$01 xpos[p16] ypos[p16]<br />
$02 state[p16]<br />
$1F<br />
<br />
===Operation===<br />
{| border="1" cellpadding="2" width=100%<br />
|- style="background:whitesmoke"<br />
|Opcode||Meaning||Description<br />
|-<br />
|$01||Draw At||Moves the given object to the given co-ordinates, and adds it to the drawing queue.<br />
|-<br />
|$02||Set State||Sets the state of the object, adds it to the drawing queue.<br />
|-<br />
|$1F||Draw||Does not change the object's position (or state?), still adds it to the drawing queue.<br />
|}<br />
<br />
===Variants===<br />
Small header games only support the parameters used with sub-opcode $01, e.g:<br />
opcode object[p16] xpos[p16] ypos[p16]<br />
Accordingly, they have three parameter bits, and hence more possible opcodes.<br />
<br />
<br />
==dummy ($A7)==<br />
<br />
===Encoding===<br />
opcode<br />
<br />
===Operation===<br />
V5 specific - The KIXX XL release of Monkey Island 2 (Amiga disk) used this opcode as a dummy, in order to remove copy protection and keep level selection.<br />
<br />
===Variants===<br />
In SCUMM V3 and V4, this opcode is used for the saveLoadVars instruction.<br />
<br />
<br />
==endCutScene ($C0)==<br />
<br />
===Encoding===<br />
opcode<br />
<br />
===Operation===<br />
Ends the cutscene, performing cleanup if necessary.<br />
<br />
<br />
==equalZero ($28)==<br />
jumps<br />
<br />
===Encoding===<br />
opcode var target[16]<br />
<br />
===Operation===<br />
unless (var == 0) goto target<br />
<br />
Target is a byte offset (measured from after this instruction), which will be added to the instruction pointer.<br />
<br />
<br />
==expression ($AC)==<br />
<br />
===Encoding===<br />
opcode result subopcode... $FF<br />
<br />
sub-opcodes:<br />
$01 value[p16]<br />
$02<br />
... $02 through $05 take the same arguments ...<br />
$05<br />
$06 nested-opcode<br />
<br />
===Operation===<br />
Expression mode operates on a stack. Values are pushed on, and operators are applied to the top two items on the stack.<br />
<br />
{| border="1" cellpadding="2" width=100%<br />
|- style="background:whitesmoke"<br />
|Opcode||Meaning||Description<br />
|-<br />
|$01||Value||Pushes a value onto the top of the stack.<br />
|-<br />
|$02||Add||stack[top - 1] + stack[top]<br />
|-<br />
|$03||Subtract||stack[top - 1] - stack[top]<br />
|-<br />
|$04||Multiply||stack[top - 1] * stack[top]<br />
|-<br />
|$05||Divide||stack[top - 1] / stack[top] (if stack[top] is 0 an error occurs)<br />
|-<br />
|$06||Nested Opcode||An entire instruction that returns a result, such as getActorScale. This is interpreted like a normal opcode, but the result is pushed onto the expression stack. (The opcode is passed the special "VAR_RESULT" parameter for "result")<br />
|}<br />
<br />
<br />
==faceActor ($09)==<br />
<br />
===Encoding===<br />
opcode actor[p8] object[p16]<br />
<br />
===Operation===<br />
Dereferences actor, tells actor to face object (presumably based on X/Y co-ordinates).<br />
<br />
<br />
==findInventory ($3D)==<br />
<br />
===Encoding===<br />
opcode result owner[p8] index[p8]<br />
<br />
===Operation===<br />
object := owner.inventory[index]<br />
Searches for all objects owned by owner (an actor or object), and returns the one at the given index (offset).<br />
<br />
<br />
==findObject ($35)==<br />
<br />
===Encoding===<br />
opcode result x[p8] y[p8]<br />
<br />
===Operation===<br />
Returns the first "touchable" local object at the given co-ordinates. Will not match on the bottom or right-hand edges of an object.<br />
<br />
<br />
==freezeScripts ($60)==<br />
<br />
===Encoding===<br />
opcode flag[p8]<br />
<br />
===Operation===<br />
Freezes all scripts (by setting the high bit on each script's status). If flag is >= $80, all freeze resistent scripts will also be frozen. If flag is 0, all scripts are unfrozen. Freezing effects are cumulative - i.e. if script A is frozen twice, and unfrozen once, it will still be frozen until it is unfrozen a second time. A script's frozen status is indicated by the high bit.<br />
<br />
<br />
==getActorCostume ($71)==<br />
<br />
===Encoding===<br />
opcode result actor[p8]<br />
<br />
===Operation===<br />
Returns the actor's current costume.<br />
<br />
<br />
==getActorElevation ($06)==<br />
<br />
===Encoding===<br />
opcode result actor[p8]<br />
<br />
===Operation===<br />
Returns the actor's current elevation.<br />
<br />
<br />
==getActorFacing ($63)==<br />
<br />
===Encoding===<br />
opcode result actor[p8]<br />
<br />
===Operation===<br />
Returns the current direction the actor is facing.<br />
<br />
<br />
==getActorMoving ($56)==<br />
<br />
===Encoding===<br />
opcode result actor[p8]<br />
<br />
===Operation===<br />
Returns the actor's moving status (0 or 1).<br />
<br />
<br />
==getActorRoom ($03)==<br />
<br />
===Encoding===<br />
opcode result actor[p8]<br />
<br />
===Operation===<br />
Returns the room the actor currently occupies?<br />
<br />
<br />
==getActorScale ($3B)==<br />
<br />
===Encoding===<br />
opcode result actor[p8]<br />
<br />
===Operation===<br />
Returns the actor's current scale.<br />
<br />
===Variants===<br />
In Indy3, this opcode is used for waitForActor.<br />
<br />
<br />
==getActorWalkBox ($7B)==<br />
<br />
===Encoding===<br />
opcode result actor[p8]<br />
<br />
===Operation===<br />
Returns the actor's walkbox.<br />
<br />
<br />
==getActorWidth ($6C)==<br />
<br />
===Encoding===<br />
opcode result actor[p8]<br />
<br />
===Operation===<br />
Returns the actor's width.<br />
<br />
<br />
==getActorX ($43)==<br />
<br />
===Encoding===<br />
opcode result actor[p16]<br />
<br />
===Operation===<br />
Returns the actor's current X co-ordinate.<br />
<br />
===Variants===<br />
In Indy3, actor is only one byte.<br />
opcode result actor[p8]<br />
<br />
<br />
==getActorY ($23)==<br />
<br />
===Encoding===<br />
opcode result actor[p16]<br />
<br />
===Operation===<br />
Returns the actor's current Y co-ordinate.<br />
<br />
===Variants===<br />
In Indy3, actor is only one byte.<br />
opcode result actor[p8]<br />
<br />
<br />
==getAnimCounter ($22)==<br />
<br />
===Encoding===<br />
opcode result actor[p8]<br />
<br />
===Operation===<br />
Returns the actor's animation counter.<br />
<br />
===Variants===<br />
This opcode is used for saveLoadGame in SCUMM V3.<br />
<br />
<br />
==getClosestObjActor ($66)==<br />
<br />
===Encoding===<br />
opcode result actor[p16]<br />
<br />
===Operation===<br />
Returns the object closest to the actor. Items that are more than 255 units (pixels in newer games, characters in older games) away from the actor will not be detected.<br />
<br />
<br />
==getDist ($34)==<br />
<br />
===Encoding===<br />
opcode result objA[p16] objB[p16]<br />
<br />
===Operation===<br />
Returns the distance between two actors/objects (objA and objB).<br />
<br />
<br />
==getInventoryCount ($31)==<br />
<br />
===Encoding===<br />
opcode result actor[p8]<br />
<br />
===Operation===<br />
Returns the number of items in an actor's inventory?<br />
<br />
<br />
==getObjectOwner ($10)==<br />
<br />
===Encoding===<br />
opcode result object[p16]<br />
<br />
===Operation===<br />
Returns the owner of an object.<br />
<br />
<br />
==getObjectState ($0F)==<br />
<br />
===Encoding===<br />
opcode result object[p16]<br />
<br />
===Operation===<br />
Returns the state of the object.<br />
<br />
===Variants===<br />
In small header games, the encoding becomes:<br />
opcode object[p16] state[p8] target[16]<br />
operation becomes<br />
unless (getState(object) == state) goto target<br />
<br />
<br />
==getRandomNumber ($16)==<br />
<br />
===Encoding===<br />
opcode result seed[p8]<br />
<br />
===Operation===<br />
Returns a new random number based on the given seed.<br />
<br />
<br />
==getScriptRunning ($68)==<br />
<br />
===Encoding===<br />
opcode result script[p8]<br />
<br />
===Operation===<br />
Returns 1 if the given script is running, 0 if it's not.<br />
<br />
<br />
==getStringWidth ($67)==<br />
<br />
===Encoding===<br />
opcode result strptr[p8]<br />
<br />
===Operation===<br />
Gets the length of the string pointed to by strptr (either a variable or direct byte), stores the returned value in result.<br />
<br />
<br />
==getVerbEntryPoint ($0B)==<br />
<br />
===Encoding===<br />
opcode result object[p16] verb[p16]<br />
<br />
===Operation===<br />
Returns the entry point for the response code/script for when the given verb is applied to the given object? i.e. gets the start of the script to run for the specific user interaction.<br />
<br />
<br />
==ifClassOfIs ($1D)==<br />
jumps<br />
<br />
===Encoding===<br />
opcode value[p16] args[v16]... target[16]<br />
<br />
===Operation===<br />
unless (value.class is one of [args.class]) goto target<br />
<br />
Compares the value's class with all classes given in args.<br />
<br />
Target is a byte offset (measured from after this instruction), which will be added to the instruction pointer.<br />
<br />
<br />
==ifNotState ($2F) (V3-4)==<br />
This opcode is not present in SCUMM V5.<br />
<br />
===Encoding===<br />
opcode object[p16] state[p8] target[16]<br />
<br />
===Operation===<br />
unless (stateOf(object) != state) goto target<br />
<br />
<br />
==ifState ($4F) (V3-4)==<br />
This opcode is not present in SCUMM V5.<br />
<br />
===Encoding===<br />
opcode object[p16] state[p8] target[16]<br />
<br />
===Operation===<br />
unless (stateOf(object) == state) goto target<br />
<br />
<br />
==increment ($46)==<br />
no parameters, uses result<br />
<br />
===Encoding===<br />
opcode result<br />
<br />
===Operation===<br />
result := result + 1<br />
<br />
Reads the variable pointed to by result, increments it, and writes it back. <br />
<br />
<br />
==isActorInBox ($1F)==<br />
<br />
===Encoding===<br />
opcode actor[p8] box[p8] target[16]<br />
<br />
===Operation===<br />
Unless the actor's co-ordinates are within the bounds of the given box, jump to target.<br />
<br />
Target is a byte offset (measured from after this instruction), which will be added to the instruction pointer.<br />
<br />
<br />
==isEqual ($48)==<br />
<br />
===Encoding===<br />
opcode var value[p16] target[16]<br />
<br />
===Operation===<br />
unless (value == var) goto target<br />
<br />
Target is a byte offset (measured from after this instruction), which will be added to the instruction pointer.<br />
<br />
<br />
==isGreater ($78)==<br />
<br />
===Encoding===<br />
opcode var value[p16] target[16]<br />
<br />
===Operation===<br />
unless (value > var) goto target<br />
<br />
Target is a byte offset (measured from after this instruction), which will be added to the instruction pointer.<br />
<br />
<br />
==isGreaterEqual ($04)==<br />
<br />
===Encoding===<br />
opcode var value[p16] target[16]<br />
<br />
===Operation===<br />
unless (value >= var) goto target<br />
<br />
Target is a byte offset (measured from after this instruction), which will be added to the instruction pointer.<br />
<br />
<br />
==isLess ($44)==<br />
<br />
===Encoding===<br />
opcode var value[p16] target[16]<br />
<br />
===Operation===<br />
unless (value < var) goto target<br />
<br />
Target is a byte offset (measured from after this instruction), which will be added to the instruction pointer.<br />
<br />
<br />
==isNotEqual ($08)==<br />
<br />
===Encoding===<br />
opcode var value[p16] target[16]<br />
<br />
===Operation===<br />
unless (value != var) goto target<br />
<br />
Target is a byte offset (measured from after this instruction), which will be added to the instruction pointer.<br />
<br />
<br />
==isSoundRunning ($7C)==<br />
<br />
===Encoding===<br />
opcode result sound[p8]<br />
<br />
===Operation===<br />
Returns 1 if sound is running, returns 0 if sound is not running or if the given sound is 0.<br />
<br />
<br />
==jumpRelative ($18)==<br />
jumps<br />
<br />
===Encoding===<br />
opcode target[16]<br />
<br />
===Operation===<br />
PC := PC + target<br />
<br />
The inline constant target is read as a signed word and added to the program counter after the instruction has been read. Therefore, if target is zero, the instruction will do nothing; if target is -3, an infinite loop will result. <br />
<br />
<br />
==lessOrEqual ($38)==<br />
jumps<br />
<br />
===Encoding===<br />
opcode var value[p16] target[16]<br />
<br />
===Operation===<br />
unless (value <= var) goto target<br />
<br />
Target is a byte offset (measured from after this instruction), which will be added to the instruction pointer.<br />
<br />
<br />
==lights ($70)==<br />
<br />
===Encoding===<br />
opcode arg1[p8] arg2[8] arg3[8]<br />
<br />
===Operation===<br />
If arg3 is 0, the "current lights" variable is set to arg1.<br />
If arg3 is 1, the size of the "flashlight" light is determined by arg1 and arg2, for width and height in stripes (which are equivalent to 8 pixels each; see [[SCUMM/Technical Reference/Image resources]]).<br />
<br />
<br />
==loadRoom ($72)==<br />
<br />
===Encoding===<br />
opcode room[p8]<br />
<br />
===Operation===<br />
Loads the given room into memory.<br />
<br />
<br />
==loadRoomWithEgo ($24)==<br />
<br />
===Encoding===<br />
opcode object[p16] room[p8] x[16] y[16]<br />
<br />
===Operation===<br />
Places the Ego actor in room at object's position. If x is not -1, Ego will start moving towards the given x and y co-ordinates. If object is not in the given room an error will occur.<br />
(I think...)<br />
<br />
<br />
==matrixOp ($30)==<br />
<br />
===Encoding===<br />
opcode sub-opcode<br />
<br />
sub-opcodes:<br />
$01 box[p8] val[p8]<br />
$02 box[p8] val[p8]<br />
$03 box[p8] val[p8]<br />
$04<br />
<br />
===Operation===<br />
This instruction manipulates boxes.<br />
<br />
{| border="1" cellpadding="2" width=100%<br />
|- style="background:whitesmoke"<br />
|Opcode||Meaning||Description<br />
|-<br />
|$01||setBoxFlags||Sets the box's flags to the given value.<br />
|-<br />
|$02||setBoxScale||Sets the box's scale.<br />
|-<br />
|$03||setBoxScale||Sets the box's scale to ((val - 1) OR $8000).<br />
|-<br />
|$04||createBoxMatrix||Initializes the matrix of boxes, by determining the distances and shortest paths between boxes.<br />
|}<br />
<br />
===Variants===<br />
SCUMM V3 only has the one instruction, which behaves like setBoxFlags:<br />
opcode box[p8] val[8]<br />
<br />
<br />
==move ($1A)==<br />
<br />
===Encoding===<br />
opcode result value[p16]<br />
<br />
===Operation===<br />
result := value<br />
<br />
Value is moved into result.<br />
<br />
<br />
==multiply ($1B)==<br />
<br />
===Encoding===<br />
opcode result value[p16]<br />
<br />
===Operation===<br />
result := result * value<br />
<br />
The variable pointed to by result is read, multiplied by value, and written back.<br />
<br />
<br />
==notEqualZero ($A8)==<br />
<br />
===Encoding===<br />
opcode var target[16]<br />
<br />
===Operation===<br />
unless (var != 0) goto target<br />
<br />
Target is a byte offset (measured from after this instruction), which will be added to the instruction pointer.<br />
<br />
<br />
==oldRoomEffect ($5C) (V4)==<br />
This opcode/instruction is only present in SCUMM V4.<br />
<br />
===Encoding===<br />
opcode sub-opcode<br />
<br />
sub-opcodes:<br />
$03 effect[p16]<br />
<br />
===Operation===<br />
Performs like sub-opcode SO_ROOM_FADE of the roomOps instruction (fade in if effect != 0, otherwise fade out).<br />
<br />
This information may not be correct; descumm says if the sub-opcode is 3, to "set" the effect, but if the sub-opcode is anything else to fade in with the given effect.<br />
<br />
===Variants===<br />
FM-Towns SCUMM V3 performs a different effect, not fully implemented in ScummVM. At the moment ScummVM just forces a redraw of the screen background.<br />
<br />
<br />
==or ($57)==<br />
one parameter, uses result<br />
<br />
===Encoding===<br />
opcode result value[p16]<br />
<br />
===Operation===<br />
result := result or value<br />
<br />
The variable pointed to by result is read, logically ORed with value, and the result written back.<br />
<br />
<br />
==override ($58)==<br />
<br />
===Encoding===<br />
opcode sub-opcode<br />
<br />
sub-opcodes:<br />
$00<br />
$01 $18 target[16]<br />
<br />
===Operation===<br />
If the sub-opcode is 0, marks the end of an override section.<br><br />
If the sub-opcode is not 0, marks the beginning of an override section. The instruction is immediately followed by a "jumpRelative" instruction.<br><br />
Overrides are used by cutscenes; if a cutscene is skipped (if the user presses the ESC key), the script will jump by the given target (offset from the beginOverride instruction).<br />
<br />
<br />
==panCameraTo ($12)==<br />
<br />
===Encoding===<br />
opcode x[p16]<br />
<br />
===Operation===<br />
Starts the camera panning to the given x co-ordinate.<br />
<br />
<br />
==pickupObject ($25)==<br />
<br />
===Encoding===<br />
opcode object[p16] room[p8]<br />
<br />
===Operation===<br />
Adds the given object (located in the given room) to the Ego actor's inventory.<br />
<br />
===Variants===<br />
In SCUMM V3 and V4, this opcode is used for drawObject.<br />
<br />
<br />
==pickupObjectOld ($50) (V4)==<br />
This opcode is not present in SCUMM V5.<br />
<br />
===Encoding===<br />
opcode object[p16]<br />
<br />
===Operation===<br />
Adds the given object (located in the given room) to the Ego actor's inventory. If object < 1, an error is raised. If the object is not found or the object is already in the inventory, this function ends gracefully.<br />
<br />
<br />
==print ($14)==<br />
<br />
===Encoding===<br />
opcode actor[p8] sub-opcode<br />
<br />
sub-opcodes<br />
$00 xpos[p16] ypos[p16]<br />
$01 colour[p8]<br />
$02 right[p16]<br />
$03 width[p16] height[p16]<br />
$04<br />
$06<br />
$07<br />
$08 offset[p16] delay[p16]<br />
$0F string[c]... $FF<br />
<br />
===Operation===<br />
Sets text properties and displays dialogue.<br />
<br />
{| border="1" cellpadding="2" width=100%<br />
|- style="background:whitesmoke"<br />
|Opcode||Meaning||Description<br />
|-<br />
|$00||SO_AT||Sets the position of the text that follows.<br />
|-<br />
|$01||SO_COLOR||Sets the colour of the text.<br />
|-<br />
|$02||SO_CLIPPED||Clips the text's right-hand side (for wrapping?).<br />
|-<br />
|$03||SO_ERASE||Erases characters (not used in ScummVM).<br />
|-<br />
|$04||SO_CENTER||Centres the text.<br />
|-<br />
|$06||SO_LEFT||Left-aligns the text.<br />
|-<br />
|$07||SO_OVERHEAD||Overhead-aligns the text.<br />
|-<br />
|$0F||SO_TEXTSTRING||Prints the text string that follows. Terminated by $FF.<br />
|}<br />
<br />
===Variants===<br />
In SCUMM V3, text function $06 sets the height of the text:<br />
$06 height[p16]<br />
<br />
In Loom CD (SCUMM V4), there is an additional text function $08 (SO_SAY_VOICE), which plays a portion of the CD audio track.<br />
$08 offset[p16] delay[p16]<br />
<br />
<br />
==printEgo ($D8)==<br />
<br />
===Encoding===<br />
opcode sub-opcode<br />
<br />
===Operation===<br />
Exactly the same as print, except the actor is implicitly Ego. See the entry for "print" for further explanation.<br />
<br />
<br />
==pseudoRoom ($CC)==<br />
<br />
===Encoding===<br />
opcode val[8] res[8]... $00<br />
<br />
===Operation===<br />
forall (res) {<br />
if (res >= $80) {<br />
_resourceMapper[res & $7F] := val<br />
}<br />
}<br />
<br />
What does this actually do? We may never know.<br />
<br />
It looks like res values always have the high bit set, e.g. 0x01 becomes 0x81.<br />
<br />
<br />
==putActor ($01)==<br />
<br />
===Encoding===<br />
opcode actor[p8] x[p16] y[p16]<br />
<br />
===Operation===<br />
Puts the actor at the given co-ordinates.<br />
<br />
<br />
==putActorAtObject ($0E)==<br />
<br />
===Encoding===<br />
opcode actor[p8] object[p16]<br />
<br />
===Operation===<br />
Puts the actor at the given object's position. If the object can not be found, a default position is returned (the centre of the screen in ScummVM).<br />
<br />
<br />
==putActorInRoom ($2D)==<br />
<br />
===Encoding===<br />
opcode actor[p8] room[p8]<br />
<br />
===Operation===<br />
Puts the actor in the given room.<br />
<br />
<br />
==resourceRoutines ($0C)==<br />
<br />
===Encoding===<br />
opcode sub-opcode<br />
<br />
sub-opcodes:<br />
$01 resID[p8]<br />
... $01 through $10 take the same arguments ...<br />
$10 resID[p8]<br />
$11<br />
$12 resID[p8]<br />
$13 resID[p8]<br />
$14 room[p8] object[p16]<br />
<br />
===Operation===<br />
resID is unique only within the resource type (e.g. script 11 will not conflict with sound 11).<br />
<br />
{| border="1" cellpadding="2" width=100%<br />
|- style="background:whitesmoke"<br />
|Opcode||Meaning||Description<br />
|-<br />
|$01||SO_LOAD_SCRIPT||Loads the given script into memory.<br />
|-<br />
|$02||SO_LOAD_SOUND||Loads the given sound into memory.<br />
|-<br />
|$03||SO_LOAD_COSTUME||Loads the given costume into memory.<br />
|-<br />
|$04||SO_LOAD_ROOM||Loads the given room into memory.<br />
|-<br />
|$05||SO_NUKE_SCRIPT||Obliterates the given script from memory.<br />
|-<br />
|$06||SO_NUKE_SOUND||Obliterates the given sound from memory.<br />
|-<br />
|$07||SO_NUKE_COSTUME||Obliterates the given costume from memory.<br />
|-<br />
|$08||SO_NUKE_ROOM||Obliterates the given room from memory.<br />
|-<br />
|$09||SO_LOCK_SCRIPT||Locks the given script.<br />
|-<br />
|$0A||SO_LOCK_SOUND||Locks the given sound.<br />
|-<br />
|$0B||SO_LOCK_COSTUME||Locks the given costume.<br />
|-<br />
|$0C||SO_LOCK_ROOM||Locks the given room.<br />
|-<br />
|$0D||SO_UNLOCK_SCRIPT||Unlocks the given script.<br />
|-<br />
|$0E||SO_UNLOCK_SOUND||Unlocks the given sound.<br />
|-<br />
|$0F||SO_UNLOCK_COSTUME||Unlocks the given costume.<br />
|-<br />
|$10||SO_UNLOCK_ROOM||Unlocks the given room.<br />
|-<br />
|$11||SO_CLEAR_HEAP||Clears the heap.<br />
|-<br />
|$12||SO_LOAD_CHARSET||Loads the given character set into memory.<br />
|-<br />
|$13||SO_NUKE_CHARSET||Obliterates the given character set from memory.<br />
|-<br />
|$14||SO_LOAD_OBJECT||Loads the given object from the given room resource.<br />
|}<br />
<br />
===Variants===<br />
FM-Towns games add the following sub-opcodes (these are not confirmed nor implemented in ScummVM):<br />
{| border="1" cellpadding="2" width=100%<br />
|- style="background:whitesmoke"<br />
|Opcode||Meaning||Description<br />
|-<br />
|$20||Unknown||Does nothing, not used in-game.<br />
|-<br />
|$21||Unknown||Does nothing, not used in-game.<br />
|-<br />
|$23||CD Volume||Possibly changes the volume of CD tracks (Loom CD). Takes 1 byte.<br />
|-<br />
|$24||Sound Volume||Sets the loudness of a sound resource. Used in Indy3 and Zak. Takes 2 bytes (left/right volumes?).<br />
|-<br />
|$25||Sound Pitch||Sets the pitch of a sound resource. Used in Indy3 and Zak. Takes 1 byte (pitch = "foo" - "center" semitones. Center is at $32 in the sound resource.)<br />
|}<br />
<br />
<br />
==roomOps ($33)==<br />
<br />
===Encoding===<br />
opcode sub-opcode<br />
<br />
sub-opcodes:<br />
$01 minX[p16] maxX[p16]<br />
$03 b[p16] h[p16]<br />
$04 red[p16] green[p16] blue[p16] aux index[p8]<br />
$05<br />
$06<br />
$07 scale1[p8] y1[p8] aux scale2[p8] y2[p8] aux slot[p8]<br />
$08 scale[p8] startcolour[p8] endcolour[p8]<br />
$09 loadflag[p8] loadslot[p8]<br />
$0A effect[p16]<br />
$0B redscale[p16] greenscale[p16] bluescale[p16] aux startcolour[p8] endcolour[p8]<br />
$0C redscale[p16] greenscale[p16] bluescale[p16] aux startcolour[p8] endcolour[p8]<br />
$0D resID[p8] filename[c]... $00<br />
$0E resID[p8] filename[c]... $00<br />
$0F resID[p8] aux start[p8] end[p8] aux time[p8]<br />
$10 colindex[p8] delay[p8]<br />
<br />
===Operation===<br />
{| border="1" cellpadding="2" width=100%<br />
|- style="background:whitesmoke"<br />
|Opcode||Meaning||Description<br />
|-<br />
|$01||SO_ROOM_SCROLL||Clamps the given arguments so scrolling does not extend past the width of the room or screen.<br />
|-<br />
|$03||SO_ROOM_SCREEN||Initialises a screen.<br />
|-<br />
|$04||SO_ROOM_PALETTE||Adjusts the room's palette.<br />
|-<br />
|$05||SO_ROOM_SHAKE_ON||Starts the room shaking.<br />
|-<br />
|$06||SO_ROOM_SHAKE_OFF||Ends the room shaking.<br />
|-<br />
|$07||SO_ROOM_SCALE||Sets the room's y scales? (slot is 1 greater than actual slot?)<br />
|-<br />
|$08||SO_ROOM_INTENSITY||Lightens/darkens the room's palette.<br />
|-<br />
|$09||SO_ROOM_SAVEGAME||Saves temporary state of the room/game?<br />
|-<br />
|$0A||SO_ROOM_FADE||If effect is 0, fades in the room. Otherwise, fades out with the given effect (taken from the high byte of effect).<br>1 = iris effect<br>2 = box wipe (upper-left to bottom-right)<br>3 = box wipe (upper-right to bottem-left)<br>4 = inverse box wipe.<br />
|-<br />
|$0B||SO_RGB_ROOM_INTENSITY||Lightens/darkens the room's palette, with different scales for red, green and blue.<br />
|-<br />
|$0C||SO_ROOM_SHADOW||Lightens/darkens the shadow palette, with different scales for red, green, and blue.<br />
|-<br />
|$0D||SO_SAVE_STRING||Saves a string resource to the given file?<br />
|-<br />
|$0E||SO_LOAD_STRING||Loads a string resource from a given file?<br />
|-<br />
|$0F||SO_ROOM_TRANSFORM||Manipulates palettes, strings?<br />
|-<br />
|$10||SO_CYCLE_SPEED||Starts colour cycling with delay? colIndex is between 0 and 16<br />
|}<br />
<br />
===Variants===<br />
SCUMM V3 (non-PC Engine) encodes the arguments before the sub-opcode:<br />
opcode arg1[p16] arg2[p16] sub-opcode<br />
<br />
Small header games include an extra sub-opcode, $02 (SO_ROOM_COLOR), which adjusts the room's palette:<br />
opcode $02 colour[p16] index[p16]<br />
... or for V3 games ...<br />
opcode colour[p16] index[p16] $02<br />
<br />
In small header games, sub-opcode $04 (SO_ROOM_PALETTE) affects the shadow palette, and only accepts two arguments, a "room colour slot" (palette entry? between 0 and 256) and an index:<br />
opcode $04 colour[p16] index[p16]<br />
... or for V3 games ...<br />
opcode colour[p16] index[p16] $04<br />
<br />
In FM-Towns games, sub-opcode $0A performs a different function and has its own sub-opcodes (some unknown and all not yet implemented in ScummVM):<br />
opcode $0A sub-opcode<br />
<br />
{| border="1" cellpadding="2" width=100%<br />
|- style="background:whitesmoke"<br />
|Opcode||Meaning||Description<br />
|-<br />
|$08||||compose kMainVirtScreen over a screen buffer<br />
|-<br />
|$09||||call 0x110:0x20 _ax=0x601 _edx=2<br />
|-<br />
|$0A||||call 0x110:0x20 _ax=0x601 _edx=3<br />
|-<br />
|$0B||||clear screen 0x1C:0x45000 sizeof(640 * 320)<br />
|-<br />
|$0C||||call 0x110:0x20 _ax=0x601 _edx=0<br />
|-<br />
|$0D||||call 0x110:0x20 _ax=0x601 _edx=1<br />
|-<br />
|$10||||enable clearing of a screen buffer in drawBitmap()<br />
|-<br />
|$11||||disable clearing of a screen buffer in drawBitmap()<br />
|-<br />
|$12||||clear a screen buffer<br />
|-<br />
|$13||||enable palette operations (palManipulate(), cyclePalette() etc.)<br />
|-<br />
|$14||||disable palette operations<br />
|-<br />
|$15||||disable clearing of screen 0x1C:0x5000 sizeof(640 * 320) in initScreens()<br />
|-<br />
|$16||||enable clearing of screen 0x1C:0x5000 sizeof(640 * 320) in initScreens()<br />
|-<br />
|$1E||||Unknown<br />
|}<br />
<br />
<br />
==saveLoadGame ($22) (V3-4)==<br />
This instruction is not present in SCUMM V5; its opcode is used for "getAnimCounter".<br />
<br />
===Encoding===<br />
opcode result arg1[p8]<br />
<br />
===Operation===<br />
The slot is determined by taking the lower 5 bits of arg1. The upper 3 bits determine an aux opcode, that performs an action described in the table below.<br />
<br />
{| border="1" cellpadding="2" width=100%<br />
|- style="background:whitesmoke"<br />
|Opcode||Meaning||Description<br />
|-<br />
|$00||Num. Available Slots||Returns the number of save slots available.<br />
|-<br />
|$20||Drive||In V3, returns the type of drive (0 = ???, 1 = A or B [floppy], 2 = hard drive).<br>In V4, sets the current drive (returns 1).<br />
|-<br />
|$40||Load Game||Loads a game from the given slot (returns 3 if successful, 5 otherwise).<br />
|-<br />
|$80||Save Game||Saves a game to the given slot (returns 0 if successful, 2 otherwise).<br />
|-<br />
|$C0||Test For Game||Tests if a save exists in the given slot (returns 6 if so, 7 otherwise).<br />
|}<br />
<br />
<br />
==saveLoadVars ($A7) (V3-4)==<br />
This instruction is not present in SCUMM V5; its opcode is used as a dummy.<br />
<br />
===Encoding===<br />
opcode sub-opcode<br />
<br />
sub-opcodes:<br />
$01 sub-sub-opcode... $00<br />
$02 sub-sub-opcode... $00<br />
<br />
$01 (save) sub-sub-opcodes:<br />
$01 resultA resultB<br />
$02 arg1[p8] arg2[p8]<br />
$03 filename[c]... $00<br />
$04<br />
$1F<br />
<br />
$02 (load) sub-sub-opcodes:<br />
$01 resultA resultB<br />
$02 arg1[p8] arg2[p8]<br />
$03 filename[c]... $00<br />
$04<br />
$1F<br />
<br />
===Operation===<br />
{| border="1" cellpadding="2" width=100%<br />
|- style="background:whitesmoke"<br />
|Opcode||Meaning||Description<br />
|-<br />
|$01||SO_SAVE_VARS||Saves variables (for saving games?)<br />
|-<br />
|$02?||SO_RESTORE_VERBS||Loads variables (for saving games?)<br>(I have not verified that restore vars is $02, as the ScummVM code only compares to $01.)<br />
|}<br />
<br />
{| border="1" cellpadding="2" width=100%<br />
|- style="background:whitesmoke"<br />
|Opcode||Meaning||Description<br />
|-<br />
|$01||Write Vars||Writes a range of variables.<br />
|-<br />
|$02||Write Strings||Writes a range of string variables.<br />
|-<br />
|$03||Open File||Opens a file for writing.<br />
|-<br />
|$04||Dummy||Does nothing.<br />
|-<br />
|$1F||Close File||Closes the last opened file.<br />
|}<br />
<br />
{| border="1" cellpadding="2" width=100%<br />
|- style="background:whitesmoke"<br />
|Opcode||Meaning||Description<br />
|-<br />
|$01||Read Vars||Reads a range of variables.<br />
|-<br />
|$02||Read Strings||Reads a range of string variables.<br />
|-<br />
|$03||Open File||Opens a file for reading.<br />
|-<br />
|$04||Dummy||Does nothing.<br />
|-<br />
|$1F||Close File||Closes the last opened file.<br />
|}<br />
<br />
<br />
==saveRestoreVerbs ($AB)==<br />
<br />
===Encoding=== <br />
opcode sub-opcode<br />
<br />
sub-opcodes: <br />
$01 start[p8] end[p8] mode[p8]<br />
$02 start[p8] end[p8] mode[p8]<br />
$03 start[p8] end[p8] mode[p8]<br />
<br />
===Operation===<br />
{| border="1" cellpadding="2" width=100%<br />
|- style="background:whitesmoke"<br />
|Opcode||Meaning||Description<br />
|-<br />
|$01||SO_SAVE_VERBS||For all verbs between start and end, sets the "saveid" to mode. <br />
|-<br />
|$02||SO_RESTORE_VERBS||For all verbs between start and end and matching mode, kills any existing verb, sets the saveid to 0 and generally inits the verb.<br />
|-<br />
|$03||SO_DELETE_VERBS||For all verbs between start and end and matching mode, kills any existing verb.<br />
|}<br />
<br />
<br />
==setCameraAt ($32)==<br />
<br />
===Encoding===<br />
opcode x[p16]<br />
<br />
===Operation===<br />
Sets the camera's x position.<br />
<br />
<br />
==setObjectName ($54)==<br />
<br />
===Encoding===<br />
opcode object[p16] name[c]... $00<br />
<br />
===Operation===<br />
Sets the given object's name.<br />
<br />
<br />
==setOwnerOf ($29)==<br />
<br />
===Encoding===<br />
opcode object[p16] owner[p8]<br />
<br />
===Operation===<br />
Sets the owner of the object.<br />
<br />
<br />
==setState ($07)==<br />
<br />
===Encoding===<br />
opcode object[p16] state[p8]<br />
<br />
===Operation===<br />
Sets the state of the object.<br />
<br />
<br />
==setVarRange ($26)==<br />
non-standard encoding<br />
<br />
===Encoding===<br />
opcode result number[8] values[8]...<br />
or<br />
opcode result number[8] values[16]...<br />
<br />
===Operation===<br />
for (i = 0; i < number; i++) {<br />
&#42;result + i := values[i];<br />
}<br />
<br />
This sets a number of variables to the given parameters. The starting variable is given as "result", and the number of variables to modify is given as "number". This is followed by the same number of values, which will be put into the variable locations. The values are constants, and can be either 16-bit, if the highest bit of the opcode is set, i.e. $A6; or 8-bit, if the highest bit of the opcode is not set, i.e. $26. Note that all values are affected by the opcode's high bit; you can't mix 8 and 16-bit values.<br />
<br />
descumm example:<br />
setVarRange(Var[178],9,[0,0,0,0,0,0,0,0,0]);<br />
<br />
This sets variables 178 to 186 (inclusive) to 0.<br />
<br />
<br />
==soundKludge ($4C)==<br />
<br />
===Encoding===<br />
opcode items[v16]...<br />
<br />
===Operation===<br />
If the first item is -1, the existing sound queue is processed. Otherwise, the list of items is added to the queue.<br />
<br />
===Variants===<br />
In SCUMM V3 (small header) games, this opcode is used for the WaitForSentence instruction.<br />
<br />
<br />
==startMusic ($02)==<br />
<br />
===Encoding===<br />
opcode music[p8]<br />
<br />
===Operation===<br />
Adds the music in to the queue to be played.<br />
<br />
===Variants===<br />
In FM-Towns (SCUMM V3) games, this instruction performs different functions (some kind of Audio CD status query function; some partially implemented in ScummVM):<br />
opcode result sub-opcode<br />
<br />
{| border="1" cellpadding="2" width=100%<br />
|- style="background:whitesmoke"<br />
|Opcode||Meaning||Description<br />
|-<br />
|$00||Is Playing||Returns true if a CD audio track is currently playing.<br />
|-<br />
|$FC||Unpause CD||Unpauses the CD audio track.<br />
|-<br />
|$FD||Pause CD||Pauses the CD audio track.<br />
|-<br />
|$FE||Get CD Sound||Returns the current CD sound.<br />
|-<br />
|$FF||CD Volume||Might return the the current CD volume in FM-Towns Loom.<br />
|-<br />
|other||Track Length||Returns the track length in seconds.<br />
|}<br />
<br />
<br />
==startObject ($37)==<br />
<br />
===Encoding===<br />
opcode object[p16] script[p8] args[v16]...<br />
<br />
===Operation===<br />
Starts the object's script (OBCD blocks), passing the given arguments.<br />
<br />
<br />
==startScript ($0A)==<br />
one parameter plus varargs, extra encoding in opcode<br />
<br />
===Encoding===<br />
opcode script[p8] args[v16]...<br />
<br />
===Operation===<br />
Spawns a new thread running the code in script script. The new script has its local variables initialised to the list args. Uninitialised variables have undefined values.<br />
<br />
The opcode carries extra information: <br />
<br />
{| border="1" cellpadding="2" width=10%<br />
|- style="background:whitesmoke"<br />
|7||6||5||4 0<br />
|-<br />
|P1||R||F||$0A<br />
|}<br />
<br />
P1 = standard parameter bit<br><br />
R = indicates that the script is recursive<br><br />
F = indicates that the script is freeze resistant (a call to freezeScripts will skip this script, unless the "force freeze" bit of the freezeScripts opcode is set).<br />
<br />
<br />
==startSound ($1C)==<br />
<br />
===Encoding===<br />
opcode sound[p8]<br />
<br />
===Operation===<br />
Adds the given sound to the sound queue to be played.<br />
<br />
<br />
==stopMusic ($20)==<br />
<br />
===Encoding===<br />
opcode<br />
<br />
===Operation===<br />
Stops all sounds.<br />
<br />
<br />
==stopObjectCode ($A0 or $00)==<br />
<br />
===Encoding===<br />
opcode<br />
<br />
===Operation===<br />
Marks the calling script as dead, to be later pruned from the thread pool. Cleans up residual arrays. Should always be the last instruction in a script.<br />
<br />
$A0 is present in LSCR and SCRP files... when does $00 occur?<br />
<br />
<br />
==stopObjectScript ($6E)==<br />
<br />
===Encoding===<br />
opcode script[p16]<br />
<br />
===Operation===<br />
Marks the given object script as dead, to be later pruned from the thread pool. Cleans up residual arrays.<br />
<br />
<br />
==stopScript ($62)==<br />
<br />
===Encoding===<br />
opcode script[p8]<br />
<br />
===Operation===<br />
Marks the given script as dead, to be later pruned from the thread pool. Cleans up residual arrays.<br />
<br />
<br />
==stopSound ($3C)==<br />
<br />
===Encoding===<br />
opcode sound[p8]<br />
<br />
===Operation===<br />
Stops the given sound.<br />
<br />
<br />
==stringOps ($27)==<br />
parameters depend on sub-opcode<br />
<br />
===Encoding===<br />
opcode sub-opcode<br />
<br />
sub-opcodes:<br />
$01 stringID[p8] string[c]... $00<br />
$02 destID[p8] srcID[p8]<br />
$03 stringID[p8] index[p8] char[c]<br />
$04 result stringID[p8] index[p8]<br />
$05 stringID[p8] size[p8]<br />
<br />
===Operation===<br />
Miscellaneous actions on strings (Arrays, referred to by resource number).<br />
<br />
{| border="1" cellpadding="2" width=100%<br />
|- style="background:whitesmoke"<br />
|Opcode||Meaning||Description<br />
|-<br />
|$01||Load String||Loads the inline null-terminated string into the resource slot given by stringID.<br />
|-<br />
|$02||Copy String||Creates a duplicate of the string at resource slot srcID into destID. The old string at destID is lost.<br />
|-<br />
|$03||Write Character||Writes char at the given index (offset) of the string resource located at slot stringID. Out of bounds accesses cause undefined behaviour.<br />
|-<br />
|$04||Read Character||Reads a byte (character) at the given index (offset) of the string resource located at slot stringID, and writes it to result. Out of bounds accesses cause undefined behaviour.<br />
|-<br />
|$05||New String||Allocates or frees a string (Array), located at resource slot stringID. The string is initialised to size; if size is zero, the string is freed.<br />
|}<br />
<br />
<br />
==subtract ($3A)==<br />
<br />
===Encoding===<br />
opcode result value[p16]<br />
<br />
===Operation===<br />
result := result - value<br />
<br />
The variable pointed to by result is read, value is subtracted from it, and the result written back.<br />
<br />
<br />
==systemOps ($98)==<br />
<br />
===Encoding===<br />
opcode sub-opcode<br />
<br />
sub-opcodes:<br />
$01<br />
$02<br />
$03<br />
<br />
===Operation===<br />
{| border="1" cellpadding="2" width=100%<br />
|- style="background:whitesmoke"<br />
|Opcode||Meaning||Description<br />
|-<br />
|$01||SO_RESTART||Restarts the game.<br />
|-<br />
|$02||SO_PAUSE||Pauses/unpauses the game.<br />
|-<br />
|$03||SO_QUIT||Quits the game.<br />
|}<br />
<br />
<br />
==verbOps ($7A)==<br />
<br />
===Encoding===<br />
opcode verbID[p8] sub-opcode... $FF<br />
<br />
sub-opcodes:<br />
$01 object[p16]<br />
$02 name[c]... $00<br />
$03 colour[p8]<br />
$04 hicolour[p8]<br />
$05 left[p16] top[p16]<br />
$06<br />
$07<br />
$08<br />
$09<br />
$10 colour[p8]<br />
$11<br />
$12 key[p8]<br />
$13<br />
$14 stringID[p16]<br />
$16 object[p16] room[p8]<br />
$17 colour[p8]<br />
<br />
===Operation===<br />
{| border="1" cellpadding="2" width=100%<br />
|- style="background:whitesmoke"<br />
|Opcode||Meaning||Description<br />
|-<br />
|$01||SO_VERB_IMAGE||Assigns an object (image) to a verb.<br />
|-<br />
|$02||SO_VERB_NAME||Assigns the in-line name to the verb slot.<br />
|-<br />
|$03||SO_VERB_COLOR||Sets the colour of the verb.<br />
|-<br />
|$04||SO_VERB_HICOLOR||Sets the highlight colour of the verb.<br />
|-<br />
|$05||SO_VERB_AT||Sets the verb's top-left co-ordinates.<br />
|-<br />
|$06||SO_VERB_ON||Makes this verb active.<br />
|-<br />
|$07||SO_VERB_OFF||Makes this verb inactive.<br />
|-<br />
|$08||SO_VERB_DELETE||Kills this verb.<br />
|-<br />
|$09||SO_VERB_NEW||Creates a verb in the slot for the given verbID. If the slot is 0 (verb doesn't already exist), will add it to the next unusued slot; if this exceeds the global maximum number of verbs an error will be raised.<br />
|-<br />
|$10||SO_VERB_DIMCOLOR||Sets the dim colour of the verb.<br />
|-<br />
|$11||SO_VERB_DIM||Dims this verb.<br />
|-<br />
|$12||SO_VERB_KEY||Sets the key code (maybe ASCII char?) associated with this verb.<br />
|-<br />
|$13||SO_VERB_CENTER||Centres the verb?<br />
|-<br />
|$14||SO_VERB_NAME_STR||Loads the given string resource into the verb's slot. If either the string resource or verb slot is not found (0), the verb resource is nuked.<br />
|-<br />
|$16||Assign Object||Assigns an object from the given room to the verb (if the object's image index is not already assigned to the given object).<br />
|-<br />
|$17||Set Back Colour||Sets the background colour of the verb?<br />
|}<br />
<br />
<br />
==wait ($AE)==<br />
<br />
===Encoding===<br />
opcode sub-opcode<br />
<br />
sub-opcodes:<br />
$01 actor[p8]<br />
$02 <br />
$03<br />
$04<br />
<br />
===Operation===<br />
{| border="1" cellpadding="2" width=100%<br />
|- style="background:whitesmoke"<br />
|Opcode||Meaning||Description<br />
|-<br />
|$01||SO_WAIT_FOR_ACTOR||If the given actor is moving, breaks and resumes at this instruction again.<br />
|-<br />
|$02||SO_WAIT_FOR_MESSAGE||If the global variable VAR_HAVE_MSG (Var[3]) is not zero, breaks and resumes at this instruction again.<br />
|-<br />
|$03||SO_WAIT_FOR_CAMERA||If the camera has not reached its destination x position, breaks and resumes at this instruction again.<br />
|-<br />
|$04||SO_WAIT_FOR_SENTENCE||If there is a sentence present?, breaks and resumes at this instruction again<br />
|}<br />
<br />
===Variants===<br />
In Indy3 (non-Macintosh), this opcode only acts as SO_WAIT_FOR_MESSAGE and omits the sub-opcode.<br />
opcode<br />
<br />
<br />
==walkActorTo ($1E)==<br />
<br />
===Encoding===<br />
opcode actor[p8] x[p16] y[p16]<br />
<br />
===Operation===<br />
Sets the actor to begin walking to the given position.<br />
<br />
<br />
==walkActorToActor ($0D)==<br />
<br />
===Encoding===<br />
opcode walker[p8] walkee[p8] distance[8]<br />
<br />
===Operation===<br />
Walks walker towards walkee's position by the given distance. Walker and walkee are both actors.<br />
<br />
<br />
==walkActorToObject ($36)==<br />
<br />
===Encoding===<br />
opcode actor[p8] object[p16]<br />
<br />
===Operation===<br />
Sets the actor to begin walking to the given object's position.<br />
<br />
=Variables=<br />
<br />
A number of variables are reserved for use by the SPUTM/SCUMM engine. Here is a list of known variables and their corresponding numbers, taken from the ScummVM source code.<br />
<br />
VAR_RESULT = 0; // descumm claims var 0 is the result var (for expressions)<br />
VAR_KEYPRESS = 0; // script_v5_.cpp claims var 0 is for keypresses...<br />
VAR_EGO = 1;<br />
VAR_CAMERA_POS_X = 2;<br />
VAR_HAVE_MSG = 3;<br />
VAR_ROOM = 4;<br />
VAR_OVERRIDE = 5;<br />
VAR_MACHINE_SPEED = 6;<br />
VAR_ME = 7;<br />
VAR_NUM_ACTOR = 8;<br />
VAR_CURRENT_LIGHTS = 9;<br />
VAR_CURRENTDRIVE = 10;<br />
VAR_TMR_1 = 11;<br />
VAR_TMR_2 = 12;<br />
VAR_TMR_3 = 13;<br />
VAR_MUSIC_TIMER = 14;<br />
VAR_ACTOR_RANGE_MIN = 15;<br />
VAR_ACTOR_RANGE_MAX = 16;<br />
VAR_CAMERA_MIN_X = 17;<br />
VAR_CAMERA_MAX_X = 18;<br />
VAR_TIMER_NEXT = 19;<br />
VAR_VIRT_MOUSE_X = 20;<br />
VAR_VIRT_MOUSE_Y = 21;<br />
VAR_ROOM_RESOURCE = 22;<br />
VAR_LAST_SOUND = 23;<br />
VAR_CUTSCENEEXIT_KEY = 24;<br />
VAR_TALK_ACTOR = 25;<br />
VAR_CAMERA_FAST_X = 26;<br />
VAR_SCROLL_SCRIPT = 27;<br />
VAR_ENTRY_SCRIPT = 28;<br />
VAR_ENTRY_SCRIPT2 = 29;<br />
VAR_EXIT_SCRIPT = 30;<br />
VAR_EXIT_SCRIPT2 = 31;<br />
VAR_VERB_SCRIPT = 32;<br />
VAR_SENTENCE_SCRIPT = 33;<br />
VAR_INVENTORY_SCRIPT = 34;<br />
VAR_CUTSCENE_START_SCRIPT = 35;<br />
VAR_CUTSCENE_END_SCRIPT = 36;<br />
VAR_CHARINC = 37;<br />
VAR_WALKTO_OBJ = 38;<br />
VAR_DEBUGMODE = 39;<br />
VAR_HEAPSPACE = 40;<br />
VAR_RESTART_KEY = 42;<br />
VAR_PAUSE_KEY = 43;<br />
VAR_MOUSE_X = 44;<br />
VAR_MOUSE_Y = 45;<br />
VAR_TIMER = 46;<br />
VAR_TIMER_TOTAL = 47;<br />
VAR_SOUNDCARD = 48;<br />
VAR_VIDEOMODE = 49;<br />
VAR_MAINMENU_KEY = 50;<br />
VAR_FIXEDDISK = 51;<br />
VAR_CURSORSTATE = 52;<br />
VAR_USERPUT = 53;<br />
VAR_V5_TALK_STRING_Y = 54;<br />
VAR_SOUNDRESULT = 56;<br />
VAR_TALKSTOP_KEY = 57;<br />
VAR_FADE_DELAY = 59;<br />
VAR_NOSUBTITLES = 60;<br />
VAR_SOUNDPARAM = 64;<br />
VAR_SOUNDPARAM2 = 65;<br />
VAR_SOUNDPARAM3 = 66;<br />
VAR_INPUTMODE = 67; // 1 is keyboard, 2 is joystick, 3 is mouse<br />
VAR_MEMORY_PERFORMANCE = 68;<br />
VAR_VIDEO_PERFORMANCE = 69;<br />
VAR_ROOM_FLAG = 70;<br />
VAR_GAME_LOADED = 71;<br />
VAR_NEW_ROOM = 72;<br />
<br />
<br />
=Table of Parameters=<br />
Please see the wiki page [[SCUMM/V5_opcodes/Table]] for a concise rendition of the above information (with a few omissions dues to the complexity of the instructions).</div>Jestar jokinhttps://wiki.scummvm.org/index.php?title=SCUMM/V5_opcodes&diff=10995SCUMM/V5 opcodes2009-04-21T03:07:41Z<p>Jestar jokin: Added some V3-4 specific info based on recent changes to script_v5.cpp incl. saveLoadVars and saveLoadGame, also general additions.</p>
<hr />
<div>=SCUMM V5 opcodes=<br />
The following conventions are used in the encoding descriptions.<br />
<br />
{| border="1" cellpadding="2" width=100%<br />
|- style="background:whitesmoke"<br />
|Term||Description<br />
|-<br />
|opcode||The instruction's opcode, with the appropriate bits set according to the parameters.<br />
|-<br />
|aux||An aux opcode that stores parameter bits and no other information. (the base aux opcode seems to always be $01)<br />
|-<br />
|sub-opcode||An aux opcode that indicates a specific function to perform (e.g. the "wait" instruction has sub-opcodes to "wait for message", "wait for actor" etc), as well as storing parameter bits if necessary.<br />
|-<br />
|result||A result pointer. (A standard word pointer, always a LE word.)<br />
|-<br />
|var||A variable pointer. Same as above, but is not written to. Because this is always a variable, the opcode is not affected like it would be with a normal parameter (described below).<br />
|-<br />
|value[8]||An 8-bit constant (a byte).<br />
|-<br />
|value[16]||A 16-bit constant (a word LE).<br />
|-<br />
|value[p8]||An 8-bit parameter. This may be encoded as a word LE if it's a pointer, or a byte if it's a constant.<br />
|-<br />
|value[p16]||A 16-bit parameter. This is always encoded as a word LE, and may be a pointer or constant.<br />
|-<br />
|value[v16]||A variable number of word LE parameters. These are encoded as a sequence of aux[8] param[p16]; param; aux contains the parameter bit to describe param (and is always $01, ignoring the parameter bits). A byte of $FF terminates the sequence. (actually always shown as "value[v16]...")<br />
|-<br />
|value[o]||The offset word for parameter value. This is only encoded if needed, but always at the position indicated. If not specified, the offset word occurs immediately after the parameter.<br />
|-<br />
|value[c]||An ASCII character. Because some instructions use null-terminated strings and some use $FF, the exact format of a string is described in the instruction. Almost always appears as "value[c]..."<br />
|-<br />
|term...||One or more terms.<br />
|}<br />
<br />
Of course, due to the non-orthogonality of the opcodes, there are lots of exceptions.<br />
<br />
<br />
==actorFollowCamera ($52)==<br />
<br />
===Encoding===<br />
opcode actor[p8]<br />
<br />
===Operation===<br />
Sets the camera to follow the given actor?<br />
<br />
<br />
==actorFromPos ($15)==<br />
<br />
===Encoding===<br />
opcode result x[p16] y[p16]<br />
<br />
===Operation===<br />
Returns the actor located at the given co-ordinates.<br />
<br />
<br />
==actorOps ($13)==<br />
parameters depend on auxiliary opcode; terminated by $FF<br />
<br />
===Encoding===<br />
opcode actor[p8] sub-opcode... $FF<br />
<br />
sub-opcodes:<br />
$00 arg1[p8]<br />
$01 costume[p8]<br />
$02 xspeed[p8] yspeed[p8]<br />
$03 sound[p8]<br />
$04 walkframe[p8]<br />
$05 starttalk[p8] endtalk[p8]<br />
$06 standframe[p8]<br />
$07 arg1[p8] arg2[p8] arg3[p8]<br />
$08<br />
$09 elevation[p16]<br />
$0A<br />
$0B index[p8] value[p8]<br />
$0C colour[p8]<br />
$0D name[c]... $00<br />
$0E initframe[p8]<br />
$10 width[p8]<br />
$11 xscale[p8] yscale[p8]<br />
$12<br />
$13 zplane[p8]<br />
$14<br />
$15 animspeed[p8]<br />
$16 mode[p8]<br />
$17 shadow[p8]<br />
<br />
===Operation===<br />
Miscellaneous actions on actors.<br />
<br />
{| border="1" cellpadding="2" width=100%<br />
|- style="background:whitesmoke"<br />
|Opcode||Meaning||Description<br />
|-<br />
|$00||dummy||A dummy case, does nothing (in ScummVM).<br />
|-<br />
|$01||SO_COSTUME||Sets the actor's costume.<br />
|-<br />
|$02||SO_STEP_DIST||Sets the actor's walking speed for x and y.<br />
|-<br />
|$03||SO_SOUND||Associates a sound with the actor (footsteps?)<br />
|-<br />
|$04||SO_WALK_ANIMATION||Sets the current frame of the walking animation.<br />
|-<br />
|$05||SO_TALK_ANIMATION||Sets the start and stop frames of the talking animation.<br />
|-<br />
|$06||SO_STAND_ANIMATION||Sets the current frame of the standing animation.<br />
|-<br />
|$07||SO_ANIMATION||Unknown; seems to be unused in ScummVM.<br />
|-<br />
|$08||SO_DEFAULT||Initializes actor.<br />
|-<br />
|$09||SO_ELEVATION||Sets the actor's elevation to the given value.<br />
|-<br />
|$0A||SO_ANIMATION_DEFAULT||Initializes the actor's animation frames.<br>Init frame = 1<br>Walk frame = 2<br>Stand frame = 3<br>Talk start frame = 4<br>Talk stop frame = 5<br />
|-<br />
|$0B||SO_PALETTE||Sets the colour at the given index to a new value (another entry in the colour lookup table/CLUT). Index must be between 0 and 31 (the number of colours in a costume).<br />
|-<br />
|$0C||SO_TALK_COLOR||Sets the actor's talk colour.<br />
|-<br />
|$0D||SO_ACTOR_NAME||Sets the actor's name to the given null-terminated string.<br />
|-<br />
|$0E||SO_INIT_ANIMATION||Sets the current frame of the initial animation.<br />
|-<br />
|$10||SO_ACTOR_WIDTH||Sets the actor's width.<br />
|-<br />
|$11||SO_ACTOR_SCALE||Sets the actor's X and Y scales.<br />
|-<br />
|$12||SO_NEVER_ZCLIP||Turns off all Z-clipping for the actor.<br />
|-<br />
|$13||SO_ALWAYS_ZCLIP||Forces the actor's Z-clipping for the given Z-plane?<br />
|-<br />
|$14||SO_IGNORE_BOXES||Ignores boxes, turns off Z-clipping, and puts actor somewhere if the actor is in the current room?<br />
|-<br />
|$15||SO_FOLLOW_BOXES||Follows boxes, turns off Z-clipping, and puts actor somewhere if the actor is in the current room?<br />
|-<br />
|$16||SO_ANIMATION_SPEED||Sets the animatino speed<br />
|-<br />
|$17||SO_SHADOW||Sets the shadow mode.<br />
|}<br />
<br />
===Variants===<br />
In SCUMM V4, sub-opcode $11 (SO_ACTOR_SCALE) only takes one parameter, so X and Y scaling is done at a 1:1 ratio.<br />
<br />
<br />
==actorSetClass ($5D)==<br />
<br />
===Encoding===<br />
opcode object[p16] classes[v16]...<br />
<br />
===Operation===<br />
Makes object inherit from all of the given classes. A class of "0" will clear all of the object's existing class data.<br />
<br />
<br />
==add ($5A)==<br />
<br />
===Encoding===<br />
opcode result value[p16]<br />
<br />
===Operation===<br />
result := result + value<br />
<br />
The variable pointed to by result is read, value is added to it, and the result written back.<br />
<br />
<br />
==and ($17)==<br />
one parameter, uses result<br />
<br />
===Encoding===<br />
opcode result value[p16]<br />
<br />
===Operation===<br />
result := result and value<br />
<br />
The variable pointed to by result is read, logically ANDed with value, and the result written back.<br />
<br />
<br />
==animateActor ($11)==<br />
<br />
===Encoding===<br />
opcode actor[p8] anim[p8]<br />
<br />
===Operation===<br />
Starts the given animation for the given actor.<br />
<br />
<br />
==breakHere ($80)==<br />
no parameters<br />
<br />
===Encoding===<br />
opcode<br />
<br />
===Operation===<br />
Deschedules the currently running thread. Execution continues at the next instruction when the thread's next timeslot comes around.<br />
<br />
<br />
==chainScript ($42)==<br />
one parameter plus varargs<br />
<br />
===Encoding===<br />
opcode script[p8] args[v16]...<br />
<br />
===Operation===<br />
Replaces the currently running script with another one. The current script is terminated immediately and the new script (determined by the given script ID), is executed in the same thread. The new script has its local variables initialised to the list args. Uninitialised variables have undefined values.<br />
<br />
<br />
==cursorCommand ($2C)==<br />
parameters depend on auxiliary opcode<br />
<br />
===Encoding===<br />
opcode sub-opcode<br />
<br />
sub-opcode can be any of the following:<br />
$01<br />
... $01 through $08 take the same arguments ...<br />
$08<br />
$0A cursornum[p8] charletter[p8]<br />
$0B index[p8] x[p8] y[p8]<br />
$0C cursor[p8]<br />
$0D charset[p8]<br />
$0E colours[v16]...<br />
<br />
===Operation===<br />
Miscellaneous actions on cursors & charsets.<br />
<br />
{| border="1" cellpadding="2" width=100%<br />
|- style="background:whitesmoke"<br />
|Opcode||Meaning||Description<br />
|-<br />
|$01||SO_CURSOR_ON||Turns the cursor on.<br />
|-<br />
|$02||SO_CURSOR_OFF||Turns the cursor off.<br />
|-<br />
|$03||SO_USERPUT_ON||Enables user input.<br />
|-<br />
|$04||SO_USERPUT_OFF||Disables user input.<br />
|-<br />
|$05||SO_CURSOR_SOFT_ON||Increments the cursor's state?<br />
|-<br />
|$06||SO_CURSOR_SOFT_OFF||Decrements the cursor's state?<br />
|-<br />
|$07||SO_USERPUT_SOFT_ON||Increments "user input" counter (when greater than 0, user input is enabled).<br />
|-<br />
|$08||SO_USERPUT_SOFT_OFF||Decrements "user input" counter (when 0 or less, user input is disabled).<br />
|-<br />
|$0A||SO_CURSOR_IMAGE||Changes the cursor image to a new one, based on image in a character set. Only used in Loom.<br />
|-<br />
|$0B||SO_CURSOR_HOTSPOT||Changes the hotspot of a cursor. Only used in Loom.<br />
|-<br />
|$0C||SO_CURSOR_SET||Changes the current cursor. Must be between 0 and 3 inclusive.<br />
|-<br />
|$0D||SO_CHARSET_SET||Initializes the given character set.<br />
|-<br />
|$0E||SO_CHARSET_COLORS||Initializes the character set data & colours to the given arguments? Must have 16 arguments?<br />
|}<br />
<br />
===Variants===<br />
In SCUMM V3, sub-opcode $0E performs a different function, to load/initialize a character set.<br />
<br />
opcode $0E arg1[p8] arg2[p8]<br />
<br />
<br />
==cutScene ($40)==<br />
<br />
===Encoding===<br />
opcode args[v16]...<br />
<br />
===Operation===<br />
??? If required, runs a script passing the given arguments. Cutscene data given by the first argument?<br />
<br />
<br />
==debug ($6B)==<br />
one parameter, no result<br />
<br />
===Encoding===<br />
opcode param[p16]<br />
<br />
===Operation===<br />
Passes the parameter to the interpreter's debugger. What this does is entirely platform-specific (and may do nothing).<br />
<br />
<br />
==decrement ($C6)==<br />
no parameters, uses result<br />
<br />
===Encoding===<br />
opcode result<br />
<br />
===Operation===<br />
result := result - 1<br />
<br />
Reads the variable pointed to by result, decrements it, and writes it back. <br />
<br />
<br />
==delay ($2E)==<br />
one constant parameter<br />
<br />
===Encoding===<br />
opcode param[24]<br />
<br />
===Operation===<br />
Suspends the current thread for the appropriate number of 1/60ths of a second. Yes, that really is a 24-bit LE constant.<br />
<br />
<br />
==delayVariable ($2B)==<br />
one constant parameter<br />
<br />
===Encoding===<br />
opcode var<br />
<br />
===Operation===<br />
var is dereferenced and the current thread suspended for that number of 1/60ths of a second.<br />
<br />
<br />
==divide ($5B)==<br />
one parameter, uses result<br />
<br />
===Encoding===<br />
opcode result value[p16]<br />
<br />
===Operation===<br />
result := result / value<br />
<br />
The variable pointed to by result is read, divided by value, and the result written back. If value is zero, the result is undefined (and the interpeter may halt with an error). <br />
<br />
<br />
==doSentence ($19)==<br />
<br />
===Encoding===<br />
opcode verb[p8] objectA[p16] objectB[p16]<br />
<br />
===Operation===<br />
Performs a verb sentence action, e.g. "Use monkey on hydrant". If verb is $FE, the current sentence script is stopped, status cleared etc.<br />
<br />
<br />
==drawBox ($3F)==<br />
two parameters, does not use result, supplementary opcode byte with three more subsequent parameters<br />
<br />
===Encoding===<br />
opcode left[p16] top[p16] auxopcode[8] right[p16] bottom[p16] colour[p8]<br />
<br />
===Operation===<br />
Draws a solid box on the backbuffer from (left, top)-(right, bottom) in the given colour.<br />
<br />
The only part of auxopcode that is relevant are the parameter bits. The rest of the opcode is ignored. <br />
<br />
<br />
==drawObject ($05)==<br />
<br />
===Encoding===<br />
opcode object[p16] sub-opcode<br />
<br />
sub-opcodes:<br />
$01 xpos[p16] ypos[p16]<br />
$02 state[p16]<br />
$1F<br />
<br />
===Operation===<br />
{| border="1" cellpadding="2" width=100%<br />
|- style="background:whitesmoke"<br />
|Opcode||Meaning||Description<br />
|-<br />
|$01||Draw At||Moves the given object to the given co-ordinates, and adds it to the drawing queue.<br />
|-<br />
|$02||Set State||Sets the state of the object, adds it to the drawing queue.<br />
|-<br />
|$1F||Draw||Does not change the object's position (or state?), still adds it to the drawing queue.<br />
|}<br />
<br />
===Variants===<br />
Small header games only support the parameters used with sub-opcode $01, e.g:<br />
opcode object[p16] xpos[p16] ypos[p16]<br />
Accordingly, they have three parameter bits, and hence more possible opcodes.<br />
<br />
<br />
==dummy ($A7)==<br />
<br />
===Encoding===<br />
opcode<br />
<br />
===Operation===<br />
V5 specific - The KIXX XL release of Monkey Island 2 (Amiga disk) used this opcode as a dummy, in order to remove copy protection and keep level selection.<br />
<br />
===Variants===<br />
In SCUMM V3 and V4, this opcode is used for the saveLoadVars instruction.<br />
<br />
<br />
==endCutScene ($C0)==<br />
<br />
===Encoding===<br />
opcode<br />
<br />
===Operation===<br />
Ends the cutscene, performing cleanup if necessary.<br />
<br />
<br />
==equalZero ($28)==<br />
jumps<br />
<br />
===Encoding===<br />
opcode var target[16]<br />
<br />
===Operation===<br />
unless (var == 0) goto target<br />
<br />
Target is a byte offset (measured from after this instruction), which will be added to the instruction pointer.<br />
<br />
<br />
==expression ($AC)==<br />
<br />
===Encoding===<br />
opcode result subopcode... $FF<br />
<br />
sub-opcodes:<br />
$01 value[p16]<br />
$02<br />
... $02 through $05 take the same arguments ...<br />
$05<br />
$06 nested-opcode<br />
<br />
===Operation===<br />
Expression mode operates on a stack. Values are pushed on, and operators are applied to the top two items on the stack.<br />
<br />
{| border="1" cellpadding="2" width=100%<br />
|- style="background:whitesmoke"<br />
|Opcode||Meaning||Description<br />
|-<br />
|$01||Value||Pushes a value onto the top of the stack.<br />
|-<br />
|$02||Add||stack[top - 1] + stack[top]<br />
|-<br />
|$03||Subtract||stack[top - 1] - stack[top]<br />
|-<br />
|$04||Multiply||stack[top - 1] * stack[top]<br />
|-<br />
|$05||Divide||stack[top - 1] / stack[top] (if stack[top] is 0 an error occurs)<br />
|-<br />
|$06||Nested Opcode||An entire instruction that returns a result, such as getActorScale. This is interpreted like a normal opcode, but the result is pushed onto the expression stack. (The opcode is passed the special "VAR_RESULT" parameter for "result")<br />
|}<br />
<br />
<br />
==faceActor ($09)==<br />
<br />
===Encoding===<br />
opcode actor[p8] object[p16]<br />
<br />
===Operation===<br />
Dereferences actor, tells actor to face object (presumably based on X/Y co-ordinates).<br />
<br />
<br />
==findInventory ($3D)==<br />
<br />
===Encoding===<br />
opcode result owner[p8] index[p8]<br />
<br />
===Operation===<br />
object := owner.inventory[index]<br />
Searches for all objects owned by owner (an actor or object), and returns the one at the given index (offset).<br />
<br />
<br />
==findObject ($35)==<br />
<br />
===Encoding===<br />
opcode result x[p8] y[p8]<br />
<br />
===Operation===<br />
Returns the first "touchable" local object at the given co-ordinates. Will not match on the bottom or right-hand edges of an object.<br />
<br />
<br />
==freezeScripts ($60)==<br />
<br />
===Encoding===<br />
opcode flag[p8]<br />
<br />
===Operation===<br />
Freezes all scripts (by setting the high bit on each script's status). If flag is >= $80, all freeze resistent scripts will also be frozen. If flag is 0, all scripts are unfrozen. Freezing effects are cumulative - i.e. if script A is frozen twice, and unfrozen once, it will still be frozen until it is unfrozen a second time. A script's frozen status is indicated by the high bit.<br />
<br />
<br />
==getActorCostume ($71)==<br />
<br />
===Encoding===<br />
opcode result actor[p8]<br />
<br />
===Operation===<br />
Returns the actor's current costume.<br />
<br />
<br />
==getActorElevation ($06)==<br />
<br />
===Encoding===<br />
opcode result actor[p8]<br />
<br />
===Operation===<br />
Returns the actor's current elevation.<br />
<br />
<br />
==getActorFacing ($63)==<br />
<br />
===Encoding===<br />
opcode result actor[p8]<br />
<br />
===Operation===<br />
Returns the current direction the actor is facing.<br />
<br />
<br />
==getActorMoving ($56)==<br />
<br />
===Encoding===<br />
opcode result actor[p8]<br />
<br />
===Operation===<br />
Returns the actor's moving status (0 or 1).<br />
<br />
<br />
==getActorRoom ($03)==<br />
<br />
===Encoding===<br />
opcode result actor[p8]<br />
<br />
===Operation===<br />
Returns the room the actor currently occupies?<br />
<br />
<br />
==getActorScale ($3B)==<br />
<br />
===Encoding===<br />
opcode result actor[p8]<br />
<br />
===Operation===<br />
Returns the actor's current scale.<br />
<br />
===Variants===<br />
In Indy3, this opcode is used for waitForActor.<br />
<br />
<br />
==getActorWalkBox ($7B)==<br />
<br />
===Encoding===<br />
opcode result actor[p8]<br />
<br />
===Operation===<br />
Returns the actor's walkbox.<br />
<br />
<br />
==getActorWidth ($6C)==<br />
<br />
===Encoding===<br />
opcode result actor[p8]<br />
<br />
===Operation===<br />
Returns the actor's width.<br />
<br />
<br />
==getActorX ($43)==<br />
<br />
===Encoding===<br />
opcode result actor[p16]<br />
<br />
===Operation===<br />
Returns the actor's current X co-ordinate.<br />
<br />
===Variants===<br />
In Indy3, actor is only one byte.<br />
opcode result actor[p8]<br />
<br />
<br />
==getActorY ($23)==<br />
<br />
===Encoding===<br />
opcode result actor[p16]<br />
<br />
===Operation===<br />
Returns the actor's current Y co-ordinate.<br />
<br />
===Variants===<br />
In Indy3, actor is only one byte.<br />
opcode result actor[p8]<br />
<br />
<br />
==getAnimCounter ($22)==<br />
<br />
===Encoding===<br />
opcode result actor[p8]<br />
<br />
===Operation===<br />
Returns the actor's animation counter.<br />
<br />
===Variants===<br />
This opcode is used for saveLoadGame in SCUMM V3.<br />
<br />
<br />
==getClosestObjActor ($66)==<br />
<br />
===Encoding===<br />
opcode result actor[p16]<br />
<br />
===Operation===<br />
Returns the object closest to the actor. Items that are more than 255 units (pixels in newer games, characters in older games) away from the actor will not be detected.<br />
<br />
<br />
==getDist ($34)==<br />
<br />
===Encoding===<br />
opcode result objA[p16] objB[p16]<br />
<br />
===Operation===<br />
Returns the distance between two actors/objects (objA and objB).<br />
<br />
<br />
==getInventoryCount ($31)==<br />
<br />
===Encoding===<br />
opcode result actor[p8]<br />
<br />
===Operation===<br />
Returns the number of items in an actor's inventory?<br />
<br />
<br />
==getObjectOwner ($10)==<br />
<br />
===Encoding===<br />
opcode result object[p16]<br />
<br />
===Operation===<br />
Returns the owner of an object.<br />
<br />
<br />
==getObjectState ($0F)==<br />
<br />
===Encoding===<br />
opcode result object[p16]<br />
<br />
===Operation===<br />
Returns the state of the object.<br />
<br />
===Variants===<br />
In small header games, the encoding becomes:<br />
opcode object[p16] state[p8] target[16]<br />
operation becomes<br />
unless (getState(object) == state) goto target<br />
<br />
<br />
==getRandomNumber ($16)==<br />
<br />
===Encoding===<br />
opcode result seed[p8]<br />
<br />
===Operation===<br />
Returns a new random number based on the given seed.<br />
<br />
<br />
==getScriptRunning ($68)==<br />
<br />
===Encoding===<br />
opcode result script[p8]<br />
<br />
===Operation===<br />
Returns 1 if the given script is running, 0 if it's not.<br />
<br />
<br />
==getStringWidth ($67)==<br />
<br />
===Encoding===<br />
opcode result strptr[p8]<br />
<br />
===Operation===<br />
Gets the length of the string pointed to by strptr (either a variable or direct byte), stores the returned value in result.<br />
<br />
<br />
==getVerbEntryPoint ($0B)==<br />
<br />
===Encoding===<br />
opcode result object[p16] verb[p16]<br />
<br />
===Operation===<br />
Returns the entry point for the response code/script for when the given verb is applied to the given object? i.e. gets the start of the script to run for the specific user interaction.<br />
<br />
<br />
==ifClassOfIs ($1D)==<br />
jumps<br />
<br />
===Encoding===<br />
opcode value[p16] args[v16]... target[16]<br />
<br />
===Operation===<br />
unless (value.class is one of [args.class]) goto target<br />
<br />
Compares the value's class with all classes given in args.<br />
<br />
Target is a byte offset (measured from after this instruction), which will be added to the instruction pointer.<br />
<br />
<br />
==ifNotState ($2F) (V3-4)==<br />
This opcode is not present in SCUMM V5.<br />
<br />
===Encoding===<br />
opcode object[p16] state[p8] target[16]<br />
<br />
===Operation===<br />
unless (stateOf(object) != state) goto target<br />
<br />
<br />
==ifState ($4F) (V3-4)==<br />
This opcode is not present in SCUMM V5.<br />
<br />
===Encoding===<br />
opcode object[p16] state[p8] target[16]<br />
<br />
===Operation===<br />
unless (stateOf(object) == state) goto target<br />
<br />
<br />
==increment ($46)==<br />
no parameters, uses result<br />
<br />
===Encoding===<br />
opcode result<br />
<br />
===Operation===<br />
result := result + 1<br />
<br />
Reads the variable pointed to by result, increments it, and writes it back. <br />
<br />
<br />
==isActorInBox ($1F)==<br />
<br />
===Encoding===<br />
opcode actor[p8] box[p8] target[16]<br />
<br />
===Operation===<br />
Unless the actor's co-ordinates are within the bounds of the given box, jump to target.<br />
<br />
Target is a byte offset (measured from after this instruction), which will be added to the instruction pointer.<br />
<br />
<br />
==isEqual ($48)==<br />
<br />
===Encoding===<br />
opcode var value[p16] target[16]<br />
<br />
===Operation===<br />
unless (value == var) goto target<br />
<br />
Target is a byte offset (measured from after this instruction), which will be added to the instruction pointer.<br />
<br />
<br />
==isGreater ($78)==<br />
<br />
===Encoding===<br />
opcode var value[p16] target[16]<br />
<br />
===Operation===<br />
unless (value > var) goto target<br />
<br />
Target is a byte offset (measured from after this instruction), which will be added to the instruction pointer.<br />
<br />
<br />
==isGreaterEqual ($04)==<br />
<br />
===Encoding===<br />
opcode var value[p16] target[16]<br />
<br />
===Operation===<br />
unless (value >= var) goto target<br />
<br />
Target is a byte offset (measured from after this instruction), which will be added to the instruction pointer.<br />
<br />
<br />
==isLess ($44)==<br />
<br />
===Encoding===<br />
opcode var value[p16] target[16]<br />
<br />
===Operation===<br />
unless (value < var) goto target<br />
<br />
Target is a byte offset (measured from after this instruction), which will be added to the instruction pointer.<br />
<br />
<br />
==isNotEqual ($08)==<br />
<br />
===Encoding===<br />
opcode var value[p16] target[16]<br />
<br />
===Operation===<br />
unless (value != var) goto target<br />
<br />
Target is a byte offset (measured from after this instruction), which will be added to the instruction pointer.<br />
<br />
<br />
==isSoundRunning ($7C)==<br />
<br />
===Encoding===<br />
opcode result sound[p8]<br />
<br />
===Operation===<br />
Returns 1 if sound is running, returns 0 if sound is not running or if the given sound is 0.<br />
<br />
<br />
==jumpRelative ($18)==<br />
jumps<br />
<br />
===Encoding===<br />
opcode target[16]<br />
<br />
===Operation===<br />
PC := PC + target<br />
<br />
The inline constant target is read as a signed word and added to the program counter after the instruction has been read. Therefore, if target is zero, the instruction will do nothing; if target is -3, an infinite loop will result. <br />
<br />
<br />
==lessOrEqual ($38)==<br />
jumps<br />
<br />
===Encoding===<br />
opcode var value[p16] target[16]<br />
<br />
===Operation===<br />
unless (value <= var) goto target<br />
<br />
Target is a byte offset (measured from after this instruction), which will be added to the instruction pointer.<br />
<br />
<br />
==lights ($70)==<br />
<br />
===Encoding===<br />
opcode arg1[p8] arg2[8] arg3[8]<br />
<br />
===Operation===<br />
If arg3 is 0, the "current lights" variable is set to arg1.<br />
If arg3 is 1, the size of the "flashlight" light is determined by arg1 and arg2, for width and height in stripes (which are equivalent to 8 pixels each; see [[SCUMM/Technical Reference/Image resources]]).<br />
<br />
<br />
==loadRoom ($72)==<br />
<br />
===Encoding===<br />
opcode room[p8]<br />
<br />
===Operation===<br />
Loads the given room into memory.<br />
<br />
<br />
==loadRoomWithEgo ($24)==<br />
<br />
===Encoding===<br />
opcode object[p16] room[p8] x[16] y[16]<br />
<br />
===Operation===<br />
Places the Ego actor in room at object's position. If x is not -1, Ego will start moving towards the given x and y co-ordinates. If object is not in the given room an error will occur.<br />
(I think...)<br />
<br />
<br />
==matrixOp ($30)==<br />
<br />
===Encoding===<br />
opcode sub-opcode<br />
<br />
sub-opcodes:<br />
$01 box[p8] val[p8]<br />
$02 box[p8] val[p8]<br />
$03 box[p8] val[p8]<br />
$04<br />
<br />
===Operation===<br />
This instruction manipulates boxes.<br />
<br />
{| border="1" cellpadding="2" width=100%<br />
|- style="background:whitesmoke"<br />
|Opcode||Meaning||Description<br />
|-<br />
|$01||setBoxFlags||Sets the box's flags to the given value.<br />
|-<br />
|$02||setBoxScale||Sets the box's scale.<br />
|-<br />
|$03||setBoxScale||Sets the box's scale to ((val - 1) OR $8000).<br />
|-<br />
|$04||createBoxMatrix||Initializes the matrix of boxes, by determining the distances and shortest paths between boxes.<br />
|}<br />
<br />
===Variants===<br />
SCUMM V3 only has the one instruction, which behaves like setBoxFlags:<br />
opcode box[p8] val[8]<br />
<br />
<br />
==move ($1A)==<br />
<br />
===Encoding===<br />
opcode result value[p16]<br />
<br />
===Operation===<br />
result := value<br />
<br />
Value is moved into result.<br />
<br />
<br />
==multiply ($1B)==<br />
<br />
===Encoding===<br />
opcode result value[p16]<br />
<br />
===Operation===<br />
result := result * value<br />
<br />
The variable pointed to by result is read, multiplied by value, and written back.<br />
<br />
<br />
==notEqualZero ($A8)==<br />
<br />
===Encoding===<br />
opcode var target[16]<br />
<br />
===Operation===<br />
unless (var != 0) goto target<br />
<br />
Target is a byte offset (measured from after this instruction), which will be added to the instruction pointer.<br />
<br />
<br />
==oldRoomEffect ($5C) (V4)==<br />
This opcode/instruction is only present in SCUMM V4.<br />
<br />
===Encoding===<br />
opcode sub-opcode<br />
<br />
sub-opcodes:<br />
$03 effect[p16]<br />
<br />
===Operation===<br />
Performs like sub-opcode SO_ROOM_FADE of the roomOps instruction (fade in if effect != 0, otherwise fade out).<br />
<br />
This information may not be correct; descumm says if the sub-opcode is 3, to "set" the effect, but if the sub-opcode is anything else to fade in with the given effect.<br />
<br />
===Variants===<br />
FM-Towns SCUMM V3 performs a different effect, not fully implemented in ScummVM. At the moment ScummVM just forces a redraw of the screen background.<br />
<br />
<br />
==or ($57)==<br />
one parameter, uses result<br />
<br />
===Encoding===<br />
opcode result value[p16]<br />
<br />
===Operation===<br />
result := result or value<br />
<br />
The variable pointed to by result is read, logically ORed with value, and the result written back.<br />
<br />
<br />
==override ($58)==<br />
<br />
===Encoding===<br />
opcode sub-opcode<br />
<br />
sub-opcodes:<br />
$00<br />
$01 $18 target[16]<br />
<br />
===Operation===<br />
If the sub-opcode is 0, marks the end of an override section.<br><br />
If the sub-opcode is not 0, marks the beginning of an override section. The instruction is immediately followed by a "jumpRelative" instruction.<br.<br />
Overrides are used by cutscenes; if a cutscene is skipped (if the user presses the ESC key), the script will jump by the given target (offset from this instruction).<br />
<br />
<br />
==panCameraTo ($12)==<br />
<br />
===Encoding===<br />
opcode x[p16]<br />
<br />
===Operation===<br />
Starts the camera panning to the given x co-ordinate.<br />
<br />
<br />
==pickupObject ($25)==<br />
<br />
===Encoding===<br />
opcode object[p16] room[p8]<br />
<br />
===Operation===<br />
Adds the given object (located in the given room) to the Ego actor's inventory.<br />
<br />
===Variants===<br />
In SCUMM V3 and V4, this opcode is used for drawObject.<br />
<br />
<br />
==pickupObjectOld ($50) (V4)==<br />
This opcode is not present in SCUMM V5.<br />
<br />
===Encoding===<br />
opcode object[p16]<br />
<br />
===Operation===<br />
Adds the given object (located in the given room) to the Ego actor's inventory. If object < 1, an error is raised. If the object is not found or the object is already in the inventory, this function ends gracefully.<br />
<br />
<br />
==print ($14)==<br />
<br />
===Encoding===<br />
opcode actor[p8] sub-opcode<br />
<br />
sub-opcodes<br />
$00 xpos[p16] ypos[p16]<br />
$01 colour[p8]<br />
$02 right[p16]<br />
$03 width[p16] height[p16]<br />
$04<br />
$06<br />
$07<br />
$08 offset[p16] delay[p16]<br />
$0F string[c]... $FF<br />
<br />
===Operation===<br />
Sets text properties and displays dialogue.<br />
<br />
{| border="1" cellpadding="2" width=100%<br />
|- style="background:whitesmoke"<br />
|Opcode||Meaning||Description<br />
|-<br />
|$00||SO_AT||Sets the position of the text that follows.<br />
|-<br />
|$01||SO_COLOR||Sets the colour of the text.<br />
|-<br />
|$02||SO_CLIPPED||Clips the text's right-hand side (for wrapping?).<br />
|-<br />
|$03||SO_ERASE||Erases characters (not used in ScummVM).<br />
|-<br />
|$04||SO_CENTER||Centres the text.<br />
|-<br />
|$06||SO_LEFT||Left-aligns the text.<br />
|-<br />
|$07||SO_OVERHEAD||Overhead-aligns the text.<br />
|-<br />
|$0F||SO_TEXTSTRING||Prints the text string that follows. Terminated by $FF.<br />
|}<br />
<br />
===Variants===<br />
In SCUMM V3, text function $06 sets the height of the text:<br />
$06 height[p16]<br />
<br />
In Loom CD (SCUMM V4), there is an additional text function $08 (SO_SAY_VOICE), which plays a portion of the CD audio track.<br />
$08 offset[p16] delay[p16]<br />
<br />
<br />
==printEgo ($D8)==<br />
<br />
===Encoding===<br />
opcode sub-opcode<br />
<br />
===Operation===<br />
Exactly the same as print, except the actor is implicitly Ego. See the entry for "print" for further explanation.<br />
<br />
<br />
==pseudoRoom ($CC)==<br />
<br />
===Encoding===<br />
opcode val[8] res[8]... $00<br />
<br />
===Operation===<br />
forall (res) {<br />
if (res >= $80) {<br />
_resourceMapper[res & $7F] := val<br />
}<br />
}<br />
<br />
What does this actually do? We may never know.<br />
<br />
It looks like res values always have the high bit set, e.g. 0x01 becomes 0x81.<br />
<br />
==putActor ($01)==<br />
<br />
===Encoding===<br />
opcode actor[p8] x[p16] y[p16]<br />
<br />
===Operation===<br />
Puts the actor at the given co-ordinates.<br />
<br />
<br />
==putActorAtObject ($0E)==<br />
<br />
===Encoding===<br />
opcode actor[p8] object[p16]<br />
<br />
===Operation===<br />
Puts the actor at the given object's position. If the object can not be found, a default position is returned (the centre of the screen in ScummVM).<br />
<br />
<br />
==putActorInRoom ($2D)==<br />
<br />
===Encoding===<br />
opcode actor[p8] room[p8]<br />
<br />
===Operation===<br />
Puts the actor in the given room.<br />
<br />
<br />
==resourceRoutines ($0C)==<br />
<br />
===Encoding===<br />
opcode sub-opcode<br />
<br />
sub-opcodes:<br />
$01 resID[p8]<br />
... $01 through $10 take the same arguments ...<br />
$10 resID[p8]<br />
$11<br />
$12 resID[p8]<br />
$13 resID[p8]<br />
$14 room[p8] object[p16]<br />
<br />
===Operation===<br />
resID is unique only within the resource type (e.g. script 11 will not conflict with sound 11).<br />
<br />
{| border="1" cellpadding="2" width=100%<br />
|- style="background:whitesmoke"<br />
|Opcode||Meaning||Description<br />
|-<br />
|$01||SO_LOAD_SCRIPT||Loads the given script into memory.<br />
|-<br />
|$02||SO_LOAD_SOUND||Loads the given sound into memory.<br />
|-<br />
|$03||SO_LOAD_COSTUME||Loads the given costume into memory.<br />
|-<br />
|$04||SO_LOAD_ROOM||Loads the given room into memory.<br />
|-<br />
|$05||SO_NUKE_SCRIPT||Obliterates the given script from memory.<br />
|-<br />
|$06||SO_NUKE_SOUND||Obliterates the given sound from memory.<br />
|-<br />
|$07||SO_NUKE_COSTUME||Obliterates the given costume from memory.<br />
|-<br />
|$08||SO_NUKE_ROOM||Obliterates the given room from memory.<br />
|-<br />
|$09||SO_LOCK_SCRIPT||Locks the given script.<br />
|-<br />
|$0A||SO_LOCK_SOUND||Locks the given sound.<br />
|-<br />
|$0B||SO_LOCK_COSTUME||Locks the given costume.<br />
|-<br />
|$0C||SO_LOCK_ROOM||Locks the given room.<br />
|-<br />
|$0D||SO_UNLOCK_SCRIPT||Unlocks the given script.<br />
|-<br />
|$0E||SO_UNLOCK_SOUND||Unlocks the given sound.<br />
|-<br />
|$0F||SO_UNLOCK_COSTUME||Unlocks the given costume.<br />
|-<br />
|$10||SO_UNLOCK_ROOM||Unlocks the given room.<br />
|-<br />
|$11||SO_CLEAR_HEAP||Clears the heap.<br />
|-<br />
|$12||SO_LOAD_CHARSET||Loads the given character set into memory.<br />
|-<br />
|$13||SO_NUKE_CHARSET||Obliterates the given character set from memory.<br />
|-<br />
|$14||SO_LOAD_OBJECT||Loads the given object from the given room resource.<br />
|}<br />
<br />
===Variants===<br />
FM-Towns games add the following sub-opcodes (these are not confirmed nor implemented in ScummVM):<br />
{| border="1" cellpadding="2" width=100%<br />
|- style="background:whitesmoke"<br />
|Opcode||Meaning||Description<br />
|-<br />
|$20||Unknown||Does nothing, not used in-game.<br />
|-<br />
|$21||Unknown||Does nothing, not used in-game.<br />
|-<br />
|$23||CD Volume||Possibly changes the volume of CD tracks (Loom CD). Takes 1 byte.<br />
|-<br />
|$24||Sound Volume||Sets the loudness of a sound resource. Used in Indy3 and Zak. Takes 2 bytes (left/right volumes?).<br />
|-<br />
|$25||Sound Pitch||Sets the pitch of a sound resource. Used in Indy3 and Zak. Takes 1 byte (pitch = "foo" - "center" semitones. Center is at $32 in the sound resource.)<br />
|}<br />
<br />
<br />
==roomOps ($33)==<br />
<br />
===Encoding===<br />
opcode sub-opcode<br />
<br />
sub-opcodes:<br />
$01 minX[p16] maxX[p16]<br />
$03 b[p16] h[p16]<br />
$04 red[p16] green[p16] blue[p16] aux index[p8]<br />
$05<br />
$06<br />
$07 scale1[p8] y1[p8] aux scale2[p8] y2[p8] aux slot[p8]<br />
$08 scale[p8] startcolour[p8] endcolour[p8]<br />
$09 loadflag[p8] loadslot[p8]<br />
$0A effect[p16]<br />
$0B redscale[p16] greenscale[p16] bluescale[p16] aux startcolour[p8] endcolour[p8]<br />
$0C redscale[p16] greenscale[p16] bluescale[p16] aux startcolour[p8] endcolour[p8]<br />
$0D resID[p8] filename[c]... $00<br />
$0E resID[p8] filename[c]... $00<br />
$0F resID[p8] aux start[p8] end[p8] aux time[p8]<br />
$10 colindex[p8] delay[p8]<br />
<br />
===Operation===<br />
{| border="1" cellpadding="2" width=100%<br />
|- style="background:whitesmoke"<br />
|Opcode||Meaning||Description<br />
|-<br />
|$01||SO_ROOM_SCROLL||Clamps the given arguments so scrolling does not extend past the width of the room or screen.<br />
|-<br />
|$03||SO_ROOM_SCREEN||Initialises a screen.<br />
|-<br />
|$04||SO_ROOM_PALETTE||Adjusts the room's palette.<br />
|-<br />
|$05||SO_ROOM_SHAKE_ON||Starts the room shaking.<br />
|-<br />
|$06||SO_ROOM_SHAKE_OFF||Ends the room shaking.<br />
|-<br />
|$07||SO_ROOM_SCALE||Sets the room's y scales? (slot is 1 greater than actual slot?)<br />
|-<br />
|$08||SO_ROOM_INTENSITY||Lightens/darkens the room's palette.<br />
|-<br />
|$09||SO_ROOM_SAVEGAME||Saves temporary state of the room/game?<br />
|-<br />
|$0A||SO_ROOM_FADE||If effect is 0, fades in the room. Otherwise, fades out with the given effect (taken from the high byte of effect).<br>1 = iris effect<br>2 = box wipe (upper-left to bottom-right)<br>3 = box wipe (upper-right to bottem-left)<br>4 = inverse box wipe.<br />
|-<br />
|$0B||SO_RGB_ROOM_INTENSITY||Lightens/darkens the room's palette, with different scales for red, green and blue.<br />
|-<br />
|$0C||SO_ROOM_SHADOW||Lightens/darkens the shadow palette, with different scales for red, green, and blue.<br />
|-<br />
|$0D||SO_SAVE_STRING||Saves a string resource to the given file?<br />
|-<br />
|$0E||SO_LOAD_STRING||Loads a string resource from a given file?<br />
|-<br />
|$0F||SO_ROOM_TRANSFORM||Manipulates palettes, strings?<br />
|-<br />
|$10||SO_CYCLE_SPEED||Starts colour cycling with delay? colIndex is between 0 and 16<br />
|}<br />
<br />
===Variants===<br />
SCUMM V3 (non-PC Engine) encodes the arguments before the sub-opcode:<br />
opcode arg1[p16] arg2[p16] sub-opcode<br />
<br />
Small header games include an extra sub-opcode, $02 (SO_ROOM_COLOR), which adjusts the room's palette:<br />
opcode $02 colour[p16] index[p16]<br />
... or for V3 games ...<br />
opcode colour[p16] index[p16] $02<br />
<br />
In small header games, sub-opcode $04 (SO_ROOM_PALETTE) affects the shadow palette, and only accepts two arguments, a "room colour slot" (palette entry? between 0 and 256) and an index:<br />
opcode $04 colour[p16] index[p16]<br />
... or for V3 games ...<br />
opcode colour[p16] index[p16] $04<br />
<br />
In FM-Towns games, sub-opcode $0A performs a different function and has its own sub-opcodes (some unknown and all not yet implemented in ScummVM):<br />
opcode $0A sub-opcode<br />
<br />
{| border="1" cellpadding="2" width=100%<br />
|- style="background:whitesmoke"<br />
|Opcode||Meaning||Description<br />
|-<br />
|$08||||compose kMainVirtScreen over a screen buffer<br />
|-<br />
|$09||||call 0x110:0x20 _ax=0x601 _edx=2<br />
|-<br />
|$0A||||call 0x110:0x20 _ax=0x601 _edx=3<br />
|-<br />
|$0B||||clear screen 0x1C:0x45000 sizeof(640 * 320)<br />
|-<br />
|$0C||||call 0x110:0x20 _ax=0x601 _edx=0<br />
|-<br />
|$0D||||call 0x110:0x20 _ax=0x601 _edx=1<br />
|-<br />
|$10||||enable clearing of a screen buffer in drawBitmap()<br />
|-<br />
|$11||||disable clearing of a screen buffer in drawBitmap()<br />
|-<br />
|$12||||clear a screen buffer<br />
|-<br />
|$13||||enable palette operations (palManipulate(), cyclePalette() etc.)<br />
|-<br />
|$14||||disable palette operations<br />
|-<br />
|$15||||disable clearing of screen 0x1C:0x5000 sizeof(640 * 320) in initScreens()<br />
|-<br />
|$16||||enable clearing of screen 0x1C:0x5000 sizeof(640 * 320) in initScreens()<br />
|-<br />
|$1E||||Unknown<br />
|}<br />
<br />
<br />
==saveLoadGame ($22) (V3-4)==<br />
This instruction is not present in SCUMM V5; its opcode is used for "getAnimCounter".<br />
<br />
===Encoding===<br />
opcode result arg1[p8]<br />
<br />
===Operation===<br />
The slot is determined by taking the lower 5 bits of arg1. The upper 3 bits determine an aux opcode, that performs an action described in the table below.<br />
<br />
{| border="1" cellpadding="2" width=100%<br />
|- style="background:whitesmoke"<br />
|Opcode||Meaning||Description<br />
|-<br />
|$00||Num. Available Slots||Returns the number of save slots available.<br />
|-<br />
|$20||Drive||In V3, returns the type of drive (0 = ???, 1 = A or B [floppy], 2 = hard drive).<br>In V4, sets the current drive (returns 1).<br />
|-<br />
|$40||Load Game||Loads a game from the given slot (returns 3 if successful, 5 otherwise).<br />
|-<br />
|$80||Save Game||Saves a game to the given slot (returns 0 if successful, 2 otherwise).<br />
|-<br />
|$C0||Test For Game||Tests if a save exists in the given slot (returns 6 if so, 7 otherwise).<br />
|}<br />
<br />
<br />
==saveLoadVars ($A7) (V3-4)==<br />
This instruction is not present in SCUMM V5; its opcode is used as a dummy.<br />
<br />
===Encoding===<br />
opcode sub-opcode<br />
<br />
sub-opcodes:<br />
$01 sub-sub-opcode... $00<br />
$02 sub-sub-opcode... $00<br />
<br />
$01 (save) sub-sub-opcodes:<br />
$01 resultA resultB<br />
$02 arg1[p8] arg2[p8]<br />
$03 filename[c]... $00<br />
$04<br />
$1F<br />
<br />
$02 (load) sub-sub-opcodes:<br />
$01 resultA resultB<br />
$02 arg1[p8] arg2[p8]<br />
$03 filename[c]... $00<br />
$04<br />
$1F<br />
<br />
===Operation===<br />
{| border="1" cellpadding="2" width=100%<br />
|- style="background:whitesmoke"<br />
|Opcode||Meaning||Description<br />
|-<br />
|$01||SO_SAVE_VARS||Saves variables (for saving games?)<br />
|-<br />
|$02?||SO_RESTORE_VERBS||Loads variables (for saving games?)<br>(I have not verified that restore vars is $02, as the ScummVM code only compares to $01.)<br />
|}<br />
<br />
{| border="1" cellpadding="2" width=100%<br />
|- style="background:whitesmoke"<br />
|Opcode||Meaning||Description<br />
|-<br />
|$01||Write Vars||Writes a range of variables.<br />
|-<br />
|$02||Write Strings||Writes a range of string variables.<br />
|-<br />
|$03||Open File||Opens a file for writing.<br />
|-<br />
|$04||Dummy||Does nothing.<br />
|-<br />
|$1F||Close File||Closes the last opened file.<br />
|}<br />
<br />
{| border="1" cellpadding="2" width=100%<br />
|- style="background:whitesmoke"<br />
|Opcode||Meaning||Description<br />
|-<br />
|$01||Read Vars||Reads a range of variables.<br />
|-<br />
|$02||Read Strings||Reads a range of string variables.<br />
|-<br />
|$03||Open File||Opens a file for reading.<br />
|-<br />
|$04||Dummy||Does nothing.<br />
|-<br />
|$1F||Close File||Closes the last opened file.<br />
|}<br />
<br />
<br />
==saveRestoreVerbs ($AB)==<br />
<br />
===Encoding=== <br />
opcode sub-opcode<br />
<br />
sub-opcodes: <br />
$01 start[p8] end[p8] mode[p8]<br />
$02 start[p8] end[p8] mode[p8]<br />
$03 start[p8] end[p8] mode[p8]<br />
<br />
===Operation===<br />
{| border="1" cellpadding="2" width=100%<br />
|- style="background:whitesmoke"<br />
|Opcode||Meaning||Description<br />
|-<br />
|$01||SO_SAVE_VERBS||For all verbs between start and end, sets the "saveid" to mode. <br />
|-<br />
|$02||SO_RESTORE_VERBS||For all verbs between start and end and matching mode, kills any existing verb, sets the saveid to 0 and generally inits the verb.<br />
|-<br />
|$03||SO_DELETE_VERBS||For all verbs between start and end and matching mode, kills any existing verb.<br />
|}<br />
<br />
<br />
==setCameraAt ($32)==<br />
<br />
===Encoding===<br />
opcode x[p16]<br />
<br />
===Operation===<br />
Sets the camera's x position.<br />
<br />
<br />
==setObjectName ($54)==<br />
<br />
===Encoding===<br />
opcode object[p16] name[c]... $00<br />
<br />
===Operation===<br />
Sets the given object's name.<br />
<br />
<br />
==setOwnerOf ($29)==<br />
<br />
===Encoding===<br />
opcode object[p16] owner[p8]<br />
<br />
===Operation===<br />
Sets the owner of the object.<br />
<br />
<br />
==setState ($07)==<br />
<br />
===Encoding===<br />
opcode object[p16] state[p8]<br />
<br />
===Operation===<br />
Sets the state of the object.<br />
<br />
<br />
==setVarRange ($26)==<br />
non-standard encoding<br />
<br />
===Encoding===<br />
opcode result number[8] values[8]...<br />
or<br />
opcode result number[8] values[16]...<br />
<br />
===Operation===<br />
for (i = 0; i < number; i++) {<br />
&#42;result + i := values[i];<br />
}<br />
<br />
This sets a number of variables to the given parameters. The starting variable is given as "result", and the number of variables to modify is given as "number". This is followed by the same number of values, which will be put into the variable locations. The values are constants, and can be either 16-bit, if the highest bit of the opcode is set, i.e. $A6; or 8-bit, if the highest bit of the opcode is not set, i.e. $26. Note that all values are affected by the opcode's high bit; you can't mix 8 and 16-bit values.<br />
<br />
descumm example:<br />
setVarRange(Var[178],9,[0,0,0,0,0,0,0,0,0]);<br />
<br />
This sets variables 178 to 186 (inclusive) to 0.<br />
<br />
<br />
==soundKludge ($4C)==<br />
<br />
===Encoding===<br />
opcode items[v16]...<br />
<br />
===Operation===<br />
If the first item is -1, the existing sound queue is processed. Otherwise, the list of items is added to the queue.<br />
<br />
===Variants===<br />
In SCUMM V3 (small header) games, this opcode is used for the WaitForSentence instruction.<br />
<br />
<br />
==startMusic ($02)==<br />
<br />
===Encoding===<br />
opcode music[p8]<br />
<br />
===Operation===<br />
Adds the music in to the queue to be played.<br />
<br />
===Variants===<br />
In FM-Towns (SCUMM V3) games, this instruction performs different functions (some kind of Audio CD status query function; some partially implemented in ScummVM):<br />
opcode result sub-opcode<br />
<br />
{| border="1" cellpadding="2" width=100%<br />
|- style="background:whitesmoke"<br />
|Opcode||Meaning||Description<br />
|-<br />
|$00||Is Playing||Returns true if a CD audio track is currently playing.<br />
|-<br />
|$FC||Unpause CD||Unpauses the CD audio track.<br />
|-<br />
|$FD||Pause CD||Pauses the CD audio track.<br />
|-<br />
|$FE||Get CD Sound||Returns the current CD sound.<br />
|-<br />
|$FF||CD Volume||Might return the the current CD volume in FM-Towns Loom.<br />
|-<br />
|other||Track Length||Returns the track length in seconds.<br />
|}<br />
<br />
<br />
==startObject ($37)==<br />
<br />
===Encoding===<br />
opcode object[p16] script[p8] args[v16]...<br />
<br />
===Operation===<br />
Starts the object's script (OBCD blocks), passing the given arguments.<br />
<br />
<br />
==startScript ($0A)==<br />
one parameter plus varargs, extra encoding in opcode<br />
<br />
===Encoding===<br />
opcode script[p8] args[v16]...<br />
<br />
===Operation===<br />
Spawns a new thread running the code in script script. The new script has its local variables initialised to the list args. Uninitialised variables have undefined values.<br />
<br />
The opcode carries extra information: <br />
<br />
{| border="1" cellpadding="2" width=10%<br />
|- style="background:whitesmoke"<br />
|7||6||5||4 0<br />
|-<br />
|P1||R||F||$0A<br />
|}<br />
<br />
P1 = standard parameter bit<br><br />
R = indicates that the script is recursive<br><br />
F = indicates that the script is freeze resistant (a call to freezeScripts will skip this script, unless the "force freeze" bit of the freezeScripts opcode is set).<br />
<br />
<br />
==startSound ($1C)==<br />
<br />
===Encoding===<br />
opcode sound[p8]<br />
<br />
===Operation===<br />
Adds the given sound to the sound queue to be played.<br />
<br />
<br />
==stopMusic ($20)==<br />
<br />
===Encoding===<br />
opcode<br />
<br />
===Operation===<br />
Stops all sounds.<br />
<br />
<br />
==stopObjectCode ($A0 or $00)==<br />
<br />
===Encoding===<br />
opcode<br />
<br />
===Operation===<br />
Marks the calling script as dead, to be later pruned from the thread pool. Cleans up residual arrays. Should always be the last instruction in a script.<br />
<br />
$A0 is present in LSCR and SCRP files... when does $00 occur?<br />
<br />
<br />
==stopObjectScript ($6E)==<br />
<br />
===Encoding===<br />
opcode script[p16]<br />
<br />
===Operation===<br />
Marks the given object script as dead, to be later pruned from the thread pool. Cleans up residual arrays.<br />
<br />
<br />
==stopScript ($62)==<br />
<br />
===Encoding===<br />
opcode script[p8]<br />
<br />
===Operation===<br />
Marks the given script as dead, to be later pruned from the thread pool. Cleans up residual arrays.<br />
<br />
<br />
==stopSound ($3C)==<br />
<br />
===Encoding===<br />
opcode sound[p8]<br />
<br />
===Operation===<br />
Stops the given sound.<br />
<br />
<br />
==stringOps ($27)==<br />
parameters depend on sub-opcode<br />
<br />
===Encoding===<br />
opcode sub-opcode<br />
<br />
sub-opcodes:<br />
$01 stringID[p8] string[c]... $00<br />
$02 destID[p8] srcID[p8]<br />
$03 stringID[p8] index[p8] char[c]<br />
$04 result stringID[p8] index[p8]<br />
$05 stringID[p8] size[p8]<br />
<br />
===Operation===<br />
Miscellaneous actions on strings (Arrays, referred to by resource number).<br />
<br />
{| border="1" cellpadding="2" width=100%<br />
|- style="background:whitesmoke"<br />
|Opcode||Meaning||Description<br />
|-<br />
|$01||Load String||Loads the inline null-terminated string into the resource slot given by stringID.<br />
|-<br />
|$02||Copy String||Creates a duplicate of the string at resource slot srcID into destID. The old string at destID is lost.<br />
|-<br />
|$03||Write Character||Writes char at the given index (offset) of the string resource located at slot stringID. Out of bounds accesses cause undefined behaviour.<br />
|-<br />
|$04||Read Character||Reads a byte (character) at the given index (offset) of the string resource located at slot stringID, and writes it to result. Out of bounds accesses cause undefined behaviour.<br />
|-<br />
|$05||New String||Allocates or frees a string (Array), located at resource slot stringID. The string is initialised to size; if size is zero, the string is freed.<br />
|}<br />
<br />
<br />
==subtract ($3A)==<br />
<br />
===Encoding===<br />
opcode result value[p16]<br />
<br />
===Operation===<br />
result := result - value<br />
<br />
The variable pointed to by result is read, value is subtracted from it, and the result written back.<br />
<br />
<br />
==systemOps ($98)==<br />
<br />
===Encoding===<br />
opcode sub-opcode<br />
<br />
sub-opcodes:<br />
$01<br />
$02<br />
$03<br />
<br />
===Operation===<br />
{| border="1" cellpadding="2" width=100%<br />
|- style="background:whitesmoke"<br />
|Opcode||Meaning||Description<br />
|-<br />
|$01||SO_RESTART||Restarts the game.<br />
|-<br />
|$02||SO_PAUSE||Pauses/unpauses the game.<br />
|-<br />
|$03||SO_QUIT||Quits the game.<br />
|}<br />
<br />
<br />
==verbOps ($7A)==<br />
<br />
===Encoding===<br />
opcode verbID[p8] sub-opcode... $FF<br />
<br />
sub-opcodes:<br />
$01 object[p16]<br />
$02 name[c]... $00<br />
$03 colour[p8]<br />
$04 hicolour[p8]<br />
$05 left[p16] top[p16]<br />
$06<br />
$07<br />
$08<br />
$09<br />
$10 colour[p8]<br />
$11<br />
$12 key[p8]<br />
$13<br />
$14 stringID[p16]<br />
$16 object[p16] room[p8]<br />
$17 colour[p8]<br />
<br />
===Operation===<br />
{| border="1" cellpadding="2" width=100%<br />
|- style="background:whitesmoke"<br />
|Opcode||Meaning||Description<br />
|-<br />
|$01||SO_VERB_IMAGE||Assigns an object (image) to a verb.<br />
|-<br />
|$02||SO_VERB_NAME||Assigns the in-line name to the verb slot.<br />
|-<br />
|$03||SO_VERB_COLOR||Sets the colour of the verb.<br />
|-<br />
|$04||SO_VERB_HICOLOR||Sets the high colour of the verb.<br />
|-<br />
|$05||SO_VERB_AT||Sets the verb's top-left co-ordinates.<br />
|-<br />
|$06||SO_VERB_ON||Makes this verb active.<br />
|-<br />
|$07||SO_VERB_OFF||Makes this verb inactive.<br />
|-<br />
|$08||SO_VERB_DELETE||Kills this verb.<br />
|-<br />
|$09||SO_VERB_NEW||Creates a verb in the slot for the given verbID. If the slot is 0 (verb doesn't already exist), will add it to the next unusued slot; if this exceeds the global maximum number of verbs an error will be raised.<br />
|-<br />
|$10||SO_VERB_DIMCOLOR||Sets the dim colour of the verb.<br />
|-<br />
|$11||SO_VERB_DIM||Dims this verb.<br />
|-<br />
|$12||SO_VERB_KEY||Sets the key code (maybe ASCII char?) associated with this verb.<br />
|-<br />
|$13||SO_VERB_CENTER||Centres the verb?<br />
|-<br />
|$14||SO_VERB_NAME_STR||Loads the given string resource into the verb's slot. If either the string resource or verb slot is not found (0), the verb resource is nuked.<br />
|-<br />
|$16||Assign Object||Assigns an object from the given room to the verb (if the object's image index is not already assigned to the given object).<br />
|-<br />
|$17||Set Back Colour||Sets the background colour of the verb?<br />
|}<br />
<br />
<br />
==wait ($AE)==<br />
<br />
===Encoding===<br />
opcode sub-opcode<br />
<br />
sub-opcodes:<br />
$01 actor[p8]<br />
$02 <br />
$03<br />
$04<br />
<br />
===Operation===<br />
{| border="1" cellpadding="2" width=100%<br />
|- style="background:whitesmoke"<br />
|Opcode||Meaning||Description<br />
|-<br />
|$01||SO_WAIT_FOR_ACTOR||If the given actor is moving, breaks and resumes at this instruction again.<br />
|-<br />
|$02||SO_WAIT_FOR_MESSAGE||If the global variable VAR_HAVE_MSG (Var[3]) is not zero, breaks and resumes at this instruction again.<br />
|-<br />
|$03||SO_WAIT_FOR_CAMERA||If the camera has not reached its destination x position, breaks and resumes at this instruction again.<br />
|-<br />
|$04||SO_WAIT_FOR_SENTENCE||If there is a sentence present?, breaks and resumes at this instruction again<br />
|}<br />
<br />
===Variants===<br />
In Indy3 (non-Macintosh), this opcode only acts as SO_WAIT_FOR_MESSAGE and omits the sub-opcode.<br />
opcode<br />
<br />
<br />
==walkActorTo ($1E)==<br />
<br />
===Encoding===<br />
opcode actor[p8] x[p16] y[p16]<br />
<br />
===Operation===<br />
Sets the actor to begin walking to the given position.<br />
<br />
<br />
==walkActorToActor ($0D)==<br />
<br />
===Encoding===<br />
opcode walker[p8] walkee[p8] distance[8]<br />
<br />
===Operation===<br />
Walks walker towards walkee's position by the given distance. Walker and walkee are both actors.<br />
<br />
<br />
==walkActorToObject ($36)==<br />
<br />
===Encoding===<br />
opcode actor[p8] object[p16]<br />
<br />
===Operation===<br />
Sets the actor to begin walking to the given object's position.<br />
<br />
=Variables=<br />
<br />
A number of variables are reserved for use by the SPUTM/SCUMM engine. Here is a list of known variables and their corresponding numbers, taken from the ScummVM source code.<br />
<br />
VAR_RESULT = 0; // descumm claims var 0 is the result var (for expressions)<br />
VAR_KEYPRESS = 0; // script_v5_.cpp claims var 0 is for keypresses...<br />
VAR_EGO = 1;<br />
VAR_CAMERA_POS_X = 2;<br />
VAR_HAVE_MSG = 3;<br />
VAR_ROOM = 4;<br />
VAR_OVERRIDE = 5;<br />
VAR_MACHINE_SPEED = 6;<br />
VAR_ME = 7;<br />
VAR_NUM_ACTOR = 8;<br />
VAR_CURRENT_LIGHTS = 9;<br />
VAR_CURRENTDRIVE = 10;<br />
VAR_TMR_1 = 11;<br />
VAR_TMR_2 = 12;<br />
VAR_TMR_3 = 13;<br />
VAR_MUSIC_TIMER = 14;<br />
VAR_ACTOR_RANGE_MIN = 15;<br />
VAR_ACTOR_RANGE_MAX = 16;<br />
VAR_CAMERA_MIN_X = 17;<br />
VAR_CAMERA_MAX_X = 18;<br />
VAR_TIMER_NEXT = 19;<br />
VAR_VIRT_MOUSE_X = 20;<br />
VAR_VIRT_MOUSE_Y = 21;<br />
VAR_ROOM_RESOURCE = 22;<br />
VAR_LAST_SOUND = 23;<br />
VAR_CUTSCENEEXIT_KEY = 24;<br />
VAR_TALK_ACTOR = 25;<br />
VAR_CAMERA_FAST_X = 26;<br />
VAR_SCROLL_SCRIPT = 27;<br />
VAR_ENTRY_SCRIPT = 28;<br />
VAR_ENTRY_SCRIPT2 = 29;<br />
VAR_EXIT_SCRIPT = 30;<br />
VAR_EXIT_SCRIPT2 = 31;<br />
VAR_VERB_SCRIPT = 32;<br />
VAR_SENTENCE_SCRIPT = 33;<br />
VAR_INVENTORY_SCRIPT = 34;<br />
VAR_CUTSCENE_START_SCRIPT = 35;<br />
VAR_CUTSCENE_END_SCRIPT = 36;<br />
VAR_CHARINC = 37;<br />
VAR_WALKTO_OBJ = 38;<br />
VAR_DEBUGMODE = 39;<br />
VAR_HEAPSPACE = 40;<br />
VAR_RESTART_KEY = 42;<br />
VAR_PAUSE_KEY = 43;<br />
VAR_MOUSE_X = 44;<br />
VAR_MOUSE_Y = 45;<br />
VAR_TIMER = 46;<br />
VAR_TIMER_TOTAL = 47;<br />
VAR_SOUNDCARD = 48;<br />
VAR_VIDEOMODE = 49;<br />
VAR_MAINMENU_KEY = 50;<br />
VAR_FIXEDDISK = 51;<br />
VAR_CURSORSTATE = 52;<br />
VAR_USERPUT = 53;<br />
VAR_V5_TALK_STRING_Y = 54;<br />
VAR_SOUNDRESULT = 56;<br />
VAR_TALKSTOP_KEY = 57;<br />
VAR_FADE_DELAY = 59;<br />
VAR_NOSUBTITLES = 60;<br />
VAR_SOUNDPARAM = 64;<br />
VAR_SOUNDPARAM2 = 65;<br />
VAR_SOUNDPARAM3 = 66;<br />
VAR_INPUTMODE = 67; // 1 is keyboard, 2 is joystick, 3 is mouse<br />
VAR_MEMORY_PERFORMANCE = 68;<br />
VAR_VIDEO_PERFORMANCE = 69;<br />
VAR_ROOM_FLAG = 70;<br />
VAR_GAME_LOADED = 71;<br />
VAR_NEW_ROOM = 72;<br />
<br />
<br />
=Table of Parameters=<br />
Please see the wiki page [[SCUMM/V5_opcodes/Table]] for a concise rendition of the above information (with a few omissions dues to the complexity of the instructions).</div>Jestar jokinhttps://wiki.scummvm.org/index.php?title=SCUMM/V5_opcodes/Table&diff=10982SCUMM/V5 opcodes/Table2009-04-19T02:36:10Z<p>Jestar jokin: /* Table of Parameters */ clearHeap does not take an argument</p>
<hr />
<div>=Table of Parameters=<br />
<br />
This table shows a summary of the [[SCUMM/V5 opcodes|SCUMM V5]] opcodes and their parameters in a concise fashion.<br />
<br />
Argument types:<br />
* V = variable<br />
* B = byte constant<br />
* W = word constant<br />
* P8 = variable or byte<br />
* P16 = variable or word<br />
* L = list<br />
* J = jump (used by almost all boolean expressions, comparisons) (equivalent to W)<br />
* D = delay; 24-bit constant (only used by delay instruction, strangely enough)<br />
* A = ASCII string, terminated by the following argument ($00, $FF, $FE...)<br />
* A0 = ASCII string, null-terminated<br />
* A1 = ASCII string, $FF terminated<br />
* FF = the hex value $FF, used for terminating some lists, strings etc.<br />
* SO = sub-opcode, variants listed underneath as "opcode$sub-opcode"<br />
* NS = non-standard encoding that cannot be sufficiently expressed in this table<br />
* + = one or more of the preceding argument (parameter bits usually don't matter)<br />
* None = does not take that argument argument<br />
<br />
<br />
{| border="1" style="text-align:center" width=100% cellpadding=2<br />
|- style="background:whitesmoke"<br />
|Instruction||Opcode||Descumm equiv.||Returns a Value||Arg 1||Arg 2||Arg 3<br />
|-<br />
|align="left" |actorFollowCamera<br />
|$52<br />
|style="color:silver; background:whitesmoke" |==<br />
|style="color:silver; background:whitesmoke" |False<br />
|P8<br />
|style="color:silver; background:whitesmoke" |None<br />
|style="color:silver; background:whitesmoke" |None<br />
|-<br />
|align="left" |actorFromPos<br />
|$15<br />
|style="color:silver; background:whitesmoke" |==<br />
|True<br />
|P16<br />
|P16<br />
|style="color:silver; background:whitesmoke" |None<br />
|-<br />
|align="left" |actorOps<br />
|$13<br />
|ActorOps<br />
|style="color:silver; background:whitesmoke" |False<br />
|P8<br />
|SO+<br />
|FF<br />
|-<br />
|align="left" |actorOps$00<br />
|$00<br />
|Unknown<br />
|style="color:silver; background:whitesmoke" |False<br />
|P8<br />
|style="color:silver; background:whitesmoke" |None<br />
|style="color:silver; background:whitesmoke" |None<br />
|-<br />
|align="left" |actorOps$01<br />
|$01<br />
|Costume<br />
|style="color:silver; background:whitesmoke" |False<br />
|P8<br />
|style="color:silver; background:whitesmoke" |None<br />
|style="color:silver; background:whitesmoke" |None<br />
|-<br />
|align="left" |actorOps$02<br />
|$02<br />
|WalkSpeed<br />
|style="color:silver; background:whitesmoke" |False<br />
|P8<br />
|P8<br />
|style="color:silver; background:whitesmoke" |None<br />
|-<br />
|align="left" |actorOps$03<br />
|$03<br />
|Sound<br />
|style="color:silver; background:whitesmoke" |False<br />
|P8<br />
|style="color:silver; background:whitesmoke" |None<br />
|style="color:silver; background:whitesmoke" |None<br />
|-<br />
|align="left" |actorOps$04<br />
|$04<br />
|WalkAnimNr<br />
|style="color:silver; background:whitesmoke" |False<br />
|P8<br />
|style="color:silver; background:whitesmoke" |None<br />
|style="color:silver; background:whitesmoke" |None<br />
|-<br />
|align="left" |actorOps$05<br />
|$05<br />
|TalkAnimNr<br />
|style="color:silver; background:whitesmoke" |False<br />
|P8<br />
|P8<br />
|style="color:silver; background:whitesmoke" |None<br />
|-<br />
|align="left" |actorOps$06<br />
|$06<br />
|StandAnimNr<br />
|style="color:silver; background:whitesmoke" |False<br />
|P8<br />
|style="color:silver; background:whitesmoke" |None<br />
|style="color:silver; background:whitesmoke" |None<br />
|-<br />
|align="left" |actorOps$07<br />
|$07<br />
|Nothing<br />
|style="color:silver; background:whitesmoke" |False<br />
|P8<br />
|P8<br />
|P8<br />
|-<br />
|align="left" |actorOps$08<br />
|$08<br />
|Init<br />
|style="color:silver; background:whitesmoke" |False<br />
|style="color:silver; background:whitesmoke" |None<br />
|style="color:silver; background:whitesmoke" |None<br />
|style="color:silver; background:whitesmoke" |None<br />
|-<br />
|align="left" |actorOps$09<br />
|$09<br />
|Elevation<br />
|style="color:silver; background:whitesmoke" |False<br />
|P16<br />
|style="color:silver; background:whitesmoke" |None<br />
|style="color:silver; background:whitesmoke" |None<br />
|-<br />
|align="left" |actorOps$0A<br />
|$0A<br />
|DefaultAnims<br />
|style="color:silver; background:whitesmoke" |False<br />
|style="color:silver; background:whitesmoke" |None<br />
|style="color:silver; background:whitesmoke" |None<br />
|style="color:silver; background:whitesmoke" |None<br />
|-<br />
|align="left" |actorOps$0B<br />
|$0B<br />
|Palette<br />
|style="color:silver; background:whitesmoke" |False<br />
|P8<br />
|P8<br />
|style="color:silver; background:whitesmoke" |None<br />
|-<br />
|align="left" |actorOps$0C<br />
|$0C<br />
|TalkColor<br />
|style="color:silver; background:whitesmoke" |False<br />
|P8<br />
|style="color:silver; background:whitesmoke" |None<br />
|style="color:silver; background:whitesmoke" |None<br />
|-<br />
|align="left" |actorOps$0D<br />
|$0D<br />
|Name<br />
|style="color:silver; background:whitesmoke" |False<br />
|A0<br />
|style="color:silver; background:whitesmoke" |None<br />
|style="color:silver; background:whitesmoke" |None<br />
|-<br />
|align="left" |actorOps$0E<br />
|$0E<br />
|InitAnimNr<br />
|style="color:silver; background:whitesmoke" |False<br />
|P8<br />
|style="color:silver; background:whitesmoke" |None<br />
|style="color:silver; background:whitesmoke" |None<br />
|-<br />
|align="left" |actorOps$10<br />
|$10<br />
|Width<br />
|style="color:silver; background:whitesmoke" |False<br />
|P8<br />
|style="color:silver; background:whitesmoke" |None<br />
|style="color:silver; background:whitesmoke" |None<br />
|-<br />
|align="left" |actorOps$11<br />
|$11<br />
|Scale<br />
|style="color:silver; background:whitesmoke" |False<br />
|P8<br />
|P8<br />
|style="color:silver; background:whitesmoke" |None<br />
|-<br />
|align="left" |actorOps$12<br />
|$12<br />
|NeverZClip<br />
|style="color:silver; background:whitesmoke" |False<br />
|style="color:silver; background:whitesmoke" |None<br />
|style="color:silver; background:whitesmoke" |None<br />
|style="color:silver; background:whitesmoke" |None<br />
|-<br />
|align="left" |actorOps$13<br />
|$13<br />
|SetZClip<br />
|style="color:silver; background:whitesmoke" |False<br />
|P8<br />
|style="color:silver; background:whitesmoke" |None<br />
|style="color:silver; background:whitesmoke" |None<br />
|-<br />
|align="left" |actorOps$14<br />
|$14<br />
|IgnoreBoxes<br />
|style="color:silver; background:whitesmoke" |False<br />
|style="color:silver; background:whitesmoke" |None<br />
|style="color:silver; background:whitesmoke" |None<br />
|style="color:silver; background:whitesmoke" |None<br />
|-<br />
|align="left" |actorOps$15<br />
|$15<br />
|FollowBoxes<br />
|style="color:silver; background:whitesmoke" |False<br />
|P8<br />
|style="color:silver; background:whitesmoke" |None<br />
|style="color:silver; background:whitesmoke" |None<br />
|-<br />
|align="left" |actorOps$16<br />
|$16<br />
|AnimSpeed<br />
|style="color:silver; background:whitesmoke" |False<br />
|P8<br />
|style="color:silver; background:whitesmoke" |None<br />
|style="color:silver; background:whitesmoke" |None<br />
|-<br />
|align="left" |actorOps$17<br />
|$17<br />
|ShadowMode<br />
|style="color:silver; background:whitesmoke" |False<br />
|P8<br />
|style="color:silver; background:whitesmoke" |None<br />
|style="color:silver; background:whitesmoke" |None<br />
|-<br />
|align="left" |actorSetClass<br />
|$5D<br />
|setClass<br />
|style="color:silver; background:whitesmoke" |False<br />
|P16<br />
|L<br />
|style="color:silver; background:whitesmoke" |None<br />
|-<br />
|align="left" |add<br />
|$5A<br />
|(inline)<br />
|True<br />
|P16<br />
|style="color:silver; background:whitesmoke" |None<br />
|style="color:silver; background:whitesmoke" |None<br />
|-<br />
|align="left" |and<br />
|$17<br />
|(inline)<br />
|True<br />
|P16<br />
|style="color:silver; background:whitesmoke" |None<br />
|style="color:silver; background:whitesmoke" |None<br />
|-<br />
|align="left" |animateActor<br />
|$11<br />
|animateCostume<br />
|style="color:silver; background:whitesmoke" |False<br />
|P8<br />
|P8<br />
|style="color:silver; background:whitesmoke" |None<br />
|-<br />
|align="left" |breakHere<br />
|$80<br />
|style="color:silver; background:whitesmoke" |==<br />
|style="color:silver; background:whitesmoke" |False<br />
|style="color:silver; background:whitesmoke" |None<br />
|style="color:silver; background:whitesmoke" |None<br />
|style="color:silver; background:whitesmoke" |None<br />
|-<br />
|align="left" |chainScript<br />
|$42<br />
|style="color:silver; background:whitesmoke" |==<br />
|style="color:silver; background:whitesmoke" |False<br />
|P8<br />
|L<br />
|style="color:silver; background:whitesmoke" |None<br />
|-<br />
|align="left" |cursorCommand<br />
|$2C<br />
|(none)<br />
|style="color:silver; background:whitesmoke" |False<br />
|SO<br />
|style="color:silver; background:whitesmoke" |None<br />
|style="color:silver; background:whitesmoke" |None<br />
|-<br />
|align="left" |cursorCommand$01<br />
|$01<br />
|CursorShow<br />
|style="color:silver; background:whitesmoke" |False<br />
|style="color:silver; background:whitesmoke" |None<br />
|style="color:silver; background:whitesmoke" |None<br />
|style="color:silver; background:whitesmoke" |None<br />
|-<br />
|align="left" |cursorCommand$02<br />
|$02<br />
|CursorHide<br />
|style="color:silver; background:whitesmoke" |False<br />
|style="color:silver; background:whitesmoke" |None<br />
|style="color:silver; background:whitesmoke" |None<br />
|style="color:silver; background:whitesmoke" |None<br />
|-<br />
|align="left" |cursorCommand$03<br />
|$03<br />
|UserputOn<br />
|style="color:silver; background:whitesmoke" |False<br />
|style="color:silver; background:whitesmoke" |None<br />
|style="color:silver; background:whitesmoke" |None<br />
|style="color:silver; background:whitesmoke" |None<br />
|-<br />
|align="left" |cursorCommand$04<br />
|$04<br />
|UserputOff<br />
|style="color:silver; background:whitesmoke" |False<br />
|style="color:silver; background:whitesmoke" |None<br />
|style="color:silver; background:whitesmoke" |None<br />
|style="color:silver; background:whitesmoke" |None<br />
|-<br />
|align="left" |cursorCommand$05<br />
|$05<br />
|CursorSoftOn<br />
|style="color:silver; background:whitesmoke" |False<br />
|style="color:silver; background:whitesmoke" |None<br />
|style="color:silver; background:whitesmoke" |None<br />
|style="color:silver; background:whitesmoke" |None<br />
|-<br />
|align="left" |cursorCommand$06<br />
|$06<br />
|CursorSoftOff<br />
|style="color:silver; background:whitesmoke" |False<br />
|style="color:silver; background:whitesmoke" |None<br />
|style="color:silver; background:whitesmoke" |None<br />
|style="color:silver; background:whitesmoke" |None<br />
|-<br />
|align="left" |cursorCommand$07<br />
|$07<br />
|UserputSoftOn<br />
|style="color:silver; background:whitesmoke" |False<br />
|style="color:silver; background:whitesmoke" |None<br />
|style="color:silver; background:whitesmoke" |None<br />
|style="color:silver; background:whitesmoke" |None<br />
|-<br />
|align="left" |cursorCommand$08<br />
|$08<br />
|UserputSoftOff<br />
|style="color:silver; background:whitesmoke" |False<br />
|style="color:silver; background:whitesmoke" |None<br />
|style="color:silver; background:whitesmoke" |None<br />
|style="color:silver; background:whitesmoke" |None<br />
|-<br />
|align="left" |cursorCommand$0A<br />
|$0A<br />
|SetCursorImg<br />
|style="color:silver; background:whitesmoke" |False<br />
|P8<br />
|P8<br />
|style="color:silver; background:whitesmoke" |None<br />
|-<br />
|align="left" |cursorCommand$0B<br />
|$0B<br />
|setCursorHotspot<br />
|style="color:silver; background:whitesmoke" |False<br />
|P8<br />
|P8<br />
|P8<br />
|-<br />
|align="left" |cursorCommand$0C<br />
|$0C<br />
|InitCursor<br />
|style="color:silver; background:whitesmoke" |False<br />
|P8<br />
|style="color:silver; background:whitesmoke" |None<br />
|style="color:silver; background:whitesmoke" |None<br />
|-<br />
|align="left" |cursorCommand$0D<br />
|$0D<br />
|InitCharset<br />
|style="color:silver; background:whitesmoke" |False<br />
|P8<br />
|style="color:silver; background:whitesmoke" |None<br />
|style="color:silver; background:whitesmoke" |None<br />
|-<br />
|align="left" |cursorCommand$0E<br />
|$0E<br />
|CursorCommand<br />
|style="color:silver; background:whitesmoke" |False<br />
|L<br />
|style="color:silver; background:whitesmoke" |None<br />
|style="color:silver; background:whitesmoke" |None<br />
|-<br />
|align="left" |cutscene<br />
|$40<br />
|style="color:silver; background:whitesmoke" |==<br />
|style="color:silver; background:whitesmoke" |False<br />
|L<br />
|style="color:silver; background:whitesmoke" |None<br />
|style="color:silver; background:whitesmoke" |None<br />
|-<br />
|align="left" |debug<br />
|$6B<br />
|debug?<br />
|style="color:silver; background:whitesmoke" |False<br />
|P16<br />
|style="color:silver; background:whitesmoke" |None<br />
|style="color:silver; background:whitesmoke" |None<br />
|-<br />
|align="left" |decrement<br />
|$C6<br />
|(inline)<br />
|True<br />
|style="color:silver; background:whitesmoke" |None<br />
|style="color:silver; background:whitesmoke" |None<br />
|style="color:silver; background:whitesmoke" |None<br />
|-<br />
|align="left" |delay<br />
|$2E<br />
|style="color:silver; background:whitesmoke" |==<br />
|style="color:silver; background:whitesmoke" |False<br />
|D<br />
|style="color:silver; background:whitesmoke" |None<br />
|style="color:silver; background:whitesmoke" |None<br />
|-<br />
|align="left" |delayVariable<br />
|$2B<br />
|style="color:silver; background:whitesmoke" |==<br />
|style="color:silver; background:whitesmoke" |False<br />
|V<br />
|style="color:silver; background:whitesmoke" |None<br />
|style="color:silver; background:whitesmoke" |None<br />
|-<br />
|align="left" |divide<br />
|$5B<br />
|(inline)<br />
|True<br />
|P16<br />
|style="color:silver; background:whitesmoke" |None<br />
|style="color:silver; background:whitesmoke" |None<br />
|-<br />
|align="left" |doSentence<br />
|$19<br />
|style="color:silver; background:whitesmoke" |==<br />
|style="color:silver; background:whitesmoke" |False<br />
|P8<br />
|P16<br />
|P16<br />
|-<br />
|align="left" |drawBox<br />
|$3F<br />
|style="color:silver; background:whitesmoke" |==<br />
|style="color:silver; background:whitesmoke" |False<br />
|P16<br />
|P16<br />
|NS<br />
|-<br />
|align="left" |drawObject<br />
|$05<br />
|style="color:silver; background:whitesmoke" |==<br />
|style="color:silver; background:whitesmoke" |False<br />
|P16<br />
|SO<br />
|style="color:silver; background:whitesmoke" |None<br />
|-<br />
|align="left" |drawObject$01<br />
|$01<br />
|setXY<br />
|style="color:silver; background:whitesmoke" |False<br />
|P16<br />
|P16<br />
|style="color:silver; background:whitesmoke" |None<br />
|-<br />
|align="left" |drawObject$02<br />
|$02<br />
|setImage<br />
|style="color:silver; background:whitesmoke" |False<br />
|P16<br />
|style="color:silver; background:whitesmoke" |None<br />
|style="color:silver; background:whitesmoke" |None<br />
|-<br />
|align="left" |drawObject$1F<br />
|$1F<br />
|()<br />
|style="color:silver; background:whitesmoke" |False<br />
|style="color:silver; background:whitesmoke" |None<br />
|style="color:silver; background:whitesmoke" |None<br />
|style="color:silver; background:whitesmoke" |None<br />
|-<br />
|align="left" |dummy<br />
|$A7<br />
|dummy(A7)<br />
|style="color:silver; background:whitesmoke" |False<br />
|style="color:silver; background:whitesmoke" |None<br />
|style="color:silver; background:whitesmoke" |None<br />
|style="color:silver; background:whitesmoke" |None<br />
|-<br />
|align="left" |endCutscene<br />
|$C0<br />
|style="color:silver; background:whitesmoke" |==<br />
|style="color:silver; background:whitesmoke" |False<br />
|style="color:silver; background:whitesmoke" |None<br />
|style="color:silver; background:whitesmoke" |None<br />
|style="color:silver; background:whitesmoke" |None<br />
|-<br />
|align="left" |equalZero<br />
|$28<br />
|inline<br />
|style="color:silver; background:whitesmoke" |False<br />
|V<br />
|J<br />
|style="color:silver; background:whitesmoke" |None<br />
|-<br />
|align="left" |expression<br />
|$AC<br />
|Exprmode<br />
|True<br />
|SO+<br />
|FF<br />
|style="color:silver; background:whitesmoke" |None<br />
|-<br />
|align="left" |expression$01<br />
|$01<br />
|(inline)<br />
|style="color:silver; background:whitesmoke" |False<br />
|P16<br />
|style="color:silver; background:whitesmoke" |None<br />
|style="color:silver; background:whitesmoke" |None<br />
|-<br />
|align="left" |expression$02<br />
|$02<br />
|(inline)<br />
|style="color:silver; background:whitesmoke" |False<br />
|style="color:silver; background:whitesmoke" |None<br />
|style="color:silver; background:whitesmoke" |None<br />
|style="color:silver; background:whitesmoke" |None<br />
|-<br />
|align="left" |expression$03<br />
|$03<br />
|(inline)<br />
|style="color:silver; background:whitesmoke" |False<br />
|style="color:silver; background:whitesmoke" |None<br />
|style="color:silver; background:whitesmoke" |None<br />
|style="color:silver; background:whitesmoke" |None<br />
|-<br />
|align="left" |expression$04<br />
|$04<br />
|(inline)<br />
|style="color:silver; background:whitesmoke" |False<br />
|style="color:silver; background:whitesmoke" |None<br />
|style="color:silver; background:whitesmoke" |None<br />
|style="color:silver; background:whitesmoke" |None<br />
|-<br />
|align="left" |expression$05<br />
|$05<br />
|(inline)<br />
|style="color:silver; background:whitesmoke" |False<br />
|style="color:silver; background:whitesmoke" |None<br />
|style="color:silver; background:whitesmoke" |None<br />
|style="color:silver; background:whitesmoke" |None<br />
|-<br />
|align="left" |expression$06<br />
|$06<br />
|(inline)<br />
|style="color:silver; background:whitesmoke" |False<br />
|NS<br />
|style="color:silver; background:whitesmoke" |None<br />
|style="color:silver; background:whitesmoke" |None<br />
|-<br />
|align="left" |faceActor<br />
|$09<br />
|style="color:silver; background:whitesmoke" |==<br />
|style="color:silver; background:whitesmoke" |False<br />
|P8<br />
|P16<br />
|style="color:silver; background:whitesmoke" |None<br />
|-<br />
|align="left" |findInventory<br />
|$3D<br />
|style="color:silver; background:whitesmoke" |==<br />
|True<br />
|P8<br />
|P8<br />
|style="color:silver; background:whitesmoke" |None<br />
|-<br />
|align="left" |findObject<br />
|$35<br />
|style="color:silver; background:whitesmoke" |==<br />
|True<br />
|P8<br />
|P8<br />
|style="color:silver; background:whitesmoke" |None<br />
|-<br />
|align="left" |freezeScripts<br />
|$60<br />
|style="color:silver; background:whitesmoke" |==<br />
|style="color:silver; background:whitesmoke" |False<br />
|P8<br />
|style="color:silver; background:whitesmoke" |None<br />
|style="color:silver; background:whitesmoke" |None<br />
|-<br />
|align="left" |getActorCostume<br />
|$71<br />
|style="color:silver; background:whitesmoke" |==<br />
|True<br />
|P8<br />
|style="color:silver; background:whitesmoke" |None<br />
|style="color:silver; background:whitesmoke" |None<br />
|-<br />
|align="left" |getActorElevation<br />
|$06<br />
|style="color:silver; background:whitesmoke" |==<br />
|True<br />
|P8<br />
|style="color:silver; background:whitesmoke" |None<br />
|style="color:silver; background:whitesmoke" |None<br />
|-<br />
|align="left" |getActorFacing<br />
|$63<br />
|style="color:silver; background:whitesmoke" |==<br />
|True<br />
|P8<br />
|style="color:silver; background:whitesmoke" |None<br />
|style="color:silver; background:whitesmoke" |None<br />
|-<br />
|align="left" |getActorMoving<br />
|$56<br />
|style="color:silver; background:whitesmoke" |==<br />
|True<br />
|P8<br />
|style="color:silver; background:whitesmoke" |None<br />
|style="color:silver; background:whitesmoke" |None<br />
|-<br />
|align="left" |getActorRoom<br />
|$03<br />
|style="color:silver; background:whitesmoke" |==<br />
|True<br />
|P8<br />
|style="color:silver; background:whitesmoke" |None<br />
|style="color:silver; background:whitesmoke" |None<br />
|-<br />
|align="left" |getActorScale<br />
|$3B<br />
|style="color:silver; background:whitesmoke" |==<br />
|True<br />
|P8<br />
|style="color:silver; background:whitesmoke" |None<br />
|style="color:silver; background:whitesmoke" |None<br />
|-<br />
|align="left" |getActorWalkBox<br />
|$7B<br />
|style="color:silver; background:whitesmoke" |==<br />
|True<br />
|P8<br />
|style="color:silver; background:whitesmoke" |None<br />
|style="color:silver; background:whitesmoke" |None<br />
|-<br />
|align="left" |getActorWidth<br />
|$6C<br />
|style="color:silver; background:whitesmoke" |==<br />
|True<br />
|P8<br />
|style="color:silver; background:whitesmoke" |None<br />
|style="color:silver; background:whitesmoke" |None<br />
|-<br />
|align="left" |getActorX<br />
|$43<br />
|style="color:silver; background:whitesmoke" |==<br />
|True<br />
|P16<br />
|style="color:silver; background:whitesmoke" |None<br />
|style="color:silver; background:whitesmoke" |None<br />
|-<br />
|align="left" |getActorY<br />
|$23<br />
|style="color:silver; background:whitesmoke" |==<br />
|True<br />
|P16<br />
|style="color:silver; background:whitesmoke" |None<br />
|style="color:silver; background:whitesmoke" |None<br />
|-<br />
|align="left" |getAnimCounter<br />
|$22<br />
|style="color:silver; background:whitesmoke" |==<br />
|True<br />
|P8<br />
|style="color:silver; background:whitesmoke" |None<br />
|style="color:silver; background:whitesmoke" |None<br />
|-<br />
|align="left" |getClosestObjActor<br />
|$66<br />
|style="color:silver; background:whitesmoke" |==<br />
|True<br />
|P16<br />
|style="color:silver; background:whitesmoke" |None<br />
|style="color:silver; background:whitesmoke" |None<br />
|-<br />
|align="left" |getDist<br />
|$34<br />
|style="color:silver; background:whitesmoke" |==<br />
|True<br />
|P16<br />
|P16<br />
|style="color:silver; background:whitesmoke" |None<br />
|-<br />
|align="left" |getInventoryCount<br />
|$31<br />
|style="color:silver; background:whitesmoke" |==<br />
|True<br />
|P8<br />
|style="color:silver; background:whitesmoke" |None<br />
|style="color:silver; background:whitesmoke" |None<br />
|-<br />
|align="left" |getObjectOwner<br />
|$10<br />
|style="color:silver; background:whitesmoke" |==<br />
|True<br />
|P16<br />
|style="color:silver; background:whitesmoke" |None<br />
|style="color:silver; background:whitesmoke" |None<br />
|-<br />
|align="left" |getObjectState<br />
|$0F<br />
|style="color:silver; background:whitesmoke" |==<br />
|True<br />
|P16<br />
|style="color:silver; background:whitesmoke" |None<br />
|style="color:silver; background:whitesmoke" |None<br />
|-<br />
|align="left" |getRandomNumber<br />
|$16<br />
|getRandomNr<br />
|True<br />
|P8<br />
|style="color:silver; background:whitesmoke" |None<br />
|style="color:silver; background:whitesmoke" |None<br />
|-<br />
|align="left" |getScriptRunning<br />
|$68<br />
|style="color:silver; background:whitesmoke" |isScriptRunning<br />
|True<br />
|P8<br />
|style="color:silver; background:whitesmoke" |None<br />
|style="color:silver; background:whitesmoke" |None<br />
|-<br />
|align="left" |getStringWidth<br />
|$67<br />
|style="color:silver; background:whitesmoke" |==<br />
|True<br />
|P8<br />
|style="color:silver; background:whitesmoke" |None<br />
|style="color:silver; background:whitesmoke" |None<br />
|-<br />
|align="left" |getVerbEntryPoint<br />
|$0B<br />
|style="color:silver; background:whitesmoke" |==<br />
|True<br />
|P16<br />
|P16<br />
|style="color:silver; background:whitesmoke" |None<br />
|-<br />
|align="left" |ifClassOfIs<br />
|$1D<br />
|classOfIs<br />
|style="color:silver; background:whitesmoke" |False<br />
|P16<br />
|L<br />
|J<br />
|-<br />
|align="left" |ifNotState<br />
|$2F<br />
|getState (inline)<br />
|style="color:silver; background:whitesmoke" |False<br />
|P16<br />
|P8<br />
|J<br />
|-<br />
|align="left" |ifState<br />
|$4F<br />
|getState (inline)<br />
|style="color:silver; background:whitesmoke" |False<br />
|P16<br />
|P8<br />
|J<br />
|-<br />
|align="left" |increment<br />
|$46<br />
|(inline)<br />
|True<br />
|style="color:silver; background:whitesmoke" |None<br />
|style="color:silver; background:whitesmoke" |None<br />
|style="color:silver; background:whitesmoke" |None<br />
|-<br />
|align="left" |isActorInBox<br />
|$1F<br />
|style="color:silver; background:whitesmoke" |==<br />
|style="color:silver; background:whitesmoke" |False<br />
|P8<br />
|P8<br />
|J<br />
|-<br />
|align="left" |isEqual<br />
|$48<br />
|(inline)<br />
|style="color:silver; background:whitesmoke" |False<br />
|V<br />
|P16<br />
|J<br />
|-<br />
|align="left" |isGreater<br />
|$78<br />
|(inline)<br />
|style="color:silver; background:whitesmoke" |False<br />
|V<br />
|P16<br />
|J<br />
|-<br />
|align="left" |isGreaterEqual<br />
|$04<br />
|(inline)<br />
|style="color:silver; background:whitesmoke" |False<br />
|V<br />
|P16<br />
|J<br />
|-<br />
|align="left" |isLess<br />
|$44<br />
|(inline)<br />
|style="color:silver; background:whitesmoke" |False<br />
|V<br />
|P16<br />
|J<br />
|-<br />
|align="left" |isNotEqual<br />
|$08<br />
|(inline)<br />
|style="color:silver; background:whitesmoke" |False<br />
|V<br />
|P16<br />
|J<br />
|-<br />
|align="left" |isSoundRunning<br />
|$7C<br />
|style="color:silver; background:whitesmoke" |==<br />
|True<br />
|P8<br />
|style="color:silver; background:whitesmoke" |None<br />
|style="color:silver; background:whitesmoke" |None<br />
|-<br />
|align="left" |jumpRelative<br />
|$18<br />
|(inline) or goto<br />
|style="color:silver; background:whitesmoke" |False<br />
|J<br />
|style="color:silver; background:whitesmoke" |None<br />
|style="color:silver; background:whitesmoke" |None<br />
|-<br />
|align="left" |lessOrEqual<br />
|$38<br />
|(inline)<br />
|style="color:silver; background:whitesmoke" |False<br />
|V<br />
|P16<br />
|J<br />
|-<br />
|align="left" |lights<br />
|$70<br />
|style="color:silver; background:whitesmoke" |==<br />
|style="color:silver; background:whitesmoke" |False<br />
|P8<br />
|B<br />
|B<br />
|-<br />
|align="left" |loadRoom<br />
|$72<br />
|style="color:silver; background:whitesmoke" |==<br />
|style="color:silver; background:whitesmoke" |False<br />
|P8<br />
|style="color:silver; background:whitesmoke" |None<br />
|style="color:silver; background:whitesmoke" |None<br />
|-<br />
|align="left" |loadRoomWithEgo<br />
|$24<br />
|style="color:silver; background:whitesmoke" |==<br />
|style="color:silver; background:whitesmoke" |False<br />
|P16<br />
|P8<br />
|NS<br />
|-<br />
|align="left" |matrixOp<br />
|$30<br />
|N/A<br />
|style="color:silver; background:whitesmoke" |False<br />
|SO<br />
|style="color:silver; background:whitesmoke" |None<br />
|style="color:silver; background:whitesmoke" |None<br />
|-<br />
|align="left" |matrixOp$01<br />
|$01<br />
|setBoxFlags<br />
|style="color:silver; background:whitesmoke" |False<br />
|P8<br />
|P8<br />
|style="color:silver; background:whitesmoke" |None<br />
|-<br />
|align="left" |matrixOp$02<br />
|$02<br />
|setBoxScale<br />
|style="color:silver; background:whitesmoke" |False<br />
|P8<br />
|P8<br />
|style="color:silver; background:whitesmoke" |None<br />
|-<br />
|align="left" |matrixOp$03<br />
|$03<br />
|SetBoxSlot<br />
|style="color:silver; background:whitesmoke" |False<br />
|P8<br />
|P8<br />
|style="color:silver; background:whitesmoke" |None<br />
|-<br />
|align="left" |matrixOp$04<br />
|$04<br />
|createBoxMatrix<br />
|style="color:silver; background:whitesmoke" |False<br />
|style="color:silver; background:whitesmoke" |None<br />
|style="color:silver; background:whitesmoke" |None<br />
|style="color:silver; background:whitesmoke" |None<br />
|-<br />
|align="left" |move<br />
|$1A<br />
|(inline)<br />
|True<br />
|P16<br />
|style="color:silver; background:whitesmoke" |None<br />
|style="color:silver; background:whitesmoke" |None<br />
|-<br />
|align="left" |multiply<br />
|$1B<br />
|(inline)<br />
|True<br />
|P16<br />
|style="color:silver; background:whitesmoke" |None<br />
|style="color:silver; background:whitesmoke" |None<br />
|-<br />
|align="left" |notEqualZero<br />
|$A8<br />
|(inline)<br />
|style="color:silver; background:whitesmoke" |False<br />
|V<br />
|J<br />
|style="color:silver; background:whitesmoke" |None<br />
|-<br />
|align="left" |oldRoomEffect<br />
|$5C<br />
|oldRoomEffect-fadein<br />
|style="color:silver; background:whitesmoke" |False<br />
|SO<br />
|style="color:silver; background:whitesmoke" |None<br />
|style="color:silver; background:whitesmoke" |None<br />
|-<br />
|align="left" |oldRoomEffect$03<br />
|$03<br />
|oldRoomEffect-set<br />
|style="color:silver; background:whitesmoke" |False<br />
|P16<br />
|style="color:silver; background:whitesmoke" |None<br />
|style="color:silver; background:whitesmoke" |None<br />
|-<br />
|align="left" |or<br />
|$57<br />
|(inline)<br />
|True<br />
|P16<br />
|style="color:silver; background:whitesmoke" |None<br />
|style="color:silver; background:whitesmoke" |None<br />
|-<br />
|align="left" |override<br />
|$58<br />
|N/A<br />
|style="color:silver; background:whitesmoke" |False<br />
|SO<br />
|style="color:silver; background:whitesmoke" |None<br />
|style="color:silver; background:whitesmoke" |None<br />
|-<br />
|align="left" |override$00<br />
|$00<br />
|endOverride<br />
|style="color:silver; background:whitesmoke" |False<br />
|style="color:silver; background:whitesmoke" |None<br />
|style="color:silver; background:whitesmoke" |None<br />
|style="color:silver; background:whitesmoke" |None<br />
|-<br />
|align="left" |override$01<br />
|$01<br />
|beginOverride<br />
|style="color:silver; background:whitesmoke" |False<br />
|NS<br />
|J<br />
|style="color:silver; background:whitesmoke" |None<br />
|-<br />
|align="left" |panCameraTo<br />
|$12<br />
|style="color:silver; background:whitesmoke" |==<br />
|style="color:silver; background:whitesmoke" |False<br />
|P16<br />
|style="color:silver; background:whitesmoke" |None<br />
|style="color:silver; background:whitesmoke" |None<br />
|-<br />
|align="left" |pickupObject<br />
|$25<br />
|style="color:silver; background:whitesmoke" |==<br />
|style="color:silver; background:whitesmoke" |False<br />
|P16<br />
|P8<br />
|style="color:silver; background:whitesmoke" |None<br />
|-<br />
|align="left" |pickupObjectOld<br />
|$50<br />
|pickupObject<br />
|style="color:silver; background:whitesmoke" |False<br />
|P16<br />
|style="color:silver; background:whitesmoke" |None<br />
|style="color:silver; background:whitesmoke" |None<br />
|-<br />
|align="left" |print<br />
|$14<br />
|style="color:silver; background:whitesmoke" |==<br />
|style="color:silver; background:whitesmoke" |False<br />
|P8<br />
|SO+<br />
|style="color:silver; background:whitesmoke" |None<br />
|-<br />
|align="left" |print$00<br />
|$00<br />
|Pos<br />
|style="color:silver; background:whitesmoke" |False<br />
|P16<br />
|P16<br />
|style="color:silver; background:whitesmoke" |None<br />
|-<br />
|align="left" |print$01<br />
|$01<br />
|Color<br />
|style="color:silver; background:whitesmoke" |False<br />
|P8<br />
|style="color:silver; background:whitesmoke" |None<br />
|style="color:silver; background:whitesmoke" |None<br />
|-<br />
|align="left" |print$02<br />
|$02<br />
|Clipped<br />
|style="color:silver; background:whitesmoke" |False<br />
|P16<br />
|style="color:silver; background:whitesmoke" |None<br />
|style="color:silver; background:whitesmoke" |None<br />
|-<br />
|align="left" |print$03<br />
|$03<br />
|RestoreBG<br />
|style="color:silver; background:whitesmoke" |False<br />
|P16<br />
|P16<br />
|style="color:silver; background:whitesmoke" |None<br />
|-<br />
|align="left" |print$04<br />
|$04<br />
|Center<br />
|style="color:silver; background:whitesmoke" |False<br />
|style="color:silver; background:whitesmoke" |None<br />
|style="color:silver; background:whitesmoke" |None<br />
|style="color:silver; background:whitesmoke" |None<br />
|-<br />
|align="left" |print$06<br />
|$06<br />
|Left<br />
|style="color:silver; background:whitesmoke" |False<br />
|style="color:silver; background:whitesmoke" |None<br />
|style="color:silver; background:whitesmoke" |None<br />
|style="color:silver; background:whitesmoke" |None<br />
|-<br />
|align="left" |print$07<br />
|$07<br />
|Overhead<br />
|style="color:silver; background:whitesmoke" |False<br />
|style="color:silver; background:whitesmoke" |None<br />
|style="color:silver; background:whitesmoke" |None<br />
|style="color:silver; background:whitesmoke" |None<br />
|-<br />
|align="left" |print$08<br />
|$08<br />
|PlayCDTrack<br />
|style="color:silver; background:whitesmoke" |False<br />
|P16<br />
|P16<br />
|style="color:silver; background:whitesmoke" |None<br />
|-<br />
|align="left" |print$0F<br />
|$0F<br />
|Text()<br />
|style="color:silver; background:whitesmoke" |False<br />
|A1<br />
|style="color:silver; background:whitesmoke" |None<br />
|style="color:silver; background:whitesmoke" |None<br />
|-<br />
|align="left" |printEgo<br />
|$D8<br />
|style="color:silver; background:whitesmoke" |==<br />
|style="color:silver; background:whitesmoke" |False<br />
|SO+<br />
|style="color:silver; background:whitesmoke" |None<br />
|style="color:silver; background:whitesmoke" |None<br />
|-<br />
|align="left" |printEgo$00<br />
|$00<br />
|Pos<br />
|style="color:silver; background:whitesmoke" |False<br />
|P16<br />
|P16<br />
|style="color:silver; background:whitesmoke" |None<br />
|-<br />
|align="left" |printEgo$01<br />
|$01<br />
|Color<br />
|style="color:silver; background:whitesmoke" |False<br />
|P8<br />
|style="color:silver; background:whitesmoke" |None<br />
|style="color:silver; background:whitesmoke" |None<br />
|-<br />
|align="left" |printEgo$02<br />
|$02<br />
|Clipped<br />
|style="color:silver; background:whitesmoke" |False<br />
|P16<br />
|style="color:silver; background:whitesmoke" |None<br />
|style="color:silver; background:whitesmoke" |None<br />
|-<br />
|align="left" |printEgo$03<br />
|$03<br />
|RestoreBG<br />
|style="color:silver; background:whitesmoke" |False<br />
|P16<br />
|P16<br />
|style="color:silver; background:whitesmoke" |None<br />
|-<br />
|align="left" |printEgo$04<br />
|$04<br />
|Center<br />
|style="color:silver; background:whitesmoke" |False<br />
|style="color:silver; background:whitesmoke" |None<br />
|style="color:silver; background:whitesmoke" |None<br />
|style="color:silver; background:whitesmoke" |None<br />
|-<br />
|align="left" |printEgo$06<br />
|$06<br />
|Left<br />
|style="color:silver; background:whitesmoke" |False<br />
|style="color:silver; background:whitesmoke" |None<br />
|style="color:silver; background:whitesmoke" |None<br />
|style="color:silver; background:whitesmoke" |None<br />
|-<br />
|align="left" |printEgo$07<br />
|$07<br />
|Overhead<br />
|style="color:silver; background:whitesmoke" |False<br />
|style="color:silver; background:whitesmoke" |None<br />
|style="color:silver; background:whitesmoke" |None<br />
|style="color:silver; background:whitesmoke" |None<br />
|-<br />
|align="left" |printEgo$08<br />
|$08<br />
|PlayCDTrack<br />
|style="color:silver; background:whitesmoke" |False<br />
|P16<br />
|P16<br />
|style="color:silver; background:whitesmoke" |None<br />
|-<br />
|align="left" |printEgo$0F<br />
|$0F<br />
|Text()<br />
|style="color:silver; background:whitesmoke" |False<br />
|A1<br />
|style="color:silver; background:whitesmoke" |None<br />
|style="color:silver; background:whitesmoke" |None<br />
|-<br />
|align="left" |pseudoRoom<br />
|$CC<br />
|PsuedoRoom<br />
|style="color:silver; background:whitesmoke" |False<br />
|B<br />
|NS<br />
|NS<br />
|-<br />
|align="left" |putActor<br />
|$01<br />
|style="color:silver; background:whitesmoke" |==<br />
|style="color:silver; background:whitesmoke" |False<br />
|P8<br />
|P16<br />
|P16<br />
|-<br />
|align="left" |putActorAtObject<br />
|$0E<br />
|style="color:silver; background:whitesmoke" |==<br />
|style="color:silver; background:whitesmoke" |False<br />
|P8<br />
|P16<br />
|style="color:silver; background:whitesmoke" |None<br />
|-<br />
|align="left" |putActorInRoom<br />
|$2D<br />
|style="color:silver; background:whitesmoke" |==<br />
|style="color:silver; background:whitesmoke" |False<br />
|P8<br />
|P8<br />
|style="color:silver; background:whitesmoke" |None<br />
|-<br />
|align="left" |resourceRoutines<br />
|$0C<br />
|Resource.<br />
|style="color:silver; background:whitesmoke" |False<br />
|SO<br />
|style="color:silver; background:whitesmoke" |None<br />
|style="color:silver; background:whitesmoke" |None<br />
|-<br />
|align="left" |resourcesRoutines$01<br />
|$01<br />
|loadScript<br />
|style="color:silver; background:whitesmoke" |False<br />
|P8<br />
|style="color:silver; background:whitesmoke" |None<br />
|style="color:silver; background:whitesmoke" |None<br />
|-<br />
|align="left" |resourcesRoutines$02<br />
|$02<br />
|loadSound<br />
|style="color:silver; background:whitesmoke" |False<br />
|P8<br />
|style="color:silver; background:whitesmoke" |None<br />
|style="color:silver; background:whitesmoke" |None<br />
|-<br />
|align="left" |resourcesRoutines$03<br />
|$03<br />
|loadCostume<br />
|style="color:silver; background:whitesmoke" |False<br />
|P8<br />
|style="color:silver; background:whitesmoke" |None<br />
|style="color:silver; background:whitesmoke" |None<br />
|-<br />
|align="left" |resourcesRoutines$04<br />
|$04<br />
|loadRoom<br />
|style="color:silver; background:whitesmoke" |False<br />
|P8<br />
|style="color:silver; background:whitesmoke" |None<br />
|style="color:silver; background:whitesmoke" |None<br />
|-<br />
|align="left" |resourcesRoutines$05<br />
|$05<br />
|nukeScript<br />
|style="color:silver; background:whitesmoke" |False<br />
|P8<br />
|style="color:silver; background:whitesmoke" |None<br />
|style="color:silver; background:whitesmoke" |None<br />
|-<br />
|align="left" |resourcesRoutines$06<br />
|$06<br />
|nukeSound<br />
|style="color:silver; background:whitesmoke" |False<br />
|P8<br />
|style="color:silver; background:whitesmoke" |None<br />
|style="color:silver; background:whitesmoke" |None<br />
|-<br />
|align="left" |resourcesRoutines$07<br />
|$07<br />
|nukeCostume<br />
|style="color:silver; background:whitesmoke" |False<br />
|P8<br />
|style="color:silver; background:whitesmoke" |None<br />
|style="color:silver; background:whitesmoke" |None<br />
|-<br />
|align="left" |resourcesRoutines$08<br />
|$08<br />
|nukeRoom<br />
|style="color:silver; background:whitesmoke" |False<br />
|P8<br />
|style="color:silver; background:whitesmoke" |None<br />
|style="color:silver; background:whitesmoke" |None<br />
|-<br />
|align="left" |resourcesRoutines$09<br />
|$09<br />
|lockScript<br />
|style="color:silver; background:whitesmoke" |False<br />
|P8<br />
|style="color:silver; background:whitesmoke" |None<br />
|style="color:silver; background:whitesmoke" |None<br />
|-<br />
|align="left" |resourcesRoutines$0A<br />
|$0A<br />
|lockSound<br />
|style="color:silver; background:whitesmoke" |False<br />
|P8<br />
|style="color:silver; background:whitesmoke" |None<br />
|style="color:silver; background:whitesmoke" |None<br />
|-<br />
|align="left" |resourcesRoutines$0B<br />
|$0B<br />
|lockCostume<br />
|style="color:silver; background:whitesmoke" |False<br />
|P8<br />
|style="color:silver; background:whitesmoke" |None<br />
|style="color:silver; background:whitesmoke" |None<br />
|-<br />
|align="left" |resourcesRoutines$0C<br />
|$0C<br />
|lockRoom<br />
|style="color:silver; background:whitesmoke" |False<br />
|P8<br />
|style="color:silver; background:whitesmoke" |None<br />
|style="color:silver; background:whitesmoke" |None<br />
|-<br />
|align="left" |resourcesRoutines$0D<br />
|$0D<br />
|unlockScript<br />
|style="color:silver; background:whitesmoke" |False<br />
|P8<br />
|style="color:silver; background:whitesmoke" |None<br />
|style="color:silver; background:whitesmoke" |None<br />
|-<br />
|align="left" |resourcesRoutines$0E<br />
|$0E<br />
|unlockSound<br />
|style="color:silver; background:whitesmoke" |False<br />
|P8<br />
|style="color:silver; background:whitesmoke" |None<br />
|style="color:silver; background:whitesmoke" |None<br />
|-<br />
|align="left" |resourcesRoutines$0F<br />
|$0F<br />
|unlockCostume<br />
|style="color:silver; background:whitesmoke" |False<br />
|P8<br />
|style="color:silver; background:whitesmoke" |None<br />
|style="color:silver; background:whitesmoke" |None<br />
|-<br />
|align="left" |resourcesRoutines$10<br />
|$10<br />
|unlockRoom<br />
|style="color:silver; background:whitesmoke" |False<br />
|P8<br />
|style="color:silver; background:whitesmoke" |None<br />
|style="color:silver; background:whitesmoke" |None<br />
|-<br />
|align="left" |resourcesRoutines$11<br />
|$11<br />
|clearHeap<br />
|style="color:silver; background:whitesmoke" |False<br />
|style="color:silver; background:whitesmoke" |None<br />
|style="color:silver; background:whitesmoke" |None<br />
|style="color:silver; background:whitesmoke" |None<br />
|-<br />
|align="left" |resourcesRoutines$12<br />
|$12<br />
|loadCharset<br />
|style="color:silver; background:whitesmoke" |False<br />
|P8<br />
|style="color:silver; background:whitesmoke" |None<br />
|style="color:silver; background:whitesmoke" |None<br />
|-<br />
|align="left" |resourcesRoutines$13<br />
|$13<br />
|nukeCharset<br />
|style="color:silver; background:whitesmoke" |False<br />
|P8<br />
|style="color:silver; background:whitesmoke" |None<br />
|style="color:silver; background:whitesmoke" |None<br />
|-<br />
|align="left" |resourcesRoutines$14<br />
|$14<br />
|loadFlObject<br />
|style="color:silver; background:whitesmoke" |False<br />
|P8<br />
|P16<br />
|style="color:silver; background:whitesmoke" |None<br />
|-<br />
|align="left" |roomOps<br />
|$33<br />
|N/A<br />
|style="color:silver; background:whitesmoke" |False<br />
|SO<br />
|style="color:silver; background:whitesmoke" |None<br />
|style="color:silver; background:whitesmoke" |None<br />
|-<br />
|align="left" |roomOps$01<br />
|$01<br />
|RoomScroll<br />
|style="color:silver; background:whitesmoke" |False<br />
|P16<br />
|P16<br />
|style="color:silver; background:whitesmoke" |None<br />
|-<br />
|align="left" |roomOps$03<br />
|$03<br />
|SetScreen<br />
|style="color:silver; background:whitesmoke" |False<br />
|P16<br />
|P16<br />
|style="color:silver; background:whitesmoke" |None<br />
|-<br />
|align="left" |roomOps$04<br />
|$04<br />
|SetPalColor<br />
|style="color:silver; background:whitesmoke" |False<br />
|P16<br />
|P16<br />
|NS<br />
|-<br />
|align="left" |roomOps$05<br />
|$05<br />
|ShakeOn<br />
|style="color:silver; background:whitesmoke" |False<br />
|style="color:silver; background:whitesmoke" |None<br />
|style="color:silver; background:whitesmoke" |None<br />
|style="color:silver; background:whitesmoke" |None<br />
|-<br />
|align="left" |roomOps$06<br />
|$06<br />
|ShakeOff<br />
|style="color:silver; background:whitesmoke" |False<br />
|style="color:silver; background:whitesmoke" |None<br />
|style="color:silver; background:whitesmoke" |None<br />
|style="color:silver; background:whitesmoke" |None<br />
|-<br />
|align="left" |roomOps$07<br />
|$07<br />
|Unused<br />
|style="color:silver; background:whitesmoke" |False<br />
|P8<br />
|P8<br />
|NS<br />
|-<br />
|align="left" |roomOps$08<br />
|$08<br />
|RoomIntensity<br />
|style="color:silver; background:whitesmoke" |False<br />
|P8<br />
|P8<br />
|P8<br />
|-<br />
|align="left" |roomOps$09<br />
|$09<br />
|saveLoad?<br />
|style="color:silver; background:whitesmoke" |False<br />
|P8<br />
|P8<br />
|style="color:silver; background:whitesmoke" |None<br />
|-<br />
|align="left" |roomOps$0A<br />
|$0A<br />
|screenEffect?<br />
|style="color:silver; background:whitesmoke" |False<br />
|P16<br />
|style="color:silver; background:whitesmoke" |None<br />
|style="color:silver; background:whitesmoke" |None<br />
|-<br />
|align="left" |roomOps$0B<br />
|$0B<br />
|setRGBRoomIntensity<br />
|style="color:silver; background:whitesmoke" |False<br />
|P16<br />
|P16<br />
|NS<br />
|-<br />
|align="left" |roomOps$0C<br />
|$0C<br />
|setRoomShadow<br />
|style="color:silver; background:whitesmoke" |False<br />
|P16<br />
|P16<br />
|NS<br />
|-<br />
|align="left" |roomOps$0D<br />
|$0D<br />
|saveString<br />
|style="color:silver; background:whitesmoke" |False<br />
|P8<br />
|A0<br />
|style="color:silver; background:whitesmoke" |None<br />
|-<br />
|align="left" |roomOps$0E<br />
|$0E<br />
|loadString<br />
|style="color:silver; background:whitesmoke" |False<br />
|P8<br />
|A0<br />
|style="color:silver; background:whitesmoke" |None<br />
|-<br />
|align="left" |roomOps$0F<br />
|$0F<br />
|palManipulate<br />
|style="color:silver; background:whitesmoke" |False<br />
|P8<br />
|NS<br />
|NS<br />
|-<br />
|align="left" |roomOps$10<br />
|$10<br />
|colorCycleDelay<br />
|style="color:silver; background:whitesmoke" |False<br />
|P8<br />
|P8<br />
|style="color:silver; background:whitesmoke" |None<br />
|-<br />
|align="left" |saveRestoreVerbs<br />
|$AB<br />
|N/A<br />
|style="color:silver; background:whitesmoke" |False<br />
|NS<br />
|NS<br />
|NS<br />
|-<br />
|align="left" |saveRestoreVerbs$01<br />
|$01<br />
|saveVerbs<br />
|style="color:silver; background:whitesmoke" |False<br />
|style="color:silver; background:whitesmoke" |None<br />
|style="color:silver; background:whitesmoke" |None<br />
|style="color:silver; background:whitesmoke" |None<br />
|-<br />
|align="left" |saveRestoreVerbs$02<br />
|$02<br />
|restoreVerbs<br />
|style="color:silver; background:whitesmoke" |False<br />
|style="color:silver; background:whitesmoke" |None<br />
|style="color:silver; background:whitesmoke" |None<br />
|style="color:silver; background:whitesmoke" |None<br />
|-<br />
|align="left" |saveRestoreVerbs$03<br />
|$03<br />
|deleteVerbs<br />
|style="color:silver; background:whitesmoke" |False<br />
|style="color:silver; background:whitesmoke" |None<br />
|style="color:silver; background:whitesmoke" |None<br />
|style="color:silver; background:whitesmoke" |None<br />
|-<br />
|align="left" |setCameraAt<br />
|$32<br />
|style="color:silver; background:whitesmoke" |==<br />
|style="color:silver; background:whitesmoke" |False<br />
|P16<br />
|style="color:silver; background:whitesmoke" |None<br />
|style="color:silver; background:whitesmoke" |None<br />
|-<br />
|align="left" |setObjectName<br />
|$54<br />
|style="color:silver; background:whitesmoke" |==<br />
|style="color:silver; background:whitesmoke" |False<br />
|P16<br />
|A0<br />
|style="color:silver; background:whitesmoke" |None<br />
|-<br />
|align="left" |setOwnerOf<br />
|$29<br />
|style="color:silver; background:whitesmoke" |==<br />
|style="color:silver; background:whitesmoke" |False<br />
|P16<br />
|P8<br />
|style="color:silver; background:whitesmoke" |None<br />
|-<br />
|align="left" |setState<br />
|$07<br />
|style="color:silver; background:whitesmoke" |==<br />
|style="color:silver; background:whitesmoke" |False<br />
|P16<br />
|P8<br />
|style="color:silver; background:whitesmoke" |None<br />
|-<br />
|align="left" |setVarRange<br />
|$26<br />
|style="color:silver; background:whitesmoke" |==<br />
|True<br />
|B<br />
|NS<br />
|NS<br />
|-<br />
|align="left" |soundKludge<br />
|$4C<br />
|style="color:silver; background:whitesmoke" |==<br />
|style="color:silver; background:whitesmoke" |False<br />
|L<br />
|style="color:silver; background:whitesmoke" |None<br />
|style="color:silver; background:whitesmoke" |None<br />
|-<br />
|align="left" |startMusic<br />
|$02<br />
|style="color:silver; background:whitesmoke" |==<br />
|style="color:silver; background:whitesmoke" |False<br />
|P8<br />
|style="color:silver; background:whitesmoke" |None<br />
|style="color:silver; background:whitesmoke" |None<br />
|-<br />
|align="left" |startObject<br />
|$37<br />
|style="color:silver; background:whitesmoke" |==<br />
|style="color:silver; background:whitesmoke" |False<br />
|P16<br />
|P8<br />
|L<br />
|-<br />
|align="left" |startScript<br />
|$0A<br />
|style="color:silver; background:whitesmoke" |==<br />
|style="color:silver; background:whitesmoke" |False<br />
|P8<br />
|L<br />
|style="color:silver; background:whitesmoke" |None<br />
|-<br />
|align="left" |startSound<br />
|$1C<br />
|style="color:silver; background:whitesmoke" |==<br />
|style="color:silver; background:whitesmoke" |False<br />
|P8<br />
|style="color:silver; background:whitesmoke" |None<br />
|style="color:silver; background:whitesmoke" |None<br />
|-<br />
|align="left" |stopMusic<br />
|$20<br />
|style="color:silver; background:whitesmoke" |==<br />
|style="color:silver; background:whitesmoke" |False<br />
|style="color:silver; background:whitesmoke" |None<br />
|style="color:silver; background:whitesmoke" |None<br />
|style="color:silver; background:whitesmoke" |None<br />
|-<br />
|align="left" |stopObjectCode<br />
|$A0<br />
|style="color:silver; background:whitesmoke" |==<br />
|style="color:silver; background:whitesmoke" |False<br />
|style="color:silver; background:whitesmoke" |None<br />
|style="color:silver; background:whitesmoke" |None<br />
|style="color:silver; background:whitesmoke" |None<br />
|-<br />
|align="left" |stopObjectScript<br />
|$6E<br />
|style="color:silver; background:whitesmoke" |==<br />
|style="color:silver; background:whitesmoke" |False<br />
|P16<br />
|style="color:silver; background:whitesmoke" |None<br />
|style="color:silver; background:whitesmoke" |None<br />
|-<br />
|align="left" |stopScript<br />
|$62<br />
|style="color:silver; background:whitesmoke" |==<br />
|style="color:silver; background:whitesmoke" |False<br />
|P8<br />
|style="color:silver; background:whitesmoke" |None<br />
|style="color:silver; background:whitesmoke" |None<br />
|-<br />
|align="left" |stopSound<br />
|$3C<br />
|style="color:silver; background:whitesmoke" |==<br />
|style="color:silver; background:whitesmoke" |False<br />
|P8<br />
|style="color:silver; background:whitesmoke" |None<br />
|style="color:silver; background:whitesmoke" |None<br />
|-<br />
|align="left" |stringOps<br />
|$27<br />
|style="color:silver; background:whitesmoke" |==<br />
|style="color:silver; background:whitesmoke" |False<br />
|SO<br />
|style="color:silver; background:whitesmoke" |None<br />
|style="color:silver; background:whitesmoke" |None<br />
|-<br />
|align="left" |stringOps$01<br />
|$01<br />
|PutCodeInString<br />
|style="color:silver; background:whitesmoke" |False<br />
|P8<br />
|A0<br />
|style="color:silver; background:whitesmoke" |None<br />
|-<br />
|align="left" |stringOps$02<br />
|$02<br />
|CopyString<br />
|style="color:silver; background:whitesmoke" |False<br />
|P8<br />
|P8<br />
|style="color:silver; background:whitesmoke" |None<br />
|-<br />
|align="left" |stringOps$03<br />
|$03<br />
|SetStringChar<br />
|style="color:silver; background:whitesmoke" |False<br />
|P8<br />
|P8<br />
|B<br />
|-<br />
|align="left" |stringOps$04<br />
|$04<br />
|GetStringChar<br />
|True<br />
|P8<br />
|P8<br />
|style="color:silver; background:whitesmoke" |None<br />
|-<br />
|align="left" |stringOps$05<br />
|$05<br />
|CreateString<br />
|style="color:silver; background:whitesmoke" |False<br />
|P8<br />
|P8<br />
|style="color:silver; background:whitesmoke" |None<br />
|-<br />
|align="left" |subtract<br />
|$3A<br />
|(inline)<br />
|True<br />
|P16<br />
|style="color:silver; background:whitesmoke" |None<br />
|style="color:silver; background:whitesmoke" |None<br />
|-<br />
|align="left" |systemOps<br />
|$98<br />
|systemOps<br />
|style="color:silver; background:whitesmoke" |False<br />
|SO<br />
|style="color:silver; background:whitesmoke" |None<br />
|style="color:silver; background:whitesmoke" |None<br />
|-<br />
|align="left" |systemOps$01<br />
|$01<br />
|N/A<br />
|style="color:silver; background:whitesmoke" |False<br />
|style="color:silver; background:whitesmoke" |None<br />
|style="color:silver; background:whitesmoke" |None<br />
|style="color:silver; background:whitesmoke" |None<br />
|-<br />
|align="left" |systemOps$02<br />
|$02<br />
|N/A<br />
|style="color:silver; background:whitesmoke" |False<br />
|style="color:silver; background:whitesmoke" |None<br />
|style="color:silver; background:whitesmoke" |None<br />
|style="color:silver; background:whitesmoke" |None<br />
|-<br />
|align="left" |systemOps$03<br />
|$03<br />
|N/A<br />
|style="color:silver; background:whitesmoke" |False<br />
|style="color:silver; background:whitesmoke" |None<br />
|style="color:silver; background:whitesmoke" |None<br />
|style="color:silver; background:whitesmoke" |None<br />
|-<br />
|align="left" |verbOps<br />
|$7A<br />
|VerbOps<br />
|style="color:silver; background:whitesmoke" |False<br />
|P8<br />
|SO+<br />
|FF<br />
|-<br />
|align="left" |verbOps$01<br />
|$01<br />
|Image<br />
|style="color:silver; background:whitesmoke" |False<br />
|P16<br />
|style="color:silver; background:whitesmoke" |None<br />
|style="color:silver; background:whitesmoke" |None<br />
|-<br />
|align="left" |verbOps$02<br />
|$02<br />
|Text<br />
|style="color:silver; background:whitesmoke" |False<br />
|A0<br />
|style="color:silver; background:whitesmoke" |None<br />
|style="color:silver; background:whitesmoke" |None<br />
|-<br />
|align="left" |verbOps$03<br />
|$03<br />
|Color<br />
|style="color:silver; background:whitesmoke" |False<br />
|P8<br />
|style="color:silver; background:whitesmoke" |None<br />
|style="color:silver; background:whitesmoke" |None<br />
|-<br />
|align="left" |verbOps$04<br />
|$04<br />
|HiColor<br />
|style="color:silver; background:whitesmoke" |False<br />
|P8<br />
|style="color:silver; background:whitesmoke" |None<br />
|style="color:silver; background:whitesmoke" |None<br />
|-<br />
|align="left" |verbOps$05<br />
|$05<br />
|SetXY<br />
|style="color:silver; background:whitesmoke" |False<br />
|P16<br />
|P16<br />
|style="color:silver; background:whitesmoke" |None<br />
|-<br />
|align="left" |verbOps$06<br />
|$06<br />
|On<br />
|style="color:silver; background:whitesmoke" |False<br />
|style="color:silver; background:whitesmoke" |None<br />
|style="color:silver; background:whitesmoke" |None<br />
|style="color:silver; background:whitesmoke" |None<br />
|-<br />
|align="left" |verbOps$07<br />
|$07<br />
|Off<br />
|style="color:silver; background:whitesmoke" |False<br />
|style="color:silver; background:whitesmoke" |None<br />
|style="color:silver; background:whitesmoke" |None<br />
|style="color:silver; background:whitesmoke" |None<br />
|-<br />
|align="left" |verbOps$08<br />
|$08<br />
|Delete<br />
|style="color:silver; background:whitesmoke" |False<br />
|style="color:silver; background:whitesmoke" |None<br />
|style="color:silver; background:whitesmoke" |None<br />
|style="color:silver; background:whitesmoke" |None<br />
|-<br />
|align="left" |verbOps$09<br />
|$09<br />
|New<br />
|style="color:silver; background:whitesmoke" |False<br />
|style="color:silver; background:whitesmoke" |None<br />
|style="color:silver; background:whitesmoke" |None<br />
|style="color:silver; background:whitesmoke" |None<br />
|-<br />
|align="left" |verbOps$10<br />
|$10<br />
|DimColor<br />
|style="color:silver; background:whitesmoke" |False<br />
|P8<br />
|style="color:silver; background:whitesmoke" |None<br />
|style="color:silver; background:whitesmoke" |None<br />
|-<br />
|align="left" |verbOps$11<br />
|$11<br />
|Dim<br />
|style="color:silver; background:whitesmoke" |False<br />
|style="color:silver; background:whitesmoke" |None<br />
|style="color:silver; background:whitesmoke" |None<br />
|style="color:silver; background:whitesmoke" |None<br />
|-<br />
|align="left" |verbOps$12<br />
|$12<br />
|Key<br />
|style="color:silver; background:whitesmoke" |False<br />
|P8<br />
|style="color:silver; background:whitesmoke" |None<br />
|style="color:silver; background:whitesmoke" |None<br />
|-<br />
|align="left" |verbOps$13<br />
|$13<br />
|Center<br />
|style="color:silver; background:whitesmoke" |False<br />
|style="color:silver; background:whitesmoke" |None<br />
|style="color:silver; background:whitesmoke" |None<br />
|style="color:silver; background:whitesmoke" |None<br />
|-<br />
|align="left" |verbOps$14<br />
|$14<br />
|SetToString<br />
|style="color:silver; background:whitesmoke" |False<br />
|P16<br />
|style="color:silver; background:whitesmoke" |None<br />
|style="color:silver; background:whitesmoke" |None<br />
|-<br />
|align="left" |verbOps$16<br />
|$16<br />
|SetToObject<br />
|style="color:silver; background:whitesmoke" |False<br />
|P16<br />
|P8<br />
|style="color:silver; background:whitesmoke" |None<br />
|-<br />
|align="left" |verbOps$17<br />
|$17<br />
|BackColor<br />
|style="color:silver; background:whitesmoke" |False<br />
|P8<br />
|style="color:silver; background:whitesmoke" |None<br />
|style="color:silver; background:whitesmoke" |None<br />
|-<br />
|align="left" |wait<br />
|$AE<br />
|N/A<br />
|style="color:silver; background:whitesmoke" |False<br />
|SO<br />
|style="color:silver; background:whitesmoke" |None<br />
|style="color:silver; background:whitesmoke" |None<br />
|-<br />
|align="left" |wait$01<br />
|$01<br />
|WaitForActor<br />
|style="color:silver; background:whitesmoke" |False<br />
|P8<br />
|style="color:silver; background:whitesmoke" |None<br />
|style="color:silver; background:whitesmoke" |None<br />
|-<br />
|align="left" |wait$02<br />
|$02<br />
|WaitForMessage<br />
|style="color:silver; background:whitesmoke" |False<br />
|style="color:silver; background:whitesmoke" |None<br />
|style="color:silver; background:whitesmoke" |None<br />
|style="color:silver; background:whitesmoke" |None<br />
|-<br />
|align="left" |wait$03<br />
|$03<br />
|WaitForCamera<br />
|style="color:silver; background:whitesmoke" |False<br />
|style="color:silver; background:whitesmoke" |None<br />
|style="color:silver; background:whitesmoke" |None<br />
|style="color:silver; background:whitesmoke" |None<br />
|-<br />
|align="left" |wait$04<br />
|$04<br />
|WaitForSentence<br />
|style="color:silver; background:whitesmoke" |False<br />
|style="color:silver; background:whitesmoke" |None<br />
|style="color:silver; background:whitesmoke" |None<br />
|style="color:silver; background:whitesmoke" |None<br />
|-<br />
|align="left" |walkActorTo<br />
|$1E<br />
|style="color:silver; background:whitesmoke" |==<br />
|style="color:silver; background:whitesmoke" |False<br />
|P8<br />
|P16<br />
|P16<br />
|-<br />
|align="left" |walkActorToActor<br />
|$0D<br />
|style="color:silver; background:whitesmoke" |==<br />
|style="color:silver; background:whitesmoke" |False<br />
|P8<br />
|P8<br />
|B<br />
|-<br />
|align="left" |walkActorToObject<br />
|$36<br />
|style="color:silver; background:whitesmoke" |==<br />
|style="color:silver; background:whitesmoke" |False<br />
|P8<br />
|P16<br />
|style="color:silver; background:whitesmoke" |None<br />
|}</div>Jestar jokinhttps://wiki.scummvm.org/index.php?title=SCUMM/V5_opcodes&diff=10981SCUMM/V5 opcodes2009-04-19T02:34:23Z<p>Jestar jokin: /* resourceRoutines ($0C) */ clearHeap doesn't take an argument</p>
<hr />
<div>=SCUMM V5 opcodes=<br />
The following conventions are used in the encoding descriptions.<br />
<br />
{| border="1" cellpadding="2" width=100%<br />
|- style="background:whitesmoke"<br />
|Term||Description<br />
|-<br />
|opcode||The instruction's opcode, with the appropriate bits set according to the parameters.<br />
|-<br />
|aux||An aux opcode that stores parameter bits and no other information. (the base aux opcode seems to always be $01)<br />
|-<br />
|sub-opcode||An aux opcode that indicates a specific function to perform (e.g. the "wait" instruction has sub-opcodes to "wait for message", "wait for actor" etc), as well as storing parameter bits if necessary.<br />
|-<br />
|result||A result pointer. (A standard word pointer, always a LE word.)<br />
|-<br />
|var||A var pointer. Same as above, but is not written to. Because this is always a var, the opcode is not affected like with normal parameter/pointers.<br />
|-<br />
|value[8]||An 8-bit constant (a byte).<br />
|-<br />
|value[16]||A 16-bit constant (a word LE).<br />
|-<br />
|value[p8]||An 8-bit parameter. This may be encoded as a word LE if it's a pointer, or a byte if it's a constant.<br />
|-<br />
|value[p16]||A 16-bit parameter. This is always encoded as a word LE, and may be a pointer or constant.<br />
|-<br />
|value[v16]||A variable number of word LE parameters. These are encoded as a sequence of aux[8] param[p16]; param; aux contains the parameter bit to describe param (and is always $01, ignoring the parameter bits). A byte of $FF terminates the sequence. (actually always shown as "value[v16]...")<br />
|-<br />
|value[o]||The offset word for parameter value. This is only encoded if needed, but always at the position indicated. If not specified, the offset word occurs immediately after the parameter.<br />
|-<br />
|value[c]||An ASCII character. Because some instructions use null-terminated strings and some use $FF, the exact format of a string is described in the instruction. Almost always appears as "value[c]..."<br />
|-<br />
|term...||One or more terms.<br />
|}<br />
<br />
Of course, due to the non-orthogonality of the opcodes, there are lots of exceptions.<br />
<br />
<br />
==actorFollowCamera ($52)==<br />
<br />
===Encoding===<br />
opcode actor[p8]<br />
<br />
===Operation===<br />
Sets the camera to follow the given actor?<br />
<br />
<br />
==actorFromPos ($15)==<br />
<br />
===Encoding===<br />
opcode result x[p16] y[p16]<br />
<br />
===Operation===<br />
Returns the actor located at the given co-ordinates.<br />
<br />
<br />
==actorOps ($13)==<br />
parameters depend on auxiliary opcode; terminated by $FF<br />
<br />
===Encoding===<br />
opcode actor[p8] sub-opcode... $FF<br />
<br />
sub-opcodes:<br />
$00 arg1[p8]<br />
$01 costume[p8]<br />
$02 xspeed[p8] yspeed[p8]<br />
$03 sound[p8]<br />
$04 walkframe[p8]<br />
$05 starttalk[p8] endtalk[p8]<br />
$06 standframe[p8]<br />
$07 arg1[p8] arg2[p8] arg3[p8]<br />
$08<br />
$09 elevation[p16]<br />
$0A<br />
$0B index[p8] value[p8]<br />
$0C colour[p8]<br />
$0D name[c]... $00<br />
$0E initframe[p8]<br />
$10 width[p8]<br />
$11 xscale[p8] yscale[p8]<br />
$12<br />
$13 zplane[p8]<br />
$14<br />
$15 animspeed[p8]<br />
$16 mode[p8]<br />
$17 shadow[p8]<br />
<br />
===Operation===<br />
Miscellaneous actions on actors.<br />
<br />
{| border="1" cellpadding="2" width=100%<br />
|- style="background:whitesmoke"<br />
|Opcode||Meaning||Description<br />
|-<br />
|$00||dummy||A dummy case, does nothing (in ScummVM).<br />
|-<br />
|$01||SO_COSTUME||Sets the actor's costume.<br />
|-<br />
|$02||SO_STEP_DIST||Sets the actor's walking speed for x and y.<br />
|-<br />
|$03||SO_SOUND||Associates a sound with the actor (footsteps?)<br />
|-<br />
|$04||SO_WALK_ANIMATION||Sets the current frame of the walking animation.<br />
|-<br />
|$05||SO_TALK_ANIMATION||Sets the start and stop frames of the talking animation.<br />
|-<br />
|$06||SO_STAND_ANIMATION||Sets the current frame of the standing animation.<br />
|-<br />
|$07||SO_ANIMATION||Unknown; seems to be unused in ScummVM.<br />
|-<br />
|$08||SO_DEFAULT||Initializes actor.<br />
|-<br />
|$09||SO_ELEVATION||Sets the actor's elevation to the given value.<br />
|-<br />
|$0A||SO_ANIMATION_DEFAULT||Initializes the actor's animation frames.<br>Init frame = 1<br>Walk frame = 2<br>Stand frame = 3<br>Talk start frame = 4<br>Talk stop frame = 5<br />
|-<br />
|$0B||SO_PALETTE||Sets the colour at the given index to a new value (another entry in the colour lookup table/CLUT). Index must be between 0 and 31 (the number of colours in a costume).<br />
|-<br />
|$0C||SO_TALK_COLOR||Sets the actor's talk colour.<br />
|-<br />
|$0D||SO_ACTOR_NAME||Sets the actor's name to the given null-terminated string.<br />
|-<br />
|$0E||SO_INIT_ANIMATION||Sets the current frame of the initial animation.<br />
|-<br />
|$10||SO_ACTOR_WIDTH||Sets the actor's width.<br />
|-<br />
|$11||SO_ACTOR_SCALE||Sets the actor's X and Y scales.<br />
|-<br />
|$12||SO_NEVER_ZCLIP||Turns off all Z-clipping for the actor.<br />
|-<br />
|$13||SO_ALWAYS_ZCLIP||Forces the actor's Z-clipping for the given Z-plane?<br />
|-<br />
|$14||SO_IGNORE_BOXES||Ignores boxes, turns off Z-clipping, and puts actor somewhere if the actor is in the current room?<br />
|-<br />
|$15||SO_FOLLOW_BOXES||Follows boxes, turns off Z-clipping, and puts actor somewhere if the actor is in the current room?<br />
|-<br />
|$16||SO_ANIMATION_SPEED||Sets the animatino speed<br />
|-<br />
|$17||SO_SHADOW||Sets the shadow mode.<br />
|}<br />
<br />
===Variants===<br />
In SCUMM V4, sub-opcode $11 (SO_ACTOR_SCALE) only takes one parameter, so X and Y scaling is done at a 1:1 ratio.<br />
<br />
<br />
==actorSetClass ($5D)==<br />
<br />
===Encoding===<br />
opcode object[p16] classes[v16]...<br />
<br />
===Operation===<br />
Makes object inherit from all of the given classes. A class of "0" will clear all of the object's existing class data.<br />
<br />
<br />
==add ($5A)==<br />
<br />
===Encoding===<br />
opcode result value[p16]<br />
<br />
===Operation===<br />
result := result + value<br />
<br />
The variable pointed to by result is read, value is added to it, and the result written back.<br />
<br />
<br />
==and ($17)==<br />
one parameter, uses result<br />
<br />
===Encoding===<br />
opcode result value[p16]<br />
<br />
===Operation===<br />
result := result and value<br />
<br />
The variable pointed to by result is read, logically ANDed with value, and the result written back.<br />
<br />
<br />
==animateActor ($11)==<br />
<br />
===Encoding===<br />
opcode actor[p8] anim[p8]<br />
<br />
===Operation===<br />
Starts the given animation for the given actor.<br />
<br />
<br />
==breakHere ($80)==<br />
no parameters<br />
<br />
===Encoding===<br />
opcode<br />
<br />
===Operation===<br />
Deschedules the currently running thread. Execution continues at the next instruction when the thread's next timeslot comes around.<br />
<br />
<br />
==chainScript ($42)==<br />
one parameter plus varargs<br />
<br />
===Encoding===<br />
opcode script[p8] args[v16]...<br />
<br />
===Operation===<br />
Replaces the currently running script with another one. The current script is terminated immediately and the new script (determined by the given script ID), is executed in the same thread. The new script has its local variables initialised to the list args. Uninitialised variables have undefined values.<br />
<br />
<br />
==cursorCommand ($2C)==<br />
parameters depend on auxiliary opcode<br />
<br />
===Encoding===<br />
opcode sub-opcode<br />
<br />
sub-opcode can be any of the following:<br />
$01<br />
... $01 through $08 take the same arguments ...<br />
$08<br />
$0A cursornum[p8] charletter[p8]<br />
$0B index[p8] x[p8] y[p8]<br />
$0C cursor[p8]<br />
$0D charset[p8]<br />
$0E colours[v16]...<br />
<br />
===Operation===<br />
Miscellaneous actions on cursors & charsets.<br />
<br />
{| border="1" cellpadding="2" width=100%<br />
|- style="background:whitesmoke"<br />
|Opcode||Meaning||Description<br />
|-<br />
|$01||SO_CURSOR_ON||Turns the cursor on.<br />
|-<br />
|$02||SO_CURSOR_OFF||Turns the cursor off.<br />
|-<br />
|$03||SO_USERPUT_ON||Enables user input.<br />
|-<br />
|$04||SO_USERPUT_OFF||Disables user input.<br />
|-<br />
|$05||SO_CURSOR_SOFT_ON||Increments the cursor's state?<br />
|-<br />
|$06||SO_CURSOR_SOFT_OFF||Decrements the cursor's state?<br />
|-<br />
|$07||SO_USERPUT_SOFT_ON||Increments "user input" counter (when greater than 0, user input is enabled).<br />
|-<br />
|$08||SO_USERPUT_SOFT_OFF||Decrements "user input" counter (when 0 or less, user input is disabled).<br />
|-<br />
|$0A||SO_CURSOR_IMAGE||Changes the cursor image to a new one, based on image in a character set. Only used in Loom.<br />
|-<br />
|$0B||SO_CURSOR_HOTSPOT||Changes the hotspot of a cursor. Only used in Loom.<br />
|-<br />
|$0C||SO_CURSOR_SET||Changes the current cursor. Must be between 0 and 3 inclusive.<br />
|-<br />
|$0D||SO_CHARSET_SET||Initializes the given character set.<br />
|-<br />
|$0E||SO_CHARSET_COLORS||Initializes the character set data & colours to the given arguments? Must have 16 arguments?<br />
|}<br />
<br />
===Variants===<br />
In SCUMM V3, sub-opcode $0E performs a different function, to load/initialize a character set.<br />
<br />
opcode $0E arg1[p8] arg2[p8]<br />
<br />
<br />
==cutScene ($40)==<br />
<br />
===Encoding===<br />
opcode args[v16]...<br />
<br />
===Operation===<br />
??? If required, runs a script passing the given arguments. Cutscene data given by the first argument?<br />
<br />
<br />
==debug ($6B)==<br />
one parameter, no result<br />
<br />
===Encoding===<br />
opcode param[p16]<br />
<br />
===Operation===<br />
Passes the parameter to the interpreter's debugger. What this does is entirely platform-specific (and may do nothing).<br />
<br />
<br />
==decrement ($C6)==<br />
no parameters, uses result<br />
<br />
===Encoding===<br />
opcode result<br />
<br />
===Operation===<br />
result := result - 1<br />
<br />
Reads the variable pointed to by result, decrements it, and writes it back. <br />
<br />
<br />
==delay ($2E)==<br />
one constant parameter<br />
<br />
===Encoding===<br />
opcode param[24]<br />
<br />
===Operation===<br />
Suspends the current thread for the appropriate number of 1/60ths of a second. Yes, that really is a 24-bit LE constant.<br />
<br />
<br />
==delayVariable ($2B)==<br />
one constant parameter<br />
<br />
===Encoding===<br />
opcode var<br />
<br />
===Operation===<br />
var is dereferenced and the current thread suspended for that number of 1/60ths of a second.<br />
<br />
<br />
==divide ($5B)==<br />
one parameter, uses result<br />
<br />
===Encoding===<br />
opcode result value[p16]<br />
<br />
===Operation===<br />
result := result / value<br />
<br />
The variable pointed to by result is read, divided by value, and the result written back. If value is zero, the result is undefined (and the interpeter may halt with an error). <br />
<br />
<br />
==doSentence ($19)==<br />
<br />
===Encoding===<br />
opcode verb[p8] objectA[p16] objectB[p16]<br />
<br />
===Operation===<br />
Performs a verb sentence action, e.g. "Use monkey on hydrant". If verb is $FE, the current sentence script is stopped, status cleared etc.<br />
<br />
<br />
==drawBox ($3F)==<br />
two parameters, does not use result, supplementary opcode byte with three more subsequent parameters<br />
<br />
===Encoding===<br />
opcode left[p16] top[p16] auxopcode[8] right[p16] bottom[p16] colour[p8]<br />
<br />
===Operation===<br />
Draws a solid box on the backbuffer from (left, top)-(right, bottom) in the given colour.<br />
<br />
The only part of auxopcode that is relevant are the parameter bits. The rest of the opcode is ignored. <br />
<br />
<br />
==drawObject ($05)==<br />
<br />
===Encoding===<br />
opcode object[p16] sub-opcode<br />
<br />
sub-opcodes:<br />
$01 xpos[p16] ypos[p16]<br />
$02 state[p16]<br />
$1F<br />
<br />
===Operation===<br />
{| border="1" cellpadding="2" width=100%<br />
|- style="background:whitesmoke"<br />
|Opcode||Meaning||Description<br />
|-<br />
|$01||Draw At||Moves the given object to the given co-ordinates, and adds it to the drawing queue.<br />
|-<br />
|$02||Set State||Sets the state of the object, adds it to the drawing queue.<br />
|-<br />
|$1F||Draw||Does not change the object's position (or state?), still adds it to the drawing queue.<br />
|}<br />
<br />
===Variants===<br />
Small header games only support the parameters used with sub-opcode $01, e.g:<br />
opcode object[p16] xpos[p16] ypos[p16]<br />
<br />
<br />
==dummy ($A7)==<br />
<br />
===Encoding===<br />
opcode<br />
<br />
===Operation===<br />
V5 specific - The KIXX XL release of Monkey Island 2 (Amiga disk) used this opcode as a dummy, in order to remove copy protection and keep level selection.<br />
<br />
===Variants===<br />
In SCUMM V3 and V4, this opcode is used for the saveLoadVars instruction.<br />
<br />
<br />
==endCutScene ($C0)==<br />
<br />
===Encoding===<br />
opcode<br />
<br />
===Operation===<br />
Ends the cutscene, performing cleanup if necessary.<br />
<br />
<br />
==equalZero ($28)==<br />
jumps<br />
<br />
===Encoding===<br />
opcode var target[16]<br />
<br />
===Operation===<br />
unless (var == 0) goto target<br />
<br />
Target is a byte offset (measured from after this instruction), which will be added to the instruction pointer.<br />
<br />
<br />
==expression ($AC)==<br />
<br />
===Encoding===<br />
opcode result subopcode... $FF<br />
<br />
sub-opcodes:<br />
$01 value[p16]<br />
$02<br />
... $02 through $05 take the same arguments ...<br />
$05<br />
$06 nested-opcode<br />
<br />
===Operation===<br />
Expression mode operates on a stack. Values are pushed on, and operators are applied to the top two items on the stack.<br />
<br />
{| border="1" cellpadding="2" width=100%<br />
|- style="background:whitesmoke"<br />
|Opcode||Meaning||Description<br />
|-<br />
|$01||Value||Pushes a value onto the top of the stack.<br />
|-<br />
|$02||Add||stack[top - 1] + stack[top]<br />
|-<br />
|$03||Subtract||stack[top - 1] - stack[top]<br />
|-<br />
|$04||Multiply||stack[top - 1] * stack[top]<br />
|-<br />
|$05||Divide||stack[top - 1] / stack[top] (if stack[top] is 0 an error occurs)<br />
|-<br />
|$06||Nested Opcode||An entire instruction that returns a result, such as getActorScale. This is interpreted like a normal opcode, but the result is pushed onto the expression stack. (The opcode is passed the special "VAR_RESULT" parameter for "result")<br />
|}<br />
<br />
<br />
==faceActor ($09)==<br />
<br />
===Encoding===<br />
opcode actor[p8] object[p16]<br />
<br />
===Operation===<br />
Dereferences actor, tells actor to face object (presumably based on X/Y co-ordinates).<br />
<br />
<br />
==findInventory ($3D)==<br />
<br />
===Encoding===<br />
opcode result owner[p8] index[p8]<br />
<br />
===Operation===<br />
object := owner.inventory[index]<br />
Searches for all objects owned by owner (an actor or object), and returns the one at the given index (offset).<br />
<br />
<br />
==findObject ($35)==<br />
<br />
===Encoding===<br />
opcode result x[p8] y[p8]<br />
<br />
===Operation===<br />
Returns the first "touchable" local object at the given co-ordinates. Will not match on the bottom or right-hand edges of an object.<br />
<br />
<br />
==freezeScripts ($60)==<br />
<br />
===Encoding===<br />
opcode flag[p8]<br />
<br />
===Operation===<br />
Freezes all scripts (by setting the high bit on each script's status). If flag is >= $80, all freeze resistent scripts will also be frozen. If flag is 0, all scripts are unfrozen. Freezing effects are cumulative - i.e. if script A is frozen twice, and unfrozen once, it will still be frozen until it is unfrozen a second time. A script's frozen status is indicated by the high bit.<br />
<br />
<br />
==getActorCostume ($71)==<br />
<br />
===Encoding===<br />
opcode result actor[p8]<br />
<br />
===Operation===<br />
Returns the actor's current costume.<br />
<br />
<br />
==getActorElevation ($06)==<br />
<br />
===Encoding===<br />
opcode result actor[p8]<br />
<br />
===Operation===<br />
Returns the actor's current elevation.<br />
<br />
<br />
==getActorFacing ($63)==<br />
<br />
===Encoding===<br />
opcode result actor[p8]<br />
<br />
===Operation===<br />
Returns the current direction the actor is facing.<br />
<br />
<br />
==getActorMoving ($56)==<br />
<br />
===Encoding===<br />
opcode result actor[p8]<br />
<br />
===Operation===<br />
Returns the actor's moving status (0 or 1).<br />
<br />
<br />
==getActorRoom ($03)==<br />
<br />
===Encoding===<br />
opcode result actor[p8]<br />
<br />
===Operation===<br />
Returns the room the actor currently occupies?<br />
<br />
<br />
==getActorScale ($3B)==<br />
<br />
===Encoding===<br />
opcode result actor[p8]<br />
<br />
===Operation===<br />
Returns the actor's current scale.<br />
<br />
===Variants===<br />
In Indy3, this opcode is used for waitForActor.<br />
<br />
<br />
==getActorWalkBox ($7B)==<br />
<br />
===Encoding===<br />
opcode result actor[p8]<br />
<br />
===Operation===<br />
Returns the actor's walkbox.<br />
<br />
<br />
==getActorWidth ($6C)==<br />
<br />
===Encoding===<br />
opcode result actor[p8]<br />
<br />
===Operation===<br />
Returns the actor's width.<br />
<br />
<br />
==getActorX ($43)==<br />
<br />
===Encoding===<br />
opcode result actor[p16]<br />
<br />
===Operation===<br />
Returns the actor's current X co-ordinate.<br />
<br />
===Variants===<br />
In Indy3, actor is only one byte.<br />
opcode result actor[p8]<br />
<br />
<br />
==getActorY ($23)==<br />
<br />
===Encoding===<br />
opcode result actor[p16]<br />
<br />
===Operation===<br />
Returns the actor's current Y co-ordinate.<br />
<br />
===Variants===<br />
In Indy3, actor is only one byte.<br />
opcode result actor[p8]<br />
<br />
<br />
==getAnimCounter ($22)==<br />
<br />
===Encoding===<br />
opcode result actor[p8]<br />
<br />
===Operation===<br />
Returns the actor's animation counter.<br />
<br />
===Variants===<br />
This opcode is used for saveLoadGame in SCUMM V3.<br />
<br />
<br />
==getClosestObjActor ($66)==<br />
<br />
===Encoding===<br />
opcode result actor[p16]<br />
<br />
===Operation===<br />
Returns the object closest to the actor. Items that are more than 255 units (pixels in newer games, characters in older games) away from the actor will not be detected.<br />
<br />
<br />
==getDist ($34)==<br />
<br />
===Encoding===<br />
opcode result objA[p16] objB[p16]<br />
<br />
===Operation===<br />
Returns the distance between two actors/objects (objA and objB).<br />
<br />
<br />
==getInventoryCount ($31)==<br />
<br />
===Encoding===<br />
opcode result actor[p8]<br />
<br />
===Operation===<br />
Returns the number of items in an actor's inventory?<br />
<br />
<br />
==getObjectOwner ($10)==<br />
<br />
===Encoding===<br />
opcode result object[p16]<br />
<br />
===Operation===<br />
Returns the owner of an object.<br />
<br />
<br />
==getObjectState ($0F)==<br />
<br />
===Encoding===<br />
opcode result object[p16]<br />
<br />
===Operation===<br />
Returns the state of the object.<br />
<br />
===Variants===<br />
In small header games, the encoding becomes:<br />
opcode object[p16] state[p8] target[16]<br />
operation becomes<br />
unless (getState(object) == state) goto target<br />
<br />
<br />
==getRandomNumber ($16)==<br />
<br />
===Encoding===<br />
opcode result seed[p8]<br />
<br />
===Operation===<br />
Returns a new random number based on the given seed.<br />
<br />
<br />
==getScriptRunning ($68)==<br />
<br />
===Encoding===<br />
opcode result script[p8]<br />
<br />
===Operation===<br />
Returns 1 if the given script is running, 0 if it's not.<br />
<br />
<br />
==getStringWidth ($67)==<br />
<br />
===Encoding===<br />
opcode result strptr[p8]<br />
<br />
===Operation===<br />
Gets the length of the string pointed to by strptr (either a variable or direct byte), stores the returned value in result.<br />
<br />
<br />
==getVerbEntryPoint ($0B)==<br />
<br />
===Encoding===<br />
opcode result object[p16] verb[p16]<br />
<br />
===Operation===<br />
Returns the entry point for the response code/script for when the given verb is applied to the given object? i.e. gets the start of the script to run for the specific user interaction.<br />
<br />
<br />
==ifClassOfIs ($1D)==<br />
jumps<br />
<br />
===Encoding===<br />
opcode value[p16] args[v16]... target[16]<br />
<br />
===Operation===<br />
unless (value.class is one of [args.class]) goto target<br />
<br />
Compares the value's class with all classes given in args.<br />
<br />
Target is a byte offset (measured from after this instruction), which will be added to the instruction pointer.<br />
<br />
==ifNotState ($2F)==<br />
<br />
===Encoding===<br />
opcode object[p16] state[p8] target[16]<br />
<br />
===Operation===<br />
unless (stateOf(object) != state) goto target<br />
<br />
<br />
==ifState ($4F)==<br />
<br />
===Encoding===<br />
opcode object[p16] state[p8] target[16]<br />
<br />
===Operation===<br />
unless (stateOf(object) == state) goto target<br />
<br />
<br />
==increment ($46)==<br />
no parameters, uses result<br />
<br />
===Encoding===<br />
opcode result<br />
<br />
===Operation===<br />
result := result + 1<br />
<br />
Reads the variable pointed to by result, increments it, and writes it back. <br />
<br />
<br />
==isActorInBox ($1F)==<br />
<br />
===Encoding===<br />
opcode actor[p8] box[p8] target[16]<br />
<br />
===Operation===<br />
Unless the actor's co-ordinates are within the bounds of the given box, jump to target.<br />
<br />
Target is a byte offset (measured from after this instruction), which will be added to the instruction pointer.<br />
<br />
<br />
==isEqual ($48)==<br />
<br />
===Encoding===<br />
opcode var value[p16] target[16]<br />
<br />
===Operation===<br />
unless (value == var) goto target<br />
<br />
Target is a byte offset (measured from after this instruction), which will be added to the instruction pointer.<br />
<br />
<br />
==isGreater ($78)==<br />
<br />
===Encoding===<br />
opcode var value[p16] target[16]<br />
<br />
===Operation===<br />
unless (value > var) goto target<br />
<br />
Target is a byte offset (measured from after this instruction), which will be added to the instruction pointer.<br />
<br />
<br />
==isGreaterEqual ($04)==<br />
<br />
===Encoding===<br />
opcode var value[p16] target[16]<br />
<br />
===Operation===<br />
unless (value >= var) goto target<br />
<br />
Target is a byte offset (measured from after this instruction), which will be added to the instruction pointer.<br />
<br />
<br />
==isLess ($44)==<br />
<br />
===Encoding===<br />
opcode var value[p16] target[16]<br />
<br />
===Operation===<br />
unless (value < var) goto target<br />
<br />
Target is a byte offset (measured from after this instruction), which will be added to the instruction pointer.<br />
<br />
<br />
==isNotEqual ($08)==<br />
<br />
===Encoding===<br />
opcode var value[p16] target[16]<br />
<br />
===Operation===<br />
unless (value != var) goto target<br />
<br />
Target is a byte offset (measured from after this instruction), which will be added to the instruction pointer.<br />
<br />
<br />
==isSoundRunning ($7C)==<br />
<br />
===Encoding===<br />
opcode result sound[p8]<br />
<br />
===Operation===<br />
Returns 1 if sound is running, returns 0 if sound is not running or if the given sound is 0.<br />
<br />
<br />
==jumpRelative ($18)==<br />
jumps<br />
<br />
===Encoding===<br />
opcode target[16]<br />
<br />
===Operation===<br />
PC := PC + target<br />
<br />
The inline constant target is read as a signed word and added to the program counter after the instruction has been read. Therefore, if target is zero, the instruction will do nothing; if target is -3, an infinite loop will result. <br />
<br />
<br />
==lessOrEqual ($38)==<br />
jumps<br />
<br />
===Encoding===<br />
opcode var value[p16] target[16]<br />
<br />
===Operation===<br />
unless (value <= var) goto target<br />
<br />
Target is a byte offset (measured from after this instruction), which will be added to the instruction pointer.<br />
<br />
<br />
==lights ($70)==<br />
<br />
===Encoding===<br />
opcode arg1[p8] arg2[8] arg3[8]<br />
<br />
===Operation===<br />
If arg3 is 0, the "current lights" variable is set to arg1.<br />
If arg3 is 1, the size of the "flashlight" light is determined by arg1 and arg2, for width and height in stripes (which are equivalent to 8 pixels each; see [[SCUMM/Technical Reference/Image resources]]).<br />
<br />
<br />
==loadRoom ($72)==<br />
<br />
===Encoding===<br />
opcode room[p8]<br />
<br />
===Operation===<br />
Loads the given room into memory.<br />
<br />
<br />
==loadRoomWithEgo ($24)==<br />
<br />
===Encoding===<br />
opcode object[p16] room[p8] x[16] y[16]<br />
<br />
===Operation===<br />
Places the Ego actor in room at object's position. If x is not -1, Ego will start moving towards the given x and y co-ordinates. If object is not in the given room an error will occur.<br />
(I think...)<br />
<br />
<br />
==matrixOp ($30)==<br />
<br />
===Encoding===<br />
opcode sub-opcode<br />
<br />
sub-opcodes:<br />
$01 box[p8] val[p8]<br />
$02 box[p8] val[p8]<br />
$03 box[p8] val[p8]<br />
$04<br />
<br />
===Operation===<br />
This instruction manipulates boxes.<br />
<br />
{| border="1" cellpadding="2" width=100%<br />
|- style="background:whitesmoke"<br />
|Opcode||Meaning||Description<br />
|-<br />
|$01||setBoxFlags||Sets the box's flags to the given value.<br />
|-<br />
|$02||setBoxScale||Sets the box's scale.<br />
|-<br />
|$03||setBoxScale||Sets the box's scale to ((val - 1) OR $8000).<br />
|-<br />
|$04||createBoxMatrix||Initializes the matrix of boxes, by determining the distances and shortest paths between boxes.<br />
|}<br />
<br />
===Variants===<br />
SCUMM V3 only has the one instruction, which behaves like setBoxFlags:<br />
opcode box[p8] val[8]<br />
<br />
<br />
==move ($1A)==<br />
<br />
===Encoding===<br />
opcode result value[p16]<br />
<br />
===Operation===<br />
result := value<br />
<br />
Value is moved into result.<br />
<br />
<br />
==multiply ($1B)==<br />
<br />
===Encoding===<br />
opcode result value[p16]<br />
<br />
===Operation===<br />
result := result * value<br />
<br />
The variable pointed to by result is read, multiplied by value, and written back.<br />
<br />
<br />
==notEqualZero ($A8)==<br />
<br />
===Encoding===<br />
opcode var target[16]<br />
<br />
===Operation===<br />
unless (var != 0) goto target<br />
<br />
Target is a byte offset (measured from after this instruction), which will be added to the instruction pointer.<br />
<br />
<br />
==oldRoomEffect ($5C)==<br />
<br />
===Encoding===<br />
opcode sub-opcode<br />
<br />
sub-opcodes:<br />
$03 effect[p16]<br />
<br />
===Operation===<br />
Performs like sub-opcode SO_ROOM_FADE of the roomOps instruction (fade in if effect != 0, otherwise fade out).<br />
<br />
This information may not be correct; descumm says if the sub-opcode is 3, to "set" the effect, but if the sub-opcode is anything else to fade in with the given effect.<br />
<br />
===Variants===<br />
FM-Towns SCUMM V3 performs a different effect, not fully implemented in ScummVM. At the moment ScummVM just forces a redraw of the screen background.<br />
<br />
<br />
==or ($57)==<br />
one parameter, uses result<br />
<br />
===Encoding===<br />
opcode result value[p16]<br />
<br />
===Operation===<br />
result := result or value<br />
<br />
The variable pointed to by result is read, logically ORed with value, and the result written back.<br />
<br />
<br />
==override ($58)==<br />
<br />
===Encoding===<br />
opcode sub-opcode<br />
<br />
sub-opcodes:<br />
$00<br />
$01 $18 target[16]<br />
<br />
===Operation===<br />
If the sub-opcode is 0, marks the end of an override section.<br><br />
If the sub-opcode is not 0, marks the beginning of an override section. The instruction is immediately followed by a "jumpRelative" instruction.<br.<br />
Overrides are used by cutscenes; if a cutscene is skipped (if the user presses the ESC key), the script will jump by the given target (offset from this instruction).<br />
<br />
<br />
==panCameraTo ($12)==<br />
<br />
===Encoding===<br />
opcode x[p16]<br />
<br />
===Operation===<br />
Starts the camera panning to the given x co-ordinate.<br />
<br />
<br />
==pickupObject ($25)==<br />
<br />
===Encoding===<br />
opcode object[p16] room[p8]<br />
<br />
===Operation===<br />
Adds the given object (located in the given room) to the Ego actor's inventory.<br />
<br />
===Variants===<br />
In SCUMM V3 and V4, this opcode is used for drawObject.<br />
<br />
<br />
==pickupObjectOld ($50)==<br />
<br />
===Encoding===<br />
opcode object[p16]<br />
<br />
===Operation===<br />
Adds the given object (located in the given room) to the Ego actor's inventory. If object < 1, an error is raised. If the object is not found or the object is already in the inventory, this function ends gracefully.<br />
<br />
<br />
==print ($14)==<br />
<br />
===Encoding===<br />
opcode actor[p8] sub-opcode<br />
<br />
sub-opcodes<br />
$00 xpos[p16] ypos[p16]<br />
$01 colour[p8]<br />
$02 right[p16]<br />
$03 width[p16] height[p16]<br />
$04<br />
$06<br />
$07<br />
$08 offset[p16] delay[p16]<br />
$0F string[c]... $FF<br />
<br />
===Operation===<br />
Sets text properties and displays dialogue.<br />
<br />
{| border="1" cellpadding="2" width=100%<br />
|- style="background:whitesmoke"<br />
|Opcode||Meaning||Description<br />
|-<br />
|$00||SO_AT||Sets the position of the text that follows.<br />
|-<br />
|$01||SO_COLOR||Sets the colour of the text.<br />
|-<br />
|$02||SO_CLIPPED||Clips the text's right-hand side (for wrapping?).<br />
|-<br />
|$03||SO_ERASE||Erases characters (not used in ScummVM).<br />
|-<br />
|$04||SO_CENTER||Centres the text.<br />
|-<br />
|$06||SO_LEFT||Left-aligns the text.<br />
|-<br />
|$07||SO_OVERHEAD||Overhead-aligns the text.<br />
|-<br />
|$0F||SO_TEXTSTRING||Prints the text string that follows. Terminated by $FF.<br />
|}<br />
<br />
===Variants===<br />
In SCUMM V3, text function $06 sets the height of the text:<br />
$06 height[p16]<br />
<br />
In Loom CD (SCUMM V4), there is an additional text function $08 (SO_SAY_VOICE), which plays a portion of the CD audio track.<br />
$08 offset[p16] delay[p16]<br />
<br />
<br />
==printEgo ($D8)==<br />
<br />
===Encoding===<br />
opcode sub-opcode<br />
<br />
===Operation===<br />
Exactly the same as print, except the actor is implicitly Ego. See the entry for "print" for further explanation.<br />
<br />
<br />
==pseudoRoom ($CC)==<br />
<br />
===Encoding===<br />
opcode val[8] res[8]... $00<br />
<br />
===Operation===<br />
forall (res) {<br />
if (res >= $80) {<br />
_resourceMapper[res & $7F] := val<br />
}<br />
}<br />
<br />
What does this actually do? We may never know.<br />
<br />
It looks like res values always have the high bit set, e.g. 0x01 becomes 0x81.<br />
<br />
==putActor ($01)==<br />
<br />
===Encoding===<br />
opcode actor[p8] x[p16] y[p16]<br />
<br />
===Operation===<br />
Puts the actor at the given co-ordinates.<br />
<br />
<br />
==putActorAtObject ($0E)==<br />
<br />
===Encoding===<br />
opcode actor[p8] object[p16]<br />
<br />
===Operation===<br />
Puts the actor at the given object's position. If the object can not be found, a default position is returned (the centre of the screen in ScummVM).<br />
<br />
<br />
==putActorInRoom ($2D)==<br />
<br />
===Encoding===<br />
opcode actor[p8] room[p8]<br />
<br />
===Operation===<br />
Puts the actor in the given room.<br />
<br />
<br />
==resourceRoutines ($0C)==<br />
<br />
===Encoding===<br />
opcode sub-opcode<br />
<br />
sub-opcodes:<br />
$01 resID[p8]<br />
... $01 through $10 take the same arguments ...<br />
$10 resID[p8]<br />
$11<br />
$12 resID[p8]<br />
$13 resID[p8]<br />
$14 room[p8] object[p16]<br />
<br />
===Operation===<br />
resID is unique only within the resource type (e.g. script 11 will not conflict with sound 11).<br />
<br />
{| border="1" cellpadding="2" width=100%<br />
|- style="background:whitesmoke"<br />
|Opcode||Meaning||Description<br />
|-<br />
|$01||SO_LOAD_SCRIPT||Loads the given script into memory.<br />
|-<br />
|$02||SO_LOAD_SOUND||Loads the given sound into memory.<br />
|-<br />
|$03||SO_LOAD_COSTUME||Loads the given costume into memory.<br />
|-<br />
|$04||SO_LOAD_ROOM||Loads the given room into memory.<br />
|-<br />
|$05||SO_NUKE_SCRIPT||Obliterates the given script from memory.<br />
|-<br />
|$06||SO_NUKE_SOUND||Obliterates the given sound from memory.<br />
|-<br />
|$07||SO_NUKE_COSTUME||Obliterates the given costume from memory.<br />
|-<br />
|$08||SO_NUKE_ROOM||Obliterates the given room from memory.<br />
|-<br />
|$09||SO_LOCK_SCRIPT||Locks the given script.<br />
|-<br />
|$0A||SO_LOCK_SOUND||Locks the given sound.<br />
|-<br />
|$0B||SO_LOCK_COSTUME||Locks the given costume.<br />
|-<br />
|$0C||SO_LOCK_ROOM||Locks the given room.<br />
|-<br />
|$0D||SO_UNLOCK_SCRIPT||Unlocks the given script.<br />
|-<br />
|$0E||SO_UNLOCK_SOUND||Unlocks the given sound.<br />
|-<br />
|$0F||SO_UNLOCK_COSTUME||Unlocks the given costume.<br />
|-<br />
|$10||SO_UNLOCK_ROOM||Unlocks the given room.<br />
|-<br />
|$11||SO_CLEAR_HEAP||Clears the heap.<br />
|-<br />
|$12||SO_LOAD_CHARSET||Loads the given character set into memory.<br />
|-<br />
|$13||SO_NUKE_CHARSET||Obliterates the given character set from memory.<br />
|-<br />
|$14||SO_LOAD_OBJECT||Loads the given object from the given room resource.<br />
|}<br />
<br />
===Variants===<br />
FM-Towns games add the following sub-opcodes (these are not confirmed nor implemented in ScummVM):<br />
{| border="1" cellpadding="2" width=100%<br />
|- style="background:whitesmoke"<br />
|Opcode||Meaning||Description<br />
|-<br />
|$20||Unknown||Does nothing, not used in-game.<br />
|-<br />
|$21||Unknown||Does nothing, not used in-game.<br />
|-<br />
|$23||CD Volume||Possibly changes the volume of CD tracks (Loom CD). Takes 1 byte.<br />
|-<br />
|$24||Sound Volume||Sets the loudness of a sound resource. Used in Indy3 and Zak. Takes 2 bytes (left/right volumes?).<br />
|-<br />
|$25||Sound Pitch||Sets the pitch of a sound resource. Used in Indy3 and Zak. Takes 1 byte (pitch = "foo" - "center" semitones. Center is at $32 in the sound resource.)<br />
|}<br />
<br />
==roomOps ($33)==<br />
<br />
===Encoding===<br />
opcode sub-opcode<br />
<br />
sub-opcodes:<br />
$01 minX[p16] maxX[p16]<br />
$03 b[p16] h[p16]<br />
$04 red[p16] green[p16] blue[p16] aux index[p8]<br />
$05<br />
$06<br />
$07 scale1[p8] y1[p8] aux scale2[p8] y2[p8] aux slot[p8]<br />
$08 scale[p8] startcolour[p8] endcolour[p8]<br />
$09 loadflag[p8] loadslot[p8]<br />
$0A effect[p16]<br />
$0B redscale[p16] greenscale[p16] bluescale[p16] aux startcolour[p8] endcolour[p8]<br />
$0C redscale[p16] greenscale[p16] bluescale[p16] aux startcolour[p8] endcolour[p8]<br />
$0D resID[p8] filename[c]... $00<br />
$0E resID[p8] filename[c]... $00<br />
$0F resID[p8] aux start[p8] end[p8] aux time[p8]<br />
$10 colindex[p8] delay[p8]<br />
<br />
===Operation===<br />
{| border="1" cellpadding="2" width=100%<br />
|- style="background:whitesmoke"<br />
|Opcode||Meaning||Description<br />
|-<br />
|$01||SO_ROOM_SCROLL||Clamps the given arguments so scrolling does not extend past the width of the room or screen.<br />
|-<br />
|$03||SO_ROOM_SCREEN||Initialises a screen.<br />
|-<br />
|$04||SO_ROOM_PALETTE||Adjusts the room's palette.<br />
|-<br />
|$05||SO_ROOM_SHAKE_ON||Starts the room shaking.<br />
|-<br />
|$06||SO_ROOM_SHAKE_OFF||Ends the room shaking.<br />
|-<br />
|$07||SO_ROOM_SCALE||Sets the room's y scales? (slot is 1 greater than actual slot?)<br />
|-<br />
|$08||SO_ROOM_INTENSITY||Lightens/darkens the room's palette.<br />
|-<br />
|$09||SO_ROOM_SAVEGAME||Saves temporary state of the room/game?<br />
|-<br />
|$0A||SO_ROOM_FADE||If effect is 0, fades in the room. Otherwise, fades out with the given effect (taken from the high byte of effect).<br>1 = iris effect<br>2 = box wipe (upper-left to bottom-right)<br>3 = box wipe (upper-right to bottem-left)<br>4 = inverse box wipe.<br />
|-<br />
|$0B||SO_RGB_ROOM_INTENSITY||Lightens/darkens the room's palette, with different scales for red, green and blue.<br />
|-<br />
|$0C||SO_ROOM_SHADOW||Lightens/darkens the shadow palette, with different scales for red, green, and blue.<br />
|-<br />
|$0D||SO_SAVE_STRING||Saves a string resource to the given file?<br />
|-<br />
|$0E||SO_LOAD_STRING||Loads a string resource from a given file?<br />
|-<br />
|$0F||SO_ROOM_TRANSFORM||Manipulates palettes, strings?<br />
|-<br />
|$10||SO_CYCLE_SPEED||Starts colour cycling with delay? colIndex is between 0 and 16<br />
|}<br />
<br />
===Variants===<br />
SCUMM V3 (non-PC Engine) encodes the arguments before the sub-opcode:<br />
opcode arg1[p16] arg2[p16] sub-opcode<br />
<br />
Small header games include an extra sub-opcode, $02 (SO_ROOM_COLOR), which adjusts the room's palette:<br />
opcode $02 colour[p16] index[p16]<br />
... or for V3 games ...<br />
opcode colour[p16] index[p16] $02<br />
<br />
In small header games, sub-opcode $04 (SO_ROOM_PALETTE) affects the shadow palette, and only accepts two arguments, a "room colour slot" (palette entry? between 0 and 256) and an index:<br />
opcode $04 colour[p16] index[p16]<br />
... or for V3 games ...<br />
opcode colour[p16] index[p16] $04<br />
<br />
In FM-Towns games, sub-opcode $0A performs a different function and has its own sub-opcodes (some unknown and all not yet implemented in ScummVM):<br />
opcode $0A sub-opcode<br />
<br />
{| border="1" cellpadding="2" width=100%<br />
|- style="background:whitesmoke"<br />
|Opcode||Meaning||Description<br />
|-<br />
|$08||||compose kMainVirtScreen over a screen buffer<br />
|-<br />
|$09||||call 0x110:0x20 _ax=0x601 _edx=2<br />
|-<br />
|$0A||||call 0x110:0x20 _ax=0x601 _edx=3<br />
|-<br />
|$0B||||clear screen 0x1C:0x45000 sizeof(640 * 320)<br />
|-<br />
|$0C||||call 0x110:0x20 _ax=0x601 _edx=0<br />
|-<br />
|$0D||||call 0x110:0x20 _ax=0x601 _edx=1<br />
|-<br />
|$10||||enable clearing of a screen buffer in drawBitmap()<br />
|-<br />
|$11||||disable clearing of a screen buffer in drawBitmap()<br />
|-<br />
|$12||||clear a screen buffer<br />
|-<br />
|$13||||enable palette operations (palManipulate(), cyclePalette() etc.)<br />
|-<br />
|$14||||disable palette operations<br />
|-<br />
|$15||||disable clearing of screen 0x1C:0x5000 sizeof(640 * 320) in initScreens()<br />
|-<br />
|$16||||enable clearing of screen 0x1C:0x5000 sizeof(640 * 320) in initScreens()<br />
|-<br />
|$1E||||Unknown<br />
|}<br />
<br />
==saveRestoreVerbs ($AB)==<br />
<br />
===Encoding=== <br />
opcode sub-opcode<br />
<br />
sub-opcodes: <br />
$01 start[p8] end[p8] mode[p8]<br />
$02 start[p8] end[p8] mode[p8]<br />
$03 start[p8] end[p8] mode[p8]<br />
<br />
===Operation===<br />
{| border="1" cellpadding="2" width=100%<br />
|- style="background:whitesmoke"<br />
|Opcode||Meaning||Description<br />
|-<br />
|$01||SO_SAVE_VERBS||For all verbs between start and end, sets the "saveid" to mode. <br />
|-<br />
|$02||SO_RESTORE_VERBS||For all verbs between start and end and matching mode, kills any existing verb, sets the saveid to 0 and generally inits the verb.<br />
|-<br />
|$03||SO_DELETE_VERBS||For all verbs between start and end and matching mode, kills any existing verb.<br />
|}<br />
<br />
==setCameraAt ($32)==<br />
<br />
===Encoding===<br />
opcode x[p16]<br />
<br />
===Operation===<br />
Sets the camera's x position.<br />
<br />
<br />
==setObjectName ($54)==<br />
<br />
===Encoding===<br />
opcode object[p16] name[c]... $00<br />
<br />
===Operation===<br />
Sets the given object's name.<br />
<br />
<br />
==setOwnerOf ($29)==<br />
<br />
===Encoding===<br />
opcode object[p16] owner[p8]<br />
<br />
===Operation===<br />
Sets the owner of the object.<br />
<br />
<br />
==setState ($07)==<br />
<br />
===Encoding===<br />
opcode object[p16] state[p8]<br />
<br />
===Operation===<br />
Sets the state of the object.<br />
<br />
<br />
==setVarRange ($26)==<br />
non-standard encoding<br />
<br />
===Encoding===<br />
opcode result number[8] values[8]...<br />
or<br />
opcode result number[8] values[16]...<br />
<br />
===Operation===<br />
for (i = 0; i < number; i++) {<br />
&#42;result + i := values[i];<br />
}<br />
<br />
This sets a number of variables to the given parameters. The starting variable is given as "result", and the number of variables to modify is given as "number". This is followed by the same number of values, which will be put into the variable locations. The values are constants, and can be either 16-bit, if the highest bit of the opcode is set, i.e. $A6; or 8-bit, if the highest bit of the opcode is not set, i.e. $26. Note that all values are affected by the opcode's high bit; you can't mix 8 and 16-bit values.<br />
<br />
descumm example:<br />
setVarRange(Var[178],9,[0,0,0,0,0,0,0,0,0]);<br />
<br />
This sets variables 178 to 186 (inclusive) to 0.<br />
<br />
<br />
==soundKludge ($4C)==<br />
<br />
===Encoding===<br />
opcode items[v16]...<br />
<br />
===Operation===<br />
If the first item is -1, the existing sound queue is processed. Otherwise, the list of items is added to the queue.<br />
<br />
===Variants===<br />
In SCUMM V3 (small header) games, this opcode is used for the WaitForSentence instruction.<br />
<br />
<br />
==startMusic ($02)==<br />
<br />
===Encoding===<br />
opcode music[p8]<br />
<br />
===Operation===<br />
Adds the music in to the queue to be played.<br />
<br />
===Variants===<br />
In FM-Towns (SCUMM V3) games, this instruction performs different functions (some kind of Audio CD status query function; some partially implemented in ScummVM):<br />
opcode result sub-opcode<br />
<br />
{| border="1" cellpadding="2" width=100%<br />
|- style="background:whitesmoke"<br />
|Opcode||Meaning||Description<br />
|-<br />
|$00||Is Playing||Returns true if a CD audio track is currently playing.<br />
|-<br />
|$FC||Unpause CD||Unpauses the CD audio track.<br />
|-<br />
|$FD||Pause CD||Pauses the CD audio track.<br />
|-<br />
|$FE||Get CD Sound||Returns the current CD sound.<br />
|-<br />
|$FF||CD Volume||Might return the the current CD volume in FM-Towns Loom.<br />
|-<br />
|other||Track Length||Returns the track length in seconds.<br />
|}<br />
<br />
<br />
==startObject ($37)==<br />
<br />
===Encoding===<br />
opcode object[p16] script[p8] args[v16]...<br />
<br />
===Operation===<br />
Starts the object's script (OBCD blocks), passing the given arguments.<br />
<br />
<br />
==startScript ($0A)==<br />
one parameter plus varargs, extra encoding in opcode<br />
<br />
===Encoding===<br />
opcode script[p8] args[v16]...<br />
<br />
===Operation===<br />
Spawns a new thread running the code in script script. The new script has its local variables initialised to the list args. Uninitialised variables have undefined values.<br />
<br />
The opcode carries extra information: <br />
<br />
{| border="1" cellpadding="2" width=10%<br />
|- style="background:whitesmoke"<br />
|7||6||5||4 0<br />
|-<br />
|P1||R||F||$0A<br />
|}<br />
<br />
P1 = standard parameter bit<br><br />
R = indicates that the script is recursive<br><br />
F = indicates that the script is freeze resistant (a call to freezeScripts will skip this script, unless the "force freeze" bit of the freezeScripts opcode is set).<br />
<br />
<br />
==startSound ($1C)==<br />
<br />
===Encoding===<br />
opcode sound[p8]<br />
<br />
===Operation===<br />
Adds the given sound to the sound queue to be played.<br />
<br />
<br />
==stopMusic ($20)==<br />
<br />
===Encoding===<br />
opcode<br />
<br />
===Operation===<br />
Stops all sounds.<br />
<br />
<br />
==stopObjectCode ($A0 or $00)==<br />
<br />
===Encoding===<br />
opcode<br />
<br />
===Operation===<br />
Marks the calling script as dead, to be later pruned from the thread pool. Cleans up residual arrays.<br />
<br />
Is $00 correct?<br />
<br />
==stopObjectScript ($6E)==<br />
<br />
===Encoding===<br />
opcode script[p16]<br />
<br />
===Operation===<br />
Marks the given object script as dead, to be later pruned from the thread pool. Cleans up residual arrays.<br />
<br />
<br />
==stopScript ($62)==<br />
<br />
===Encoding===<br />
opcode script[p8]<br />
<br />
===Operation===<br />
Marks the given script as dead, to be later pruned from the thread pool. Cleans up residual arrays.<br />
<br />
<br />
==stopSound ($3C)==<br />
<br />
===Encoding===<br />
opcode sound[p8]<br />
<br />
===Operation===<br />
Stops the given sound.<br />
<br />
<br />
==stringOps ($27)==<br />
parameters depend on sub-opcode<br />
<br />
===Encoding===<br />
opcode sub-opcode<br />
<br />
sub-opcodes:<br />
$01 stringID[p8] string[c]... $00<br />
$02 destID[p8] srcID[p8]<br />
$03 stringID[p8] index[p8] char[c]<br />
$04 result stringID[p8] index[p8]<br />
$05 stringID[p8] size[p8]<br />
<br />
===Operation===<br />
Miscellaneous actions on strings (Arrays, referred to by resource number).<br />
<br />
{| border="1" cellpadding="2" width=100%<br />
|- style="background:whitesmoke"<br />
|Opcode||Meaning||Description<br />
|-<br />
|$01||Load String||Loads the inline null-terminated string into the resource slot given by stringID.<br />
|-<br />
|$02||Copy String||Creates a duplicate of the string at resource slot srcID into destID. The old string at destID is lost.<br />
|-<br />
|$03||Write Character||Writes char at the given index (offset) of the string resource located at slot stringID. Out of bounds accesses cause undefined behaviour.<br />
|-<br />
|$04||Read Character||Reads a byte (character) at the given index (offset) of the string resource located at slot stringID, and writes it to result. Out of bounds accesses cause undefined behaviour.<br />
|-<br />
|$05||New String||Allocates or frees a string (Array), located at resource slot stringID. The string is initialised to size; if size is zero, the string is freed.<br />
|}<br />
<br />
<br />
==subtract ($3A)==<br />
<br />
===Encoding===<br />
opcode result value[p16]<br />
<br />
===Operation===<br />
result := result - value<br />
<br />
The variable pointed to by result is read, value is subtracted from it, and the result written back.<br />
<br />
<br />
==systemOps ($98)==<br />
<br />
===Encoding===<br />
opcode sub-opcode<br />
<br />
sub-opcodes:<br />
$01<br />
$02<br />
$03<br />
<br />
===Operation===<br />
{| border="1" cellpadding="2" width=100%<br />
|- style="background:whitesmoke"<br />
|Opcode||Meaning||Description<br />
|-<br />
|$01||SO_RESTART||Restarts the game.<br />
|-<br />
|$02||SO_PAUSE||Pauses/unpauses the game.<br />
|-<br />
|$03||SO_QUIT||Quits the game.<br />
|}<br />
<br />
<br />
==verbOps ($7A)==<br />
<br />
===Encoding===<br />
opcode verbID[p8] sub-opcode... $FF<br />
<br />
sub-opcodes:<br />
$01 object[p16]<br />
$02 name[c]... $00<br />
$03 colour[p8]<br />
$04 hicolour[p8]<br />
$05 left[p16] top[p16]<br />
$06<br />
$07<br />
$08<br />
$09<br />
$10 colour[p8]<br />
$11<br />
$12 key[p8]<br />
$13<br />
$14 stringID[p16]<br />
$16 object[p16] room[p8]<br />
$17 colour[p8]<br />
<br />
===Operation===<br />
{| border="1" cellpadding="2" width=100%<br />
|- style="background:whitesmoke"<br />
|Opcode||Meaning||Description<br />
|-<br />
|$01||SO_VERB_IMAGE||Assigns an object (image) to a verb.<br />
|-<br />
|$02||SO_VERB_NAME||Assigns the in-line name to the verb slot.<br />
|-<br />
|$03||SO_VERB_COLOR||Sets the colour of the verb.<br />
|-<br />
|$04||SO_VERB_HICOLOR||Sets the high colour of the verb.<br />
|-<br />
|$05||SO_VERB_AT||Sets the verb's top-left co-ordinates.<br />
|-<br />
|$06||SO_VERB_ON||Makes this verb active.<br />
|-<br />
|$07||SO_VERB_OFF||Makes this verb inactive.<br />
|-<br />
|$08||SO_VERB_DELETE||Kills this verb.<br />
|-<br />
|$09||SO_VERB_NEW||Creates a verb in the slot for the given verbID. If the slot is 0 (verb doesn't already exist), will add it to the next unusued slot; if this exceeds the global maximum number of verbs an error will be raised.<br />
|-<br />
|$10||SO_VERB_DIMCOLOR||Sets the dim colour of the verb.<br />
|-<br />
|$11||SO_VERB_DIM||Dims this verb.<br />
|-<br />
|$12||SO_VERB_KEY||Sets the key code (maybe ASCII char?) associated with this verb.<br />
|-<br />
|$13||SO_VERB_CENTER||Centres the verb?<br />
|-<br />
|$14||SO_VERB_NAME_STR||Loads the given string resource into the verb's slot. If either the string resource or verb slot is not found (0), the verb resource is nuked.<br />
|-<br />
|$16||Assign Object||Assigns an object from the given room to the verb (if the object's image index is not already assigned to the given object).<br />
|-<br />
|$17||Set Back Colour||Sets the background colour of the verb?<br />
|}<br />
<br />
<br />
==wait ($AE)==<br />
<br />
===Encoding===<br />
opcode sub-opcode<br />
<br />
sub-opcodes:<br />
$01 actor[p8]<br />
$02 <br />
$03<br />
$04<br />
<br />
===Operation===<br />
{| border="1" cellpadding="2" width=100%<br />
|- style="background:whitesmoke"<br />
|Opcode||Meaning||Description<br />
|-<br />
|$01||SO_WAIT_FOR_ACTOR||If the given actor is moving, breaks and resumes at this instruction again.<br />
|-<br />
|$02||SO_WAIT_FOR_MESSAGE||If the global variable VAR_HAVE_MSG (Var[3]) is not zero, breaks and resumes at this instruction again.<br />
|-<br />
|$03||SO_WAIT_FOR_CAMERA||If the camera has not reached its destination x position, breaks and resumes at this instruction again.<br />
|-<br />
|$04||SO_WAIT_FOR_SENTENCE||If there is a sentence present?, breaks and resumes at this instruction again<br />
|}<br />
<br />
===Variants===<br />
In Indy3 (non-Macintosh), this opcode only acts as SO_WAIT_FOR_MESSAGE and omits the sub-opcode.<br />
opcode<br />
<br />
<br />
==walkActorTo ($1E)==<br />
<br />
===Encoding===<br />
opcode actor[p8] x[p16] y[p16]<br />
<br />
===Operation===<br />
Sets the actor to begin walking to the given position.<br />
<br />
<br />
==walkActorToActor ($0D)==<br />
<br />
===Encoding===<br />
opcode walker[p8] walkee[p8] distance[8]<br />
<br />
===Operation===<br />
Walks walker towards walkee's position by the given distance. Walker and walkee are both actors.<br />
<br />
<br />
==walkActorToObject ($36)==<br />
<br />
===Encoding===<br />
opcode actor[p8] object[p16]<br />
<br />
===Operation===<br />
Sets the actor to begin walking to the given object's position.<br />
<br />
=Variables=<br />
<br />
A number of variables are reserved for use by the SPUTM/SCUMM engine. Here is a list of known variables and their corresponding numbers, taken from the ScummVM source code.<br />
<br />
VAR_RESULT = 0; // descumm claims var 0 is the result var (for expressions)<br />
VAR_KEYPRESS = 0; // script_v5_.cpp claims var 0 is for keypresses...<br />
VAR_EGO = 1;<br />
VAR_CAMERA_POS_X = 2;<br />
VAR_HAVE_MSG = 3;<br />
VAR_ROOM = 4;<br />
VAR_OVERRIDE = 5;<br />
VAR_MACHINE_SPEED = 6;<br />
VAR_ME = 7;<br />
VAR_NUM_ACTOR = 8;<br />
VAR_CURRENT_LIGHTS = 9;<br />
VAR_CURRENTDRIVE = 10;<br />
VAR_TMR_1 = 11;<br />
VAR_TMR_2 = 12;<br />
VAR_TMR_3 = 13;<br />
VAR_MUSIC_TIMER = 14;<br />
VAR_ACTOR_RANGE_MIN = 15;<br />
VAR_ACTOR_RANGE_MAX = 16;<br />
VAR_CAMERA_MIN_X = 17;<br />
VAR_CAMERA_MAX_X = 18;<br />
VAR_TIMER_NEXT = 19;<br />
VAR_VIRT_MOUSE_X = 20;<br />
VAR_VIRT_MOUSE_Y = 21;<br />
VAR_ROOM_RESOURCE = 22;<br />
VAR_LAST_SOUND = 23;<br />
VAR_CUTSCENEEXIT_KEY = 24;<br />
VAR_TALK_ACTOR = 25;<br />
VAR_CAMERA_FAST_X = 26;<br />
VAR_SCROLL_SCRIPT = 27;<br />
VAR_ENTRY_SCRIPT = 28;<br />
VAR_ENTRY_SCRIPT2 = 29;<br />
VAR_EXIT_SCRIPT = 30;<br />
VAR_EXIT_SCRIPT2 = 31;<br />
VAR_VERB_SCRIPT = 32;<br />
VAR_SENTENCE_SCRIPT = 33;<br />
VAR_INVENTORY_SCRIPT = 34;<br />
VAR_CUTSCENE_START_SCRIPT = 35;<br />
VAR_CUTSCENE_END_SCRIPT = 36;<br />
VAR_CHARINC = 37;<br />
VAR_WALKTO_OBJ = 38;<br />
VAR_DEBUGMODE = 39;<br />
VAR_HEAPSPACE = 40;<br />
VAR_RESTART_KEY = 42;<br />
VAR_PAUSE_KEY = 43;<br />
VAR_MOUSE_X = 44;<br />
VAR_MOUSE_Y = 45;<br />
VAR_TIMER = 46;<br />
VAR_TIMER_TOTAL = 47;<br />
VAR_SOUNDCARD = 48;<br />
VAR_VIDEOMODE = 49;<br />
VAR_MAINMENU_KEY = 50;<br />
VAR_FIXEDDISK = 51;<br />
VAR_CURSORSTATE = 52;<br />
VAR_USERPUT = 53;<br />
VAR_V5_TALK_STRING_Y = 54;<br />
VAR_SOUNDRESULT = 56;<br />
VAR_TALKSTOP_KEY = 57;<br />
VAR_FADE_DELAY = 59;<br />
VAR_NOSUBTITLES = 60;<br />
VAR_SOUNDPARAM = 64;<br />
VAR_SOUNDPARAM2 = 65;<br />
VAR_SOUNDPARAM3 = 66;<br />
VAR_INPUTMODE = 67; // 1 is keyboard, 2 is joystick, 3 is mouse<br />
VAR_MEMORY_PERFORMANCE = 68;<br />
VAR_VIDEO_PERFORMANCE = 69;<br />
VAR_ROOM_FLAG = 70;<br />
VAR_GAME_LOADED = 71;<br />
VAR_NEW_ROOM = 72;<br />
<br />
<br />
=Table of Parameters=<br />
Please see the wiki page [[SCUMM/V5_opcodes/Table]].</div>Jestar jokinhttps://wiki.scummvm.org/index.php?title=SCUMM/V5_opcodes/Table&diff=10978SCUMM/V5 opcodes/Table2009-04-17T03:25:35Z<p>Jestar jokin: /* Table of Parameters */ stopObjectCode opcode is $A0</p>
<hr />
<div>=Table of Parameters=<br />
<br />
This table shows a summary of the [[SCUMM/V5 opcodes|SCUMM V5]] opcodes and their parameters in a concise fashion.<br />
<br />
Argument types:<br />
* V = variable<br />
* B = byte constant<br />
* W = word constant<br />
* P8 = variable or byte<br />
* P16 = variable or word<br />
* L = list<br />
* J = jump (used by almost all boolean expressions, comparisons) (equivalent to W)<br />
* D = delay; 24-bit constant (only used by delay instruction, strangely enough)<br />
* A = ASCII string, terminated by the following argument ($00, $FF, $FE...)<br />
* A0 = ASCII string, null-terminated<br />
* A1 = ASCII string, $FF terminated<br />
* FF = the hex value $FF, used for terminating some lists, strings etc.<br />
* SO = sub-opcode, variants listed underneath as "opcode$sub-opcode"<br />
* NS = non-standard encoding that cannot be sufficiently expressed in this table<br />
* + = one or more of the preceding argument (parameter bits usually don't matter)<br />
* None = does not take that argument argument<br />
<br />
<br />
{| border="1" style="text-align:center" width=100% cellpadding=2<br />
|- style="background:whitesmoke"<br />
|Instruction||Opcode||Descumm equiv.||Returns a Value||Arg 1||Arg 2||Arg 3<br />
|-<br />
|align="left" |actorFollowCamera<br />
|$52<br />
|style="color:silver; background:whitesmoke" |==<br />
|style="color:silver; background:whitesmoke" |False<br />
|P8<br />
|style="color:silver; background:whitesmoke" |None<br />
|style="color:silver; background:whitesmoke" |None<br />
|-<br />
|align="left" |actorFromPos<br />
|$15<br />
|style="color:silver; background:whitesmoke" |==<br />
|True<br />
|P16<br />
|P16<br />
|style="color:silver; background:whitesmoke" |None<br />
|-<br />
|align="left" |actorOps<br />
|$13<br />
|ActorOps<br />
|style="color:silver; background:whitesmoke" |False<br />
|P8<br />
|SO+<br />
|FF<br />
|-<br />
|align="left" |actorOps$00<br />
|$00<br />
|Unknown<br />
|style="color:silver; background:whitesmoke" |False<br />
|P8<br />
|style="color:silver; background:whitesmoke" |None<br />
|style="color:silver; background:whitesmoke" |None<br />
|-<br />
|align="left" |actorOps$01<br />
|$01<br />
|Costume<br />
|style="color:silver; background:whitesmoke" |False<br />
|P8<br />
|style="color:silver; background:whitesmoke" |None<br />
|style="color:silver; background:whitesmoke" |None<br />
|-<br />
|align="left" |actorOps$02<br />
|$02<br />
|WalkSpeed<br />
|style="color:silver; background:whitesmoke" |False<br />
|P8<br />
|P8<br />
|style="color:silver; background:whitesmoke" |None<br />
|-<br />
|align="left" |actorOps$03<br />
|$03<br />
|Sound<br />
|style="color:silver; background:whitesmoke" |False<br />
|P8<br />
|style="color:silver; background:whitesmoke" |None<br />
|style="color:silver; background:whitesmoke" |None<br />
|-<br />
|align="left" |actorOps$04<br />
|$04<br />
|WalkAnimNr<br />
|style="color:silver; background:whitesmoke" |False<br />
|P8<br />
|style="color:silver; background:whitesmoke" |None<br />
|style="color:silver; background:whitesmoke" |None<br />
|-<br />
|align="left" |actorOps$05<br />
|$05<br />
|TalkAnimNr<br />
|style="color:silver; background:whitesmoke" |False<br />
|P8<br />
|P8<br />
|style="color:silver; background:whitesmoke" |None<br />
|-<br />
|align="left" |actorOps$06<br />
|$06<br />
|StandAnimNr<br />
|style="color:silver; background:whitesmoke" |False<br />
|P8<br />
|style="color:silver; background:whitesmoke" |None<br />
|style="color:silver; background:whitesmoke" |None<br />
|-<br />
|align="left" |actorOps$07<br />
|$07<br />
|Nothing<br />
|style="color:silver; background:whitesmoke" |False<br />
|P8<br />
|P8<br />
|P8<br />
|-<br />
|align="left" |actorOps$08<br />
|$08<br />
|Init<br />
|style="color:silver; background:whitesmoke" |False<br />
|style="color:silver; background:whitesmoke" |None<br />
|style="color:silver; background:whitesmoke" |None<br />
|style="color:silver; background:whitesmoke" |None<br />
|-<br />
|align="left" |actorOps$09<br />
|$09<br />
|Elevation<br />
|style="color:silver; background:whitesmoke" |False<br />
|P16<br />
|style="color:silver; background:whitesmoke" |None<br />
|style="color:silver; background:whitesmoke" |None<br />
|-<br />
|align="left" |actorOps$0A<br />
|$0A<br />
|DefaultAnims<br />
|style="color:silver; background:whitesmoke" |False<br />
|style="color:silver; background:whitesmoke" |None<br />
|style="color:silver; background:whitesmoke" |None<br />
|style="color:silver; background:whitesmoke" |None<br />
|-<br />
|align="left" |actorOps$0B<br />
|$0B<br />
|Palette<br />
|style="color:silver; background:whitesmoke" |False<br />
|P8<br />
|P8<br />
|style="color:silver; background:whitesmoke" |None<br />
|-<br />
|align="left" |actorOps$0C<br />
|$0C<br />
|TalkColor<br />
|style="color:silver; background:whitesmoke" |False<br />
|P8<br />
|style="color:silver; background:whitesmoke" |None<br />
|style="color:silver; background:whitesmoke" |None<br />
|-<br />
|align="left" |actorOps$0D<br />
|$0D<br />
|Name<br />
|style="color:silver; background:whitesmoke" |False<br />
|A0<br />
|style="color:silver; background:whitesmoke" |None<br />
|style="color:silver; background:whitesmoke" |None<br />
|-<br />
|align="left" |actorOps$0E<br />
|$0E<br />
|InitAnimNr<br />
|style="color:silver; background:whitesmoke" |False<br />
|P8<br />
|style="color:silver; background:whitesmoke" |None<br />
|style="color:silver; background:whitesmoke" |None<br />
|-<br />
|align="left" |actorOps$10<br />
|$10<br />
|Width<br />
|style="color:silver; background:whitesmoke" |False<br />
|P8<br />
|style="color:silver; background:whitesmoke" |None<br />
|style="color:silver; background:whitesmoke" |None<br />
|-<br />
|align="left" |actorOps$11<br />
|$11<br />
|Scale<br />
|style="color:silver; background:whitesmoke" |False<br />
|P8<br />
|P8<br />
|style="color:silver; background:whitesmoke" |None<br />
|-<br />
|align="left" |actorOps$12<br />
|$12<br />
|NeverZClip<br />
|style="color:silver; background:whitesmoke" |False<br />
|style="color:silver; background:whitesmoke" |None<br />
|style="color:silver; background:whitesmoke" |None<br />
|style="color:silver; background:whitesmoke" |None<br />
|-<br />
|align="left" |actorOps$13<br />
|$13<br />
|SetZClip<br />
|style="color:silver; background:whitesmoke" |False<br />
|P8<br />
|style="color:silver; background:whitesmoke" |None<br />
|style="color:silver; background:whitesmoke" |None<br />
|-<br />
|align="left" |actorOps$14<br />
|$14<br />
|IgnoreBoxes<br />
|style="color:silver; background:whitesmoke" |False<br />
|style="color:silver; background:whitesmoke" |None<br />
|style="color:silver; background:whitesmoke" |None<br />
|style="color:silver; background:whitesmoke" |None<br />
|-<br />
|align="left" |actorOps$15<br />
|$15<br />
|FollowBoxes<br />
|style="color:silver; background:whitesmoke" |False<br />
|P8<br />
|style="color:silver; background:whitesmoke" |None<br />
|style="color:silver; background:whitesmoke" |None<br />
|-<br />
|align="left" |actorOps$16<br />
|$16<br />
|AnimSpeed<br />
|style="color:silver; background:whitesmoke" |False<br />
|P8<br />
|style="color:silver; background:whitesmoke" |None<br />
|style="color:silver; background:whitesmoke" |None<br />
|-<br />
|align="left" |actorOps$17<br />
|$17<br />
|ShadowMode<br />
|style="color:silver; background:whitesmoke" |False<br />
|P8<br />
|style="color:silver; background:whitesmoke" |None<br />
|style="color:silver; background:whitesmoke" |None<br />
|-<br />
|align="left" |actorSetClass<br />
|$5D<br />
|setClass<br />
|style="color:silver; background:whitesmoke" |False<br />
|P16<br />
|L<br />
|style="color:silver; background:whitesmoke" |None<br />
|-<br />
|align="left" |add<br />
|$5A<br />
|(inline)<br />
|True<br />
|P16<br />
|style="color:silver; background:whitesmoke" |None<br />
|style="color:silver; background:whitesmoke" |None<br />
|-<br />
|align="left" |and<br />
|$17<br />
|(inline)<br />
|True<br />
|P16<br />
|style="color:silver; background:whitesmoke" |None<br />
|style="color:silver; background:whitesmoke" |None<br />
|-<br />
|align="left" |animateActor<br />
|$11<br />
|animateCostume<br />
|style="color:silver; background:whitesmoke" |False<br />
|P8<br />
|P8<br />
|style="color:silver; background:whitesmoke" |None<br />
|-<br />
|align="left" |breakHere<br />
|$80<br />
|style="color:silver; background:whitesmoke" |==<br />
|style="color:silver; background:whitesmoke" |False<br />
|style="color:silver; background:whitesmoke" |None<br />
|style="color:silver; background:whitesmoke" |None<br />
|style="color:silver; background:whitesmoke" |None<br />
|-<br />
|align="left" |chainScript<br />
|$42<br />
|style="color:silver; background:whitesmoke" |==<br />
|style="color:silver; background:whitesmoke" |False<br />
|P8<br />
|L<br />
|style="color:silver; background:whitesmoke" |None<br />
|-<br />
|align="left" |cursorCommand<br />
|$2C<br />
|(none)<br />
|style="color:silver; background:whitesmoke" |False<br />
|SO<br />
|style="color:silver; background:whitesmoke" |None<br />
|style="color:silver; background:whitesmoke" |None<br />
|-<br />
|align="left" |cursorCommand$01<br />
|$01<br />
|CursorShow<br />
|style="color:silver; background:whitesmoke" |False<br />
|style="color:silver; background:whitesmoke" |None<br />
|style="color:silver; background:whitesmoke" |None<br />
|style="color:silver; background:whitesmoke" |None<br />
|-<br />
|align="left" |cursorCommand$02<br />
|$02<br />
|CursorHide<br />
|style="color:silver; background:whitesmoke" |False<br />
|style="color:silver; background:whitesmoke" |None<br />
|style="color:silver; background:whitesmoke" |None<br />
|style="color:silver; background:whitesmoke" |None<br />
|-<br />
|align="left" |cursorCommand$03<br />
|$03<br />
|UserputOn<br />
|style="color:silver; background:whitesmoke" |False<br />
|style="color:silver; background:whitesmoke" |None<br />
|style="color:silver; background:whitesmoke" |None<br />
|style="color:silver; background:whitesmoke" |None<br />
|-<br />
|align="left" |cursorCommand$04<br />
|$04<br />
|UserputOff<br />
|style="color:silver; background:whitesmoke" |False<br />
|style="color:silver; background:whitesmoke" |None<br />
|style="color:silver; background:whitesmoke" |None<br />
|style="color:silver; background:whitesmoke" |None<br />
|-<br />
|align="left" |cursorCommand$05<br />
|$05<br />
|CursorSoftOn<br />
|style="color:silver; background:whitesmoke" |False<br />
|style="color:silver; background:whitesmoke" |None<br />
|style="color:silver; background:whitesmoke" |None<br />
|style="color:silver; background:whitesmoke" |None<br />
|-<br />
|align="left" |cursorCommand$06<br />
|$06<br />
|CursorSoftOff<br />
|style="color:silver; background:whitesmoke" |False<br />
|style="color:silver; background:whitesmoke" |None<br />
|style="color:silver; background:whitesmoke" |None<br />
|style="color:silver; background:whitesmoke" |None<br />
|-<br />
|align="left" |cursorCommand$07<br />
|$07<br />
|UserputSoftOn<br />
|style="color:silver; background:whitesmoke" |False<br />
|style="color:silver; background:whitesmoke" |None<br />
|style="color:silver; background:whitesmoke" |None<br />
|style="color:silver; background:whitesmoke" |None<br />
|-<br />
|align="left" |cursorCommand$08<br />
|$08<br />
|UserputSoftOff<br />
|style="color:silver; background:whitesmoke" |False<br />
|style="color:silver; background:whitesmoke" |None<br />
|style="color:silver; background:whitesmoke" |None<br />
|style="color:silver; background:whitesmoke" |None<br />
|-<br />
|align="left" |cursorCommand$0A<br />
|$0A<br />
|SetCursorImg<br />
|style="color:silver; background:whitesmoke" |False<br />
|P8<br />
|P8<br />
|style="color:silver; background:whitesmoke" |None<br />
|-<br />
|align="left" |cursorCommand$0B<br />
|$0B<br />
|setCursorHotspot<br />
|style="color:silver; background:whitesmoke" |False<br />
|P8<br />
|P8<br />
|P8<br />
|-<br />
|align="left" |cursorCommand$0C<br />
|$0C<br />
|InitCursor<br />
|style="color:silver; background:whitesmoke" |False<br />
|P8<br />
|style="color:silver; background:whitesmoke" |None<br />
|style="color:silver; background:whitesmoke" |None<br />
|-<br />
|align="left" |cursorCommand$0D<br />
|$0D<br />
|InitCharset<br />
|style="color:silver; background:whitesmoke" |False<br />
|P8<br />
|style="color:silver; background:whitesmoke" |None<br />
|style="color:silver; background:whitesmoke" |None<br />
|-<br />
|align="left" |cursorCommand$0E<br />
|$0E<br />
|CursorCommand<br />
|style="color:silver; background:whitesmoke" |False<br />
|L<br />
|style="color:silver; background:whitesmoke" |None<br />
|style="color:silver; background:whitesmoke" |None<br />
|-<br />
|align="left" |cutscene<br />
|$40<br />
|style="color:silver; background:whitesmoke" |==<br />
|style="color:silver; background:whitesmoke" |False<br />
|L<br />
|style="color:silver; background:whitesmoke" |None<br />
|style="color:silver; background:whitesmoke" |None<br />
|-<br />
|align="left" |debug<br />
|$6B<br />
|debug?<br />
|style="color:silver; background:whitesmoke" |False<br />
|P16<br />
|style="color:silver; background:whitesmoke" |None<br />
|style="color:silver; background:whitesmoke" |None<br />
|-<br />
|align="left" |decrement<br />
|$C6<br />
|(inline)<br />
|True<br />
|style="color:silver; background:whitesmoke" |None<br />
|style="color:silver; background:whitesmoke" |None<br />
|style="color:silver; background:whitesmoke" |None<br />
|-<br />
|align="left" |delay<br />
|$2E<br />
|style="color:silver; background:whitesmoke" |==<br />
|style="color:silver; background:whitesmoke" |False<br />
|D<br />
|style="color:silver; background:whitesmoke" |None<br />
|style="color:silver; background:whitesmoke" |None<br />
|-<br />
|align="left" |delayVariable<br />
|$2B<br />
|style="color:silver; background:whitesmoke" |==<br />
|style="color:silver; background:whitesmoke" |False<br />
|V<br />
|style="color:silver; background:whitesmoke" |None<br />
|style="color:silver; background:whitesmoke" |None<br />
|-<br />
|align="left" |divide<br />
|$5B<br />
|(inline)<br />
|True<br />
|P16<br />
|style="color:silver; background:whitesmoke" |None<br />
|style="color:silver; background:whitesmoke" |None<br />
|-<br />
|align="left" |doSentence<br />
|$19<br />
|style="color:silver; background:whitesmoke" |==<br />
|style="color:silver; background:whitesmoke" |False<br />
|P8<br />
|P16<br />
|P16<br />
|-<br />
|align="left" |drawBox<br />
|$3F<br />
|style="color:silver; background:whitesmoke" |==<br />
|style="color:silver; background:whitesmoke" |False<br />
|P16<br />
|P16<br />
|NS<br />
|-<br />
|align="left" |drawObject<br />
|$05<br />
|style="color:silver; background:whitesmoke" |==<br />
|style="color:silver; background:whitesmoke" |False<br />
|P16<br />
|SO<br />
|style="color:silver; background:whitesmoke" |None<br />
|-<br />
|align="left" |drawObject$01<br />
|$01<br />
|setXY<br />
|style="color:silver; background:whitesmoke" |False<br />
|P16<br />
|P16<br />
|style="color:silver; background:whitesmoke" |None<br />
|-<br />
|align="left" |drawObject$02<br />
|$02<br />
|setImage<br />
|style="color:silver; background:whitesmoke" |False<br />
|P16<br />
|style="color:silver; background:whitesmoke" |None<br />
|style="color:silver; background:whitesmoke" |None<br />
|-<br />
|align="left" |drawObject$1F<br />
|$1F<br />
|()<br />
|style="color:silver; background:whitesmoke" |False<br />
|style="color:silver; background:whitesmoke" |None<br />
|style="color:silver; background:whitesmoke" |None<br />
|style="color:silver; background:whitesmoke" |None<br />
|-<br />
|align="left" |dummy<br />
|$A7<br />
|dummy(A7)<br />
|style="color:silver; background:whitesmoke" |False<br />
|style="color:silver; background:whitesmoke" |None<br />
|style="color:silver; background:whitesmoke" |None<br />
|style="color:silver; background:whitesmoke" |None<br />
|-<br />
|align="left" |endCutscene<br />
|$C0<br />
|style="color:silver; background:whitesmoke" |==<br />
|style="color:silver; background:whitesmoke" |False<br />
|style="color:silver; background:whitesmoke" |None<br />
|style="color:silver; background:whitesmoke" |None<br />
|style="color:silver; background:whitesmoke" |None<br />
|-<br />
|align="left" |equalZero<br />
|$28<br />
|inline<br />
|style="color:silver; background:whitesmoke" |False<br />
|V<br />
|J<br />
|style="color:silver; background:whitesmoke" |None<br />
|-<br />
|align="left" |expression<br />
|$AC<br />
|Exprmode<br />
|True<br />
|SO+<br />
|FF<br />
|style="color:silver; background:whitesmoke" |None<br />
|-<br />
|align="left" |expression$01<br />
|$01<br />
|(inline)<br />
|style="color:silver; background:whitesmoke" |False<br />
|P16<br />
|style="color:silver; background:whitesmoke" |None<br />
|style="color:silver; background:whitesmoke" |None<br />
|-<br />
|align="left" |expression$02<br />
|$02<br />
|(inline)<br />
|style="color:silver; background:whitesmoke" |False<br />
|style="color:silver; background:whitesmoke" |None<br />
|style="color:silver; background:whitesmoke" |None<br />
|style="color:silver; background:whitesmoke" |None<br />
|-<br />
|align="left" |expression$03<br />
|$03<br />
|(inline)<br />
|style="color:silver; background:whitesmoke" |False<br />
|style="color:silver; background:whitesmoke" |None<br />
|style="color:silver; background:whitesmoke" |None<br />
|style="color:silver; background:whitesmoke" |None<br />
|-<br />
|align="left" |expression$04<br />
|$04<br />
|(inline)<br />
|style="color:silver; background:whitesmoke" |False<br />
|style="color:silver; background:whitesmoke" |None<br />
|style="color:silver; background:whitesmoke" |None<br />
|style="color:silver; background:whitesmoke" |None<br />
|-<br />
|align="left" |expression$05<br />
|$05<br />
|(inline)<br />
|style="color:silver; background:whitesmoke" |False<br />
|style="color:silver; background:whitesmoke" |None<br />
|style="color:silver; background:whitesmoke" |None<br />
|style="color:silver; background:whitesmoke" |None<br />
|-<br />
|align="left" |expression$06<br />
|$06<br />
|(inline)<br />
|style="color:silver; background:whitesmoke" |False<br />
|NS<br />
|style="color:silver; background:whitesmoke" |None<br />
|style="color:silver; background:whitesmoke" |None<br />
|-<br />
|align="left" |faceActor<br />
|$09<br />
|style="color:silver; background:whitesmoke" |==<br />
|style="color:silver; background:whitesmoke" |False<br />
|P8<br />
|P16<br />
|style="color:silver; background:whitesmoke" |None<br />
|-<br />
|align="left" |findInventory<br />
|$3D<br />
|style="color:silver; background:whitesmoke" |==<br />
|True<br />
|P8<br />
|P8<br />
|style="color:silver; background:whitesmoke" |None<br />
|-<br />
|align="left" |findObject<br />
|$35<br />
|style="color:silver; background:whitesmoke" |==<br />
|True<br />
|P8<br />
|P8<br />
|style="color:silver; background:whitesmoke" |None<br />
|-<br />
|align="left" |freezeScripts<br />
|$60<br />
|style="color:silver; background:whitesmoke" |==<br />
|style="color:silver; background:whitesmoke" |False<br />
|P8<br />
|style="color:silver; background:whitesmoke" |None<br />
|style="color:silver; background:whitesmoke" |None<br />
|-<br />
|align="left" |getActorCostume<br />
|$71<br />
|style="color:silver; background:whitesmoke" |==<br />
|True<br />
|P8<br />
|style="color:silver; background:whitesmoke" |None<br />
|style="color:silver; background:whitesmoke" |None<br />
|-<br />
|align="left" |getActorElevation<br />
|$06<br />
|style="color:silver; background:whitesmoke" |==<br />
|True<br />
|P8<br />
|style="color:silver; background:whitesmoke" |None<br />
|style="color:silver; background:whitesmoke" |None<br />
|-<br />
|align="left" |getActorFacing<br />
|$63<br />
|style="color:silver; background:whitesmoke" |==<br />
|True<br />
|P8<br />
|style="color:silver; background:whitesmoke" |None<br />
|style="color:silver; background:whitesmoke" |None<br />
|-<br />
|align="left" |getActorMoving<br />
|$56<br />
|style="color:silver; background:whitesmoke" |==<br />
|True<br />
|P8<br />
|style="color:silver; background:whitesmoke" |None<br />
|style="color:silver; background:whitesmoke" |None<br />
|-<br />
|align="left" |getActorRoom<br />
|$03<br />
|style="color:silver; background:whitesmoke" |==<br />
|True<br />
|P8<br />
|style="color:silver; background:whitesmoke" |None<br />
|style="color:silver; background:whitesmoke" |None<br />
|-<br />
|align="left" |getActorScale<br />
|$3B<br />
|style="color:silver; background:whitesmoke" |==<br />
|True<br />
|P8<br />
|style="color:silver; background:whitesmoke" |None<br />
|style="color:silver; background:whitesmoke" |None<br />
|-<br />
|align="left" |getActorWalkBox<br />
|$7B<br />
|style="color:silver; background:whitesmoke" |==<br />
|True<br />
|P8<br />
|style="color:silver; background:whitesmoke" |None<br />
|style="color:silver; background:whitesmoke" |None<br />
|-<br />
|align="left" |getActorWidth<br />
|$6C<br />
|style="color:silver; background:whitesmoke" |==<br />
|True<br />
|P8<br />
|style="color:silver; background:whitesmoke" |None<br />
|style="color:silver; background:whitesmoke" |None<br />
|-<br />
|align="left" |getActorX<br />
|$43<br />
|style="color:silver; background:whitesmoke" |==<br />
|True<br />
|P16<br />
|style="color:silver; background:whitesmoke" |None<br />
|style="color:silver; background:whitesmoke" |None<br />
|-<br />
|align="left" |getActorY<br />
|$23<br />
|style="color:silver; background:whitesmoke" |==<br />
|True<br />
|P16<br />
|style="color:silver; background:whitesmoke" |None<br />
|style="color:silver; background:whitesmoke" |None<br />
|-<br />
|align="left" |getAnimCounter<br />
|$22<br />
|style="color:silver; background:whitesmoke" |==<br />
|True<br />
|P8<br />
|style="color:silver; background:whitesmoke" |None<br />
|style="color:silver; background:whitesmoke" |None<br />
|-<br />
|align="left" |getClosestObjActor<br />
|$66<br />
|style="color:silver; background:whitesmoke" |==<br />
|True<br />
|P16<br />
|style="color:silver; background:whitesmoke" |None<br />
|style="color:silver; background:whitesmoke" |None<br />
|-<br />
|align="left" |getDist<br />
|$34<br />
|style="color:silver; background:whitesmoke" |==<br />
|True<br />
|P16<br />
|P16<br />
|style="color:silver; background:whitesmoke" |None<br />
|-<br />
|align="left" |getInventoryCount<br />
|$31<br />
|style="color:silver; background:whitesmoke" |==<br />
|True<br />
|P8<br />
|style="color:silver; background:whitesmoke" |None<br />
|style="color:silver; background:whitesmoke" |None<br />
|-<br />
|align="left" |getObjectOwner<br />
|$10<br />
|style="color:silver; background:whitesmoke" |==<br />
|True<br />
|P16<br />
|style="color:silver; background:whitesmoke" |None<br />
|style="color:silver; background:whitesmoke" |None<br />
|-<br />
|align="left" |getObjectState<br />
|$0F<br />
|style="color:silver; background:whitesmoke" |==<br />
|True<br />
|P16<br />
|style="color:silver; background:whitesmoke" |None<br />
|style="color:silver; background:whitesmoke" |None<br />
|-<br />
|align="left" |getRandomNumber<br />
|$16<br />
|getRandomNr<br />
|True<br />
|P8<br />
|style="color:silver; background:whitesmoke" |None<br />
|style="color:silver; background:whitesmoke" |None<br />
|-<br />
|align="left" |getScriptRunning<br />
|$68<br />
|style="color:silver; background:whitesmoke" |isScriptRunning<br />
|True<br />
|P8<br />
|style="color:silver; background:whitesmoke" |None<br />
|style="color:silver; background:whitesmoke" |None<br />
|-<br />
|align="left" |getStringWidth<br />
|$67<br />
|style="color:silver; background:whitesmoke" |==<br />
|True<br />
|P8<br />
|style="color:silver; background:whitesmoke" |None<br />
|style="color:silver; background:whitesmoke" |None<br />
|-<br />
|align="left" |getVerbEntryPoint<br />
|$0B<br />
|style="color:silver; background:whitesmoke" |==<br />
|True<br />
|P16<br />
|P16<br />
|style="color:silver; background:whitesmoke" |None<br />
|-<br />
|align="left" |ifClassOfIs<br />
|$1D<br />
|classOfIs<br />
|style="color:silver; background:whitesmoke" |False<br />
|P16<br />
|L<br />
|J<br />
|-<br />
|align="left" |ifNotState<br />
|$2F<br />
|getState (inline)<br />
|style="color:silver; background:whitesmoke" |False<br />
|P16<br />
|P8<br />
|J<br />
|-<br />
|align="left" |ifState<br />
|$4F<br />
|getState (inline)<br />
|style="color:silver; background:whitesmoke" |False<br />
|P16<br />
|P8<br />
|J<br />
|-<br />
|align="left" |increment<br />
|$46<br />
|(inline)<br />
|True<br />
|style="color:silver; background:whitesmoke" |None<br />
|style="color:silver; background:whitesmoke" |None<br />
|style="color:silver; background:whitesmoke" |None<br />
|-<br />
|align="left" |isActorInBox<br />
|$1F<br />
|style="color:silver; background:whitesmoke" |==<br />
|style="color:silver; background:whitesmoke" |False<br />
|P8<br />
|P8<br />
|J<br />
|-<br />
|align="left" |isEqual<br />
|$48<br />
|(inline)<br />
|style="color:silver; background:whitesmoke" |False<br />
|V<br />
|P16<br />
|J<br />
|-<br />
|align="left" |isGreater<br />
|$78<br />
|(inline)<br />
|style="color:silver; background:whitesmoke" |False<br />
|V<br />
|P16<br />
|J<br />
|-<br />
|align="left" |isGreaterEqual<br />
|$04<br />
|(inline)<br />
|style="color:silver; background:whitesmoke" |False<br />
|V<br />
|P16<br />
|J<br />
|-<br />
|align="left" |isLess<br />
|$44<br />
|(inline)<br />
|style="color:silver; background:whitesmoke" |False<br />
|V<br />
|P16<br />
|J<br />
|-<br />
|align="left" |isNotEqual<br />
|$08<br />
|(inline)<br />
|style="color:silver; background:whitesmoke" |False<br />
|V<br />
|P16<br />
|J<br />
|-<br />
|align="left" |isSoundRunning<br />
|$7C<br />
|style="color:silver; background:whitesmoke" |==<br />
|True<br />
|P8<br />
|style="color:silver; background:whitesmoke" |None<br />
|style="color:silver; background:whitesmoke" |None<br />
|-<br />
|align="left" |jumpRelative<br />
|$18<br />
|(inline) or goto<br />
|style="color:silver; background:whitesmoke" |False<br />
|J<br />
|style="color:silver; background:whitesmoke" |None<br />
|style="color:silver; background:whitesmoke" |None<br />
|-<br />
|align="left" |lessOrEqual<br />
|$38<br />
|(inline)<br />
|style="color:silver; background:whitesmoke" |False<br />
|V<br />
|P16<br />
|J<br />
|-<br />
|align="left" |lights<br />
|$70<br />
|style="color:silver; background:whitesmoke" |==<br />
|style="color:silver; background:whitesmoke" |False<br />
|P8<br />
|B<br />
|B<br />
|-<br />
|align="left" |loadRoom<br />
|$72<br />
|style="color:silver; background:whitesmoke" |==<br />
|style="color:silver; background:whitesmoke" |False<br />
|P8<br />
|style="color:silver; background:whitesmoke" |None<br />
|style="color:silver; background:whitesmoke" |None<br />
|-<br />
|align="left" |loadRoomWithEgo<br />
|$24<br />
|style="color:silver; background:whitesmoke" |==<br />
|style="color:silver; background:whitesmoke" |False<br />
|P16<br />
|P8<br />
|NS<br />
|-<br />
|align="left" |matrixOp<br />
|$30<br />
|N/A<br />
|style="color:silver; background:whitesmoke" |False<br />
|SO<br />
|style="color:silver; background:whitesmoke" |None<br />
|style="color:silver; background:whitesmoke" |None<br />
|-<br />
|align="left" |matrixOp$01<br />
|$01<br />
|setBoxFlags<br />
|style="color:silver; background:whitesmoke" |False<br />
|P8<br />
|P8<br />
|style="color:silver; background:whitesmoke" |None<br />
|-<br />
|align="left" |matrixOp$02<br />
|$02<br />
|setBoxScale<br />
|style="color:silver; background:whitesmoke" |False<br />
|P8<br />
|P8<br />
|style="color:silver; background:whitesmoke" |None<br />
|-<br />
|align="left" |matrixOp$03<br />
|$03<br />
|SetBoxSlot<br />
|style="color:silver; background:whitesmoke" |False<br />
|P8<br />
|P8<br />
|style="color:silver; background:whitesmoke" |None<br />
|-<br />
|align="left" |matrixOp$04<br />
|$04<br />
|createBoxMatrix<br />
|style="color:silver; background:whitesmoke" |False<br />
|style="color:silver; background:whitesmoke" |None<br />
|style="color:silver; background:whitesmoke" |None<br />
|style="color:silver; background:whitesmoke" |None<br />
|-<br />
|align="left" |move<br />
|$1A<br />
|(inline)<br />
|True<br />
|P16<br />
|style="color:silver; background:whitesmoke" |None<br />
|style="color:silver; background:whitesmoke" |None<br />
|-<br />
|align="left" |multiply<br />
|$1B<br />
|(inline)<br />
|True<br />
|P16<br />
|style="color:silver; background:whitesmoke" |None<br />
|style="color:silver; background:whitesmoke" |None<br />
|-<br />
|align="left" |notEqualZero<br />
|$A8<br />
|(inline)<br />
|style="color:silver; background:whitesmoke" |False<br />
|V<br />
|J<br />
|style="color:silver; background:whitesmoke" |None<br />
|-<br />
|align="left" |oldRoomEffect<br />
|$5C<br />
|oldRoomEffect-fadein<br />
|style="color:silver; background:whitesmoke" |False<br />
|SO<br />
|style="color:silver; background:whitesmoke" |None<br />
|style="color:silver; background:whitesmoke" |None<br />
|-<br />
|align="left" |oldRoomEffect$03<br />
|$03<br />
|oldRoomEffect-set<br />
|style="color:silver; background:whitesmoke" |False<br />
|P16<br />
|style="color:silver; background:whitesmoke" |None<br />
|style="color:silver; background:whitesmoke" |None<br />
|-<br />
|align="left" |or<br />
|$57<br />
|(inline)<br />
|True<br />
|P16<br />
|style="color:silver; background:whitesmoke" |None<br />
|style="color:silver; background:whitesmoke" |None<br />
|-<br />
|align="left" |override<br />
|$58<br />
|N/A<br />
|style="color:silver; background:whitesmoke" |False<br />
|SO<br />
|style="color:silver; background:whitesmoke" |None<br />
|style="color:silver; background:whitesmoke" |None<br />
|-<br />
|align="left" |override$00<br />
|$00<br />
|endOverride<br />
|style="color:silver; background:whitesmoke" |False<br />
|style="color:silver; background:whitesmoke" |None<br />
|style="color:silver; background:whitesmoke" |None<br />
|style="color:silver; background:whitesmoke" |None<br />
|-<br />
|align="left" |override$01<br />
|$01<br />
|beginOverride<br />
|style="color:silver; background:whitesmoke" |False<br />
|NS<br />
|J<br />
|style="color:silver; background:whitesmoke" |None<br />
|-<br />
|align="left" |panCameraTo<br />
|$12<br />
|style="color:silver; background:whitesmoke" |==<br />
|style="color:silver; background:whitesmoke" |False<br />
|P16<br />
|style="color:silver; background:whitesmoke" |None<br />
|style="color:silver; background:whitesmoke" |None<br />
|-<br />
|align="left" |pickupObject<br />
|$25<br />
|style="color:silver; background:whitesmoke" |==<br />
|style="color:silver; background:whitesmoke" |False<br />
|P16<br />
|P8<br />
|style="color:silver; background:whitesmoke" |None<br />
|-<br />
|align="left" |pickupObjectOld<br />
|$50<br />
|pickupObject<br />
|style="color:silver; background:whitesmoke" |False<br />
|P16<br />
|style="color:silver; background:whitesmoke" |None<br />
|style="color:silver; background:whitesmoke" |None<br />
|-<br />
|align="left" |print<br />
|$14<br />
|style="color:silver; background:whitesmoke" |==<br />
|style="color:silver; background:whitesmoke" |False<br />
|P8<br />
|SO+<br />
|style="color:silver; background:whitesmoke" |None<br />
|-<br />
|align="left" |print$00<br />
|$00<br />
|Pos<br />
|style="color:silver; background:whitesmoke" |False<br />
|P16<br />
|P16<br />
|style="color:silver; background:whitesmoke" |None<br />
|-<br />
|align="left" |print$01<br />
|$01<br />
|Color<br />
|style="color:silver; background:whitesmoke" |False<br />
|P8<br />
|style="color:silver; background:whitesmoke" |None<br />
|style="color:silver; background:whitesmoke" |None<br />
|-<br />
|align="left" |print$02<br />
|$02<br />
|Clipped<br />
|style="color:silver; background:whitesmoke" |False<br />
|P16<br />
|style="color:silver; background:whitesmoke" |None<br />
|style="color:silver; background:whitesmoke" |None<br />
|-<br />
|align="left" |print$03<br />
|$03<br />
|RestoreBG<br />
|style="color:silver; background:whitesmoke" |False<br />
|P16<br />
|P16<br />
|style="color:silver; background:whitesmoke" |None<br />
|-<br />
|align="left" |print$04<br />
|$04<br />
|Center<br />
|style="color:silver; background:whitesmoke" |False<br />
|style="color:silver; background:whitesmoke" |None<br />
|style="color:silver; background:whitesmoke" |None<br />
|style="color:silver; background:whitesmoke" |None<br />
|-<br />
|align="left" |print$06<br />
|$06<br />
|Left<br />
|style="color:silver; background:whitesmoke" |False<br />
|style="color:silver; background:whitesmoke" |None<br />
|style="color:silver; background:whitesmoke" |None<br />
|style="color:silver; background:whitesmoke" |None<br />
|-<br />
|align="left" |print$07<br />
|$07<br />
|Overhead<br />
|style="color:silver; background:whitesmoke" |False<br />
|style="color:silver; background:whitesmoke" |None<br />
|style="color:silver; background:whitesmoke" |None<br />
|style="color:silver; background:whitesmoke" |None<br />
|-<br />
|align="left" |print$08<br />
|$08<br />
|PlayCDTrack<br />
|style="color:silver; background:whitesmoke" |False<br />
|P16<br />
|P16<br />
|style="color:silver; background:whitesmoke" |None<br />
|-<br />
|align="left" |print$0F<br />
|$0F<br />
|Text()<br />
|style="color:silver; background:whitesmoke" |False<br />
|A1<br />
|style="color:silver; background:whitesmoke" |None<br />
|style="color:silver; background:whitesmoke" |None<br />
|-<br />
|align="left" |printEgo<br />
|$D8<br />
|style="color:silver; background:whitesmoke" |==<br />
|style="color:silver; background:whitesmoke" |False<br />
|SO+<br />
|style="color:silver; background:whitesmoke" |None<br />
|style="color:silver; background:whitesmoke" |None<br />
|-<br />
|align="left" |printEgo$00<br />
|$00<br />
|Pos<br />
|style="color:silver; background:whitesmoke" |False<br />
|P16<br />
|P16<br />
|style="color:silver; background:whitesmoke" |None<br />
|-<br />
|align="left" |printEgo$01<br />
|$01<br />
|Color<br />
|style="color:silver; background:whitesmoke" |False<br />
|P8<br />
|style="color:silver; background:whitesmoke" |None<br />
|style="color:silver; background:whitesmoke" |None<br />
|-<br />
|align="left" |printEgo$02<br />
|$02<br />
|Clipped<br />
|style="color:silver; background:whitesmoke" |False<br />
|P16<br />
|style="color:silver; background:whitesmoke" |None<br />
|style="color:silver; background:whitesmoke" |None<br />
|-<br />
|align="left" |printEgo$03<br />
|$03<br />
|RestoreBG<br />
|style="color:silver; background:whitesmoke" |False<br />
|P16<br />
|P16<br />
|style="color:silver; background:whitesmoke" |None<br />
|-<br />
|align="left" |printEgo$04<br />
|$04<br />
|Center<br />
|style="color:silver; background:whitesmoke" |False<br />
|style="color:silver; background:whitesmoke" |None<br />
|style="color:silver; background:whitesmoke" |None<br />
|style="color:silver; background:whitesmoke" |None<br />
|-<br />
|align="left" |printEgo$06<br />
|$06<br />
|Left<br />
|style="color:silver; background:whitesmoke" |False<br />
|style="color:silver; background:whitesmoke" |None<br />
|style="color:silver; background:whitesmoke" |None<br />
|style="color:silver; background:whitesmoke" |None<br />
|-<br />
|align="left" |printEgo$07<br />
|$07<br />
|Overhead<br />
|style="color:silver; background:whitesmoke" |False<br />
|style="color:silver; background:whitesmoke" |None<br />
|style="color:silver; background:whitesmoke" |None<br />
|style="color:silver; background:whitesmoke" |None<br />
|-<br />
|align="left" |printEgo$08<br />
|$08<br />
|PlayCDTrack<br />
|style="color:silver; background:whitesmoke" |False<br />
|P16<br />
|P16<br />
|style="color:silver; background:whitesmoke" |None<br />
|-<br />
|align="left" |printEgo$0F<br />
|$0F<br />
|Text()<br />
|style="color:silver; background:whitesmoke" |False<br />
|A1<br />
|style="color:silver; background:whitesmoke" |None<br />
|style="color:silver; background:whitesmoke" |None<br />
|-<br />
|align="left" |pseudoRoom<br />
|$CC<br />
|PsuedoRoom<br />
|style="color:silver; background:whitesmoke" |False<br />
|B<br />
|NS<br />
|NS<br />
|-<br />
|align="left" |putActor<br />
|$01<br />
|style="color:silver; background:whitesmoke" |==<br />
|style="color:silver; background:whitesmoke" |False<br />
|P8<br />
|P16<br />
|P16<br />
|-<br />
|align="left" |putActorAtObject<br />
|$0E<br />
|style="color:silver; background:whitesmoke" |==<br />
|style="color:silver; background:whitesmoke" |False<br />
|P8<br />
|P16<br />
|style="color:silver; background:whitesmoke" |None<br />
|-<br />
|align="left" |putActorInRoom<br />
|$2D<br />
|style="color:silver; background:whitesmoke" |==<br />
|style="color:silver; background:whitesmoke" |False<br />
|P8<br />
|P8<br />
|style="color:silver; background:whitesmoke" |None<br />
|-<br />
|align="left" |resourceRoutines<br />
|$0C<br />
|Resource.<br />
|style="color:silver; background:whitesmoke" |False<br />
|SO<br />
|style="color:silver; background:whitesmoke" |None<br />
|style="color:silver; background:whitesmoke" |None<br />
|-<br />
|align="left" |resourcesRoutines$01<br />
|$01<br />
|loadScript<br />
|style="color:silver; background:whitesmoke" |False<br />
|P8<br />
|style="color:silver; background:whitesmoke" |None<br />
|style="color:silver; background:whitesmoke" |None<br />
|-<br />
|align="left" |resourcesRoutines$02<br />
|$02<br />
|loadSound<br />
|style="color:silver; background:whitesmoke" |False<br />
|P8<br />
|style="color:silver; background:whitesmoke" |None<br />
|style="color:silver; background:whitesmoke" |None<br />
|-<br />
|align="left" |resourcesRoutines$03<br />
|$03<br />
|loadCostume<br />
|style="color:silver; background:whitesmoke" |False<br />
|P8<br />
|style="color:silver; background:whitesmoke" |None<br />
|style="color:silver; background:whitesmoke" |None<br />
|-<br />
|align="left" |resourcesRoutines$04<br />
|$04<br />
|loadRoom<br />
|style="color:silver; background:whitesmoke" |False<br />
|P8<br />
|style="color:silver; background:whitesmoke" |None<br />
|style="color:silver; background:whitesmoke" |None<br />
|-<br />
|align="left" |resourcesRoutines$05<br />
|$05<br />
|nukeScript<br />
|style="color:silver; background:whitesmoke" |False<br />
|P8<br />
|style="color:silver; background:whitesmoke" |None<br />
|style="color:silver; background:whitesmoke" |None<br />
|-<br />
|align="left" |resourcesRoutines$06<br />
|$06<br />
|nukeSound<br />
|style="color:silver; background:whitesmoke" |False<br />
|P8<br />
|style="color:silver; background:whitesmoke" |None<br />
|style="color:silver; background:whitesmoke" |None<br />
|-<br />
|align="left" |resourcesRoutines$07<br />
|$07<br />
|nukeCostume<br />
|style="color:silver; background:whitesmoke" |False<br />
|P8<br />
|style="color:silver; background:whitesmoke" |None<br />
|style="color:silver; background:whitesmoke" |None<br />
|-<br />
|align="left" |resourcesRoutines$08<br />
|$08<br />
|nukeRoom<br />
|style="color:silver; background:whitesmoke" |False<br />
|P8<br />
|style="color:silver; background:whitesmoke" |None<br />
|style="color:silver; background:whitesmoke" |None<br />
|-<br />
|align="left" |resourcesRoutines$09<br />
|$09<br />
|lockScript<br />
|style="color:silver; background:whitesmoke" |False<br />
|P8<br />
|style="color:silver; background:whitesmoke" |None<br />
|style="color:silver; background:whitesmoke" |None<br />
|-<br />
|align="left" |resourcesRoutines$0A<br />
|$0A<br />
|lockSound<br />
|style="color:silver; background:whitesmoke" |False<br />
|P8<br />
|style="color:silver; background:whitesmoke" |None<br />
|style="color:silver; background:whitesmoke" |None<br />
|-<br />
|align="left" |resourcesRoutines$0B<br />
|$0B<br />
|lockCostume<br />
|style="color:silver; background:whitesmoke" |False<br />
|P8<br />
|style="color:silver; background:whitesmoke" |None<br />
|style="color:silver; background:whitesmoke" |None<br />
|-<br />
|align="left" |resourcesRoutines$0C<br />
|$0C<br />
|lockRoom<br />
|style="color:silver; background:whitesmoke" |False<br />
|P8<br />
|style="color:silver; background:whitesmoke" |None<br />
|style="color:silver; background:whitesmoke" |None<br />
|-<br />
|align="left" |resourcesRoutines$0D<br />
|$0D<br />
|unlockScript<br />
|style="color:silver; background:whitesmoke" |False<br />
|P8<br />
|style="color:silver; background:whitesmoke" |None<br />
|style="color:silver; background:whitesmoke" |None<br />
|-<br />
|align="left" |resourcesRoutines$0E<br />
|$0E<br />
|unlockSound<br />
|style="color:silver; background:whitesmoke" |False<br />
|P8<br />
|style="color:silver; background:whitesmoke" |None<br />
|style="color:silver; background:whitesmoke" |None<br />
|-<br />
|align="left" |resourcesRoutines$0F<br />
|$0F<br />
|unlockCostume<br />
|style="color:silver; background:whitesmoke" |False<br />
|P8<br />
|style="color:silver; background:whitesmoke" |None<br />
|style="color:silver; background:whitesmoke" |None<br />
|-<br />
|align="left" |resourcesRoutines$10<br />
|$10<br />
|unlockRoom<br />
|style="color:silver; background:whitesmoke" |False<br />
|P8<br />
|style="color:silver; background:whitesmoke" |None<br />
|style="color:silver; background:whitesmoke" |None<br />
|-<br />
|align="left" |resourcesRoutines$11<br />
|$11<br />
|clearHeap<br />
|style="color:silver; background:whitesmoke" |False<br />
|P8<br />
|style="color:silver; background:whitesmoke" |None<br />
|style="color:silver; background:whitesmoke" |None<br />
|-<br />
|align="left" |resourcesRoutines$12<br />
|$12<br />
|loadCharset<br />
|style="color:silver; background:whitesmoke" |False<br />
|P8<br />
|style="color:silver; background:whitesmoke" |None<br />
|style="color:silver; background:whitesmoke" |None<br />
|-<br />
|align="left" |resourcesRoutines$13<br />
|$13<br />
|nukeCharset<br />
|style="color:silver; background:whitesmoke" |False<br />
|P8<br />
|style="color:silver; background:whitesmoke" |None<br />
|style="color:silver; background:whitesmoke" |None<br />
|-<br />
|align="left" |resourcesRoutines$14<br />
|$14<br />
|loadFlObject<br />
|style="color:silver; background:whitesmoke" |False<br />
|P8<br />
|P16<br />
|style="color:silver; background:whitesmoke" |None<br />
|-<br />
|align="left" |roomOps<br />
|$33<br />
|N/A<br />
|style="color:silver; background:whitesmoke" |False<br />
|SO<br />
|style="color:silver; background:whitesmoke" |None<br />
|style="color:silver; background:whitesmoke" |None<br />
|-<br />
|align="left" |roomOps$01<br />
|$01<br />
|RoomScroll<br />
|style="color:silver; background:whitesmoke" |False<br />
|P16<br />
|P16<br />
|style="color:silver; background:whitesmoke" |None<br />
|-<br />
|align="left" |roomOps$03<br />
|$03<br />
|SetScreen<br />
|style="color:silver; background:whitesmoke" |False<br />
|P16<br />
|P16<br />
|style="color:silver; background:whitesmoke" |None<br />
|-<br />
|align="left" |roomOps$04<br />
|$04<br />
|SetPalColor<br />
|style="color:silver; background:whitesmoke" |False<br />
|P16<br />
|P16<br />
|NS<br />
|-<br />
|align="left" |roomOps$05<br />
|$05<br />
|ShakeOn<br />
|style="color:silver; background:whitesmoke" |False<br />
|style="color:silver; background:whitesmoke" |None<br />
|style="color:silver; background:whitesmoke" |None<br />
|style="color:silver; background:whitesmoke" |None<br />
|-<br />
|align="left" |roomOps$06<br />
|$06<br />
|ShakeOff<br />
|style="color:silver; background:whitesmoke" |False<br />
|style="color:silver; background:whitesmoke" |None<br />
|style="color:silver; background:whitesmoke" |None<br />
|style="color:silver; background:whitesmoke" |None<br />
|-<br />
|align="left" |roomOps$07<br />
|$07<br />
|Unused<br />
|style="color:silver; background:whitesmoke" |False<br />
|P8<br />
|P8<br />
|NS<br />
|-<br />
|align="left" |roomOps$08<br />
|$08<br />
|RoomIntensity<br />
|style="color:silver; background:whitesmoke" |False<br />
|P8<br />
|P8<br />
|P8<br />
|-<br />
|align="left" |roomOps$09<br />
|$09<br />
|saveLoad?<br />
|style="color:silver; background:whitesmoke" |False<br />
|P8<br />
|P8<br />
|style="color:silver; background:whitesmoke" |None<br />
|-<br />
|align="left" |roomOps$0A<br />
|$0A<br />
|screenEffect?<br />
|style="color:silver; background:whitesmoke" |False<br />
|P16<br />
|style="color:silver; background:whitesmoke" |None<br />
|style="color:silver; background:whitesmoke" |None<br />
|-<br />
|align="left" |roomOps$0B<br />
|$0B<br />
|setRGBRoomIntensity<br />
|style="color:silver; background:whitesmoke" |False<br />
|P16<br />
|P16<br />
|NS<br />
|-<br />
|align="left" |roomOps$0C<br />
|$0C<br />
|setRoomShadow<br />
|style="color:silver; background:whitesmoke" |False<br />
|P16<br />
|P16<br />
|NS<br />
|-<br />
|align="left" |roomOps$0D<br />
|$0D<br />
|saveString<br />
|style="color:silver; background:whitesmoke" |False<br />
|P8<br />
|A0<br />
|style="color:silver; background:whitesmoke" |None<br />
|-<br />
|align="left" |roomOps$0E<br />
|$0E<br />
|loadString<br />
|style="color:silver; background:whitesmoke" |False<br />
|P8<br />
|A0<br />
|style="color:silver; background:whitesmoke" |None<br />
|-<br />
|align="left" |roomOps$0F<br />
|$0F<br />
|palManipulate<br />
|style="color:silver; background:whitesmoke" |False<br />
|P8<br />
|NS<br />
|NS<br />
|-<br />
|align="left" |roomOps$10<br />
|$10<br />
|colorCycleDelay<br />
|style="color:silver; background:whitesmoke" |False<br />
|P8<br />
|P8<br />
|style="color:silver; background:whitesmoke" |None<br />
|-<br />
|align="left" |saveRestoreVerbs<br />
|$AB<br />
|N/A<br />
|style="color:silver; background:whitesmoke" |False<br />
|NS<br />
|NS<br />
|NS<br />
|-<br />
|align="left" |saveRestoreVerbs$01<br />
|$01<br />
|saveVerbs<br />
|style="color:silver; background:whitesmoke" |False<br />
|style="color:silver; background:whitesmoke" |None<br />
|style="color:silver; background:whitesmoke" |None<br />
|style="color:silver; background:whitesmoke" |None<br />
|-<br />
|align="left" |saveRestoreVerbs$02<br />
|$02<br />
|restoreVerbs<br />
|style="color:silver; background:whitesmoke" |False<br />
|style="color:silver; background:whitesmoke" |None<br />
|style="color:silver; background:whitesmoke" |None<br />
|style="color:silver; background:whitesmoke" |None<br />
|-<br />
|align="left" |saveRestoreVerbs$03<br />
|$03<br />
|deleteVerbs<br />
|style="color:silver; background:whitesmoke" |False<br />
|style="color:silver; background:whitesmoke" |None<br />
|style="color:silver; background:whitesmoke" |None<br />
|style="color:silver; background:whitesmoke" |None<br />
|-<br />
|align="left" |setCameraAt<br />
|$32<br />
|style="color:silver; background:whitesmoke" |==<br />
|style="color:silver; background:whitesmoke" |False<br />
|P16<br />
|style="color:silver; background:whitesmoke" |None<br />
|style="color:silver; background:whitesmoke" |None<br />
|-<br />
|align="left" |setObjectName<br />
|$54<br />
|style="color:silver; background:whitesmoke" |==<br />
|style="color:silver; background:whitesmoke" |False<br />
|P16<br />
|A0<br />
|style="color:silver; background:whitesmoke" |None<br />
|-<br />
|align="left" |setOwnerOf<br />
|$29<br />
|style="color:silver; background:whitesmoke" |==<br />
|style="color:silver; background:whitesmoke" |False<br />
|P16<br />
|P8<br />
|style="color:silver; background:whitesmoke" |None<br />
|-<br />
|align="left" |setState<br />
|$07<br />
|style="color:silver; background:whitesmoke" |==<br />
|style="color:silver; background:whitesmoke" |False<br />
|P16<br />
|P8<br />
|style="color:silver; background:whitesmoke" |None<br />
|-<br />
|align="left" |setVarRange<br />
|$26<br />
|style="color:silver; background:whitesmoke" |==<br />
|True<br />
|B<br />
|NS<br />
|NS<br />
|-<br />
|align="left" |soundKludge<br />
|$4C<br />
|style="color:silver; background:whitesmoke" |==<br />
|style="color:silver; background:whitesmoke" |False<br />
|L<br />
|style="color:silver; background:whitesmoke" |None<br />
|style="color:silver; background:whitesmoke" |None<br />
|-<br />
|align="left" |startMusic<br />
|$02<br />
|style="color:silver; background:whitesmoke" |==<br />
|style="color:silver; background:whitesmoke" |False<br />
|P8<br />
|style="color:silver; background:whitesmoke" |None<br />
|style="color:silver; background:whitesmoke" |None<br />
|-<br />
|align="left" |startObject<br />
|$37<br />
|style="color:silver; background:whitesmoke" |==<br />
|style="color:silver; background:whitesmoke" |False<br />
|P16<br />
|P8<br />
|L<br />
|-<br />
|align="left" |startScript<br />
|$0A<br />
|style="color:silver; background:whitesmoke" |==<br />
|style="color:silver; background:whitesmoke" |False<br />
|P8<br />
|L<br />
|style="color:silver; background:whitesmoke" |None<br />
|-<br />
|align="left" |startSound<br />
|$1C<br />
|style="color:silver; background:whitesmoke" |==<br />
|style="color:silver; background:whitesmoke" |False<br />
|P8<br />
|style="color:silver; background:whitesmoke" |None<br />
|style="color:silver; background:whitesmoke" |None<br />
|-<br />
|align="left" |stopMusic<br />
|$20<br />
|style="color:silver; background:whitesmoke" |==<br />
|style="color:silver; background:whitesmoke" |False<br />
|style="color:silver; background:whitesmoke" |None<br />
|style="color:silver; background:whitesmoke" |None<br />
|style="color:silver; background:whitesmoke" |None<br />
|-<br />
|align="left" |stopObjectCode<br />
|$A0<br />
|style="color:silver; background:whitesmoke" |==<br />
|style="color:silver; background:whitesmoke" |False<br />
|style="color:silver; background:whitesmoke" |None<br />
|style="color:silver; background:whitesmoke" |None<br />
|style="color:silver; background:whitesmoke" |None<br />
|-<br />
|align="left" |stopObjectScript<br />
|$6E<br />
|style="color:silver; background:whitesmoke" |==<br />
|style="color:silver; background:whitesmoke" |False<br />
|P16<br />
|style="color:silver; background:whitesmoke" |None<br />
|style="color:silver; background:whitesmoke" |None<br />
|-<br />
|align="left" |stopScript<br />
|$62<br />
|style="color:silver; background:whitesmoke" |==<br />
|style="color:silver; background:whitesmoke" |False<br />
|P8<br />
|style="color:silver; background:whitesmoke" |None<br />
|style="color:silver; background:whitesmoke" |None<br />
|-<br />
|align="left" |stopSound<br />
|$3C<br />
|style="color:silver; background:whitesmoke" |==<br />
|style="color:silver; background:whitesmoke" |False<br />
|P8<br />
|style="color:silver; background:whitesmoke" |None<br />
|style="color:silver; background:whitesmoke" |None<br />
|-<br />
|align="left" |stringOps<br />
|$27<br />
|style="color:silver; background:whitesmoke" |==<br />
|style="color:silver; background:whitesmoke" |False<br />
|SO<br />
|style="color:silver; background:whitesmoke" |None<br />
|style="color:silver; background:whitesmoke" |None<br />
|-<br />
|align="left" |stringOps$01<br />
|$01<br />
|PutCodeInString<br />
|style="color:silver; background:whitesmoke" |False<br />
|P8<br />
|A0<br />
|style="color:silver; background:whitesmoke" |None<br />
|-<br />
|align="left" |stringOps$02<br />
|$02<br />
|CopyString<br />
|style="color:silver; background:whitesmoke" |False<br />
|P8<br />
|P8<br />
|style="color:silver; background:whitesmoke" |None<br />
|-<br />
|align="left" |stringOps$03<br />
|$03<br />
|SetStringChar<br />
|style="color:silver; background:whitesmoke" |False<br />
|P8<br />
|P8<br />
|B<br />
|-<br />
|align="left" |stringOps$04<br />
|$04<br />
|GetStringChar<br />
|True<br />
|P8<br />
|P8<br />
|style="color:silver; background:whitesmoke" |None<br />
|-<br />
|align="left" |stringOps$05<br />
|$05<br />
|CreateString<br />
|style="color:silver; background:whitesmoke" |False<br />
|P8<br />
|P8<br />
|style="color:silver; background:whitesmoke" |None<br />
|-<br />
|align="left" |subtract<br />
|$3A<br />
|(inline)<br />
|True<br />
|P16<br />
|style="color:silver; background:whitesmoke" |None<br />
|style="color:silver; background:whitesmoke" |None<br />
|-<br />
|align="left" |systemOps<br />
|$98<br />
|systemOps<br />
|style="color:silver; background:whitesmoke" |False<br />
|SO<br />
|style="color:silver; background:whitesmoke" |None<br />
|style="color:silver; background:whitesmoke" |None<br />
|-<br />
|align="left" |systemOps$01<br />
|$01<br />
|N/A<br />
|style="color:silver; background:whitesmoke" |False<br />
|style="color:silver; background:whitesmoke" |None<br />
|style="color:silver; background:whitesmoke" |None<br />
|style="color:silver; background:whitesmoke" |None<br />
|-<br />
|align="left" |systemOps$02<br />
|$02<br />
|N/A<br />
|style="color:silver; background:whitesmoke" |False<br />
|style="color:silver; background:whitesmoke" |None<br />
|style="color:silver; background:whitesmoke" |None<br />
|style="color:silver; background:whitesmoke" |None<br />
|-<br />
|align="left" |systemOps$03<br />
|$03<br />
|N/A<br />
|style="color:silver; background:whitesmoke" |False<br />
|style="color:silver; background:whitesmoke" |None<br />
|style="color:silver; background:whitesmoke" |None<br />
|style="color:silver; background:whitesmoke" |None<br />
|-<br />
|align="left" |verbOps<br />
|$7A<br />
|VerbOps<br />
|style="color:silver; background:whitesmoke" |False<br />
|P8<br />
|SO+<br />
|FF<br />
|-<br />
|align="left" |verbOps$01<br />
|$01<br />
|Image<br />
|style="color:silver; background:whitesmoke" |False<br />
|P16<br />
|style="color:silver; background:whitesmoke" |None<br />
|style="color:silver; background:whitesmoke" |None<br />
|-<br />
|align="left" |verbOps$02<br />
|$02<br />
|Text<br />
|style="color:silver; background:whitesmoke" |False<br />
|A0<br />
|style="color:silver; background:whitesmoke" |None<br />
|style="color:silver; background:whitesmoke" |None<br />
|-<br />
|align="left" |verbOps$03<br />
|$03<br />
|Color<br />
|style="color:silver; background:whitesmoke" |False<br />
|P8<br />
|style="color:silver; background:whitesmoke" |None<br />
|style="color:silver; background:whitesmoke" |None<br />
|-<br />
|align="left" |verbOps$04<br />
|$04<br />
|HiColor<br />
|style="color:silver; background:whitesmoke" |False<br />
|P8<br />
|style="color:silver; background:whitesmoke" |None<br />
|style="color:silver; background:whitesmoke" |None<br />
|-<br />
|align="left" |verbOps$05<br />
|$05<br />
|SetXY<br />
|style="color:silver; background:whitesmoke" |False<br />
|P16<br />
|P16<br />
|style="color:silver; background:whitesmoke" |None<br />
|-<br />
|align="left" |verbOps$06<br />
|$06<br />
|On<br />
|style="color:silver; background:whitesmoke" |False<br />
|style="color:silver; background:whitesmoke" |None<br />
|style="color:silver; background:whitesmoke" |None<br />
|style="color:silver; background:whitesmoke" |None<br />
|-<br />
|align="left" |verbOps$07<br />
|$07<br />
|Off<br />
|style="color:silver; background:whitesmoke" |False<br />
|style="color:silver; background:whitesmoke" |None<br />
|style="color:silver; background:whitesmoke" |None<br />
|style="color:silver; background:whitesmoke" |None<br />
|-<br />
|align="left" |verbOps$08<br />
|$08<br />
|Delete<br />
|style="color:silver; background:whitesmoke" |False<br />
|style="color:silver; background:whitesmoke" |None<br />
|style="color:silver; background:whitesmoke" |None<br />
|style="color:silver; background:whitesmoke" |None<br />
|-<br />
|align="left" |verbOps$09<br />
|$09<br />
|New<br />
|style="color:silver; background:whitesmoke" |False<br />
|style="color:silver; background:whitesmoke" |None<br />
|style="color:silver; background:whitesmoke" |None<br />
|style="color:silver; background:whitesmoke" |None<br />
|-<br />
|align="left" |verbOps$10<br />
|$10<br />
|DimColor<br />
|style="color:silver; background:whitesmoke" |False<br />
|P8<br />
|style="color:silver; background:whitesmoke" |None<br />
|style="color:silver; background:whitesmoke" |None<br />
|-<br />
|align="left" |verbOps$11<br />
|$11<br />
|Dim<br />
|style="color:silver; background:whitesmoke" |False<br />
|style="color:silver; background:whitesmoke" |None<br />
|style="color:silver; background:whitesmoke" |None<br />
|style="color:silver; background:whitesmoke" |None<br />
|-<br />
|align="left" |verbOps$12<br />
|$12<br />
|Key<br />
|style="color:silver; background:whitesmoke" |False<br />
|P8<br />
|style="color:silver; background:whitesmoke" |None<br />
|style="color:silver; background:whitesmoke" |None<br />
|-<br />
|align="left" |verbOps$13<br />
|$13<br />
|Center<br />
|style="color:silver; background:whitesmoke" |False<br />
|style="color:silver; background:whitesmoke" |None<br />
|style="color:silver; background:whitesmoke" |None<br />
|style="color:silver; background:whitesmoke" |None<br />
|-<br />
|align="left" |verbOps$14<br />
|$14<br />
|SetToString<br />
|style="color:silver; background:whitesmoke" |False<br />
|P16<br />
|style="color:silver; background:whitesmoke" |None<br />
|style="color:silver; background:whitesmoke" |None<br />
|-<br />
|align="left" |verbOps$16<br />
|$16<br />
|SetToObject<br />
|style="color:silver; background:whitesmoke" |False<br />
|P16<br />
|P8<br />
|style="color:silver; background:whitesmoke" |None<br />
|-<br />
|align="left" |verbOps$17<br />
|$17<br />
|BackColor<br />
|style="color:silver; background:whitesmoke" |False<br />
|P8<br />
|style="color:silver; background:whitesmoke" |None<br />
|style="color:silver; background:whitesmoke" |None<br />
|-<br />
|align="left" |wait<br />
|$AE<br />
|N/A<br />
|style="color:silver; background:whitesmoke" |False<br />
|SO<br />
|style="color:silver; background:whitesmoke" |None<br />
|style="color:silver; background:whitesmoke" |None<br />
|-<br />
|align="left" |wait$01<br />
|$01<br />
|WaitForActor<br />
|style="color:silver; background:whitesmoke" |False<br />
|P8<br />
|style="color:silver; background:whitesmoke" |None<br />
|style="color:silver; background:whitesmoke" |None<br />
|-<br />
|align="left" |wait$02<br />
|$02<br />
|WaitForMessage<br />
|style="color:silver; background:whitesmoke" |False<br />
|style="color:silver; background:whitesmoke" |None<br />
|style="color:silver; background:whitesmoke" |None<br />
|style="color:silver; background:whitesmoke" |None<br />
|-<br />
|align="left" |wait$03<br />
|$03<br />
|WaitForCamera<br />
|style="color:silver; background:whitesmoke" |False<br />
|style="color:silver; background:whitesmoke" |None<br />
|style="color:silver; background:whitesmoke" |None<br />
|style="color:silver; background:whitesmoke" |None<br />
|-<br />
|align="left" |wait$04<br />
|$04<br />
|WaitForSentence<br />
|style="color:silver; background:whitesmoke" |False<br />
|style="color:silver; background:whitesmoke" |None<br />
|style="color:silver; background:whitesmoke" |None<br />
|style="color:silver; background:whitesmoke" |None<br />
|-<br />
|align="left" |walkActorTo<br />
|$1E<br />
|style="color:silver; background:whitesmoke" |==<br />
|style="color:silver; background:whitesmoke" |False<br />
|P8<br />
|P16<br />
|P16<br />
|-<br />
|align="left" |walkActorToActor<br />
|$0D<br />
|style="color:silver; background:whitesmoke" |==<br />
|style="color:silver; background:whitesmoke" |False<br />
|P8<br />
|P8<br />
|B<br />
|-<br />
|align="left" |walkActorToObject<br />
|$36<br />
|style="color:silver; background:whitesmoke" |==<br />
|style="color:silver; background:whitesmoke" |False<br />
|P8<br />
|P16<br />
|style="color:silver; background:whitesmoke" |None<br />
|}</div>Jestar jokinhttps://wiki.scummvm.org/index.php?title=SCUMM/V5_opcodes&diff=10977SCUMM/V5 opcodes2009-04-17T03:24:08Z<p>Jestar jokin: /* stopObjectCode ($00) */ stopObjectCode opcode is $A0</p>
<hr />
<div>=SCUMM V5 opcodes=<br />
The following conventions are used in the encoding descriptions.<br />
<br />
{| border="1" cellpadding="2" width=100%<br />
|- style="background:whitesmoke"<br />
|Term||Description<br />
|-<br />
|opcode||The instruction's opcode, with the appropriate bits set according to the parameters.<br />
|-<br />
|aux||An aux opcode that stores parameter bits and no other information. (the base aux opcode seems to always be $01)<br />
|-<br />
|sub-opcode||An aux opcode that indicates a specific function to perform (e.g. the "wait" instruction has sub-opcodes to "wait for message", "wait for actor" etc), as well as storing parameter bits if necessary.<br />
|-<br />
|result||A result pointer. (A standard word pointer, always a LE word.)<br />
|-<br />
|var||A var pointer. Same as above, but is not written to. Because this is always a var, the opcode is not affected like with normal parameter/pointers.<br />
|-<br />
|value[8]||An 8-bit constant (a byte).<br />
|-<br />
|value[16]||A 16-bit constant (a word LE).<br />
|-<br />
|value[p8]||An 8-bit parameter. This may be encoded as a word LE if it's a pointer, or a byte if it's a constant.<br />
|-<br />
|value[p16]||A 16-bit parameter. This is always encoded as a word LE, and may be a pointer or constant.<br />
|-<br />
|value[v16]||A variable number of word LE parameters. These are encoded as a sequence of aux[8] param[p16]; param; aux contains the parameter bit to describe param (and is always $01, ignoring the parameter bits). A byte of $FF terminates the sequence. (actually always shown as "value[v16]...")<br />
|-<br />
|value[o]||The offset word for parameter value. This is only encoded if needed, but always at the position indicated. If not specified, the offset word occurs immediately after the parameter.<br />
|-<br />
|value[c]||An ASCII character. Because some instructions use null-terminated strings and some use $FF, the exact format of a string is described in the instruction. Almost always appears as "value[c]..."<br />
|-<br />
|term...||One or more terms.<br />
|}<br />
<br />
Of course, due to the non-orthogonality of the opcodes, there are lots of exceptions.<br />
<br />
<br />
==actorFollowCamera ($52)==<br />
<br />
===Encoding===<br />
opcode actor[p8]<br />
<br />
===Operation===<br />
Sets the camera to follow the given actor?<br />
<br />
<br />
==actorFromPos ($15)==<br />
<br />
===Encoding===<br />
opcode result x[p16] y[p16]<br />
<br />
===Operation===<br />
Returns the actor located at the given co-ordinates.<br />
<br />
<br />
==actorOps ($13)==<br />
parameters depend on auxiliary opcode; terminated by $FF<br />
<br />
===Encoding===<br />
opcode actor[p8] sub-opcode... $FF<br />
<br />
sub-opcodes:<br />
$00 arg1[p8]<br />
$01 costume[p8]<br />
$02 xspeed[p8] yspeed[p8]<br />
$03 sound[p8]<br />
$04 walkframe[p8]<br />
$05 starttalk[p8] endtalk[p8]<br />
$06 standframe[p8]<br />
$07 arg1[p8] arg2[p8] arg3[p8]<br />
$08<br />
$09 elevation[p16]<br />
$0A<br />
$0B index[p8] value[p8]<br />
$0C colour[p8]<br />
$0D name[c]... $00<br />
$0E initframe[p8]<br />
$10 width[p8]<br />
$11 xscale[p8] yscale[p8]<br />
$12<br />
$13 zplane[p8]<br />
$14<br />
$15 animspeed[p8]<br />
$16 mode[p8]<br />
$17 shadow[p8]<br />
<br />
===Operation===<br />
Miscellaneous actions on actors.<br />
<br />
{| border="1" cellpadding="2" width=100%<br />
|- style="background:whitesmoke"<br />
|Opcode||Meaning||Description<br />
|-<br />
|$00||dummy||A dummy case, does nothing (in ScummVM).<br />
|-<br />
|$01||SO_COSTUME||Sets the actor's costume.<br />
|-<br />
|$02||SO_STEP_DIST||Sets the actor's walking speed for x and y.<br />
|-<br />
|$03||SO_SOUND||Associates a sound with the actor (footsteps?)<br />
|-<br />
|$04||SO_WALK_ANIMATION||Sets the current frame of the walking animation.<br />
|-<br />
|$05||SO_TALK_ANIMATION||Sets the start and stop frames of the talking animation.<br />
|-<br />
|$06||SO_STAND_ANIMATION||Sets the current frame of the standing animation.<br />
|-<br />
|$07||SO_ANIMATION||Unknown; seems to be unused in ScummVM.<br />
|-<br />
|$08||SO_DEFAULT||Initializes actor.<br />
|-<br />
|$09||SO_ELEVATION||Sets the actor's elevation to the given value.<br />
|-<br />
|$0A||SO_ANIMATION_DEFAULT||Initializes the actor's animation frames.<br>Init frame = 1<br>Walk frame = 2<br>Stand frame = 3<br>Talk start frame = 4<br>Talk stop frame = 5<br />
|-<br />
|$0B||SO_PALETTE||Sets the colour at the given index to a new value (another entry in the colour lookup table/CLUT). Index must be between 0 and 31 (the number of colours in a costume).<br />
|-<br />
|$0C||SO_TALK_COLOR||Sets the actor's talk colour.<br />
|-<br />
|$0D||SO_ACTOR_NAME||Sets the actor's name to the given null-terminated string.<br />
|-<br />
|$0E||SO_INIT_ANIMATION||Sets the current frame of the initial animation.<br />
|-<br />
|$10||SO_ACTOR_WIDTH||Sets the actor's width.<br />
|-<br />
|$11||SO_ACTOR_SCALE||Sets the actor's X and Y scales.<br />
|-<br />
|$12||SO_NEVER_ZCLIP||Turns off all Z-clipping for the actor.<br />
|-<br />
|$13||SO_ALWAYS_ZCLIP||Forces the actor's Z-clipping for the given Z-plane?<br />
|-<br />
|$14||SO_IGNORE_BOXES||Ignores boxes, turns off Z-clipping, and puts actor somewhere if the actor is in the current room?<br />
|-<br />
|$15||SO_FOLLOW_BOXES||Follows boxes, turns off Z-clipping, and puts actor somewhere if the actor is in the current room?<br />
|-<br />
|$16||SO_ANIMATION_SPEED||Sets the animatino speed<br />
|-<br />
|$17||SO_SHADOW||Sets the shadow mode.<br />
|}<br />
<br />
===Variants===<br />
In SCUMM V4, sub-opcode $11 (SO_ACTOR_SCALE) only takes one parameter, so X and Y scaling is done at a 1:1 ratio.<br />
<br />
<br />
==actorSetClass ($5D)==<br />
<br />
===Encoding===<br />
opcode object[p16] classes[v16]...<br />
<br />
===Operation===<br />
Makes object inherit from all of the given classes. A class of "0" will clear all of the object's existing class data.<br />
<br />
<br />
==add ($5A)==<br />
<br />
===Encoding===<br />
opcode result value[p16]<br />
<br />
===Operation===<br />
result := result + value<br />
<br />
The variable pointed to by result is read, value is added to it, and the result written back.<br />
<br />
<br />
==and ($17)==<br />
one parameter, uses result<br />
<br />
===Encoding===<br />
opcode result value[p16]<br />
<br />
===Operation===<br />
result := result and value<br />
<br />
The variable pointed to by result is read, logically ANDed with value, and the result written back.<br />
<br />
<br />
==animateActor ($11)==<br />
<br />
===Encoding===<br />
opcode actor[p8] anim[p8]<br />
<br />
===Operation===<br />
Starts the given animation for the given actor.<br />
<br />
<br />
==breakHere ($80)==<br />
no parameters<br />
<br />
===Encoding===<br />
opcode<br />
<br />
===Operation===<br />
Deschedules the currently running thread. Execution continues at the next instruction when the thread's next timeslot comes around.<br />
<br />
<br />
==chainScript ($42)==<br />
one parameter plus varargs<br />
<br />
===Encoding===<br />
opcode script[p8] args[v16]...<br />
<br />
===Operation===<br />
Replaces the currently running script with another one. The current script is terminated immediately and the new script (determined by the given script ID), is executed in the same thread. The new script has its local variables initialised to the list args. Uninitialised variables have undefined values.<br />
<br />
<br />
==cursorCommand ($2C)==<br />
parameters depend on auxiliary opcode<br />
<br />
===Encoding===<br />
opcode sub-opcode<br />
<br />
sub-opcode can be any of the following:<br />
$01<br />
... $01 through $08 take the same arguments ...<br />
$08<br />
$0A cursornum[p8] charletter[p8]<br />
$0B index[p8] x[p8] y[p8]<br />
$0C cursor[p8]<br />
$0D charset[p8]<br />
$0E colours[v16]...<br />
<br />
===Operation===<br />
Miscellaneous actions on cursors & charsets.<br />
<br />
{| border="1" cellpadding="2" width=100%<br />
|- style="background:whitesmoke"<br />
|Opcode||Meaning||Description<br />
|-<br />
|$01||SO_CURSOR_ON||Turns the cursor on.<br />
|-<br />
|$02||SO_CURSOR_OFF||Turns the cursor off.<br />
|-<br />
|$03||SO_USERPUT_ON||Enables user input.<br />
|-<br />
|$04||SO_USERPUT_OFF||Disables user input.<br />
|-<br />
|$05||SO_CURSOR_SOFT_ON||Increments the cursor's state?<br />
|-<br />
|$06||SO_CURSOR_SOFT_OFF||Decrements the cursor's state?<br />
|-<br />
|$07||SO_USERPUT_SOFT_ON||Increments "user input" counter (when greater than 0, user input is enabled).<br />
|-<br />
|$08||SO_USERPUT_SOFT_OFF||Decrements "user input" counter (when 0 or less, user input is disabled).<br />
|-<br />
|$0A||SO_CURSOR_IMAGE||Changes the cursor image to a new one, based on image in a character set. Only used in Loom.<br />
|-<br />
|$0B||SO_CURSOR_HOTSPOT||Changes the hotspot of a cursor. Only used in Loom.<br />
|-<br />
|$0C||SO_CURSOR_SET||Changes the current cursor. Must be between 0 and 3 inclusive.<br />
|-<br />
|$0D||SO_CHARSET_SET||Initializes the given character set.<br />
|-<br />
|$0E||SO_CHARSET_COLORS||Initializes the character set data & colours to the given arguments? Must have 16 arguments?<br />
|}<br />
<br />
===Variants===<br />
In SCUMM V3, sub-opcode $0E performs a different function, to load/initialize a character set.<br />
<br />
opcode $0E arg1[p8] arg2[p8]<br />
<br />
<br />
==cutScene ($40)==<br />
<br />
===Encoding===<br />
opcode args[v16]...<br />
<br />
===Operation===<br />
??? If required, runs a script passing the given arguments. Cutscene data given by the first argument?<br />
<br />
<br />
==debug ($6B)==<br />
one parameter, no result<br />
<br />
===Encoding===<br />
opcode param[p16]<br />
<br />
===Operation===<br />
Passes the parameter to the interpreter's debugger. What this does is entirely platform-specific (and may do nothing).<br />
<br />
<br />
==decrement ($C6)==<br />
no parameters, uses result<br />
<br />
===Encoding===<br />
opcode result<br />
<br />
===Operation===<br />
result := result - 1<br />
<br />
Reads the variable pointed to by result, decrements it, and writes it back. <br />
<br />
<br />
==delay ($2E)==<br />
one constant parameter<br />
<br />
===Encoding===<br />
opcode param[24]<br />
<br />
===Operation===<br />
Suspends the current thread for the appropriate number of 1/60ths of a second. Yes, that really is a 24-bit LE constant.<br />
<br />
<br />
==delayVariable ($2B)==<br />
one constant parameter<br />
<br />
===Encoding===<br />
opcode var<br />
<br />
===Operation===<br />
var is dereferenced and the current thread suspended for that number of 1/60ths of a second.<br />
<br />
<br />
==divide ($5B)==<br />
one parameter, uses result<br />
<br />
===Encoding===<br />
opcode result value[p16]<br />
<br />
===Operation===<br />
result := result / value<br />
<br />
The variable pointed to by result is read, divided by value, and the result written back. If value is zero, the result is undefined (and the interpeter may halt with an error). <br />
<br />
<br />
==doSentence ($19)==<br />
<br />
===Encoding===<br />
opcode verb[p8] objectA[p16] objectB[p16]<br />
<br />
===Operation===<br />
Performs a verb sentence action, e.g. "Use monkey on hydrant". If verb is $FE, the current sentence script is stopped, status cleared etc.<br />
<br />
<br />
==drawBox ($3F)==<br />
two parameters, does not use result, supplementary opcode byte with three more subsequent parameters<br />
<br />
===Encoding===<br />
opcode left[p16] top[p16] auxopcode[8] right[p16] bottom[p16] colour[p8]<br />
<br />
===Operation===<br />
Draws a solid box on the backbuffer from (left, top)-(right, bottom) in the given colour.<br />
<br />
The only part of auxopcode that is relevant are the parameter bits. The rest of the opcode is ignored. <br />
<br />
<br />
==drawObject ($05)==<br />
<br />
===Encoding===<br />
opcode object[p16] sub-opcode<br />
<br />
sub-opcodes:<br />
$01 xpos[p16] ypos[p16]<br />
$02 state[p16]<br />
$1F<br />
<br />
===Operation===<br />
{| border="1" cellpadding="2" width=100%<br />
|- style="background:whitesmoke"<br />
|Opcode||Meaning||Description<br />
|-<br />
|$01||Draw At||Moves the given object to the given co-ordinates, and adds it to the drawing queue.<br />
|-<br />
|$02||Set State||Sets the state of the object, adds it to the drawing queue.<br />
|-<br />
|$1F||Draw||Does not change the object's position (or state?), still adds it to the drawing queue.<br />
|}<br />
<br />
===Variants===<br />
Small header games only support the parameters used with sub-opcode $01, e.g:<br />
opcode object[p16] xpos[p16] ypos[p16]<br />
<br />
<br />
==dummy ($A7)==<br />
<br />
===Encoding===<br />
opcode<br />
<br />
===Operation===<br />
V5 specific - The KIXX XL release of Monkey Island 2 (Amiga disk) used this opcode as a dummy, in order to remove copy protection and keep level selection.<br />
<br />
===Variants===<br />
In SCUMM V3 and V4, this opcode is used for the saveLoadVars instruction.<br />
<br />
<br />
==endCutScene ($C0)==<br />
<br />
===Encoding===<br />
opcode<br />
<br />
===Operation===<br />
Ends the cutscene, performing cleanup if necessary.<br />
<br />
<br />
==equalZero ($28)==<br />
jumps<br />
<br />
===Encoding===<br />
opcode var target[16]<br />
<br />
===Operation===<br />
unless (var == 0) goto target<br />
<br />
Target is a byte offset (measured from after this instruction), which will be added to the instruction pointer.<br />
<br />
<br />
==expression ($AC)==<br />
<br />
===Encoding===<br />
opcode result subopcode... $FF<br />
<br />
sub-opcodes:<br />
$01 value[p16]<br />
$02<br />
... $02 through $05 take the same arguments ...<br />
$05<br />
$06 nested-opcode<br />
<br />
===Operation===<br />
Expression mode operates on a stack. Values are pushed on, and operators are applied to the top two items on the stack.<br />
<br />
{| border="1" cellpadding="2" width=100%<br />
|- style="background:whitesmoke"<br />
|Opcode||Meaning||Description<br />
|-<br />
|$01||Value||Pushes a value onto the top of the stack.<br />
|-<br />
|$02||Add||stack[top - 1] + stack[top]<br />
|-<br />
|$03||Subtract||stack[top - 1] - stack[top]<br />
|-<br />
|$04||Multiply||stack[top - 1] * stack[top]<br />
|-<br />
|$05||Divide||stack[top - 1] / stack[top] (if stack[top] is 0 an error occurs)<br />
|-<br />
|$06||Nested Opcode||An entire instruction that returns a result, such as getActorScale. This is interpreted like a normal opcode, but the result is pushed onto the expression stack. (The opcode is passed the special "VAR_RESULT" parameter for "result")<br />
|}<br />
<br />
<br />
==faceActor ($09)==<br />
<br />
===Encoding===<br />
opcode actor[p8] object[p16]<br />
<br />
===Operation===<br />
Dereferences actor, tells actor to face object (presumably based on X/Y co-ordinates).<br />
<br />
<br />
==findInventory ($3D)==<br />
<br />
===Encoding===<br />
opcode result owner[p8] index[p8]<br />
<br />
===Operation===<br />
object := owner.inventory[index]<br />
Searches for all objects owned by owner (an actor or object), and returns the one at the given index (offset).<br />
<br />
<br />
==findObject ($35)==<br />
<br />
===Encoding===<br />
opcode result x[p8] y[p8]<br />
<br />
===Operation===<br />
Returns the first "touchable" local object at the given co-ordinates. Will not match on the bottom or right-hand edges of an object.<br />
<br />
<br />
==freezeScripts ($60)==<br />
<br />
===Encoding===<br />
opcode flag[p8]<br />
<br />
===Operation===<br />
Freezes all scripts (by setting the high bit on each script's status). If flag is >= $80, all freeze resistent scripts will also be frozen. If flag is 0, all scripts are unfrozen. Freezing effects are cumulative - i.e. if script A is frozen twice, and unfrozen once, it will still be frozen until it is unfrozen a second time. A script's frozen status is indicated by the high bit.<br />
<br />
<br />
==getActorCostume ($71)==<br />
<br />
===Encoding===<br />
opcode result actor[p8]<br />
<br />
===Operation===<br />
Returns the actor's current costume.<br />
<br />
<br />
==getActorElevation ($06)==<br />
<br />
===Encoding===<br />
opcode result actor[p8]<br />
<br />
===Operation===<br />
Returns the actor's current elevation.<br />
<br />
<br />
==getActorFacing ($63)==<br />
<br />
===Encoding===<br />
opcode result actor[p8]<br />
<br />
===Operation===<br />
Returns the current direction the actor is facing.<br />
<br />
<br />
==getActorMoving ($56)==<br />
<br />
===Encoding===<br />
opcode result actor[p8]<br />
<br />
===Operation===<br />
Returns the actor's moving status (0 or 1).<br />
<br />
<br />
==getActorRoom ($03)==<br />
<br />
===Encoding===<br />
opcode result actor[p8]<br />
<br />
===Operation===<br />
Returns the room the actor currently occupies?<br />
<br />
<br />
==getActorScale ($3B)==<br />
<br />
===Encoding===<br />
opcode result actor[p8]<br />
<br />
===Operation===<br />
Returns the actor's current scale.<br />
<br />
===Variants===<br />
In Indy3, this opcode is used for waitForActor.<br />
<br />
<br />
==getActorWalkBox ($7B)==<br />
<br />
===Encoding===<br />
opcode result actor[p8]<br />
<br />
===Operation===<br />
Returns the actor's walkbox.<br />
<br />
<br />
==getActorWidth ($6C)==<br />
<br />
===Encoding===<br />
opcode result actor[p8]<br />
<br />
===Operation===<br />
Returns the actor's width.<br />
<br />
<br />
==getActorX ($43)==<br />
<br />
===Encoding===<br />
opcode result actor[p16]<br />
<br />
===Operation===<br />
Returns the actor's current X co-ordinate.<br />
<br />
===Variants===<br />
In Indy3, actor is only one byte.<br />
opcode result actor[p8]<br />
<br />
<br />
==getActorY ($23)==<br />
<br />
===Encoding===<br />
opcode result actor[p16]<br />
<br />
===Operation===<br />
Returns the actor's current Y co-ordinate.<br />
<br />
===Variants===<br />
In Indy3, actor is only one byte.<br />
opcode result actor[p8]<br />
<br />
<br />
==getAnimCounter ($22)==<br />
<br />
===Encoding===<br />
opcode result actor[p8]<br />
<br />
===Operation===<br />
Returns the actor's animation counter.<br />
<br />
===Variants===<br />
This opcode is used for saveLoadGame in SCUMM V3.<br />
<br />
<br />
==getClosestObjActor ($66)==<br />
<br />
===Encoding===<br />
opcode result actor[p16]<br />
<br />
===Operation===<br />
Returns the object closest to the actor. Items that are more than 255 units (pixels in newer games, characters in older games) away from the actor will not be detected.<br />
<br />
<br />
==getDist ($34)==<br />
<br />
===Encoding===<br />
opcode result objA[p16] objB[p16]<br />
<br />
===Operation===<br />
Returns the distance between two actors/objects (objA and objB).<br />
<br />
<br />
==getInventoryCount ($31)==<br />
<br />
===Encoding===<br />
opcode result actor[p8]<br />
<br />
===Operation===<br />
Returns the number of items in an actor's inventory?<br />
<br />
<br />
==getObjectOwner ($10)==<br />
<br />
===Encoding===<br />
opcode result object[p16]<br />
<br />
===Operation===<br />
Returns the owner of an object.<br />
<br />
<br />
==getObjectState ($0F)==<br />
<br />
===Encoding===<br />
opcode result object[p16]<br />
<br />
===Operation===<br />
Returns the state of the object.<br />
<br />
===Variants===<br />
In small header games, the encoding becomes:<br />
opcode object[p16] state[p8] target[16]<br />
operation becomes<br />
unless (getState(object) == state) goto target<br />
<br />
<br />
==getRandomNumber ($16)==<br />
<br />
===Encoding===<br />
opcode result seed[p8]<br />
<br />
===Operation===<br />
Returns a new random number based on the given seed.<br />
<br />
<br />
==getScriptRunning ($68)==<br />
<br />
===Encoding===<br />
opcode result script[p8]<br />
<br />
===Operation===<br />
Returns 1 if the given script is running, 0 if it's not.<br />
<br />
<br />
==getStringWidth ($67)==<br />
<br />
===Encoding===<br />
opcode result strptr[p8]<br />
<br />
===Operation===<br />
Gets the length of the string pointed to by strptr (either a variable or direct byte), stores the returned value in result.<br />
<br />
<br />
==getVerbEntryPoint ($0B)==<br />
<br />
===Encoding===<br />
opcode result object[p16] verb[p16]<br />
<br />
===Operation===<br />
Returns the entry point for the response code/script for when the given verb is applied to the given object? i.e. gets the start of the script to run for the specific user interaction.<br />
<br />
<br />
==ifClassOfIs ($1D)==<br />
jumps<br />
<br />
===Encoding===<br />
opcode value[p16] args[v16]... target[16]<br />
<br />
===Operation===<br />
unless (value.class is one of [args.class]) goto target<br />
<br />
Compares the value's class with all classes given in args.<br />
<br />
Target is a byte offset (measured from after this instruction), which will be added to the instruction pointer.<br />
<br />
==ifNotState ($2F)==<br />
<br />
===Encoding===<br />
opcode object[p16] state[p8] target[16]<br />
<br />
===Operation===<br />
unless (stateOf(object) != state) goto target<br />
<br />
<br />
==ifState ($4F)==<br />
<br />
===Encoding===<br />
opcode object[p16] state[p8] target[16]<br />
<br />
===Operation===<br />
unless (stateOf(object) == state) goto target<br />
<br />
<br />
==increment ($46)==<br />
no parameters, uses result<br />
<br />
===Encoding===<br />
opcode result<br />
<br />
===Operation===<br />
result := result + 1<br />
<br />
Reads the variable pointed to by result, increments it, and writes it back. <br />
<br />
<br />
==isActorInBox ($1F)==<br />
<br />
===Encoding===<br />
opcode actor[p8] box[p8] target[16]<br />
<br />
===Operation===<br />
Unless the actor's co-ordinates are within the bounds of the given box, jump to target.<br />
<br />
Target is a byte offset (measured from after this instruction), which will be added to the instruction pointer.<br />
<br />
<br />
==isEqual ($48)==<br />
<br />
===Encoding===<br />
opcode var value[p16] target[16]<br />
<br />
===Operation===<br />
unless (value == var) goto target<br />
<br />
Target is a byte offset (measured from after this instruction), which will be added to the instruction pointer.<br />
<br />
<br />
==isGreater ($78)==<br />
<br />
===Encoding===<br />
opcode var value[p16] target[16]<br />
<br />
===Operation===<br />
unless (value > var) goto target<br />
<br />
Target is a byte offset (measured from after this instruction), which will be added to the instruction pointer.<br />
<br />
<br />
==isGreaterEqual ($04)==<br />
<br />
===Encoding===<br />
opcode var value[p16] target[16]<br />
<br />
===Operation===<br />
unless (value >= var) goto target<br />
<br />
Target is a byte offset (measured from after this instruction), which will be added to the instruction pointer.<br />
<br />
<br />
==isLess ($44)==<br />
<br />
===Encoding===<br />
opcode var value[p16] target[16]<br />
<br />
===Operation===<br />
unless (value < var) goto target<br />
<br />
Target is a byte offset (measured from after this instruction), which will be added to the instruction pointer.<br />
<br />
<br />
==isNotEqual ($08)==<br />
<br />
===Encoding===<br />
opcode var value[p16] target[16]<br />
<br />
===Operation===<br />
unless (value != var) goto target<br />
<br />
Target is a byte offset (measured from after this instruction), which will be added to the instruction pointer.<br />
<br />
<br />
==isSoundRunning ($7C)==<br />
<br />
===Encoding===<br />
opcode result sound[p8]<br />
<br />
===Operation===<br />
Returns 1 if sound is running, returns 0 if sound is not running or if the given sound is 0.<br />
<br />
<br />
==jumpRelative ($18)==<br />
jumps<br />
<br />
===Encoding===<br />
opcode target[16]<br />
<br />
===Operation===<br />
PC := PC + target<br />
<br />
The inline constant target is read as a signed word and added to the program counter after the instruction has been read. Therefore, if target is zero, the instruction will do nothing; if target is -3, an infinite loop will result. <br />
<br />
<br />
==lessOrEqual ($38)==<br />
jumps<br />
<br />
===Encoding===<br />
opcode var value[p16] target[16]<br />
<br />
===Operation===<br />
unless (value <= var) goto target<br />
<br />
Target is a byte offset (measured from after this instruction), which will be added to the instruction pointer.<br />
<br />
<br />
==lights ($70)==<br />
<br />
===Encoding===<br />
opcode arg1[p8] arg2[8] arg3[8]<br />
<br />
===Operation===<br />
If arg3 is 0, the "current lights" variable is set to arg1.<br />
If arg3 is 1, the size of the "flashlight" light is determined by arg1 and arg2, for width and height in stripes (which are equivalent to 8 pixels each; see [[SCUMM/Technical Reference/Image resources]]).<br />
<br />
<br />
==loadRoom ($72)==<br />
<br />
===Encoding===<br />
opcode room[p8]<br />
<br />
===Operation===<br />
Loads the given room into memory.<br />
<br />
<br />
==loadRoomWithEgo ($24)==<br />
<br />
===Encoding===<br />
opcode object[p16] room[p8] x[16] y[16]<br />
<br />
===Operation===<br />
Places the Ego actor in room at object's position. If x is not -1, Ego will start moving towards the given x and y co-ordinates. If object is not in the given room an error will occur.<br />
(I think...)<br />
<br />
<br />
==matrixOp ($30)==<br />
<br />
===Encoding===<br />
opcode sub-opcode<br />
<br />
sub-opcodes:<br />
$01 box[p8] val[p8]<br />
$02 box[p8] val[p8]<br />
$03 box[p8] val[p8]<br />
$04<br />
<br />
===Operation===<br />
This instruction manipulates boxes.<br />
<br />
{| border="1" cellpadding="2" width=100%<br />
|- style="background:whitesmoke"<br />
|Opcode||Meaning||Description<br />
|-<br />
|$01||setBoxFlags||Sets the box's flags to the given value.<br />
|-<br />
|$02||setBoxScale||Sets the box's scale.<br />
|-<br />
|$03||setBoxScale||Sets the box's scale to ((val - 1) OR $8000).<br />
|-<br />
|$04||createBoxMatrix||Initializes the matrix of boxes, by determining the distances and shortest paths between boxes.<br />
|}<br />
<br />
===Variants===<br />
SCUMM V3 only has the one instruction, which behaves like setBoxFlags:<br />
opcode box[p8] val[8]<br />
<br />
<br />
==move ($1A)==<br />
<br />
===Encoding===<br />
opcode result value[p16]<br />
<br />
===Operation===<br />
result := value<br />
<br />
Value is moved into result.<br />
<br />
<br />
==multiply ($1B)==<br />
<br />
===Encoding===<br />
opcode result value[p16]<br />
<br />
===Operation===<br />
result := result * value<br />
<br />
The variable pointed to by result is read, multiplied by value, and written back.<br />
<br />
<br />
==notEqualZero ($A8)==<br />
<br />
===Encoding===<br />
opcode var target[16]<br />
<br />
===Operation===<br />
unless (var != 0) goto target<br />
<br />
Target is a byte offset (measured from after this instruction), which will be added to the instruction pointer.<br />
<br />
<br />
==oldRoomEffect ($5C)==<br />
<br />
===Encoding===<br />
opcode sub-opcode<br />
<br />
sub-opcodes:<br />
$03 effect[p16]<br />
<br />
===Operation===<br />
Performs like sub-opcode SO_ROOM_FADE of the roomOps instruction (fade in if effect != 0, otherwise fade out).<br />
<br />
This information may not be correct; descumm says if the sub-opcode is 3, to "set" the effect, but if the sub-opcode is anything else to fade in with the given effect.<br />
<br />
===Variants===<br />
FM-Towns SCUMM V3 performs a different effect, not fully implemented in ScummVM. At the moment ScummVM just forces a redraw of the screen background.<br />
<br />
<br />
==or ($57)==<br />
one parameter, uses result<br />
<br />
===Encoding===<br />
opcode result value[p16]<br />
<br />
===Operation===<br />
result := result or value<br />
<br />
The variable pointed to by result is read, logically ORed with value, and the result written back.<br />
<br />
<br />
==override ($58)==<br />
<br />
===Encoding===<br />
opcode sub-opcode<br />
<br />
sub-opcodes:<br />
$00<br />
$01 $18 target[16]<br />
<br />
===Operation===<br />
If the sub-opcode is 0, marks the end of an override section.<br><br />
If the sub-opcode is not 0, marks the beginning of an override section. The instruction is immediately followed by a "jumpRelative" instruction.<br.<br />
Overrides are used by cutscenes; if a cutscene is skipped (if the user presses the ESC key), the script will jump by the given target (offset from this instruction).<br />
<br />
<br />
==panCameraTo ($12)==<br />
<br />
===Encoding===<br />
opcode x[p16]<br />
<br />
===Operation===<br />
Starts the camera panning to the given x co-ordinate.<br />
<br />
<br />
==pickupObject ($25)==<br />
<br />
===Encoding===<br />
opcode object[p16] room[p8]<br />
<br />
===Operation===<br />
Adds the given object (located in the given room) to the Ego actor's inventory.<br />
<br />
===Variants===<br />
In SCUMM V3 and V4, this opcode is used for drawObject.<br />
<br />
<br />
==pickupObjectOld ($50)==<br />
<br />
===Encoding===<br />
opcode object[p16]<br />
<br />
===Operation===<br />
Adds the given object (located in the given room) to the Ego actor's inventory. If object < 1, an error is raised. If the object is not found or the object is already in the inventory, this function ends gracefully.<br />
<br />
<br />
==print ($14)==<br />
<br />
===Encoding===<br />
opcode actor[p8] sub-opcode<br />
<br />
sub-opcodes<br />
$00 xpos[p16] ypos[p16]<br />
$01 colour[p8]<br />
$02 right[p16]<br />
$03 width[p16] height[p16]<br />
$04<br />
$06<br />
$07<br />
$08 offset[p16] delay[p16]<br />
$0F string[c]... $FF<br />
<br />
===Operation===<br />
Sets text properties and displays dialogue.<br />
<br />
{| border="1" cellpadding="2" width=100%<br />
|- style="background:whitesmoke"<br />
|Opcode||Meaning||Description<br />
|-<br />
|$00||SO_AT||Sets the position of the text that follows.<br />
|-<br />
|$01||SO_COLOR||Sets the colour of the text.<br />
|-<br />
|$02||SO_CLIPPED||Clips the text's right-hand side (for wrapping?).<br />
|-<br />
|$03||SO_ERASE||Erases characters (not used in ScummVM).<br />
|-<br />
|$04||SO_CENTER||Centres the text.<br />
|-<br />
|$06||SO_LEFT||Left-aligns the text.<br />
|-<br />
|$07||SO_OVERHEAD||Overhead-aligns the text.<br />
|-<br />
|$0F||SO_TEXTSTRING||Prints the text string that follows. Terminated by $FF.<br />
|}<br />
<br />
===Variants===<br />
In SCUMM V3, text function $06 sets the height of the text:<br />
$06 height[p16]<br />
<br />
In Loom CD (SCUMM V4), there is an additional text function $08 (SO_SAY_VOICE), which plays a portion of the CD audio track.<br />
$08 offset[p16] delay[p16]<br />
<br />
<br />
==printEgo ($D8)==<br />
<br />
===Encoding===<br />
opcode sub-opcode<br />
<br />
===Operation===<br />
Exactly the same as print, except the actor is implicitly Ego. See the entry for "print" for further explanation.<br />
<br />
<br />
==pseudoRoom ($CC)==<br />
<br />
===Encoding===<br />
opcode val[8] res[8]... $00<br />
<br />
===Operation===<br />
forall (res) {<br />
if (res >= $80) {<br />
_resourceMapper[res & $7F] := val<br />
}<br />
}<br />
<br />
What does this actually do? We may never know.<br />
<br />
It looks like res values always have the high bit set, e.g. 0x01 becomes 0x81.<br />
<br />
==putActor ($01)==<br />
<br />
===Encoding===<br />
opcode actor[p8] x[p16] y[p16]<br />
<br />
===Operation===<br />
Puts the actor at the given co-ordinates.<br />
<br />
<br />
==putActorAtObject ($0E)==<br />
<br />
===Encoding===<br />
opcode actor[p8] object[p16]<br />
<br />
===Operation===<br />
Puts the actor at the given object's position. If the object can not be found, a default position is returned (the centre of the screen in ScummVM).<br />
<br />
<br />
==putActorInRoom ($2D)==<br />
<br />
===Encoding===<br />
opcode actor[p8] room[p8]<br />
<br />
===Operation===<br />
Puts the actor in the given room.<br />
<br />
<br />
==resourceRoutines ($0C)==<br />
<br />
===Encoding===<br />
opcode sub-opcode<br />
<br />
sub-opcodes:<br />
$01 resID[p8]<br />
... $01 through $13 take the same arguments ...<br />
$13 resID[p8]<br />
$14 room[p8] object[p16]<br />
<br />
===Operation===<br />
resID is unique only within the resource type (e.g. script 11 will not conflict with sound 11).<br />
<br />
{| border="1" cellpadding="2" width=100%<br />
|- style="background:whitesmoke"<br />
|Opcode||Meaning||Description<br />
|-<br />
|$01||SO_LOAD_SCRIPT||Loads the given script into memory.<br />
|-<br />
|$02||SO_LOAD_SOUND||Loads the given sound into memory.<br />
|-<br />
|$03||SO_LOAD_COSTUME||Loads the given costume into memory.<br />
|-<br />
|$04||SO_LOAD_ROOM||Loads the given room into memory.<br />
|-<br />
|$05||SO_NUKE_SCRIPT||Obliterates the given script from memory.<br />
|-<br />
|$06||SO_NUKE_SOUND||Obliterates the given sound from memory.<br />
|-<br />
|$07||SO_NUKE_COSTUME||Obliterates the given costume from memory.<br />
|-<br />
|$08||SO_NUKE_ROOM||Obliterates the given room from memory.<br />
|-<br />
|$09||SO_LOCK_SCRIPT||Locks the given script.<br />
|-<br />
|$0A||SO_LOCK_SOUND||Locks the given sound.<br />
|-<br />
|$0B||SO_LOCK_COSTUME||Locks the given costume.<br />
|-<br />
|$0C||SO_LOCK_ROOM||Locks the given room.<br />
|-<br />
|$0D||SO_UNLOCK_SCRIPT||Unlocks the given script.<br />
|-<br />
|$0E||SO_UNLOCK_SOUND||Unlocks the given sound.<br />
|-<br />
|$0F||SO_UNLOCK_COSTUME||Unlocks the given costume.<br />
|-<br />
|$10||SO_UNLOCK_ROOM||Unlocks the given room.<br />
|-<br />
|$11||SO_CLEAR_HEAP||Clears the heap.<br />
|-<br />
|$12||SO_LOAD_CHARSET||Loads the given character set into memory.<br />
|-<br />
|$13||SO_NUKE_CHARSET||Obliterates the given character set from memory.<br />
|-<br />
|$14||SO_LOAD_OBJECT||Loads the given object from the given room resource.<br />
|}<br />
<br />
===Variants===<br />
FM-Towns games add the following sub-opcodes (these are not confirmed nor implemented in ScummVM):<br />
{| border="1" cellpadding="2" width=100%<br />
|- style="background:whitesmoke"<br />
|Opcode||Meaning||Description<br />
|-<br />
|$20||Unknown||Does nothing, not used in-game.<br />
|-<br />
|$21||Unknown||Does nothing, not used in-game.<br />
|-<br />
|$23||CD Volume||Possibly changes the volume of CD tracks (Loom CD). Takes 1 byte.<br />
|-<br />
|$24||Sound Volume||Sets the loudness of a sound resource. Used in Indy3 and Zak. Takes 2 bytes (left/right volumes?).<br />
|-<br />
|$25||Sound Pitch||Sets the pitch of a sound resource. Used in Indy3 and Zak. Takes 1 byte (pitch = "foo" - "center" semitones. Center is at $32 in the sound resource.)<br />
|}<br />
<br />
<br />
==roomOps ($33)==<br />
<br />
===Encoding===<br />
opcode sub-opcode<br />
<br />
sub-opcodes:<br />
$01 minX[p16] maxX[p16]<br />
$03 b[p16] h[p16]<br />
$04 red[p16] green[p16] blue[p16] aux index[p8]<br />
$05<br />
$06<br />
$07 scale1[p8] y1[p8] aux scale2[p8] y2[p8] aux slot[p8]<br />
$08 scale[p8] startcolour[p8] endcolour[p8]<br />
$09 loadflag[p8] loadslot[p8]<br />
$0A effect[p16]<br />
$0B redscale[p16] greenscale[p16] bluescale[p16] aux startcolour[p8] endcolour[p8]<br />
$0C redscale[p16] greenscale[p16] bluescale[p16] aux startcolour[p8] endcolour[p8]<br />
$0D resID[p8] filename[c]... $00<br />
$0E resID[p8] filename[c]... $00<br />
$0F resID[p8] aux start[p8] end[p8] aux time[p8]<br />
$10 colindex[p8] delay[p8]<br />
<br />
===Operation===<br />
{| border="1" cellpadding="2" width=100%<br />
|- style="background:whitesmoke"<br />
|Opcode||Meaning||Description<br />
|-<br />
|$01||SO_ROOM_SCROLL||Clamps the given arguments so scrolling does not extend past the width of the room or screen.<br />
|-<br />
|$03||SO_ROOM_SCREEN||Initialises a screen.<br />
|-<br />
|$04||SO_ROOM_PALETTE||Adjusts the room's palette.<br />
|-<br />
|$05||SO_ROOM_SHAKE_ON||Starts the room shaking.<br />
|-<br />
|$06||SO_ROOM_SHAKE_OFF||Ends the room shaking.<br />
|-<br />
|$07||SO_ROOM_SCALE||Sets the room's y scales? (slot is 1 greater than actual slot?)<br />
|-<br />
|$08||SO_ROOM_INTENSITY||Lightens/darkens the room's palette.<br />
|-<br />
|$09||SO_ROOM_SAVEGAME||Saves temporary state of the room/game?<br />
|-<br />
|$0A||SO_ROOM_FADE||If effect is 0, fades in the room. Otherwise, fades out with the given effect (taken from the high byte of effect).<br>1 = iris effect<br>2 = box wipe (upper-left to bottom-right)<br>3 = box wipe (upper-right to bottem-left)<br>4 = inverse box wipe.<br />
|-<br />
|$0B||SO_RGB_ROOM_INTENSITY||Lightens/darkens the room's palette, with different scales for red, green and blue.<br />
|-<br />
|$0C||SO_ROOM_SHADOW||Lightens/darkens the shadow palette, with different scales for red, green, and blue.<br />
|-<br />
|$0D||SO_SAVE_STRING||Saves a string resource to the given file?<br />
|-<br />
|$0E||SO_LOAD_STRING||Loads a string resource from a given file?<br />
|-<br />
|$0F||SO_ROOM_TRANSFORM||Manipulates palettes, strings?<br />
|-<br />
|$10||SO_CYCLE_SPEED||Starts colour cycling with delay? colIndex is between 0 and 16<br />
|}<br />
<br />
===Variants===<br />
SCUMM V3 (non-PC Engine) encodes the arguments before the sub-opcode:<br />
opcode arg1[p16] arg2[p16] sub-opcode<br />
<br />
Small header games include an extra sub-opcode, $02 (SO_ROOM_COLOR), which adjusts the room's palette:<br />
opcode $02 colour[p16] index[p16]<br />
... or for V3 games ...<br />
opcode colour[p16] index[p16] $02<br />
<br />
In small header games, sub-opcode $04 (SO_ROOM_PALETTE) affects the shadow palette, and only accepts two arguments, a "room colour slot" (palette entry? between 0 and 256) and an index:<br />
opcode $04 colour[p16] index[p16]<br />
... or for V3 games ...<br />
opcode colour[p16] index[p16] $04<br />
<br />
In FM-Towns games, sub-opcode $0A performs a different function and has its own sub-opcodes (some unknown and all not yet implemented in ScummVM):<br />
opcode $0A sub-opcode<br />
<br />
{| border="1" cellpadding="2" width=100%<br />
|- style="background:whitesmoke"<br />
|Opcode||Meaning||Description<br />
|-<br />
|$08||||compose kMainVirtScreen over a screen buffer<br />
|-<br />
|$09||||call 0x110:0x20 _ax=0x601 _edx=2<br />
|-<br />
|$0A||||call 0x110:0x20 _ax=0x601 _edx=3<br />
|-<br />
|$0B||||clear screen 0x1C:0x45000 sizeof(640 * 320)<br />
|-<br />
|$0C||||call 0x110:0x20 _ax=0x601 _edx=0<br />
|-<br />
|$0D||||call 0x110:0x20 _ax=0x601 _edx=1<br />
|-<br />
|$10||||enable clearing of a screen buffer in drawBitmap()<br />
|-<br />
|$11||||disable clearing of a screen buffer in drawBitmap()<br />
|-<br />
|$12||||clear a screen buffer<br />
|-<br />
|$13||||enable palette operations (palManipulate(), cyclePalette() etc.)<br />
|-<br />
|$14||||disable palette operations<br />
|-<br />
|$15||||disable clearing of screen 0x1C:0x5000 sizeof(640 * 320) in initScreens()<br />
|-<br />
|$16||||enable clearing of screen 0x1C:0x5000 sizeof(640 * 320) in initScreens()<br />
|-<br />
|$1E||||Unknown<br />
|}<br />
<br />
==saveRestoreVerbs ($AB)==<br />
<br />
===Encoding=== <br />
opcode sub-opcode<br />
<br />
sub-opcodes: <br />
$01 start[p8] end[p8] mode[p8]<br />
$02 start[p8] end[p8] mode[p8]<br />
$03 start[p8] end[p8] mode[p8]<br />
<br />
===Operation===<br />
{| border="1" cellpadding="2" width=100%<br />
|- style="background:whitesmoke"<br />
|Opcode||Meaning||Description<br />
|-<br />
|$01||SO_SAVE_VERBS||For all verbs between start and end, sets the "saveid" to mode. <br />
|-<br />
|$02||SO_RESTORE_VERBS||For all verbs between start and end and matching mode, kills any existing verb, sets the saveid to 0 and generally inits the verb.<br />
|-<br />
|$03||SO_DELETE_VERBS||For all verbs between start and end and matching mode, kills any existing verb.<br />
|}<br />
<br />
==setCameraAt ($32)==<br />
<br />
===Encoding===<br />
opcode x[p16]<br />
<br />
===Operation===<br />
Sets the camera's x position.<br />
<br />
<br />
==setObjectName ($54)==<br />
<br />
===Encoding===<br />
opcode object[p16] name[c]... $00<br />
<br />
===Operation===<br />
Sets the given object's name.<br />
<br />
<br />
==setOwnerOf ($29)==<br />
<br />
===Encoding===<br />
opcode object[p16] owner[p8]<br />
<br />
===Operation===<br />
Sets the owner of the object.<br />
<br />
<br />
==setState ($07)==<br />
<br />
===Encoding===<br />
opcode object[p16] state[p8]<br />
<br />
===Operation===<br />
Sets the state of the object.<br />
<br />
<br />
==setVarRange ($26)==<br />
non-standard encoding<br />
<br />
===Encoding===<br />
opcode result number[8] values[8]...<br />
or<br />
opcode result number[8] values[16]...<br />
<br />
===Operation===<br />
for (i = 0; i < number; i++) {<br />
&#42;result + i := values[i];<br />
}<br />
<br />
This sets a number of variables to the given parameters. The starting variable is given as "result", and the number of variables to modify is given as "number". This is followed by the same number of values, which will be put into the variable locations. The values are constants, and can be either 16-bit, if the highest bit of the opcode is set, i.e. $A6; or 8-bit, if the highest bit of the opcode is not set, i.e. $26. Note that all values are affected by the opcode's high bit; you can't mix 8 and 16-bit values.<br />
<br />
descumm example:<br />
setVarRange(Var[178],9,[0,0,0,0,0,0,0,0,0]);<br />
<br />
This sets variables 178 to 186 (inclusive) to 0.<br />
<br />
<br />
==soundKludge ($4C)==<br />
<br />
===Encoding===<br />
opcode items[v16]...<br />
<br />
===Operation===<br />
If the first item is -1, the existing sound queue is processed. Otherwise, the list of items is added to the queue.<br />
<br />
===Variants===<br />
In SCUMM V3 (small header) games, this opcode is used for the WaitForSentence instruction.<br />
<br />
<br />
==startMusic ($02)==<br />
<br />
===Encoding===<br />
opcode music[p8]<br />
<br />
===Operation===<br />
Adds the music in to the queue to be played.<br />
<br />
===Variants===<br />
In FM-Towns (SCUMM V3) games, this instruction performs different functions (some kind of Audio CD status query function; some partially implemented in ScummVM):<br />
opcode result sub-opcode<br />
<br />
{| border="1" cellpadding="2" width=100%<br />
|- style="background:whitesmoke"<br />
|Opcode||Meaning||Description<br />
|-<br />
|$00||Is Playing||Returns true if a CD audio track is currently playing.<br />
|-<br />
|$FC||Unpause CD||Unpauses the CD audio track.<br />
|-<br />
|$FD||Pause CD||Pauses the CD audio track.<br />
|-<br />
|$FE||Get CD Sound||Returns the current CD sound.<br />
|-<br />
|$FF||CD Volume||Might return the the current CD volume in FM-Towns Loom.<br />
|-<br />
|other||Track Length||Returns the track length in seconds.<br />
|}<br />
<br />
<br />
==startObject ($37)==<br />
<br />
===Encoding===<br />
opcode object[p16] script[p8] args[v16]...<br />
<br />
===Operation===<br />
Starts the object's script (OBCD blocks), passing the given arguments.<br />
<br />
<br />
==startScript ($0A)==<br />
one parameter plus varargs, extra encoding in opcode<br />
<br />
===Encoding===<br />
opcode script[p8] args[v16]...<br />
<br />
===Operation===<br />
Spawns a new thread running the code in script script. The new script has its local variables initialised to the list args. Uninitialised variables have undefined values.<br />
<br />
The opcode carries extra information: <br />
<br />
{| border="1" cellpadding="2" width=10%<br />
|- style="background:whitesmoke"<br />
|7||6||5||4 0<br />
|-<br />
|P1||R||F||$0A<br />
|}<br />
<br />
P1 = standard parameter bit<br><br />
R = indicates that the script is recursive<br><br />
F = indicates that the script is freeze resistant (a call to freezeScripts will skip this script, unless the "force freeze" bit of the freezeScripts opcode is set).<br />
<br />
<br />
==startSound ($1C)==<br />
<br />
===Encoding===<br />
opcode sound[p8]<br />
<br />
===Operation===<br />
Adds the given sound to the sound queue to be played.<br />
<br />
<br />
==stopMusic ($20)==<br />
<br />
===Encoding===<br />
opcode<br />
<br />
===Operation===<br />
Stops all sounds.<br />
<br />
<br />
==stopObjectCode ($A0 or $00)==<br />
<br />
===Encoding===<br />
opcode<br />
<br />
===Operation===<br />
Marks the calling script as dead, to be later pruned from the thread pool. Cleans up residual arrays.<br />
<br />
Is $00 correct?<br />
<br />
==stopObjectScript ($6E)==<br />
<br />
===Encoding===<br />
opcode script[p16]<br />
<br />
===Operation===<br />
Marks the given object script as dead, to be later pruned from the thread pool. Cleans up residual arrays.<br />
<br />
<br />
==stopScript ($62)==<br />
<br />
===Encoding===<br />
opcode script[p8]<br />
<br />
===Operation===<br />
Marks the given script as dead, to be later pruned from the thread pool. Cleans up residual arrays.<br />
<br />
<br />
==stopSound ($3C)==<br />
<br />
===Encoding===<br />
opcode sound[p8]<br />
<br />
===Operation===<br />
Stops the given sound.<br />
<br />
<br />
==stringOps ($27)==<br />
parameters depend on sub-opcode<br />
<br />
===Encoding===<br />
opcode sub-opcode<br />
<br />
sub-opcodes:<br />
$01 stringID[p8] string[c]... $00<br />
$02 destID[p8] srcID[p8]<br />
$03 stringID[p8] index[p8] char[c]<br />
$04 result stringID[p8] index[p8]<br />
$05 stringID[p8] size[p8]<br />
<br />
===Operation===<br />
Miscellaneous actions on strings (Arrays, referred to by resource number).<br />
<br />
{| border="1" cellpadding="2" width=100%<br />
|- style="background:whitesmoke"<br />
|Opcode||Meaning||Description<br />
|-<br />
|$01||Load String||Loads the inline null-terminated string into the resource slot given by stringID.<br />
|-<br />
|$02||Copy String||Creates a duplicate of the string at resource slot srcID into destID. The old string at destID is lost.<br />
|-<br />
|$03||Write Character||Writes char at the given index (offset) of the string resource located at slot stringID. Out of bounds accesses cause undefined behaviour.<br />
|-<br />
|$04||Read Character||Reads a byte (character) at the given index (offset) of the string resource located at slot stringID, and writes it to result. Out of bounds accesses cause undefined behaviour.<br />
|-<br />
|$05||New String||Allocates or frees a string (Array), located at resource slot stringID. The string is initialised to size; if size is zero, the string is freed.<br />
|}<br />
<br />
<br />
==subtract ($3A)==<br />
<br />
===Encoding===<br />
opcode result value[p16]<br />
<br />
===Operation===<br />
result := result - value<br />
<br />
The variable pointed to by result is read, value is subtracted from it, and the result written back.<br />
<br />
<br />
==systemOps ($98)==<br />
<br />
===Encoding===<br />
opcode sub-opcode<br />
<br />
sub-opcodes:<br />
$01<br />
$02<br />
$03<br />
<br />
===Operation===<br />
{| border="1" cellpadding="2" width=100%<br />
|- style="background:whitesmoke"<br />
|Opcode||Meaning||Description<br />
|-<br />
|$01||SO_RESTART||Restarts the game.<br />
|-<br />
|$02||SO_PAUSE||Pauses/unpauses the game.<br />
|-<br />
|$03||SO_QUIT||Quits the game.<br />
|}<br />
<br />
<br />
==verbOps ($7A)==<br />
<br />
===Encoding===<br />
opcode verbID[p8] sub-opcode... $FF<br />
<br />
sub-opcodes:<br />
$01 object[p16]<br />
$02 name[c]... $00<br />
$03 colour[p8]<br />
$04 hicolour[p8]<br />
$05 left[p16] top[p16]<br />
$06<br />
$07<br />
$08<br />
$09<br />
$10 colour[p8]<br />
$11<br />
$12 key[p8]<br />
$13<br />
$14 stringID[p16]<br />
$16 object[p16] room[p8]<br />
$17 colour[p8]<br />
<br />
===Operation===<br />
{| border="1" cellpadding="2" width=100%<br />
|- style="background:whitesmoke"<br />
|Opcode||Meaning||Description<br />
|-<br />
|$01||SO_VERB_IMAGE||Assigns an object (image) to a verb.<br />
|-<br />
|$02||SO_VERB_NAME||Assigns the in-line name to the verb slot.<br />
|-<br />
|$03||SO_VERB_COLOR||Sets the colour of the verb.<br />
|-<br />
|$04||SO_VERB_HICOLOR||Sets the high colour of the verb.<br />
|-<br />
|$05||SO_VERB_AT||Sets the verb's top-left co-ordinates.<br />
|-<br />
|$06||SO_VERB_ON||Makes this verb active.<br />
|-<br />
|$07||SO_VERB_OFF||Makes this verb inactive.<br />
|-<br />
|$08||SO_VERB_DELETE||Kills this verb.<br />
|-<br />
|$09||SO_VERB_NEW||Creates a verb in the slot for the given verbID. If the slot is 0 (verb doesn't already exist), will add it to the next unusued slot; if this exceeds the global maximum number of verbs an error will be raised.<br />
|-<br />
|$10||SO_VERB_DIMCOLOR||Sets the dim colour of the verb.<br />
|-<br />
|$11||SO_VERB_DIM||Dims this verb.<br />
|-<br />
|$12||SO_VERB_KEY||Sets the key code (maybe ASCII char?) associated with this verb.<br />
|-<br />
|$13||SO_VERB_CENTER||Centres the verb?<br />
|-<br />
|$14||SO_VERB_NAME_STR||Loads the given string resource into the verb's slot. If either the string resource or verb slot is not found (0), the verb resource is nuked.<br />
|-<br />
|$16||Assign Object||Assigns an object from the given room to the verb (if the object's image index is not already assigned to the given object).<br />
|-<br />
|$17||Set Back Colour||Sets the background colour of the verb?<br />
|}<br />
<br />
<br />
==wait ($AE)==<br />
<br />
===Encoding===<br />
opcode sub-opcode<br />
<br />
sub-opcodes:<br />
$01 actor[p8]<br />
$02 <br />
$03<br />
$04<br />
<br />
===Operation===<br />
{| border="1" cellpadding="2" width=100%<br />
|- style="background:whitesmoke"<br />
|Opcode||Meaning||Description<br />
|-<br />
|$01||SO_WAIT_FOR_ACTOR||If the given actor is moving, breaks and resumes at this instruction again.<br />
|-<br />
|$02||SO_WAIT_FOR_MESSAGE||If the global variable VAR_HAVE_MSG (Var[3]) is not zero, breaks and resumes at this instruction again.<br />
|-<br />
|$03||SO_WAIT_FOR_CAMERA||If the camera has not reached its destination x position, breaks and resumes at this instruction again.<br />
|-<br />
|$04||SO_WAIT_FOR_SENTENCE||If there is a sentence present?, breaks and resumes at this instruction again<br />
|}<br />
<br />
===Variants===<br />
In Indy3 (non-Macintosh), this opcode only acts as SO_WAIT_FOR_MESSAGE and omits the sub-opcode.<br />
opcode<br />
<br />
<br />
==walkActorTo ($1E)==<br />
<br />
===Encoding===<br />
opcode actor[p8] x[p16] y[p16]<br />
<br />
===Operation===<br />
Sets the actor to begin walking to the given position.<br />
<br />
<br />
==walkActorToActor ($0D)==<br />
<br />
===Encoding===<br />
opcode walker[p8] walkee[p8] distance[8]<br />
<br />
===Operation===<br />
Walks walker towards walkee's position by the given distance. Walker and walkee are both actors.<br />
<br />
<br />
==walkActorToObject ($36)==<br />
<br />
===Encoding===<br />
opcode actor[p8] object[p16]<br />
<br />
===Operation===<br />
Sets the actor to begin walking to the given object's position.<br />
<br />
=Variables=<br />
<br />
A number of variables are reserved for use by the SPUTM/SCUMM engine. Here is a list of known variables and their corresponding numbers, taken from the ScummVM source code.<br />
<br />
VAR_RESULT = 0; // descumm claims var 0 is the result var (for expressions)<br />
VAR_KEYPRESS = 0; // script_v5_.cpp claims var 0 is for keypresses...<br />
VAR_EGO = 1;<br />
VAR_CAMERA_POS_X = 2;<br />
VAR_HAVE_MSG = 3;<br />
VAR_ROOM = 4;<br />
VAR_OVERRIDE = 5;<br />
VAR_MACHINE_SPEED = 6;<br />
VAR_ME = 7;<br />
VAR_NUM_ACTOR = 8;<br />
VAR_CURRENT_LIGHTS = 9;<br />
VAR_CURRENTDRIVE = 10;<br />
VAR_TMR_1 = 11;<br />
VAR_TMR_2 = 12;<br />
VAR_TMR_3 = 13;<br />
VAR_MUSIC_TIMER = 14;<br />
VAR_ACTOR_RANGE_MIN = 15;<br />
VAR_ACTOR_RANGE_MAX = 16;<br />
VAR_CAMERA_MIN_X = 17;<br />
VAR_CAMERA_MAX_X = 18;<br />
VAR_TIMER_NEXT = 19;<br />
VAR_VIRT_MOUSE_X = 20;<br />
VAR_VIRT_MOUSE_Y = 21;<br />
VAR_ROOM_RESOURCE = 22;<br />
VAR_LAST_SOUND = 23;<br />
VAR_CUTSCENEEXIT_KEY = 24;<br />
VAR_TALK_ACTOR = 25;<br />
VAR_CAMERA_FAST_X = 26;<br />
VAR_SCROLL_SCRIPT = 27;<br />
VAR_ENTRY_SCRIPT = 28;<br />
VAR_ENTRY_SCRIPT2 = 29;<br />
VAR_EXIT_SCRIPT = 30;<br />
VAR_EXIT_SCRIPT2 = 31;<br />
VAR_VERB_SCRIPT = 32;<br />
VAR_SENTENCE_SCRIPT = 33;<br />
VAR_INVENTORY_SCRIPT = 34;<br />
VAR_CUTSCENE_START_SCRIPT = 35;<br />
VAR_CUTSCENE_END_SCRIPT = 36;<br />
VAR_CHARINC = 37;<br />
VAR_WALKTO_OBJ = 38;<br />
VAR_DEBUGMODE = 39;<br />
VAR_HEAPSPACE = 40;<br />
VAR_RESTART_KEY = 42;<br />
VAR_PAUSE_KEY = 43;<br />
VAR_MOUSE_X = 44;<br />
VAR_MOUSE_Y = 45;<br />
VAR_TIMER = 46;<br />
VAR_TIMER_TOTAL = 47;<br />
VAR_SOUNDCARD = 48;<br />
VAR_VIDEOMODE = 49;<br />
VAR_MAINMENU_KEY = 50;<br />
VAR_FIXEDDISK = 51;<br />
VAR_CURSORSTATE = 52;<br />
VAR_USERPUT = 53;<br />
VAR_V5_TALK_STRING_Y = 54;<br />
VAR_SOUNDRESULT = 56;<br />
VAR_TALKSTOP_KEY = 57;<br />
VAR_FADE_DELAY = 59;<br />
VAR_NOSUBTITLES = 60;<br />
VAR_SOUNDPARAM = 64;<br />
VAR_SOUNDPARAM2 = 65;<br />
VAR_SOUNDPARAM3 = 66;<br />
VAR_INPUTMODE = 67; // 1 is keyboard, 2 is joystick, 3 is mouse<br />
VAR_MEMORY_PERFORMANCE = 68;<br />
VAR_VIDEO_PERFORMANCE = 69;<br />
VAR_ROOM_FLAG = 70;<br />
VAR_GAME_LOADED = 71;<br />
VAR_NEW_ROOM = 72;<br />
<br />
<br />
=Table of Parameters=<br />
Please see the wiki page [[SCUMM/V5_opcodes/Table]].</div>Jestar jokinhttps://wiki.scummvm.org/index.php?title=SCUMM/V5_opcodes/Table&diff=10976SCUMM/V5 opcodes/Table2009-04-16T13:04:28Z<p>Jestar jokin: /* Table of Parameters */ classOfIs argument can be expressed as a standard list</p>
<hr />
<div>=Table of Parameters=<br />
<br />
This table shows a summary of the [[SCUMM/V5 opcodes|SCUMM V5]] opcodes and their parameters in a concise fashion.<br />
<br />
Argument types:<br />
* V = variable<br />
* B = byte constant<br />
* W = word constant<br />
* P8 = variable or byte<br />
* P16 = variable or word<br />
* L = list<br />
* J = jump (used by almost all boolean expressions, comparisons) (equivalent to W)<br />
* D = delay; 24-bit constant (only used by delay instruction, strangely enough)<br />
* A = ASCII string, terminated by the following argument ($00, $FF, $FE...)<br />
* A0 = ASCII string, null-terminated<br />
* A1 = ASCII string, $FF terminated<br />
* FF = the hex value $FF, used for terminating some lists, strings etc.<br />
* SO = sub-opcode, variants listed underneath as "opcode$sub-opcode"<br />
* NS = non-standard encoding that cannot be sufficiently expressed in this table<br />
* + = one or more of the preceding argument (parameter bits usually don't matter)<br />
* None = does not take that argument argument<br />
<br />
<br />
{| border="1" style="text-align:center" width=100% cellpadding=2<br />
|- style="background:whitesmoke"<br />
|Instruction||Opcode||Descumm equiv.||Returns a Value||Arg 1||Arg 2||Arg 3<br />
|-<br />
|align="left" |actorFollowCamera<br />
|$52<br />
|style="color:silver; background:whitesmoke" |==<br />
|style="color:silver; background:whitesmoke" |False<br />
|P8<br />
|style="color:silver; background:whitesmoke" |None<br />
|style="color:silver; background:whitesmoke" |None<br />
|-<br />
|align="left" |actorFromPos<br />
|$15<br />
|style="color:silver; background:whitesmoke" |==<br />
|True<br />
|P16<br />
|P16<br />
|style="color:silver; background:whitesmoke" |None<br />
|-<br />
|align="left" |actorOps<br />
|$13<br />
|ActorOps<br />
|style="color:silver; background:whitesmoke" |False<br />
|P8<br />
|SO+<br />
|FF<br />
|-<br />
|align="left" |actorOps$00<br />
|$00<br />
|Unknown<br />
|style="color:silver; background:whitesmoke" |False<br />
|P8<br />
|style="color:silver; background:whitesmoke" |None<br />
|style="color:silver; background:whitesmoke" |None<br />
|-<br />
|align="left" |actorOps$01<br />
|$01<br />
|Costume<br />
|style="color:silver; background:whitesmoke" |False<br />
|P8<br />
|style="color:silver; background:whitesmoke" |None<br />
|style="color:silver; background:whitesmoke" |None<br />
|-<br />
|align="left" |actorOps$02<br />
|$02<br />
|WalkSpeed<br />
|style="color:silver; background:whitesmoke" |False<br />
|P8<br />
|P8<br />
|style="color:silver; background:whitesmoke" |None<br />
|-<br />
|align="left" |actorOps$03<br />
|$03<br />
|Sound<br />
|style="color:silver; background:whitesmoke" |False<br />
|P8<br />
|style="color:silver; background:whitesmoke" |None<br />
|style="color:silver; background:whitesmoke" |None<br />
|-<br />
|align="left" |actorOps$04<br />
|$04<br />
|WalkAnimNr<br />
|style="color:silver; background:whitesmoke" |False<br />
|P8<br />
|style="color:silver; background:whitesmoke" |None<br />
|style="color:silver; background:whitesmoke" |None<br />
|-<br />
|align="left" |actorOps$05<br />
|$05<br />
|TalkAnimNr<br />
|style="color:silver; background:whitesmoke" |False<br />
|P8<br />
|P8<br />
|style="color:silver; background:whitesmoke" |None<br />
|-<br />
|align="left" |actorOps$06<br />
|$06<br />
|StandAnimNr<br />
|style="color:silver; background:whitesmoke" |False<br />
|P8<br />
|style="color:silver; background:whitesmoke" |None<br />
|style="color:silver; background:whitesmoke" |None<br />
|-<br />
|align="left" |actorOps$07<br />
|$07<br />
|Nothing<br />
|style="color:silver; background:whitesmoke" |False<br />
|P8<br />
|P8<br />
|P8<br />
|-<br />
|align="left" |actorOps$08<br />
|$08<br />
|Init<br />
|style="color:silver; background:whitesmoke" |False<br />
|style="color:silver; background:whitesmoke" |None<br />
|style="color:silver; background:whitesmoke" |None<br />
|style="color:silver; background:whitesmoke" |None<br />
|-<br />
|align="left" |actorOps$09<br />
|$09<br />
|Elevation<br />
|style="color:silver; background:whitesmoke" |False<br />
|P16<br />
|style="color:silver; background:whitesmoke" |None<br />
|style="color:silver; background:whitesmoke" |None<br />
|-<br />
|align="left" |actorOps$0A<br />
|$0A<br />
|DefaultAnims<br />
|style="color:silver; background:whitesmoke" |False<br />
|style="color:silver; background:whitesmoke" |None<br />
|style="color:silver; background:whitesmoke" |None<br />
|style="color:silver; background:whitesmoke" |None<br />
|-<br />
|align="left" |actorOps$0B<br />
|$0B<br />
|Palette<br />
|style="color:silver; background:whitesmoke" |False<br />
|P8<br />
|P8<br />
|style="color:silver; background:whitesmoke" |None<br />
|-<br />
|align="left" |actorOps$0C<br />
|$0C<br />
|TalkColor<br />
|style="color:silver; background:whitesmoke" |False<br />
|P8<br />
|style="color:silver; background:whitesmoke" |None<br />
|style="color:silver; background:whitesmoke" |None<br />
|-<br />
|align="left" |actorOps$0D<br />
|$0D<br />
|Name<br />
|style="color:silver; background:whitesmoke" |False<br />
|A0<br />
|style="color:silver; background:whitesmoke" |None<br />
|style="color:silver; background:whitesmoke" |None<br />
|-<br />
|align="left" |actorOps$0E<br />
|$0E<br />
|InitAnimNr<br />
|style="color:silver; background:whitesmoke" |False<br />
|P8<br />
|style="color:silver; background:whitesmoke" |None<br />
|style="color:silver; background:whitesmoke" |None<br />
|-<br />
|align="left" |actorOps$10<br />
|$10<br />
|Width<br />
|style="color:silver; background:whitesmoke" |False<br />
|P8<br />
|style="color:silver; background:whitesmoke" |None<br />
|style="color:silver; background:whitesmoke" |None<br />
|-<br />
|align="left" |actorOps$11<br />
|$11<br />
|Scale<br />
|style="color:silver; background:whitesmoke" |False<br />
|P8<br />
|P8<br />
|style="color:silver; background:whitesmoke" |None<br />
|-<br />
|align="left" |actorOps$12<br />
|$12<br />
|NeverZClip<br />
|style="color:silver; background:whitesmoke" |False<br />
|style="color:silver; background:whitesmoke" |None<br />
|style="color:silver; background:whitesmoke" |None<br />
|style="color:silver; background:whitesmoke" |None<br />
|-<br />
|align="left" |actorOps$13<br />
|$13<br />
|SetZClip<br />
|style="color:silver; background:whitesmoke" |False<br />
|P8<br />
|style="color:silver; background:whitesmoke" |None<br />
|style="color:silver; background:whitesmoke" |None<br />
|-<br />
|align="left" |actorOps$14<br />
|$14<br />
|IgnoreBoxes<br />
|style="color:silver; background:whitesmoke" |False<br />
|style="color:silver; background:whitesmoke" |None<br />
|style="color:silver; background:whitesmoke" |None<br />
|style="color:silver; background:whitesmoke" |None<br />
|-<br />
|align="left" |actorOps$15<br />
|$15<br />
|FollowBoxes<br />
|style="color:silver; background:whitesmoke" |False<br />
|P8<br />
|style="color:silver; background:whitesmoke" |None<br />
|style="color:silver; background:whitesmoke" |None<br />
|-<br />
|align="left" |actorOps$16<br />
|$16<br />
|AnimSpeed<br />
|style="color:silver; background:whitesmoke" |False<br />
|P8<br />
|style="color:silver; background:whitesmoke" |None<br />
|style="color:silver; background:whitesmoke" |None<br />
|-<br />
|align="left" |actorOps$17<br />
|$17<br />
|ShadowMode<br />
|style="color:silver; background:whitesmoke" |False<br />
|P8<br />
|style="color:silver; background:whitesmoke" |None<br />
|style="color:silver; background:whitesmoke" |None<br />
|-<br />
|align="left" |actorSetClass<br />
|$5D<br />
|setClass<br />
|style="color:silver; background:whitesmoke" |False<br />
|P16<br />
|L<br />
|style="color:silver; background:whitesmoke" |None<br />
|-<br />
|align="left" |add<br />
|$5A<br />
|(inline)<br />
|True<br />
|P16<br />
|style="color:silver; background:whitesmoke" |None<br />
|style="color:silver; background:whitesmoke" |None<br />
|-<br />
|align="left" |and<br />
|$17<br />
|(inline)<br />
|True<br />
|P16<br />
|style="color:silver; background:whitesmoke" |None<br />
|style="color:silver; background:whitesmoke" |None<br />
|-<br />
|align="left" |animateActor<br />
|$11<br />
|animateCostume<br />
|style="color:silver; background:whitesmoke" |False<br />
|P8<br />
|P8<br />
|style="color:silver; background:whitesmoke" |None<br />
|-<br />
|align="left" |breakHere<br />
|$80<br />
|style="color:silver; background:whitesmoke" |==<br />
|style="color:silver; background:whitesmoke" |False<br />
|style="color:silver; background:whitesmoke" |None<br />
|style="color:silver; background:whitesmoke" |None<br />
|style="color:silver; background:whitesmoke" |None<br />
|-<br />
|align="left" |chainScript<br />
|$42<br />
|style="color:silver; background:whitesmoke" |==<br />
|style="color:silver; background:whitesmoke" |False<br />
|P8<br />
|L<br />
|style="color:silver; background:whitesmoke" |None<br />
|-<br />
|align="left" |cursorCommand<br />
|$2C<br />
|(none)<br />
|style="color:silver; background:whitesmoke" |False<br />
|SO<br />
|style="color:silver; background:whitesmoke" |None<br />
|style="color:silver; background:whitesmoke" |None<br />
|-<br />
|align="left" |cursorCommand$01<br />
|$01<br />
|CursorShow<br />
|style="color:silver; background:whitesmoke" |False<br />
|style="color:silver; background:whitesmoke" |None<br />
|style="color:silver; background:whitesmoke" |None<br />
|style="color:silver; background:whitesmoke" |None<br />
|-<br />
|align="left" |cursorCommand$02<br />
|$02<br />
|CursorHide<br />
|style="color:silver; background:whitesmoke" |False<br />
|style="color:silver; background:whitesmoke" |None<br />
|style="color:silver; background:whitesmoke" |None<br />
|style="color:silver; background:whitesmoke" |None<br />
|-<br />
|align="left" |cursorCommand$03<br />
|$03<br />
|UserputOn<br />
|style="color:silver; background:whitesmoke" |False<br />
|style="color:silver; background:whitesmoke" |None<br />
|style="color:silver; background:whitesmoke" |None<br />
|style="color:silver; background:whitesmoke" |None<br />
|-<br />
|align="left" |cursorCommand$04<br />
|$04<br />
|UserputOff<br />
|style="color:silver; background:whitesmoke" |False<br />
|style="color:silver; background:whitesmoke" |None<br />
|style="color:silver; background:whitesmoke" |None<br />
|style="color:silver; background:whitesmoke" |None<br />
|-<br />
|align="left" |cursorCommand$05<br />
|$05<br />
|CursorSoftOn<br />
|style="color:silver; background:whitesmoke" |False<br />
|style="color:silver; background:whitesmoke" |None<br />
|style="color:silver; background:whitesmoke" |None<br />
|style="color:silver; background:whitesmoke" |None<br />
|-<br />
|align="left" |cursorCommand$06<br />
|$06<br />
|CursorSoftOff<br />
|style="color:silver; background:whitesmoke" |False<br />
|style="color:silver; background:whitesmoke" |None<br />
|style="color:silver; background:whitesmoke" |None<br />
|style="color:silver; background:whitesmoke" |None<br />
|-<br />
|align="left" |cursorCommand$07<br />
|$07<br />
|UserputSoftOn<br />
|style="color:silver; background:whitesmoke" |False<br />
|style="color:silver; background:whitesmoke" |None<br />
|style="color:silver; background:whitesmoke" |None<br />
|style="color:silver; background:whitesmoke" |None<br />
|-<br />
|align="left" |cursorCommand$08<br />
|$08<br />
|UserputSoftOff<br />
|style="color:silver; background:whitesmoke" |False<br />
|style="color:silver; background:whitesmoke" |None<br />
|style="color:silver; background:whitesmoke" |None<br />
|style="color:silver; background:whitesmoke" |None<br />
|-<br />
|align="left" |cursorCommand$0A<br />
|$0A<br />
|SetCursorImg<br />
|style="color:silver; background:whitesmoke" |False<br />
|P8<br />
|P8<br />
|style="color:silver; background:whitesmoke" |None<br />
|-<br />
|align="left" |cursorCommand$0B<br />
|$0B<br />
|setCursorHotspot<br />
|style="color:silver; background:whitesmoke" |False<br />
|P8<br />
|P8<br />
|P8<br />
|-<br />
|align="left" |cursorCommand$0C<br />
|$0C<br />
|InitCursor<br />
|style="color:silver; background:whitesmoke" |False<br />
|P8<br />
|style="color:silver; background:whitesmoke" |None<br />
|style="color:silver; background:whitesmoke" |None<br />
|-<br />
|align="left" |cursorCommand$0D<br />
|$0D<br />
|InitCharset<br />
|style="color:silver; background:whitesmoke" |False<br />
|P8<br />
|style="color:silver; background:whitesmoke" |None<br />
|style="color:silver; background:whitesmoke" |None<br />
|-<br />
|align="left" |cursorCommand$0E<br />
|$0E<br />
|CursorCommand<br />
|style="color:silver; background:whitesmoke" |False<br />
|L<br />
|style="color:silver; background:whitesmoke" |None<br />
|style="color:silver; background:whitesmoke" |None<br />
|-<br />
|align="left" |cutscene<br />
|$40<br />
|style="color:silver; background:whitesmoke" |==<br />
|style="color:silver; background:whitesmoke" |False<br />
|L<br />
|style="color:silver; background:whitesmoke" |None<br />
|style="color:silver; background:whitesmoke" |None<br />
|-<br />
|align="left" |debug<br />
|$6B<br />
|debug?<br />
|style="color:silver; background:whitesmoke" |False<br />
|P16<br />
|style="color:silver; background:whitesmoke" |None<br />
|style="color:silver; background:whitesmoke" |None<br />
|-<br />
|align="left" |decrement<br />
|$C6<br />
|(inline)<br />
|True<br />
|style="color:silver; background:whitesmoke" |None<br />
|style="color:silver; background:whitesmoke" |None<br />
|style="color:silver; background:whitesmoke" |None<br />
|-<br />
|align="left" |delay<br />
|$2E<br />
|style="color:silver; background:whitesmoke" |==<br />
|style="color:silver; background:whitesmoke" |False<br />
|D<br />
|style="color:silver; background:whitesmoke" |None<br />
|style="color:silver; background:whitesmoke" |None<br />
|-<br />
|align="left" |delayVariable<br />
|$2B<br />
|style="color:silver; background:whitesmoke" |==<br />
|style="color:silver; background:whitesmoke" |False<br />
|V<br />
|style="color:silver; background:whitesmoke" |None<br />
|style="color:silver; background:whitesmoke" |None<br />
|-<br />
|align="left" |divide<br />
|$5B<br />
|(inline)<br />
|True<br />
|P16<br />
|style="color:silver; background:whitesmoke" |None<br />
|style="color:silver; background:whitesmoke" |None<br />
|-<br />
|align="left" |doSentence<br />
|$19<br />
|style="color:silver; background:whitesmoke" |==<br />
|style="color:silver; background:whitesmoke" |False<br />
|P8<br />
|P16<br />
|P16<br />
|-<br />
|align="left" |drawBox<br />
|$3F<br />
|style="color:silver; background:whitesmoke" |==<br />
|style="color:silver; background:whitesmoke" |False<br />
|P16<br />
|P16<br />
|NS<br />
|-<br />
|align="left" |drawObject<br />
|$05<br />
|style="color:silver; background:whitesmoke" |==<br />
|style="color:silver; background:whitesmoke" |False<br />
|P16<br />
|SO<br />
|style="color:silver; background:whitesmoke" |None<br />
|-<br />
|align="left" |drawObject$01<br />
|$01<br />
|setXY<br />
|style="color:silver; background:whitesmoke" |False<br />
|P16<br />
|P16<br />
|style="color:silver; background:whitesmoke" |None<br />
|-<br />
|align="left" |drawObject$02<br />
|$02<br />
|setImage<br />
|style="color:silver; background:whitesmoke" |False<br />
|P16<br />
|style="color:silver; background:whitesmoke" |None<br />
|style="color:silver; background:whitesmoke" |None<br />
|-<br />
|align="left" |drawObject$1F<br />
|$1F<br />
|()<br />
|style="color:silver; background:whitesmoke" |False<br />
|style="color:silver; background:whitesmoke" |None<br />
|style="color:silver; background:whitesmoke" |None<br />
|style="color:silver; background:whitesmoke" |None<br />
|-<br />
|align="left" |dummy<br />
|$A7<br />
|dummy(A7)<br />
|style="color:silver; background:whitesmoke" |False<br />
|style="color:silver; background:whitesmoke" |None<br />
|style="color:silver; background:whitesmoke" |None<br />
|style="color:silver; background:whitesmoke" |None<br />
|-<br />
|align="left" |endCutscene<br />
|$C0<br />
|style="color:silver; background:whitesmoke" |==<br />
|style="color:silver; background:whitesmoke" |False<br />
|style="color:silver; background:whitesmoke" |None<br />
|style="color:silver; background:whitesmoke" |None<br />
|style="color:silver; background:whitesmoke" |None<br />
|-<br />
|align="left" |equalZero<br />
|$28<br />
|inline<br />
|style="color:silver; background:whitesmoke" |False<br />
|V<br />
|J<br />
|style="color:silver; background:whitesmoke" |None<br />
|-<br />
|align="left" |expression<br />
|$AC<br />
|Exprmode<br />
|True<br />
|SO+<br />
|FF<br />
|style="color:silver; background:whitesmoke" |None<br />
|-<br />
|align="left" |expression$01<br />
|$01<br />
|(inline)<br />
|style="color:silver; background:whitesmoke" |False<br />
|P16<br />
|style="color:silver; background:whitesmoke" |None<br />
|style="color:silver; background:whitesmoke" |None<br />
|-<br />
|align="left" |expression$02<br />
|$02<br />
|(inline)<br />
|style="color:silver; background:whitesmoke" |False<br />
|style="color:silver; background:whitesmoke" |None<br />
|style="color:silver; background:whitesmoke" |None<br />
|style="color:silver; background:whitesmoke" |None<br />
|-<br />
|align="left" |expression$03<br />
|$03<br />
|(inline)<br />
|style="color:silver; background:whitesmoke" |False<br />
|style="color:silver; background:whitesmoke" |None<br />
|style="color:silver; background:whitesmoke" |None<br />
|style="color:silver; background:whitesmoke" |None<br />
|-<br />
|align="left" |expression$04<br />
|$04<br />
|(inline)<br />
|style="color:silver; background:whitesmoke" |False<br />
|style="color:silver; background:whitesmoke" |None<br />
|style="color:silver; background:whitesmoke" |None<br />
|style="color:silver; background:whitesmoke" |None<br />
|-<br />
|align="left" |expression$05<br />
|$05<br />
|(inline)<br />
|style="color:silver; background:whitesmoke" |False<br />
|style="color:silver; background:whitesmoke" |None<br />
|style="color:silver; background:whitesmoke" |None<br />
|style="color:silver; background:whitesmoke" |None<br />
|-<br />
|align="left" |expression$06<br />
|$06<br />
|(inline)<br />
|style="color:silver; background:whitesmoke" |False<br />
|NS<br />
|style="color:silver; background:whitesmoke" |None<br />
|style="color:silver; background:whitesmoke" |None<br />
|-<br />
|align="left" |faceActor<br />
|$09<br />
|style="color:silver; background:whitesmoke" |==<br />
|style="color:silver; background:whitesmoke" |False<br />
|P8<br />
|P16<br />
|style="color:silver; background:whitesmoke" |None<br />
|-<br />
|align="left" |findInventory<br />
|$3D<br />
|style="color:silver; background:whitesmoke" |==<br />
|True<br />
|P8<br />
|P8<br />
|style="color:silver; background:whitesmoke" |None<br />
|-<br />
|align="left" |findObject<br />
|$35<br />
|style="color:silver; background:whitesmoke" |==<br />
|True<br />
|P8<br />
|P8<br />
|style="color:silver; background:whitesmoke" |None<br />
|-<br />
|align="left" |freezeScripts<br />
|$60<br />
|style="color:silver; background:whitesmoke" |==<br />
|style="color:silver; background:whitesmoke" |False<br />
|P8<br />
|style="color:silver; background:whitesmoke" |None<br />
|style="color:silver; background:whitesmoke" |None<br />
|-<br />
|align="left" |getActorCostume<br />
|$71<br />
|style="color:silver; background:whitesmoke" |==<br />
|True<br />
|P8<br />
|style="color:silver; background:whitesmoke" |None<br />
|style="color:silver; background:whitesmoke" |None<br />
|-<br />
|align="left" |getActorElevation<br />
|$06<br />
|style="color:silver; background:whitesmoke" |==<br />
|True<br />
|P8<br />
|style="color:silver; background:whitesmoke" |None<br />
|style="color:silver; background:whitesmoke" |None<br />
|-<br />
|align="left" |getActorFacing<br />
|$63<br />
|style="color:silver; background:whitesmoke" |==<br />
|True<br />
|P8<br />
|style="color:silver; background:whitesmoke" |None<br />
|style="color:silver; background:whitesmoke" |None<br />
|-<br />
|align="left" |getActorMoving<br />
|$56<br />
|style="color:silver; background:whitesmoke" |==<br />
|True<br />
|P8<br />
|style="color:silver; background:whitesmoke" |None<br />
|style="color:silver; background:whitesmoke" |None<br />
|-<br />
|align="left" |getActorRoom<br />
|$03<br />
|style="color:silver; background:whitesmoke" |==<br />
|True<br />
|P8<br />
|style="color:silver; background:whitesmoke" |None<br />
|style="color:silver; background:whitesmoke" |None<br />
|-<br />
|align="left" |getActorScale<br />
|$3B<br />
|style="color:silver; background:whitesmoke" |==<br />
|True<br />
|P8<br />
|style="color:silver; background:whitesmoke" |None<br />
|style="color:silver; background:whitesmoke" |None<br />
|-<br />
|align="left" |getActorWalkBox<br />
|$7B<br />
|style="color:silver; background:whitesmoke" |==<br />
|True<br />
|P8<br />
|style="color:silver; background:whitesmoke" |None<br />
|style="color:silver; background:whitesmoke" |None<br />
|-<br />
|align="left" |getActorWidth<br />
|$6C<br />
|style="color:silver; background:whitesmoke" |==<br />
|True<br />
|P8<br />
|style="color:silver; background:whitesmoke" |None<br />
|style="color:silver; background:whitesmoke" |None<br />
|-<br />
|align="left" |getActorX<br />
|$43<br />
|style="color:silver; background:whitesmoke" |==<br />
|True<br />
|P16<br />
|style="color:silver; background:whitesmoke" |None<br />
|style="color:silver; background:whitesmoke" |None<br />
|-<br />
|align="left" |getActorY<br />
|$23<br />
|style="color:silver; background:whitesmoke" |==<br />
|True<br />
|P16<br />
|style="color:silver; background:whitesmoke" |None<br />
|style="color:silver; background:whitesmoke" |None<br />
|-<br />
|align="left" |getAnimCounter<br />
|$22<br />
|style="color:silver; background:whitesmoke" |==<br />
|True<br />
|P8<br />
|style="color:silver; background:whitesmoke" |None<br />
|style="color:silver; background:whitesmoke" |None<br />
|-<br />
|align="left" |getClosestObjActor<br />
|$66<br />
|style="color:silver; background:whitesmoke" |==<br />
|True<br />
|P16<br />
|style="color:silver; background:whitesmoke" |None<br />
|style="color:silver; background:whitesmoke" |None<br />
|-<br />
|align="left" |getDist<br />
|$34<br />
|style="color:silver; background:whitesmoke" |==<br />
|True<br />
|P16<br />
|P16<br />
|style="color:silver; background:whitesmoke" |None<br />
|-<br />
|align="left" |getInventoryCount<br />
|$31<br />
|style="color:silver; background:whitesmoke" |==<br />
|True<br />
|P8<br />
|style="color:silver; background:whitesmoke" |None<br />
|style="color:silver; background:whitesmoke" |None<br />
|-<br />
|align="left" |getObjectOwner<br />
|$10<br />
|style="color:silver; background:whitesmoke" |==<br />
|True<br />
|P16<br />
|style="color:silver; background:whitesmoke" |None<br />
|style="color:silver; background:whitesmoke" |None<br />
|-<br />
|align="left" |getObjectState<br />
|$0F<br />
|style="color:silver; background:whitesmoke" |==<br />
|True<br />
|P16<br />
|style="color:silver; background:whitesmoke" |None<br />
|style="color:silver; background:whitesmoke" |None<br />
|-<br />
|align="left" |getRandomNumber<br />
|$16<br />
|getRandomNr<br />
|True<br />
|P8<br />
|style="color:silver; background:whitesmoke" |None<br />
|style="color:silver; background:whitesmoke" |None<br />
|-<br />
|align="left" |getScriptRunning<br />
|$68<br />
|style="color:silver; background:whitesmoke" |isScriptRunning<br />
|True<br />
|P8<br />
|style="color:silver; background:whitesmoke" |None<br />
|style="color:silver; background:whitesmoke" |None<br />
|-<br />
|align="left" |getStringWidth<br />
|$67<br />
|style="color:silver; background:whitesmoke" |==<br />
|True<br />
|P8<br />
|style="color:silver; background:whitesmoke" |None<br />
|style="color:silver; background:whitesmoke" |None<br />
|-<br />
|align="left" |getVerbEntryPoint<br />
|$0B<br />
|style="color:silver; background:whitesmoke" |==<br />
|True<br />
|P16<br />
|P16<br />
|style="color:silver; background:whitesmoke" |None<br />
|-<br />
|align="left" |ifClassOfIs<br />
|$1D<br />
|classOfIs<br />
|style="color:silver; background:whitesmoke" |False<br />
|P16<br />
|L<br />
|J<br />
|-<br />
|align="left" |ifNotState<br />
|$2F<br />
|getState (inline)<br />
|style="color:silver; background:whitesmoke" |False<br />
|P16<br />
|P8<br />
|J<br />
|-<br />
|align="left" |ifState<br />
|$4F<br />
|getState (inline)<br />
|style="color:silver; background:whitesmoke" |False<br />
|P16<br />
|P8<br />
|J<br />
|-<br />
|align="left" |increment<br />
|$46<br />
|(inline)<br />
|True<br />
|style="color:silver; background:whitesmoke" |None<br />
|style="color:silver; background:whitesmoke" |None<br />
|style="color:silver; background:whitesmoke" |None<br />
|-<br />
|align="left" |isActorInBox<br />
|$1F<br />
|style="color:silver; background:whitesmoke" |==<br />
|style="color:silver; background:whitesmoke" |False<br />
|P8<br />
|P8<br />
|J<br />
|-<br />
|align="left" |isEqual<br />
|$48<br />
|(inline)<br />
|style="color:silver; background:whitesmoke" |False<br />
|V<br />
|P16<br />
|J<br />
|-<br />
|align="left" |isGreater<br />
|$78<br />
|(inline)<br />
|style="color:silver; background:whitesmoke" |False<br />
|V<br />
|P16<br />
|J<br />
|-<br />
|align="left" |isGreaterEqual<br />
|$04<br />
|(inline)<br />
|style="color:silver; background:whitesmoke" |False<br />
|V<br />
|P16<br />
|J<br />
|-<br />
|align="left" |isLess<br />
|$44<br />
|(inline)<br />
|style="color:silver; background:whitesmoke" |False<br />
|V<br />
|P16<br />
|J<br />
|-<br />
|align="left" |isNotEqual<br />
|$08<br />
|(inline)<br />
|style="color:silver; background:whitesmoke" |False<br />
|V<br />
|P16<br />
|J<br />
|-<br />
|align="left" |isSoundRunning<br />
|$7C<br />
|style="color:silver; background:whitesmoke" |==<br />
|True<br />
|P8<br />
|style="color:silver; background:whitesmoke" |None<br />
|style="color:silver; background:whitesmoke" |None<br />
|-<br />
|align="left" |jumpRelative<br />
|$18<br />
|(inline) or goto<br />
|style="color:silver; background:whitesmoke" |False<br />
|J<br />
|style="color:silver; background:whitesmoke" |None<br />
|style="color:silver; background:whitesmoke" |None<br />
|-<br />
|align="left" |lessOrEqual<br />
|$38<br />
|(inline)<br />
|style="color:silver; background:whitesmoke" |False<br />
|V<br />
|P16<br />
|J<br />
|-<br />
|align="left" |lights<br />
|$70<br />
|style="color:silver; background:whitesmoke" |==<br />
|style="color:silver; background:whitesmoke" |False<br />
|P8<br />
|B<br />
|B<br />
|-<br />
|align="left" |loadRoom<br />
|$72<br />
|style="color:silver; background:whitesmoke" |==<br />
|style="color:silver; background:whitesmoke" |False<br />
|P8<br />
|style="color:silver; background:whitesmoke" |None<br />
|style="color:silver; background:whitesmoke" |None<br />
|-<br />
|align="left" |loadRoomWithEgo<br />
|$24<br />
|style="color:silver; background:whitesmoke" |==<br />
|style="color:silver; background:whitesmoke" |False<br />
|P16<br />
|P8<br />
|NS<br />
|-<br />
|align="left" |matrixOp<br />
|$30<br />
|N/A<br />
|style="color:silver; background:whitesmoke" |False<br />
|SO<br />
|style="color:silver; background:whitesmoke" |None<br />
|style="color:silver; background:whitesmoke" |None<br />
|-<br />
|align="left" |matrixOp$01<br />
|$01<br />
|setBoxFlags<br />
|style="color:silver; background:whitesmoke" |False<br />
|P8<br />
|P8<br />
|style="color:silver; background:whitesmoke" |None<br />
|-<br />
|align="left" |matrixOp$02<br />
|$02<br />
|setBoxScale<br />
|style="color:silver; background:whitesmoke" |False<br />
|P8<br />
|P8<br />
|style="color:silver; background:whitesmoke" |None<br />
|-<br />
|align="left" |matrixOp$03<br />
|$03<br />
|SetBoxSlot<br />
|style="color:silver; background:whitesmoke" |False<br />
|P8<br />
|P8<br />
|style="color:silver; background:whitesmoke" |None<br />
|-<br />
|align="left" |matrixOp$04<br />
|$04<br />
|createBoxMatrix<br />
|style="color:silver; background:whitesmoke" |False<br />
|style="color:silver; background:whitesmoke" |None<br />
|style="color:silver; background:whitesmoke" |None<br />
|style="color:silver; background:whitesmoke" |None<br />
|-<br />
|align="left" |move<br />
|$1A<br />
|(inline)<br />
|True<br />
|P16<br />
|style="color:silver; background:whitesmoke" |None<br />
|style="color:silver; background:whitesmoke" |None<br />
|-<br />
|align="left" |multiply<br />
|$1B<br />
|(inline)<br />
|True<br />
|P16<br />
|style="color:silver; background:whitesmoke" |None<br />
|style="color:silver; background:whitesmoke" |None<br />
|-<br />
|align="left" |notEqualZero<br />
|$A8<br />
|(inline)<br />
|style="color:silver; background:whitesmoke" |False<br />
|V<br />
|J<br />
|style="color:silver; background:whitesmoke" |None<br />
|-<br />
|align="left" |oldRoomEffect<br />
|$5C<br />
|oldRoomEffect-fadein<br />
|style="color:silver; background:whitesmoke" |False<br />
|SO<br />
|style="color:silver; background:whitesmoke" |None<br />
|style="color:silver; background:whitesmoke" |None<br />
|-<br />
|align="left" |oldRoomEffect$03<br />
|$03<br />
|oldRoomEffect-set<br />
|style="color:silver; background:whitesmoke" |False<br />
|P16<br />
|style="color:silver; background:whitesmoke" |None<br />
|style="color:silver; background:whitesmoke" |None<br />
|-<br />
|align="left" |or<br />
|$57<br />
|(inline)<br />
|True<br />
|P16<br />
|style="color:silver; background:whitesmoke" |None<br />
|style="color:silver; background:whitesmoke" |None<br />
|-<br />
|align="left" |override<br />
|$58<br />
|N/A<br />
|style="color:silver; background:whitesmoke" |False<br />
|SO<br />
|style="color:silver; background:whitesmoke" |None<br />
|style="color:silver; background:whitesmoke" |None<br />
|-<br />
|align="left" |override$00<br />
|$00<br />
|endOverride<br />
|style="color:silver; background:whitesmoke" |False<br />
|style="color:silver; background:whitesmoke" |None<br />
|style="color:silver; background:whitesmoke" |None<br />
|style="color:silver; background:whitesmoke" |None<br />
|-<br />
|align="left" |override$01<br />
|$01<br />
|beginOverride<br />
|style="color:silver; background:whitesmoke" |False<br />
|NS<br />
|J<br />
|style="color:silver; background:whitesmoke" |None<br />
|-<br />
|align="left" |panCameraTo<br />
|$12<br />
|style="color:silver; background:whitesmoke" |==<br />
|style="color:silver; background:whitesmoke" |False<br />
|P16<br />
|style="color:silver; background:whitesmoke" |None<br />
|style="color:silver; background:whitesmoke" |None<br />
|-<br />
|align="left" |pickupObject<br />
|$25<br />
|style="color:silver; background:whitesmoke" |==<br />
|style="color:silver; background:whitesmoke" |False<br />
|P16<br />
|P8<br />
|style="color:silver; background:whitesmoke" |None<br />
|-<br />
|align="left" |pickupObjectOld<br />
|$50<br />
|pickupObject<br />
|style="color:silver; background:whitesmoke" |False<br />
|P16<br />
|style="color:silver; background:whitesmoke" |None<br />
|style="color:silver; background:whitesmoke" |None<br />
|-<br />
|align="left" |print<br />
|$14<br />
|style="color:silver; background:whitesmoke" |==<br />
|style="color:silver; background:whitesmoke" |False<br />
|P8<br />
|SO+<br />
|style="color:silver; background:whitesmoke" |None<br />
|-<br />
|align="left" |print$00<br />
|$00<br />
|Pos<br />
|style="color:silver; background:whitesmoke" |False<br />
|P16<br />
|P16<br />
|style="color:silver; background:whitesmoke" |None<br />
|-<br />
|align="left" |print$01<br />
|$01<br />
|Color<br />
|style="color:silver; background:whitesmoke" |False<br />
|P8<br />
|style="color:silver; background:whitesmoke" |None<br />
|style="color:silver; background:whitesmoke" |None<br />
|-<br />
|align="left" |print$02<br />
|$02<br />
|Clipped<br />
|style="color:silver; background:whitesmoke" |False<br />
|P16<br />
|style="color:silver; background:whitesmoke" |None<br />
|style="color:silver; background:whitesmoke" |None<br />
|-<br />
|align="left" |print$03<br />
|$03<br />
|RestoreBG<br />
|style="color:silver; background:whitesmoke" |False<br />
|P16<br />
|P16<br />
|style="color:silver; background:whitesmoke" |None<br />
|-<br />
|align="left" |print$04<br />
|$04<br />
|Center<br />
|style="color:silver; background:whitesmoke" |False<br />
|style="color:silver; background:whitesmoke" |None<br />
|style="color:silver; background:whitesmoke" |None<br />
|style="color:silver; background:whitesmoke" |None<br />
|-<br />
|align="left" |print$06<br />
|$06<br />
|Left<br />
|style="color:silver; background:whitesmoke" |False<br />
|style="color:silver; background:whitesmoke" |None<br />
|style="color:silver; background:whitesmoke" |None<br />
|style="color:silver; background:whitesmoke" |None<br />
|-<br />
|align="left" |print$07<br />
|$07<br />
|Overhead<br />
|style="color:silver; background:whitesmoke" |False<br />
|style="color:silver; background:whitesmoke" |None<br />
|style="color:silver; background:whitesmoke" |None<br />
|style="color:silver; background:whitesmoke" |None<br />
|-<br />
|align="left" |print$08<br />
|$08<br />
|PlayCDTrack<br />
|style="color:silver; background:whitesmoke" |False<br />
|P16<br />
|P16<br />
|style="color:silver; background:whitesmoke" |None<br />
|-<br />
|align="left" |print$0F<br />
|$0F<br />
|Text()<br />
|style="color:silver; background:whitesmoke" |False<br />
|A1<br />
|style="color:silver; background:whitesmoke" |None<br />
|style="color:silver; background:whitesmoke" |None<br />
|-<br />
|align="left" |printEgo<br />
|$D8<br />
|style="color:silver; background:whitesmoke" |==<br />
|style="color:silver; background:whitesmoke" |False<br />
|SO+<br />
|style="color:silver; background:whitesmoke" |None<br />
|style="color:silver; background:whitesmoke" |None<br />
|-<br />
|align="left" |printEgo$00<br />
|$00<br />
|Pos<br />
|style="color:silver; background:whitesmoke" |False<br />
|P16<br />
|P16<br />
|style="color:silver; background:whitesmoke" |None<br />
|-<br />
|align="left" |printEgo$01<br />
|$01<br />
|Color<br />
|style="color:silver; background:whitesmoke" |False<br />
|P8<br />
|style="color:silver; background:whitesmoke" |None<br />
|style="color:silver; background:whitesmoke" |None<br />
|-<br />
|align="left" |printEgo$02<br />
|$02<br />
|Clipped<br />
|style="color:silver; background:whitesmoke" |False<br />
|P16<br />
|style="color:silver; background:whitesmoke" |None<br />
|style="color:silver; background:whitesmoke" |None<br />
|-<br />
|align="left" |printEgo$03<br />
|$03<br />
|RestoreBG<br />
|style="color:silver; background:whitesmoke" |False<br />
|P16<br />
|P16<br />
|style="color:silver; background:whitesmoke" |None<br />
|-<br />
|align="left" |printEgo$04<br />
|$04<br />
|Center<br />
|style="color:silver; background:whitesmoke" |False<br />
|style="color:silver; background:whitesmoke" |None<br />
|style="color:silver; background:whitesmoke" |None<br />
|style="color:silver; background:whitesmoke" |None<br />
|-<br />
|align="left" |printEgo$06<br />
|$06<br />
|Left<br />
|style="color:silver; background:whitesmoke" |False<br />
|style="color:silver; background:whitesmoke" |None<br />
|style="color:silver; background:whitesmoke" |None<br />
|style="color:silver; background:whitesmoke" |None<br />
|-<br />
|align="left" |printEgo$07<br />
|$07<br />
|Overhead<br />
|style="color:silver; background:whitesmoke" |False<br />
|style="color:silver; background:whitesmoke" |None<br />
|style="color:silver; background:whitesmoke" |None<br />
|style="color:silver; background:whitesmoke" |None<br />
|-<br />
|align="left" |printEgo$08<br />
|$08<br />
|PlayCDTrack<br />
|style="color:silver; background:whitesmoke" |False<br />
|P16<br />
|P16<br />
|style="color:silver; background:whitesmoke" |None<br />
|-<br />
|align="left" |printEgo$0F<br />
|$0F<br />
|Text()<br />
|style="color:silver; background:whitesmoke" |False<br />
|A1<br />
|style="color:silver; background:whitesmoke" |None<br />
|style="color:silver; background:whitesmoke" |None<br />
|-<br />
|align="left" |pseudoRoom<br />
|$CC<br />
|PsuedoRoom<br />
|style="color:silver; background:whitesmoke" |False<br />
|B<br />
|NS<br />
|NS<br />
|-<br />
|align="left" |putActor<br />
|$01<br />
|style="color:silver; background:whitesmoke" |==<br />
|style="color:silver; background:whitesmoke" |False<br />
|P8<br />
|P16<br />
|P16<br />
|-<br />
|align="left" |putActorAtObject<br />
|$0E<br />
|style="color:silver; background:whitesmoke" |==<br />
|style="color:silver; background:whitesmoke" |False<br />
|P8<br />
|P16<br />
|style="color:silver; background:whitesmoke" |None<br />
|-<br />
|align="left" |putActorInRoom<br />
|$2D<br />
|style="color:silver; background:whitesmoke" |==<br />
|style="color:silver; background:whitesmoke" |False<br />
|P8<br />
|P8<br />
|style="color:silver; background:whitesmoke" |None<br />
|-<br />
|align="left" |resourceRoutines<br />
|$0C<br />
|Resource.<br />
|style="color:silver; background:whitesmoke" |False<br />
|SO<br />
|style="color:silver; background:whitesmoke" |None<br />
|style="color:silver; background:whitesmoke" |None<br />
|-<br />
|align="left" |resourcesRoutines$01<br />
|$01<br />
|loadScript<br />
|style="color:silver; background:whitesmoke" |False<br />
|P8<br />
|style="color:silver; background:whitesmoke" |None<br />
|style="color:silver; background:whitesmoke" |None<br />
|-<br />
|align="left" |resourcesRoutines$02<br />
|$02<br />
|loadSound<br />
|style="color:silver; background:whitesmoke" |False<br />
|P8<br />
|style="color:silver; background:whitesmoke" |None<br />
|style="color:silver; background:whitesmoke" |None<br />
|-<br />
|align="left" |resourcesRoutines$03<br />
|$03<br />
|loadCostume<br />
|style="color:silver; background:whitesmoke" |False<br />
|P8<br />
|style="color:silver; background:whitesmoke" |None<br />
|style="color:silver; background:whitesmoke" |None<br />
|-<br />
|align="left" |resourcesRoutines$04<br />
|$04<br />
|loadRoom<br />
|style="color:silver; background:whitesmoke" |False<br />
|P8<br />
|style="color:silver; background:whitesmoke" |None<br />
|style="color:silver; background:whitesmoke" |None<br />
|-<br />
|align="left" |resourcesRoutines$05<br />
|$05<br />
|nukeScript<br />
|style="color:silver; background:whitesmoke" |False<br />
|P8<br />
|style="color:silver; background:whitesmoke" |None<br />
|style="color:silver; background:whitesmoke" |None<br />
|-<br />
|align="left" |resourcesRoutines$06<br />
|$06<br />
|nukeSound<br />
|style="color:silver; background:whitesmoke" |False<br />
|P8<br />
|style="color:silver; background:whitesmoke" |None<br />
|style="color:silver; background:whitesmoke" |None<br />
|-<br />
|align="left" |resourcesRoutines$07<br />
|$07<br />
|nukeCostume<br />
|style="color:silver; background:whitesmoke" |False<br />
|P8<br />
|style="color:silver; background:whitesmoke" |None<br />
|style="color:silver; background:whitesmoke" |None<br />
|-<br />
|align="left" |resourcesRoutines$08<br />
|$08<br />
|nukeRoom<br />
|style="color:silver; background:whitesmoke" |False<br />
|P8<br />
|style="color:silver; background:whitesmoke" |None<br />
|style="color:silver; background:whitesmoke" |None<br />
|-<br />
|align="left" |resourcesRoutines$09<br />
|$09<br />
|lockScript<br />
|style="color:silver; background:whitesmoke" |False<br />
|P8<br />
|style="color:silver; background:whitesmoke" |None<br />
|style="color:silver; background:whitesmoke" |None<br />
|-<br />
|align="left" |resourcesRoutines$0A<br />
|$0A<br />
|lockSound<br />
|style="color:silver; background:whitesmoke" |False<br />
|P8<br />
|style="color:silver; background:whitesmoke" |None<br />
|style="color:silver; background:whitesmoke" |None<br />
|-<br />
|align="left" |resourcesRoutines$0B<br />
|$0B<br />
|lockCostume<br />
|style="color:silver; background:whitesmoke" |False<br />
|P8<br />
|style="color:silver; background:whitesmoke" |None<br />
|style="color:silver; background:whitesmoke" |None<br />
|-<br />
|align="left" |resourcesRoutines$0C<br />
|$0C<br />
|lockRoom<br />
|style="color:silver; background:whitesmoke" |False<br />
|P8<br />
|style="color:silver; background:whitesmoke" |None<br />
|style="color:silver; background:whitesmoke" |None<br />
|-<br />
|align="left" |resourcesRoutines$0D<br />
|$0D<br />
|unlockScript<br />
|style="color:silver; background:whitesmoke" |False<br />
|P8<br />
|style="color:silver; background:whitesmoke" |None<br />
|style="color:silver; background:whitesmoke" |None<br />
|-<br />
|align="left" |resourcesRoutines$0E<br />
|$0E<br />
|unlockSound<br />
|style="color:silver; background:whitesmoke" |False<br />
|P8<br />
|style="color:silver; background:whitesmoke" |None<br />
|style="color:silver; background:whitesmoke" |None<br />
|-<br />
|align="left" |resourcesRoutines$0F<br />
|$0F<br />
|unlockCostume<br />
|style="color:silver; background:whitesmoke" |False<br />
|P8<br />
|style="color:silver; background:whitesmoke" |None<br />
|style="color:silver; background:whitesmoke" |None<br />
|-<br />
|align="left" |resourcesRoutines$10<br />
|$10<br />
|unlockRoom<br />
|style="color:silver; background:whitesmoke" |False<br />
|P8<br />
|style="color:silver; background:whitesmoke" |None<br />
|style="color:silver; background:whitesmoke" |None<br />
|-<br />
|align="left" |resourcesRoutines$11<br />
|$11<br />
|clearHeap<br />
|style="color:silver; background:whitesmoke" |False<br />
|P8<br />
|style="color:silver; background:whitesmoke" |None<br />
|style="color:silver; background:whitesmoke" |None<br />
|-<br />
|align="left" |resourcesRoutines$12<br />
|$12<br />
|loadCharset<br />
|style="color:silver; background:whitesmoke" |False<br />
|P8<br />
|style="color:silver; background:whitesmoke" |None<br />
|style="color:silver; background:whitesmoke" |None<br />
|-<br />
|align="left" |resourcesRoutines$13<br />
|$13<br />
|nukeCharset<br />
|style="color:silver; background:whitesmoke" |False<br />
|P8<br />
|style="color:silver; background:whitesmoke" |None<br />
|style="color:silver; background:whitesmoke" |None<br />
|-<br />
|align="left" |resourcesRoutines$14<br />
|$14<br />
|loadFlObject<br />
|style="color:silver; background:whitesmoke" |False<br />
|P8<br />
|P16<br />
|style="color:silver; background:whitesmoke" |None<br />
|-<br />
|align="left" |roomOps<br />
|$33<br />
|N/A<br />
|style="color:silver; background:whitesmoke" |False<br />
|SO<br />
|style="color:silver; background:whitesmoke" |None<br />
|style="color:silver; background:whitesmoke" |None<br />
|-<br />
|align="left" |roomOps$01<br />
|$01<br />
|RoomScroll<br />
|style="color:silver; background:whitesmoke" |False<br />
|P16<br />
|P16<br />
|style="color:silver; background:whitesmoke" |None<br />
|-<br />
|align="left" |roomOps$03<br />
|$03<br />
|SetScreen<br />
|style="color:silver; background:whitesmoke" |False<br />
|P16<br />
|P16<br />
|style="color:silver; background:whitesmoke" |None<br />
|-<br />
|align="left" |roomOps$04<br />
|$04<br />
|SetPalColor<br />
|style="color:silver; background:whitesmoke" |False<br />
|P16<br />
|P16<br />
|NS<br />
|-<br />
|align="left" |roomOps$05<br />
|$05<br />
|ShakeOn<br />
|style="color:silver; background:whitesmoke" |False<br />
|style="color:silver; background:whitesmoke" |None<br />
|style="color:silver; background:whitesmoke" |None<br />
|style="color:silver; background:whitesmoke" |None<br />
|-<br />
|align="left" |roomOps$06<br />
|$06<br />
|ShakeOff<br />
|style="color:silver; background:whitesmoke" |False<br />
|style="color:silver; background:whitesmoke" |None<br />
|style="color:silver; background:whitesmoke" |None<br />
|style="color:silver; background:whitesmoke" |None<br />
|-<br />
|align="left" |roomOps$07<br />
|$07<br />
|Unused<br />
|style="color:silver; background:whitesmoke" |False<br />
|P8<br />
|P8<br />
|NS<br />
|-<br />
|align="left" |roomOps$08<br />
|$08<br />
|RoomIntensity<br />
|style="color:silver; background:whitesmoke" |False<br />
|P8<br />
|P8<br />
|P8<br />
|-<br />
|align="left" |roomOps$09<br />
|$09<br />
|saveLoad?<br />
|style="color:silver; background:whitesmoke" |False<br />
|P8<br />
|P8<br />
|style="color:silver; background:whitesmoke" |None<br />
|-<br />
|align="left" |roomOps$0A<br />
|$0A<br />
|screenEffect?<br />
|style="color:silver; background:whitesmoke" |False<br />
|P16<br />
|style="color:silver; background:whitesmoke" |None<br />
|style="color:silver; background:whitesmoke" |None<br />
|-<br />
|align="left" |roomOps$0B<br />
|$0B<br />
|setRGBRoomIntensity<br />
|style="color:silver; background:whitesmoke" |False<br />
|P16<br />
|P16<br />
|NS<br />
|-<br />
|align="left" |roomOps$0C<br />
|$0C<br />
|setRoomShadow<br />
|style="color:silver; background:whitesmoke" |False<br />
|P16<br />
|P16<br />
|NS<br />
|-<br />
|align="left" |roomOps$0D<br />
|$0D<br />
|saveString<br />
|style="color:silver; background:whitesmoke" |False<br />
|P8<br />
|A0<br />
|style="color:silver; background:whitesmoke" |None<br />
|-<br />
|align="left" |roomOps$0E<br />
|$0E<br />
|loadString<br />
|style="color:silver; background:whitesmoke" |False<br />
|P8<br />
|A0<br />
|style="color:silver; background:whitesmoke" |None<br />
|-<br />
|align="left" |roomOps$0F<br />
|$0F<br />
|palManipulate<br />
|style="color:silver; background:whitesmoke" |False<br />
|P8<br />
|NS<br />
|NS<br />
|-<br />
|align="left" |roomOps$10<br />
|$10<br />
|colorCycleDelay<br />
|style="color:silver; background:whitesmoke" |False<br />
|P8<br />
|P8<br />
|style="color:silver; background:whitesmoke" |None<br />
|-<br />
|align="left" |saveRestoreVerbs<br />
|$AB<br />
|N/A<br />
|style="color:silver; background:whitesmoke" |False<br />
|NS<br />
|NS<br />
|NS<br />
|-<br />
|align="left" |saveRestoreVerbs$01<br />
|$01<br />
|saveVerbs<br />
|style="color:silver; background:whitesmoke" |False<br />
|style="color:silver; background:whitesmoke" |None<br />
|style="color:silver; background:whitesmoke" |None<br />
|style="color:silver; background:whitesmoke" |None<br />
|-<br />
|align="left" |saveRestoreVerbs$02<br />
|$02<br />
|restoreVerbs<br />
|style="color:silver; background:whitesmoke" |False<br />
|style="color:silver; background:whitesmoke" |None<br />
|style="color:silver; background:whitesmoke" |None<br />
|style="color:silver; background:whitesmoke" |None<br />
|-<br />
|align="left" |saveRestoreVerbs$03<br />
|$03<br />
|deleteVerbs<br />
|style="color:silver; background:whitesmoke" |False<br />
|style="color:silver; background:whitesmoke" |None<br />
|style="color:silver; background:whitesmoke" |None<br />
|style="color:silver; background:whitesmoke" |None<br />
|-<br />
|align="left" |setCameraAt<br />
|$32<br />
|style="color:silver; background:whitesmoke" |==<br />
|style="color:silver; background:whitesmoke" |False<br />
|P16<br />
|style="color:silver; background:whitesmoke" |None<br />
|style="color:silver; background:whitesmoke" |None<br />
|-<br />
|align="left" |setObjectName<br />
|$54<br />
|style="color:silver; background:whitesmoke" |==<br />
|style="color:silver; background:whitesmoke" |False<br />
|P16<br />
|A0<br />
|style="color:silver; background:whitesmoke" |None<br />
|-<br />
|align="left" |setOwnerOf<br />
|$29<br />
|style="color:silver; background:whitesmoke" |==<br />
|style="color:silver; background:whitesmoke" |False<br />
|P16<br />
|P8<br />
|style="color:silver; background:whitesmoke" |None<br />
|-<br />
|align="left" |setState<br />
|$07<br />
|style="color:silver; background:whitesmoke" |==<br />
|style="color:silver; background:whitesmoke" |False<br />
|P16<br />
|P8<br />
|style="color:silver; background:whitesmoke" |None<br />
|-<br />
|align="left" |setVarRange<br />
|$26<br />
|style="color:silver; background:whitesmoke" |==<br />
|True<br />
|B<br />
|NS<br />
|NS<br />
|-<br />
|align="left" |soundKludge<br />
|$4C<br />
|style="color:silver; background:whitesmoke" |==<br />
|style="color:silver; background:whitesmoke" |False<br />
|L<br />
|style="color:silver; background:whitesmoke" |None<br />
|style="color:silver; background:whitesmoke" |None<br />
|-<br />
|align="left" |startMusic<br />
|$02<br />
|style="color:silver; background:whitesmoke" |==<br />
|style="color:silver; background:whitesmoke" |False<br />
|P8<br />
|style="color:silver; background:whitesmoke" |None<br />
|style="color:silver; background:whitesmoke" |None<br />
|-<br />
|align="left" |startObject<br />
|$37<br />
|style="color:silver; background:whitesmoke" |==<br />
|style="color:silver; background:whitesmoke" |False<br />
|P16<br />
|P8<br />
|L<br />
|-<br />
|align="left" |startScript<br />
|$0A<br />
|style="color:silver; background:whitesmoke" |==<br />
|style="color:silver; background:whitesmoke" |False<br />
|P8<br />
|L<br />
|style="color:silver; background:whitesmoke" |None<br />
|-<br />
|align="left" |startSound<br />
|$1C<br />
|style="color:silver; background:whitesmoke" |==<br />
|style="color:silver; background:whitesmoke" |False<br />
|P8<br />
|style="color:silver; background:whitesmoke" |None<br />
|style="color:silver; background:whitesmoke" |None<br />
|-<br />
|align="left" |stopMusic<br />
|$20<br />
|style="color:silver; background:whitesmoke" |==<br />
|style="color:silver; background:whitesmoke" |False<br />
|style="color:silver; background:whitesmoke" |None<br />
|style="color:silver; background:whitesmoke" |None<br />
|style="color:silver; background:whitesmoke" |None<br />
|-<br />
|align="left" |stopObjectCode<br />
|$00<br />
|style="color:silver; background:whitesmoke" |==<br />
|style="color:silver; background:whitesmoke" |False<br />
|style="color:silver; background:whitesmoke" |None<br />
|style="color:silver; background:whitesmoke" |None<br />
|style="color:silver; background:whitesmoke" |None<br />
|-<br />
|align="left" |stopObjectScript<br />
|$6E<br />
|style="color:silver; background:whitesmoke" |==<br />
|style="color:silver; background:whitesmoke" |False<br />
|P16<br />
|style="color:silver; background:whitesmoke" |None<br />
|style="color:silver; background:whitesmoke" |None<br />
|-<br />
|align="left" |stopScript<br />
|$62<br />
|style="color:silver; background:whitesmoke" |==<br />
|style="color:silver; background:whitesmoke" |False<br />
|P8<br />
|style="color:silver; background:whitesmoke" |None<br />
|style="color:silver; background:whitesmoke" |None<br />
|-<br />
|align="left" |stopSound<br />
|$3C<br />
|style="color:silver; background:whitesmoke" |==<br />
|style="color:silver; background:whitesmoke" |False<br />
|P8<br />
|style="color:silver; background:whitesmoke" |None<br />
|style="color:silver; background:whitesmoke" |None<br />
|-<br />
|align="left" |stringOps<br />
|$27<br />
|style="color:silver; background:whitesmoke" |==<br />
|style="color:silver; background:whitesmoke" |False<br />
|SO<br />
|style="color:silver; background:whitesmoke" |None<br />
|style="color:silver; background:whitesmoke" |None<br />
|-<br />
|align="left" |stringOps$01<br />
|$01<br />
|PutCodeInString<br />
|style="color:silver; background:whitesmoke" |False<br />
|P8<br />
|A0<br />
|style="color:silver; background:whitesmoke" |None<br />
|-<br />
|align="left" |stringOps$02<br />
|$02<br />
|CopyString<br />
|style="color:silver; background:whitesmoke" |False<br />
|P8<br />
|P8<br />
|style="color:silver; background:whitesmoke" |None<br />
|-<br />
|align="left" |stringOps$03<br />
|$03<br />
|SetStringChar<br />
|style="color:silver; background:whitesmoke" |False<br />
|P8<br />
|P8<br />
|B<br />
|-<br />
|align="left" |stringOps$04<br />
|$04<br />
|GetStringChar<br />
|True<br />
|P8<br />
|P8<br />
|style="color:silver; background:whitesmoke" |None<br />
|-<br />
|align="left" |stringOps$05<br />
|$05<br />
|CreateString<br />
|style="color:silver; background:whitesmoke" |False<br />
|P8<br />
|P8<br />
|style="color:silver; background:whitesmoke" |None<br />
|-<br />
|align="left" |subtract<br />
|$3A<br />
|(inline)<br />
|True<br />
|P16<br />
|style="color:silver; background:whitesmoke" |None<br />
|style="color:silver; background:whitesmoke" |None<br />
|-<br />
|align="left" |systemOps<br />
|$98<br />
|systemOps<br />
|style="color:silver; background:whitesmoke" |False<br />
|SO<br />
|style="color:silver; background:whitesmoke" |None<br />
|style="color:silver; background:whitesmoke" |None<br />
|-<br />
|align="left" |systemOps$01<br />
|$01<br />
|N/A<br />
|style="color:silver; background:whitesmoke" |False<br />
|style="color:silver; background:whitesmoke" |None<br />
|style="color:silver; background:whitesmoke" |None<br />
|style="color:silver; background:whitesmoke" |None<br />
|-<br />
|align="left" |systemOps$02<br />
|$02<br />
|N/A<br />
|style="color:silver; background:whitesmoke" |False<br />
|style="color:silver; background:whitesmoke" |None<br />
|style="color:silver; background:whitesmoke" |None<br />
|style="color:silver; background:whitesmoke" |None<br />
|-<br />
|align="left" |systemOps$03<br />
|$03<br />
|N/A<br />
|style="color:silver; background:whitesmoke" |False<br />
|style="color:silver; background:whitesmoke" |None<br />
|style="color:silver; background:whitesmoke" |None<br />
|style="color:silver; background:whitesmoke" |None<br />
|-<br />
|align="left" |verbOps<br />
|$7A<br />
|VerbOps<br />
|style="color:silver; background:whitesmoke" |False<br />
|P8<br />
|SO+<br />
|FF<br />
|-<br />
|align="left" |verbOps$01<br />
|$01<br />
|Image<br />
|style="color:silver; background:whitesmoke" |False<br />
|P16<br />
|style="color:silver; background:whitesmoke" |None<br />
|style="color:silver; background:whitesmoke" |None<br />
|-<br />
|align="left" |verbOps$02<br />
|$02<br />
|Text<br />
|style="color:silver; background:whitesmoke" |False<br />
|A0<br />
|style="color:silver; background:whitesmoke" |None<br />
|style="color:silver; background:whitesmoke" |None<br />
|-<br />
|align="left" |verbOps$03<br />
|$03<br />
|Color<br />
|style="color:silver; background:whitesmoke" |False<br />
|P8<br />
|style="color:silver; background:whitesmoke" |None<br />
|style="color:silver; background:whitesmoke" |None<br />
|-<br />
|align="left" |verbOps$04<br />
|$04<br />
|HiColor<br />
|style="color:silver; background:whitesmoke" |False<br />
|P8<br />
|style="color:silver; background:whitesmoke" |None<br />
|style="color:silver; background:whitesmoke" |None<br />
|-<br />
|align="left" |verbOps$05<br />
|$05<br />
|SetXY<br />
|style="color:silver; background:whitesmoke" |False<br />
|P16<br />
|P16<br />
|style="color:silver; background:whitesmoke" |None<br />
|-<br />
|align="left" |verbOps$06<br />
|$06<br />
|On<br />
|style="color:silver; background:whitesmoke" |False<br />
|style="color:silver; background:whitesmoke" |None<br />
|style="color:silver; background:whitesmoke" |None<br />
|style="color:silver; background:whitesmoke" |None<br />
|-<br />
|align="left" |verbOps$07<br />
|$07<br />
|Off<br />
|style="color:silver; background:whitesmoke" |False<br />
|style="color:silver; background:whitesmoke" |None<br />
|style="color:silver; background:whitesmoke" |None<br />
|style="color:silver; background:whitesmoke" |None<br />
|-<br />
|align="left" |verbOps$08<br />
|$08<br />
|Delete<br />
|style="color:silver; background:whitesmoke" |False<br />
|style="color:silver; background:whitesmoke" |None<br />
|style="color:silver; background:whitesmoke" |None<br />
|style="color:silver; background:whitesmoke" |None<br />
|-<br />
|align="left" |verbOps$09<br />
|$09<br />
|New<br />
|style="color:silver; background:whitesmoke" |False<br />
|style="color:silver; background:whitesmoke" |None<br />
|style="color:silver; background:whitesmoke" |None<br />
|style="color:silver; background:whitesmoke" |None<br />
|-<br />
|align="left" |verbOps$10<br />
|$10<br />
|DimColor<br />
|style="color:silver; background:whitesmoke" |False<br />
|P8<br />
|style="color:silver; background:whitesmoke" |None<br />
|style="color:silver; background:whitesmoke" |None<br />
|-<br />
|align="left" |verbOps$11<br />
|$11<br />
|Dim<br />
|style="color:silver; background:whitesmoke" |False<br />
|style="color:silver; background:whitesmoke" |None<br />
|style="color:silver; background:whitesmoke" |None<br />
|style="color:silver; background:whitesmoke" |None<br />
|-<br />
|align="left" |verbOps$12<br />
|$12<br />
|Key<br />
|style="color:silver; background:whitesmoke" |False<br />
|P8<br />
|style="color:silver; background:whitesmoke" |None<br />
|style="color:silver; background:whitesmoke" |None<br />
|-<br />
|align="left" |verbOps$13<br />
|$13<br />
|Center<br />
|style="color:silver; background:whitesmoke" |False<br />
|style="color:silver; background:whitesmoke" |None<br />
|style="color:silver; background:whitesmoke" |None<br />
|style="color:silver; background:whitesmoke" |None<br />
|-<br />
|align="left" |verbOps$14<br />
|$14<br />
|SetToString<br />
|style="color:silver; background:whitesmoke" |False<br />
|P16<br />
|style="color:silver; background:whitesmoke" |None<br />
|style="color:silver; background:whitesmoke" |None<br />
|-<br />
|align="left" |verbOps$16<br />
|$16<br />
|SetToObject<br />
|style="color:silver; background:whitesmoke" |False<br />
|P16<br />
|P8<br />
|style="color:silver; background:whitesmoke" |None<br />
|-<br />
|align="left" |verbOps$17<br />
|$17<br />
|BackColor<br />
|style="color:silver; background:whitesmoke" |False<br />
|P8<br />
|style="color:silver; background:whitesmoke" |None<br />
|style="color:silver; background:whitesmoke" |None<br />
|-<br />
|align="left" |wait<br />
|$AE<br />
|N/A<br />
|style="color:silver; background:whitesmoke" |False<br />
|SO<br />
|style="color:silver; background:whitesmoke" |None<br />
|style="color:silver; background:whitesmoke" |None<br />
|-<br />
|align="left" |wait$01<br />
|$01<br />
|WaitForActor<br />
|style="color:silver; background:whitesmoke" |False<br />
|P8<br />
|style="color:silver; background:whitesmoke" |None<br />
|style="color:silver; background:whitesmoke" |None<br />
|-<br />
|align="left" |wait$02<br />
|$02<br />
|WaitForMessage<br />
|style="color:silver; background:whitesmoke" |False<br />
|style="color:silver; background:whitesmoke" |None<br />
|style="color:silver; background:whitesmoke" |None<br />
|style="color:silver; background:whitesmoke" |None<br />
|-<br />
|align="left" |wait$03<br />
|$03<br />
|WaitForCamera<br />
|style="color:silver; background:whitesmoke" |False<br />
|style="color:silver; background:whitesmoke" |None<br />
|style="color:silver; background:whitesmoke" |None<br />
|style="color:silver; background:whitesmoke" |None<br />
|-<br />
|align="left" |wait$04<br />
|$04<br />
|WaitForSentence<br />
|style="color:silver; background:whitesmoke" |False<br />
|style="color:silver; background:whitesmoke" |None<br />
|style="color:silver; background:whitesmoke" |None<br />
|style="color:silver; background:whitesmoke" |None<br />
|-<br />
|align="left" |walkActorTo<br />
|$1E<br />
|style="color:silver; background:whitesmoke" |==<br />
|style="color:silver; background:whitesmoke" |False<br />
|P8<br />
|P16<br />
|P16<br />
|-<br />
|align="left" |walkActorToActor<br />
|$0D<br />
|style="color:silver; background:whitesmoke" |==<br />
|style="color:silver; background:whitesmoke" |False<br />
|P8<br />
|P8<br />
|B<br />
|-<br />
|align="left" |walkActorToObject<br />
|$36<br />
|style="color:silver; background:whitesmoke" |==<br />
|style="color:silver; background:whitesmoke" |False<br />
|P8<br />
|P16<br />
|style="color:silver; background:whitesmoke" |None<br />
|}</div>Jestar jokinhttps://wiki.scummvm.org/index.php?title=SCUMM/V5_opcodes&diff=10975SCUMM/V5 opcodes2009-04-16T12:49:21Z<p>Jestar jokin: /* ifClassOfIs ($1D) */ args is a standard arg list</p>
<hr />
<div>=SCUMM V5 opcodes=<br />
The following conventions are used in the encoding descriptions.<br />
<br />
{| border="1" cellpadding="2" width=100%<br />
|- style="background:whitesmoke"<br />
|Term||Description<br />
|-<br />
|opcode||The instruction's opcode, with the appropriate bits set according to the parameters.<br />
|-<br />
|aux||An aux opcode that stores parameter bits and no other information. (the base aux opcode seems to always be $01)<br />
|-<br />
|sub-opcode||An aux opcode that indicates a specific function to perform (e.g. the "wait" instruction has sub-opcodes to "wait for message", "wait for actor" etc), as well as storing parameter bits if necessary.<br />
|-<br />
|result||A result pointer. (A standard word pointer, always a LE word.)<br />
|-<br />
|var||A var pointer. Same as above, but is not written to. Because this is always a var, the opcode is not affected like with normal parameter/pointers.<br />
|-<br />
|value[8]||An 8-bit constant (a byte).<br />
|-<br />
|value[16]||A 16-bit constant (a word LE).<br />
|-<br />
|value[p8]||An 8-bit parameter. This may be encoded as a word LE if it's a pointer, or a byte if it's a constant.<br />
|-<br />
|value[p16]||A 16-bit parameter. This is always encoded as a word LE, and may be a pointer or constant.<br />
|-<br />
|value[v16]||A variable number of word LE parameters. These are encoded as a sequence of aux[8] param[p16]; param; aux contains the parameter bit to describe param (and is always $01, ignoring the parameter bits). A byte of $FF terminates the sequence. (actually always shown as "value[v16]...")<br />
|-<br />
|value[o]||The offset word for parameter value. This is only encoded if needed, but always at the position indicated. If not specified, the offset word occurs immediately after the parameter.<br />
|-<br />
|value[c]||An ASCII character. Because some instructions use null-terminated strings and some use $FF, the exact format of a string is described in the instruction. Almost always appears as "value[c]..."<br />
|-<br />
|term...||One or more terms.<br />
|}<br />
<br />
Of course, due to the non-orthogonality of the opcodes, there are lots of exceptions.<br />
<br />
<br />
==actorFollowCamera ($52)==<br />
<br />
===Encoding===<br />
opcode actor[p8]<br />
<br />
===Operation===<br />
Sets the camera to follow the given actor?<br />
<br />
<br />
==actorFromPos ($15)==<br />
<br />
===Encoding===<br />
opcode result x[p16] y[p16]<br />
<br />
===Operation===<br />
Returns the actor located at the given co-ordinates.<br />
<br />
<br />
==actorOps ($13)==<br />
parameters depend on auxiliary opcode; terminated by $FF<br />
<br />
===Encoding===<br />
opcode actor[p8] sub-opcode... $FF<br />
<br />
sub-opcodes:<br />
$00 arg1[p8]<br />
$01 costume[p8]<br />
$02 xspeed[p8] yspeed[p8]<br />
$03 sound[p8]<br />
$04 walkframe[p8]<br />
$05 starttalk[p8] endtalk[p8]<br />
$06 standframe[p8]<br />
$07 arg1[p8] arg2[p8] arg3[p8]<br />
$08<br />
$09 elevation[p16]<br />
$0A<br />
$0B index[p8] value[p8]<br />
$0C colour[p8]<br />
$0D name[c]... $00<br />
$0E initframe[p8]<br />
$10 width[p8]<br />
$11 xscale[p8] yscale[p8]<br />
$12<br />
$13 zplane[p8]<br />
$14<br />
$15 animspeed[p8]<br />
$16 mode[p8]<br />
$17 shadow[p8]<br />
<br />
===Operation===<br />
Miscellaneous actions on actors.<br />
<br />
{| border="1" cellpadding="2" width=100%<br />
|- style="background:whitesmoke"<br />
|Opcode||Meaning||Description<br />
|-<br />
|$00||dummy||A dummy case, does nothing (in ScummVM).<br />
|-<br />
|$01||SO_COSTUME||Sets the actor's costume.<br />
|-<br />
|$02||SO_STEP_DIST||Sets the actor's walking speed for x and y.<br />
|-<br />
|$03||SO_SOUND||Associates a sound with the actor (footsteps?)<br />
|-<br />
|$04||SO_WALK_ANIMATION||Sets the current frame of the walking animation.<br />
|-<br />
|$05||SO_TALK_ANIMATION||Sets the start and stop frames of the talking animation.<br />
|-<br />
|$06||SO_STAND_ANIMATION||Sets the current frame of the standing animation.<br />
|-<br />
|$07||SO_ANIMATION||Unknown; seems to be unused in ScummVM.<br />
|-<br />
|$08||SO_DEFAULT||Initializes actor.<br />
|-<br />
|$09||SO_ELEVATION||Sets the actor's elevation to the given value.<br />
|-<br />
|$0A||SO_ANIMATION_DEFAULT||Initializes the actor's animation frames.<br>Init frame = 1<br>Walk frame = 2<br>Stand frame = 3<br>Talk start frame = 4<br>Talk stop frame = 5<br />
|-<br />
|$0B||SO_PALETTE||Sets the colour at the given index to a new value (another entry in the colour lookup table/CLUT). Index must be between 0 and 31 (the number of colours in a costume).<br />
|-<br />
|$0C||SO_TALK_COLOR||Sets the actor's talk colour.<br />
|-<br />
|$0D||SO_ACTOR_NAME||Sets the actor's name to the given null-terminated string.<br />
|-<br />
|$0E||SO_INIT_ANIMATION||Sets the current frame of the initial animation.<br />
|-<br />
|$10||SO_ACTOR_WIDTH||Sets the actor's width.<br />
|-<br />
|$11||SO_ACTOR_SCALE||Sets the actor's X and Y scales.<br />
|-<br />
|$12||SO_NEVER_ZCLIP||Turns off all Z-clipping for the actor.<br />
|-<br />
|$13||SO_ALWAYS_ZCLIP||Forces the actor's Z-clipping for the given Z-plane?<br />
|-<br />
|$14||SO_IGNORE_BOXES||Ignores boxes, turns off Z-clipping, and puts actor somewhere if the actor is in the current room?<br />
|-<br />
|$15||SO_FOLLOW_BOXES||Follows boxes, turns off Z-clipping, and puts actor somewhere if the actor is in the current room?<br />
|-<br />
|$16||SO_ANIMATION_SPEED||Sets the animatino speed<br />
|-<br />
|$17||SO_SHADOW||Sets the shadow mode.<br />
|}<br />
<br />
===Variants===<br />
In SCUMM V4, sub-opcode $11 (SO_ACTOR_SCALE) only takes one parameter, so X and Y scaling is done at a 1:1 ratio.<br />
<br />
<br />
==actorSetClass ($5D)==<br />
<br />
===Encoding===<br />
opcode object[p16] classes[v16]...<br />
<br />
===Operation===<br />
Makes object inherit from all of the given classes. A class of "0" will clear all of the object's existing class data.<br />
<br />
<br />
==add ($5A)==<br />
<br />
===Encoding===<br />
opcode result value[p16]<br />
<br />
===Operation===<br />
result := result + value<br />
<br />
The variable pointed to by result is read, value is added to it, and the result written back.<br />
<br />
<br />
==and ($17)==<br />
one parameter, uses result<br />
<br />
===Encoding===<br />
opcode result value[p16]<br />
<br />
===Operation===<br />
result := result and value<br />
<br />
The variable pointed to by result is read, logically ANDed with value, and the result written back.<br />
<br />
<br />
==animateActor ($11)==<br />
<br />
===Encoding===<br />
opcode actor[p8] anim[p8]<br />
<br />
===Operation===<br />
Starts the given animation for the given actor.<br />
<br />
<br />
==breakHere ($80)==<br />
no parameters<br />
<br />
===Encoding===<br />
opcode<br />
<br />
===Operation===<br />
Deschedules the currently running thread. Execution continues at the next instruction when the thread's next timeslot comes around.<br />
<br />
<br />
==chainScript ($42)==<br />
one parameter plus varargs<br />
<br />
===Encoding===<br />
opcode script[p8] args[v16]...<br />
<br />
===Operation===<br />
Replaces the currently running script with another one. The current script is terminated immediately and the new script (determined by the given script ID), is executed in the same thread. The new script has its local variables initialised to the list args. Uninitialised variables have undefined values.<br />
<br />
<br />
==cursorCommand ($2C)==<br />
parameters depend on auxiliary opcode<br />
<br />
===Encoding===<br />
opcode sub-opcode<br />
<br />
sub-opcode can be any of the following:<br />
$01<br />
... $01 through $08 take the same arguments ...<br />
$08<br />
$0A cursornum[p8] charletter[p8]<br />
$0B index[p8] x[p8] y[p8]<br />
$0C cursor[p8]<br />
$0D charset[p8]<br />
$0E colours[v16]...<br />
<br />
===Operation===<br />
Miscellaneous actions on cursors & charsets.<br />
<br />
{| border="1" cellpadding="2" width=100%<br />
|- style="background:whitesmoke"<br />
|Opcode||Meaning||Description<br />
|-<br />
|$01||SO_CURSOR_ON||Turns the cursor on.<br />
|-<br />
|$02||SO_CURSOR_OFF||Turns the cursor off.<br />
|-<br />
|$03||SO_USERPUT_ON||Enables user input.<br />
|-<br />
|$04||SO_USERPUT_OFF||Disables user input.<br />
|-<br />
|$05||SO_CURSOR_SOFT_ON||Increments the cursor's state?<br />
|-<br />
|$06||SO_CURSOR_SOFT_OFF||Decrements the cursor's state?<br />
|-<br />
|$07||SO_USERPUT_SOFT_ON||Increments "user input" counter (when greater than 0, user input is enabled).<br />
|-<br />
|$08||SO_USERPUT_SOFT_OFF||Decrements "user input" counter (when 0 or less, user input is disabled).<br />
|-<br />
|$0A||SO_CURSOR_IMAGE||Changes the cursor image to a new one, based on image in a character set. Only used in Loom.<br />
|-<br />
|$0B||SO_CURSOR_HOTSPOT||Changes the hotspot of a cursor. Only used in Loom.<br />
|-<br />
|$0C||SO_CURSOR_SET||Changes the current cursor. Must be between 0 and 3 inclusive.<br />
|-<br />
|$0D||SO_CHARSET_SET||Initializes the given character set.<br />
|-<br />
|$0E||SO_CHARSET_COLORS||Initializes the character set data & colours to the given arguments? Must have 16 arguments?<br />
|}<br />
<br />
===Variants===<br />
In SCUMM V3, sub-opcode $0E performs a different function, to load/initialize a character set.<br />
<br />
opcode $0E arg1[p8] arg2[p8]<br />
<br />
<br />
==cutScene ($40)==<br />
<br />
===Encoding===<br />
opcode args[v16]...<br />
<br />
===Operation===<br />
??? If required, runs a script passing the given arguments. Cutscene data given by the first argument?<br />
<br />
<br />
==debug ($6B)==<br />
one parameter, no result<br />
<br />
===Encoding===<br />
opcode param[p16]<br />
<br />
===Operation===<br />
Passes the parameter to the interpreter's debugger. What this does is entirely platform-specific (and may do nothing).<br />
<br />
<br />
==decrement ($C6)==<br />
no parameters, uses result<br />
<br />
===Encoding===<br />
opcode result<br />
<br />
===Operation===<br />
result := result - 1<br />
<br />
Reads the variable pointed to by result, decrements it, and writes it back. <br />
<br />
<br />
==delay ($2E)==<br />
one constant parameter<br />
<br />
===Encoding===<br />
opcode param[24]<br />
<br />
===Operation===<br />
Suspends the current thread for the appropriate number of 1/60ths of a second. Yes, that really is a 24-bit LE constant.<br />
<br />
<br />
==delayVariable ($2B)==<br />
one constant parameter<br />
<br />
===Encoding===<br />
opcode var<br />
<br />
===Operation===<br />
var is dereferenced and the current thread suspended for that number of 1/60ths of a second.<br />
<br />
<br />
==divide ($5B)==<br />
one parameter, uses result<br />
<br />
===Encoding===<br />
opcode result value[p16]<br />
<br />
===Operation===<br />
result := result / value<br />
<br />
The variable pointed to by result is read, divided by value, and the result written back. If value is zero, the result is undefined (and the interpeter may halt with an error). <br />
<br />
<br />
==doSentence ($19)==<br />
<br />
===Encoding===<br />
opcode verb[p8] objectA[p16] objectB[p16]<br />
<br />
===Operation===<br />
Performs a verb sentence action, e.g. "Use monkey on hydrant". If verb is $FE, the current sentence script is stopped, status cleared etc.<br />
<br />
<br />
==drawBox ($3F)==<br />
two parameters, does not use result, supplementary opcode byte with three more subsequent parameters<br />
<br />
===Encoding===<br />
opcode left[p16] top[p16] auxopcode[8] right[p16] bottom[p16] colour[p8]<br />
<br />
===Operation===<br />
Draws a solid box on the backbuffer from (left, top)-(right, bottom) in the given colour.<br />
<br />
The only part of auxopcode that is relevant are the parameter bits. The rest of the opcode is ignored. <br />
<br />
<br />
==drawObject ($05)==<br />
<br />
===Encoding===<br />
opcode object[p16] sub-opcode<br />
<br />
sub-opcodes:<br />
$01 xpos[p16] ypos[p16]<br />
$02 state[p16]<br />
$1F<br />
<br />
===Operation===<br />
{| border="1" cellpadding="2" width=100%<br />
|- style="background:whitesmoke"<br />
|Opcode||Meaning||Description<br />
|-<br />
|$01||Draw At||Moves the given object to the given co-ordinates, and adds it to the drawing queue.<br />
|-<br />
|$02||Set State||Sets the state of the object, adds it to the drawing queue.<br />
|-<br />
|$1F||Draw||Does not change the object's position (or state?), still adds it to the drawing queue.<br />
|}<br />
<br />
===Variants===<br />
Small header games only support the parameters used with sub-opcode $01, e.g:<br />
opcode object[p16] xpos[p16] ypos[p16]<br />
<br />
<br />
==dummy ($A7)==<br />
<br />
===Encoding===<br />
opcode<br />
<br />
===Operation===<br />
V5 specific - The KIXX XL release of Monkey Island 2 (Amiga disk) used this opcode as a dummy, in order to remove copy protection and keep level selection.<br />
<br />
===Variants===<br />
In SCUMM V3 and V4, this opcode is used for the saveLoadVars instruction.<br />
<br />
<br />
==endCutScene ($C0)==<br />
<br />
===Encoding===<br />
opcode<br />
<br />
===Operation===<br />
Ends the cutscene, performing cleanup if necessary.<br />
<br />
<br />
==equalZero ($28)==<br />
jumps<br />
<br />
===Encoding===<br />
opcode var target[16]<br />
<br />
===Operation===<br />
unless (var == 0) goto target<br />
<br />
Target is a byte offset (measured from after this instruction), which will be added to the instruction pointer.<br />
<br />
<br />
==expression ($AC)==<br />
<br />
===Encoding===<br />
opcode result subopcode... $FF<br />
<br />
sub-opcodes:<br />
$01 value[p16]<br />
$02<br />
... $02 through $05 take the same arguments ...<br />
$05<br />
$06 nested-opcode<br />
<br />
===Operation===<br />
Expression mode operates on a stack. Values are pushed on, and operators are applied to the top two items on the stack.<br />
<br />
{| border="1" cellpadding="2" width=100%<br />
|- style="background:whitesmoke"<br />
|Opcode||Meaning||Description<br />
|-<br />
|$01||Value||Pushes a value onto the top of the stack.<br />
|-<br />
|$02||Add||stack[top - 1] + stack[top]<br />
|-<br />
|$03||Subtract||stack[top - 1] - stack[top]<br />
|-<br />
|$04||Multiply||stack[top - 1] * stack[top]<br />
|-<br />
|$05||Divide||stack[top - 1] / stack[top] (if stack[top] is 0 an error occurs)<br />
|-<br />
|$06||Nested Opcode||An entire instruction that returns a result, such as getActorScale. This is interpreted like a normal opcode, but the result is pushed onto the expression stack. (The opcode is passed the special "VAR_RESULT" parameter for "result")<br />
|}<br />
<br />
<br />
==faceActor ($09)==<br />
<br />
===Encoding===<br />
opcode actor[p8] object[p16]<br />
<br />
===Operation===<br />
Dereferences actor, tells actor to face object (presumably based on X/Y co-ordinates).<br />
<br />
<br />
==findInventory ($3D)==<br />
<br />
===Encoding===<br />
opcode result owner[p8] index[p8]<br />
<br />
===Operation===<br />
object := owner.inventory[index]<br />
Searches for all objects owned by owner (an actor or object), and returns the one at the given index (offset).<br />
<br />
<br />
==findObject ($35)==<br />
<br />
===Encoding===<br />
opcode result x[p8] y[p8]<br />
<br />
===Operation===<br />
Returns the first "touchable" local object at the given co-ordinates. Will not match on the bottom or right-hand edges of an object.<br />
<br />
<br />
==freezeScripts ($60)==<br />
<br />
===Encoding===<br />
opcode flag[p8]<br />
<br />
===Operation===<br />
Freezes all scripts (by setting the high bit on each script's status). If flag is >= $80, all freeze resistent scripts will also be frozen. If flag is 0, all scripts are unfrozen. Freezing effects are cumulative - i.e. if script A is frozen twice, and unfrozen once, it will still be frozen until it is unfrozen a second time. A script's frozen status is indicated by the high bit.<br />
<br />
<br />
==getActorCostume ($71)==<br />
<br />
===Encoding===<br />
opcode result actor[p8]<br />
<br />
===Operation===<br />
Returns the actor's current costume.<br />
<br />
<br />
==getActorElevation ($06)==<br />
<br />
===Encoding===<br />
opcode result actor[p8]<br />
<br />
===Operation===<br />
Returns the actor's current elevation.<br />
<br />
<br />
==getActorFacing ($63)==<br />
<br />
===Encoding===<br />
opcode result actor[p8]<br />
<br />
===Operation===<br />
Returns the current direction the actor is facing.<br />
<br />
<br />
==getActorMoving ($56)==<br />
<br />
===Encoding===<br />
opcode result actor[p8]<br />
<br />
===Operation===<br />
Returns the actor's moving status (0 or 1).<br />
<br />
<br />
==getActorRoom ($03)==<br />
<br />
===Encoding===<br />
opcode result actor[p8]<br />
<br />
===Operation===<br />
Returns the room the actor currently occupies?<br />
<br />
<br />
==getActorScale ($3B)==<br />
<br />
===Encoding===<br />
opcode result actor[p8]<br />
<br />
===Operation===<br />
Returns the actor's current scale.<br />
<br />
===Variants===<br />
In Indy3, this opcode is used for waitForActor.<br />
<br />
<br />
==getActorWalkBox ($7B)==<br />
<br />
===Encoding===<br />
opcode result actor[p8]<br />
<br />
===Operation===<br />
Returns the actor's walkbox.<br />
<br />
<br />
==getActorWidth ($6C)==<br />
<br />
===Encoding===<br />
opcode result actor[p8]<br />
<br />
===Operation===<br />
Returns the actor's width.<br />
<br />
<br />
==getActorX ($43)==<br />
<br />
===Encoding===<br />
opcode result actor[p16]<br />
<br />
===Operation===<br />
Returns the actor's current X co-ordinate.<br />
<br />
===Variants===<br />
In Indy3, actor is only one byte.<br />
opcode result actor[p8]<br />
<br />
<br />
==getActorY ($23)==<br />
<br />
===Encoding===<br />
opcode result actor[p16]<br />
<br />
===Operation===<br />
Returns the actor's current Y co-ordinate.<br />
<br />
===Variants===<br />
In Indy3, actor is only one byte.<br />
opcode result actor[p8]<br />
<br />
<br />
==getAnimCounter ($22)==<br />
<br />
===Encoding===<br />
opcode result actor[p8]<br />
<br />
===Operation===<br />
Returns the actor's animation counter.<br />
<br />
===Variants===<br />
This opcode is used for saveLoadGame in SCUMM V3.<br />
<br />
<br />
==getClosestObjActor ($66)==<br />
<br />
===Encoding===<br />
opcode result actor[p16]<br />
<br />
===Operation===<br />
Returns the object closest to the actor. Items that are more than 255 units (pixels in newer games, characters in older games) away from the actor will not be detected.<br />
<br />
<br />
==getDist ($34)==<br />
<br />
===Encoding===<br />
opcode result objA[p16] objB[p16]<br />
<br />
===Operation===<br />
Returns the distance between two actors/objects (objA and objB).<br />
<br />
<br />
==getInventoryCount ($31)==<br />
<br />
===Encoding===<br />
opcode result actor[p8]<br />
<br />
===Operation===<br />
Returns the number of items in an actor's inventory?<br />
<br />
<br />
==getObjectOwner ($10)==<br />
<br />
===Encoding===<br />
opcode result object[p16]<br />
<br />
===Operation===<br />
Returns the owner of an object.<br />
<br />
<br />
==getObjectState ($0F)==<br />
<br />
===Encoding===<br />
opcode result object[p16]<br />
<br />
===Operation===<br />
Returns the state of the object.<br />
<br />
===Variants===<br />
In small header games, the encoding becomes:<br />
opcode object[p16] state[p8] target[16]<br />
operation becomes<br />
unless (getState(object) == state) goto target<br />
<br />
<br />
==getRandomNumber ($16)==<br />
<br />
===Encoding===<br />
opcode result seed[p8]<br />
<br />
===Operation===<br />
Returns a new random number based on the given seed.<br />
<br />
<br />
==getScriptRunning ($68)==<br />
<br />
===Encoding===<br />
opcode result script[p8]<br />
<br />
===Operation===<br />
Returns 1 if the given script is running, 0 if it's not.<br />
<br />
<br />
==getStringWidth ($67)==<br />
<br />
===Encoding===<br />
opcode result strptr[p8]<br />
<br />
===Operation===<br />
Gets the length of the string pointed to by strptr (either a variable or direct byte), stores the returned value in result.<br />
<br />
<br />
==getVerbEntryPoint ($0B)==<br />
<br />
===Encoding===<br />
opcode result object[p16] verb[p16]<br />
<br />
===Operation===<br />
Returns the entry point for the response code/script for when the given verb is applied to the given object? i.e. gets the start of the script to run for the specific user interaction.<br />
<br />
<br />
==ifClassOfIs ($1D)==<br />
jumps<br />
<br />
===Encoding===<br />
opcode value[p16] args[v16]... target[16]<br />
<br />
===Operation===<br />
unless (value.class is one of [args.class]) goto target<br />
<br />
Compares the value's class with all classes given in args.<br />
<br />
Target is a byte offset (measured from after this instruction), which will be added to the instruction pointer.<br />
<br />
==ifNotState ($2F)==<br />
<br />
===Encoding===<br />
opcode object[p16] state[p8] target[16]<br />
<br />
===Operation===<br />
unless (stateOf(object) != state) goto target<br />
<br />
<br />
==ifState ($4F)==<br />
<br />
===Encoding===<br />
opcode object[p16] state[p8] target[16]<br />
<br />
===Operation===<br />
unless (stateOf(object) == state) goto target<br />
<br />
<br />
==increment ($46)==<br />
no parameters, uses result<br />
<br />
===Encoding===<br />
opcode result<br />
<br />
===Operation===<br />
result := result + 1<br />
<br />
Reads the variable pointed to by result, increments it, and writes it back. <br />
<br />
<br />
==isActorInBox ($1F)==<br />
<br />
===Encoding===<br />
opcode actor[p8] box[p8] target[16]<br />
<br />
===Operation===<br />
Unless the actor's co-ordinates are within the bounds of the given box, jump to target.<br />
<br />
Target is a byte offset (measured from after this instruction), which will be added to the instruction pointer.<br />
<br />
<br />
==isEqual ($48)==<br />
<br />
===Encoding===<br />
opcode var value[p16] target[16]<br />
<br />
===Operation===<br />
unless (value == var) goto target<br />
<br />
Target is a byte offset (measured from after this instruction), which will be added to the instruction pointer.<br />
<br />
<br />
==isGreater ($78)==<br />
<br />
===Encoding===<br />
opcode var value[p16] target[16]<br />
<br />
===Operation===<br />
unless (value > var) goto target<br />
<br />
Target is a byte offset (measured from after this instruction), which will be added to the instruction pointer.<br />
<br />
<br />
==isGreaterEqual ($04)==<br />
<br />
===Encoding===<br />
opcode var value[p16] target[16]<br />
<br />
===Operation===<br />
unless (value >= var) goto target<br />
<br />
Target is a byte offset (measured from after this instruction), which will be added to the instruction pointer.<br />
<br />
<br />
==isLess ($44)==<br />
<br />
===Encoding===<br />
opcode var value[p16] target[16]<br />
<br />
===Operation===<br />
unless (value < var) goto target<br />
<br />
Target is a byte offset (measured from after this instruction), which will be added to the instruction pointer.<br />
<br />
<br />
==isNotEqual ($08)==<br />
<br />
===Encoding===<br />
opcode var value[p16] target[16]<br />
<br />
===Operation===<br />
unless (value != var) goto target<br />
<br />
Target is a byte offset (measured from after this instruction), which will be added to the instruction pointer.<br />
<br />
<br />
==isSoundRunning ($7C)==<br />
<br />
===Encoding===<br />
opcode result sound[p8]<br />
<br />
===Operation===<br />
Returns 1 if sound is running, returns 0 if sound is not running or if the given sound is 0.<br />
<br />
<br />
==jumpRelative ($18)==<br />
jumps<br />
<br />
===Encoding===<br />
opcode target[16]<br />
<br />
===Operation===<br />
PC := PC + target<br />
<br />
The inline constant target is read as a signed word and added to the program counter after the instruction has been read. Therefore, if target is zero, the instruction will do nothing; if target is -3, an infinite loop will result. <br />
<br />
<br />
==lessOrEqual ($38)==<br />
jumps<br />
<br />
===Encoding===<br />
opcode var value[p16] target[16]<br />
<br />
===Operation===<br />
unless (value <= var) goto target<br />
<br />
Target is a byte offset (measured from after this instruction), which will be added to the instruction pointer.<br />
<br />
<br />
==lights ($70)==<br />
<br />
===Encoding===<br />
opcode arg1[p8] arg2[8] arg3[8]<br />
<br />
===Operation===<br />
If arg3 is 0, the "current lights" variable is set to arg1.<br />
If arg3 is 1, the size of the "flashlight" light is determined by arg1 and arg2, for width and height in stripes (which are equivalent to 8 pixels each; see [[SCUMM/Technical Reference/Image resources]]).<br />
<br />
<br />
==loadRoom ($72)==<br />
<br />
===Encoding===<br />
opcode room[p8]<br />
<br />
===Operation===<br />
Loads the given room into memory.<br />
<br />
<br />
==loadRoomWithEgo ($24)==<br />
<br />
===Encoding===<br />
opcode object[p16] room[p8] x[16] y[16]<br />
<br />
===Operation===<br />
Places the Ego actor in room at object's position. If x is not -1, Ego will start moving towards the given x and y co-ordinates. If object is not in the given room an error will occur.<br />
(I think...)<br />
<br />
<br />
==matrixOp ($30)==<br />
<br />
===Encoding===<br />
opcode sub-opcode<br />
<br />
sub-opcodes:<br />
$01 box[p8] val[p8]<br />
$02 box[p8] val[p8]<br />
$03 box[p8] val[p8]<br />
$04<br />
<br />
===Operation===<br />
This instruction manipulates boxes.<br />
<br />
{| border="1" cellpadding="2" width=100%<br />
|- style="background:whitesmoke"<br />
|Opcode||Meaning||Description<br />
|-<br />
|$01||setBoxFlags||Sets the box's flags to the given value.<br />
|-<br />
|$02||setBoxScale||Sets the box's scale.<br />
|-<br />
|$03||setBoxScale||Sets the box's scale to ((val - 1) OR $8000).<br />
|-<br />
|$04||createBoxMatrix||Initializes the matrix of boxes, by determining the distances and shortest paths between boxes.<br />
|}<br />
<br />
===Variants===<br />
SCUMM V3 only has the one instruction, which behaves like setBoxFlags:<br />
opcode box[p8] val[8]<br />
<br />
<br />
==move ($1A)==<br />
<br />
===Encoding===<br />
opcode result value[p16]<br />
<br />
===Operation===<br />
result := value<br />
<br />
Value is moved into result.<br />
<br />
<br />
==multiply ($1B)==<br />
<br />
===Encoding===<br />
opcode result value[p16]<br />
<br />
===Operation===<br />
result := result * value<br />
<br />
The variable pointed to by result is read, multiplied by value, and written back.<br />
<br />
<br />
==notEqualZero ($A8)==<br />
<br />
===Encoding===<br />
opcode var target[16]<br />
<br />
===Operation===<br />
unless (var != 0) goto target<br />
<br />
Target is a byte offset (measured from after this instruction), which will be added to the instruction pointer.<br />
<br />
<br />
==oldRoomEffect ($5C)==<br />
<br />
===Encoding===<br />
opcode sub-opcode<br />
<br />
sub-opcodes:<br />
$03 effect[p16]<br />
<br />
===Operation===<br />
Performs like sub-opcode SO_ROOM_FADE of the roomOps instruction (fade in if effect != 0, otherwise fade out).<br />
<br />
This information may not be correct; descumm says if the sub-opcode is 3, to "set" the effect, but if the sub-opcode is anything else to fade in with the given effect.<br />
<br />
===Variants===<br />
FM-Towns SCUMM V3 performs a different effect, not fully implemented in ScummVM. At the moment ScummVM just forces a redraw of the screen background.<br />
<br />
<br />
==or ($57)==<br />
one parameter, uses result<br />
<br />
===Encoding===<br />
opcode result value[p16]<br />
<br />
===Operation===<br />
result := result or value<br />
<br />
The variable pointed to by result is read, logically ORed with value, and the result written back.<br />
<br />
<br />
==override ($58)==<br />
<br />
===Encoding===<br />
opcode sub-opcode<br />
<br />
sub-opcodes:<br />
$00<br />
$01 $18 target[16]<br />
<br />
===Operation===<br />
If the sub-opcode is 0, marks the end of an override section.<br><br />
If the sub-opcode is not 0, marks the beginning of an override section. The instruction is immediately followed by a "jumpRelative" instruction.<br.<br />
Overrides are used by cutscenes; if a cutscene is skipped (if the user presses the ESC key), the script will jump by the given target (offset from this instruction).<br />
<br />
<br />
==panCameraTo ($12)==<br />
<br />
===Encoding===<br />
opcode x[p16]<br />
<br />
===Operation===<br />
Starts the camera panning to the given x co-ordinate.<br />
<br />
<br />
==pickupObject ($25)==<br />
<br />
===Encoding===<br />
opcode object[p16] room[p8]<br />
<br />
===Operation===<br />
Adds the given object (located in the given room) to the Ego actor's inventory.<br />
<br />
===Variants===<br />
In SCUMM V3 and V4, this opcode is used for drawObject.<br />
<br />
<br />
==pickupObjectOld ($50)==<br />
<br />
===Encoding===<br />
opcode object[p16]<br />
<br />
===Operation===<br />
Adds the given object (located in the given room) to the Ego actor's inventory. If object < 1, an error is raised. If the object is not found or the object is already in the inventory, this function ends gracefully.<br />
<br />
<br />
==print ($14)==<br />
<br />
===Encoding===<br />
opcode actor[p8] sub-opcode<br />
<br />
sub-opcodes<br />
$00 xpos[p16] ypos[p16]<br />
$01 colour[p8]<br />
$02 right[p16]<br />
$03 width[p16] height[p16]<br />
$04<br />
$06<br />
$07<br />
$08 offset[p16] delay[p16]<br />
$0F string[c]... $FF<br />
<br />
===Operation===<br />
Sets text properties and displays dialogue.<br />
<br />
{| border="1" cellpadding="2" width=100%<br />
|- style="background:whitesmoke"<br />
|Opcode||Meaning||Description<br />
|-<br />
|$00||SO_AT||Sets the position of the text that follows.<br />
|-<br />
|$01||SO_COLOR||Sets the colour of the text.<br />
|-<br />
|$02||SO_CLIPPED||Clips the text's right-hand side (for wrapping?).<br />
|-<br />
|$03||SO_ERASE||Erases characters (not used in ScummVM).<br />
|-<br />
|$04||SO_CENTER||Centres the text.<br />
|-<br />
|$06||SO_LEFT||Left-aligns the text.<br />
|-<br />
|$07||SO_OVERHEAD||Overhead-aligns the text.<br />
|-<br />
|$0F||SO_TEXTSTRING||Prints the text string that follows. Terminated by $FF.<br />
|}<br />
<br />
===Variants===<br />
In SCUMM V3, text function $06 sets the height of the text:<br />
$06 height[p16]<br />
<br />
In Loom CD (SCUMM V4), there is an additional text function $08 (SO_SAY_VOICE), which plays a portion of the CD audio track.<br />
$08 offset[p16] delay[p16]<br />
<br />
<br />
==printEgo ($D8)==<br />
<br />
===Encoding===<br />
opcode sub-opcode<br />
<br />
===Operation===<br />
Exactly the same as print, except the actor is implicitly Ego. See the entry for "print" for further explanation.<br />
<br />
<br />
==pseudoRoom ($CC)==<br />
<br />
===Encoding===<br />
opcode val[8] res[8]... $00<br />
<br />
===Operation===<br />
forall (res) {<br />
if (res >= $80) {<br />
_resourceMapper[res & $7F] := val<br />
}<br />
}<br />
<br />
What does this actually do? We may never know.<br />
<br />
It looks like res values always have the high bit set, e.g. 0x01 becomes 0x81.<br />
<br />
==putActor ($01)==<br />
<br />
===Encoding===<br />
opcode actor[p8] x[p16] y[p16]<br />
<br />
===Operation===<br />
Puts the actor at the given co-ordinates.<br />
<br />
<br />
==putActorAtObject ($0E)==<br />
<br />
===Encoding===<br />
opcode actor[p8] object[p16]<br />
<br />
===Operation===<br />
Puts the actor at the given object's position. If the object can not be found, a default position is returned (the centre of the screen in ScummVM).<br />
<br />
<br />
==putActorInRoom ($2D)==<br />
<br />
===Encoding===<br />
opcode actor[p8] room[p8]<br />
<br />
===Operation===<br />
Puts the actor in the given room.<br />
<br />
<br />
==resourceRoutines ($0C)==<br />
<br />
===Encoding===<br />
opcode sub-opcode<br />
<br />
sub-opcodes:<br />
$01 resID[p8]<br />
... $01 through $13 take the same arguments ...<br />
$13 resID[p8]<br />
$14 room[p8] object[p16]<br />
<br />
===Operation===<br />
resID is unique only within the resource type (e.g. script 11 will not conflict with sound 11).<br />
<br />
{| border="1" cellpadding="2" width=100%<br />
|- style="background:whitesmoke"<br />
|Opcode||Meaning||Description<br />
|-<br />
|$01||SO_LOAD_SCRIPT||Loads the given script into memory.<br />
|-<br />
|$02||SO_LOAD_SOUND||Loads the given sound into memory.<br />
|-<br />
|$03||SO_LOAD_COSTUME||Loads the given costume into memory.<br />
|-<br />
|$04||SO_LOAD_ROOM||Loads the given room into memory.<br />
|-<br />
|$05||SO_NUKE_SCRIPT||Obliterates the given script from memory.<br />
|-<br />
|$06||SO_NUKE_SOUND||Obliterates the given sound from memory.<br />
|-<br />
|$07||SO_NUKE_COSTUME||Obliterates the given costume from memory.<br />
|-<br />
|$08||SO_NUKE_ROOM||Obliterates the given room from memory.<br />
|-<br />
|$09||SO_LOCK_SCRIPT||Locks the given script.<br />
|-<br />
|$0A||SO_LOCK_SOUND||Locks the given sound.<br />
|-<br />
|$0B||SO_LOCK_COSTUME||Locks the given costume.<br />
|-<br />
|$0C||SO_LOCK_ROOM||Locks the given room.<br />
|-<br />
|$0D||SO_UNLOCK_SCRIPT||Unlocks the given script.<br />
|-<br />
|$0E||SO_UNLOCK_SOUND||Unlocks the given sound.<br />
|-<br />
|$0F||SO_UNLOCK_COSTUME||Unlocks the given costume.<br />
|-<br />
|$10||SO_UNLOCK_ROOM||Unlocks the given room.<br />
|-<br />
|$11||SO_CLEAR_HEAP||Clears the heap.<br />
|-<br />
|$12||SO_LOAD_CHARSET||Loads the given character set into memory.<br />
|-<br />
|$13||SO_NUKE_CHARSET||Obliterates the given character set from memory.<br />
|-<br />
|$14||SO_LOAD_OBJECT||Loads the given object from the given room resource.<br />
|}<br />
<br />
===Variants===<br />
FM-Towns games add the following sub-opcodes (these are not confirmed nor implemented in ScummVM):<br />
{| border="1" cellpadding="2" width=100%<br />
|- style="background:whitesmoke"<br />
|Opcode||Meaning||Description<br />
|-<br />
|$20||Unknown||Does nothing, not used in-game.<br />
|-<br />
|$21||Unknown||Does nothing, not used in-game.<br />
|-<br />
|$23||CD Volume||Possibly changes the volume of CD tracks (Loom CD). Takes 1 byte.<br />
|-<br />
|$24||Sound Volume||Sets the loudness of a sound resource. Used in Indy3 and Zak. Takes 2 bytes (left/right volumes?).<br />
|-<br />
|$25||Sound Pitch||Sets the pitch of a sound resource. Used in Indy3 and Zak. Takes 1 byte (pitch = "foo" - "center" semitones. Center is at $32 in the sound resource.)<br />
|}<br />
<br />
<br />
==roomOps ($33)==<br />
<br />
===Encoding===<br />
opcode sub-opcode<br />
<br />
sub-opcodes:<br />
$01 minX[p16] maxX[p16]<br />
$03 b[p16] h[p16]<br />
$04 red[p16] green[p16] blue[p16] aux index[p8]<br />
$05<br />
$06<br />
$07 scale1[p8] y1[p8] aux scale2[p8] y2[p8] aux slot[p8]<br />
$08 scale[p8] startcolour[p8] endcolour[p8]<br />
$09 loadflag[p8] loadslot[p8]<br />
$0A effect[p16]<br />
$0B redscale[p16] greenscale[p16] bluescale[p16] aux startcolour[p8] endcolour[p8]<br />
$0C redscale[p16] greenscale[p16] bluescale[p16] aux startcolour[p8] endcolour[p8]<br />
$0D resID[p8] filename[c]... $00<br />
$0E resID[p8] filename[c]... $00<br />
$0F resID[p8] aux start[p8] end[p8] aux time[p8]<br />
$10 colindex[p8] delay[p8]<br />
<br />
===Operation===<br />
{| border="1" cellpadding="2" width=100%<br />
|- style="background:whitesmoke"<br />
|Opcode||Meaning||Description<br />
|-<br />
|$01||SO_ROOM_SCROLL||Clamps the given arguments so scrolling does not extend past the width of the room or screen.<br />
|-<br />
|$03||SO_ROOM_SCREEN||Initialises a screen.<br />
|-<br />
|$04||SO_ROOM_PALETTE||Adjusts the room's palette.<br />
|-<br />
|$05||SO_ROOM_SHAKE_ON||Starts the room shaking.<br />
|-<br />
|$06||SO_ROOM_SHAKE_OFF||Ends the room shaking.<br />
|-<br />
|$07||SO_ROOM_SCALE||Sets the room's y scales? (slot is 1 greater than actual slot?)<br />
|-<br />
|$08||SO_ROOM_INTENSITY||Lightens/darkens the room's palette.<br />
|-<br />
|$09||SO_ROOM_SAVEGAME||Saves temporary state of the room/game?<br />
|-<br />
|$0A||SO_ROOM_FADE||If effect is 0, fades in the room. Otherwise, fades out with the given effect (taken from the high byte of effect).<br>1 = iris effect<br>2 = box wipe (upper-left to bottom-right)<br>3 = box wipe (upper-right to bottem-left)<br>4 = inverse box wipe.<br />
|-<br />
|$0B||SO_RGB_ROOM_INTENSITY||Lightens/darkens the room's palette, with different scales for red, green and blue.<br />
|-<br />
|$0C||SO_ROOM_SHADOW||Lightens/darkens the shadow palette, with different scales for red, green, and blue.<br />
|-<br />
|$0D||SO_SAVE_STRING||Saves a string resource to the given file?<br />
|-<br />
|$0E||SO_LOAD_STRING||Loads a string resource from a given file?<br />
|-<br />
|$0F||SO_ROOM_TRANSFORM||Manipulates palettes, strings?<br />
|-<br />
|$10||SO_CYCLE_SPEED||Starts colour cycling with delay? colIndex is between 0 and 16<br />
|}<br />
<br />
===Variants===<br />
SCUMM V3 (non-PC Engine) encodes the arguments before the sub-opcode:<br />
opcode arg1[p16] arg2[p16] sub-opcode<br />
<br />
Small header games include an extra sub-opcode, $02 (SO_ROOM_COLOR), which adjusts the room's palette:<br />
opcode $02 colour[p16] index[p16]<br />
... or for V3 games ...<br />
opcode colour[p16] index[p16] $02<br />
<br />
In small header games, sub-opcode $04 (SO_ROOM_PALETTE) affects the shadow palette, and only accepts two arguments, a "room colour slot" (palette entry? between 0 and 256) and an index:<br />
opcode $04 colour[p16] index[p16]<br />
... or for V3 games ...<br />
opcode colour[p16] index[p16] $04<br />
<br />
In FM-Towns games, sub-opcode $0A performs a different function and has its own sub-opcodes (some unknown and all not yet implemented in ScummVM):<br />
opcode $0A sub-opcode<br />
<br />
{| border="1" cellpadding="2" width=100%<br />
|- style="background:whitesmoke"<br />
|Opcode||Meaning||Description<br />
|-<br />
|$08||||compose kMainVirtScreen over a screen buffer<br />
|-<br />
|$09||||call 0x110:0x20 _ax=0x601 _edx=2<br />
|-<br />
|$0A||||call 0x110:0x20 _ax=0x601 _edx=3<br />
|-<br />
|$0B||||clear screen 0x1C:0x45000 sizeof(640 * 320)<br />
|-<br />
|$0C||||call 0x110:0x20 _ax=0x601 _edx=0<br />
|-<br />
|$0D||||call 0x110:0x20 _ax=0x601 _edx=1<br />
|-<br />
|$10||||enable clearing of a screen buffer in drawBitmap()<br />
|-<br />
|$11||||disable clearing of a screen buffer in drawBitmap()<br />
|-<br />
|$12||||clear a screen buffer<br />
|-<br />
|$13||||enable palette operations (palManipulate(), cyclePalette() etc.)<br />
|-<br />
|$14||||disable palette operations<br />
|-<br />
|$15||||disable clearing of screen 0x1C:0x5000 sizeof(640 * 320) in initScreens()<br />
|-<br />
|$16||||enable clearing of screen 0x1C:0x5000 sizeof(640 * 320) in initScreens()<br />
|-<br />
|$1E||||Unknown<br />
|}<br />
<br />
==saveRestoreVerbs ($AB)==<br />
<br />
===Encoding=== <br />
opcode sub-opcode<br />
<br />
sub-opcodes: <br />
$01 start[p8] end[p8] mode[p8]<br />
$02 start[p8] end[p8] mode[p8]<br />
$03 start[p8] end[p8] mode[p8]<br />
<br />
===Operation===<br />
{| border="1" cellpadding="2" width=100%<br />
|- style="background:whitesmoke"<br />
|Opcode||Meaning||Description<br />
|-<br />
|$01||SO_SAVE_VERBS||For all verbs between start and end, sets the "saveid" to mode. <br />
|-<br />
|$02||SO_RESTORE_VERBS||For all verbs between start and end and matching mode, kills any existing verb, sets the saveid to 0 and generally inits the verb.<br />
|-<br />
|$03||SO_DELETE_VERBS||For all verbs between start and end and matching mode, kills any existing verb.<br />
|}<br />
<br />
==setCameraAt ($32)==<br />
<br />
===Encoding===<br />
opcode x[p16]<br />
<br />
===Operation===<br />
Sets the camera's x position.<br />
<br />
<br />
==setObjectName ($54)==<br />
<br />
===Encoding===<br />
opcode object[p16] name[c]... $00<br />
<br />
===Operation===<br />
Sets the given object's name.<br />
<br />
<br />
==setOwnerOf ($29)==<br />
<br />
===Encoding===<br />
opcode object[p16] owner[p8]<br />
<br />
===Operation===<br />
Sets the owner of the object.<br />
<br />
<br />
==setState ($07)==<br />
<br />
===Encoding===<br />
opcode object[p16] state[p8]<br />
<br />
===Operation===<br />
Sets the state of the object.<br />
<br />
<br />
==setVarRange ($26)==<br />
non-standard encoding<br />
<br />
===Encoding===<br />
opcode result number[8] values[8]...<br />
or<br />
opcode result number[8] values[16]...<br />
<br />
===Operation===<br />
for (i = 0; i < number; i++) {<br />
&#42;result + i := values[i];<br />
}<br />
<br />
This sets a number of variables to the given parameters. The starting variable is given as "result", and the number of variables to modify is given as "number". This is followed by the same number of values, which will be put into the variable locations. The values are constants, and can be either 16-bit, if the highest bit of the opcode is set, i.e. $A6; or 8-bit, if the highest bit of the opcode is not set, i.e. $26. Note that all values are affected by the opcode's high bit; you can't mix 8 and 16-bit values.<br />
<br />
descumm example:<br />
setVarRange(Var[178],9,[0,0,0,0,0,0,0,0,0]);<br />
<br />
This sets variables 178 to 186 (inclusive) to 0.<br />
<br />
<br />
==soundKludge ($4C)==<br />
<br />
===Encoding===<br />
opcode items[v16]...<br />
<br />
===Operation===<br />
If the first item is -1, the existing sound queue is processed. Otherwise, the list of items is added to the queue.<br />
<br />
===Variants===<br />
In SCUMM V3 (small header) games, this opcode is used for the WaitForSentence instruction.<br />
<br />
<br />
==startMusic ($02)==<br />
<br />
===Encoding===<br />
opcode music[p8]<br />
<br />
===Operation===<br />
Adds the music in to the queue to be played.<br />
<br />
===Variants===<br />
In FM-Towns (SCUMM V3) games, this instruction performs different functions (some kind of Audio CD status query function; some partially implemented in ScummVM):<br />
opcode result sub-opcode<br />
<br />
{| border="1" cellpadding="2" width=100%<br />
|- style="background:whitesmoke"<br />
|Opcode||Meaning||Description<br />
|-<br />
|$00||Is Playing||Returns true if a CD audio track is currently playing.<br />
|-<br />
|$FC||Unpause CD||Unpauses the CD audio track.<br />
|-<br />
|$FD||Pause CD||Pauses the CD audio track.<br />
|-<br />
|$FE||Get CD Sound||Returns the current CD sound.<br />
|-<br />
|$FF||CD Volume||Might return the the current CD volume in FM-Towns Loom.<br />
|-<br />
|other||Track Length||Returns the track length in seconds.<br />
|}<br />
<br />
<br />
==startObject ($37)==<br />
<br />
===Encoding===<br />
opcode object[p16] script[p8] args[v16]...<br />
<br />
===Operation===<br />
Starts the object's script (OBCD blocks), passing the given arguments.<br />
<br />
<br />
==startScript ($0A)==<br />
one parameter plus varargs, extra encoding in opcode<br />
<br />
===Encoding===<br />
opcode script[p8] args[v16]...<br />
<br />
===Operation===<br />
Spawns a new thread running the code in script script. The new script has its local variables initialised to the list args. Uninitialised variables have undefined values.<br />
<br />
The opcode carries extra information: <br />
<br />
{| border="1" cellpadding="2" width=10%<br />
|- style="background:whitesmoke"<br />
|7||6||5||4 0<br />
|-<br />
|P1||R||F||$0A<br />
|}<br />
<br />
P1 = standard parameter bit<br><br />
R = indicates that the script is recursive<br><br />
F = indicates that the script is freeze resistant (a call to freezeScripts will skip this script, unless the "force freeze" bit of the freezeScripts opcode is set).<br />
<br />
<br />
==startSound ($1C)==<br />
<br />
===Encoding===<br />
opcode sound[p8]<br />
<br />
===Operation===<br />
Adds the given sound to the sound queue to be played.<br />
<br />
<br />
==stopMusic ($20)==<br />
<br />
===Encoding===<br />
opcode<br />
<br />
===Operation===<br />
Stops all sounds.<br />
<br />
<br />
==stopObjectCode ($00)==<br />
<br />
===Encoding===<br />
opcode<br />
<br />
===Operation===<br />
Marks the calling script as dead, to be later pruned from the thread pool. Cleans up residual arrays.<br />
<br />
<br />
==stopObjectScript ($6E)==<br />
<br />
===Encoding===<br />
opcode script[p16]<br />
<br />
===Operation===<br />
Marks the given object script as dead, to be later pruned from the thread pool. Cleans up residual arrays.<br />
<br />
<br />
==stopScript ($62)==<br />
<br />
===Encoding===<br />
opcode script[p8]<br />
<br />
===Operation===<br />
Marks the given script as dead, to be later pruned from the thread pool. Cleans up residual arrays.<br />
<br />
<br />
==stopSound ($3C)==<br />
<br />
===Encoding===<br />
opcode sound[p8]<br />
<br />
===Operation===<br />
Stops the given sound.<br />
<br />
<br />
==stringOps ($27)==<br />
parameters depend on sub-opcode<br />
<br />
===Encoding===<br />
opcode sub-opcode<br />
<br />
sub-opcodes:<br />
$01 stringID[p8] string[c]... $00<br />
$02 destID[p8] srcID[p8]<br />
$03 stringID[p8] index[p8] char[c]<br />
$04 result stringID[p8] index[p8]<br />
$05 stringID[p8] size[p8]<br />
<br />
===Operation===<br />
Miscellaneous actions on strings (Arrays, referred to by resource number).<br />
<br />
{| border="1" cellpadding="2" width=100%<br />
|- style="background:whitesmoke"<br />
|Opcode||Meaning||Description<br />
|-<br />
|$01||Load String||Loads the inline null-terminated string into the resource slot given by stringID.<br />
|-<br />
|$02||Copy String||Creates a duplicate of the string at resource slot srcID into destID. The old string at destID is lost.<br />
|-<br />
|$03||Write Character||Writes char at the given index (offset) of the string resource located at slot stringID. Out of bounds accesses cause undefined behaviour.<br />
|-<br />
|$04||Read Character||Reads a byte (character) at the given index (offset) of the string resource located at slot stringID, and writes it to result. Out of bounds accesses cause undefined behaviour.<br />
|-<br />
|$05||New String||Allocates or frees a string (Array), located at resource slot stringID. The string is initialised to size; if size is zero, the string is freed.<br />
|}<br />
<br />
<br />
==subtract ($3A)==<br />
<br />
===Encoding===<br />
opcode result value[p16]<br />
<br />
===Operation===<br />
result := result - value<br />
<br />
The variable pointed to by result is read, value is subtracted from it, and the result written back.<br />
<br />
<br />
==systemOps ($98)==<br />
<br />
===Encoding===<br />
opcode sub-opcode<br />
<br />
sub-opcodes:<br />
$01<br />
$02<br />
$03<br />
<br />
===Operation===<br />
{| border="1" cellpadding="2" width=100%<br />
|- style="background:whitesmoke"<br />
|Opcode||Meaning||Description<br />
|-<br />
|$01||SO_RESTART||Restarts the game.<br />
|-<br />
|$02||SO_PAUSE||Pauses/unpauses the game.<br />
|-<br />
|$03||SO_QUIT||Quits the game.<br />
|}<br />
<br />
<br />
==verbOps ($7A)==<br />
<br />
===Encoding===<br />
opcode verbID[p8] sub-opcode... $FF<br />
<br />
sub-opcodes:<br />
$01 object[p16]<br />
$02 name[c]... $00<br />
$03 colour[p8]<br />
$04 hicolour[p8]<br />
$05 left[p16] top[p16]<br />
$06<br />
$07<br />
$08<br />
$09<br />
$10 colour[p8]<br />
$11<br />
$12 key[p8]<br />
$13<br />
$14 stringID[p16]<br />
$16 object[p16] room[p8]<br />
$17 colour[p8]<br />
<br />
===Operation===<br />
{| border="1" cellpadding="2" width=100%<br />
|- style="background:whitesmoke"<br />
|Opcode||Meaning||Description<br />
|-<br />
|$01||SO_VERB_IMAGE||Assigns an object (image) to a verb.<br />
|-<br />
|$02||SO_VERB_NAME||Assigns the in-line name to the verb slot.<br />
|-<br />
|$03||SO_VERB_COLOR||Sets the colour of the verb.<br />
|-<br />
|$04||SO_VERB_HICOLOR||Sets the high colour of the verb.<br />
|-<br />
|$05||SO_VERB_AT||Sets the verb's top-left co-ordinates.<br />
|-<br />
|$06||SO_VERB_ON||Makes this verb active.<br />
|-<br />
|$07||SO_VERB_OFF||Makes this verb inactive.<br />
|-<br />
|$08||SO_VERB_DELETE||Kills this verb.<br />
|-<br />
|$09||SO_VERB_NEW||Creates a verb in the slot for the given verbID. If the slot is 0 (verb doesn't already exist), will add it to the next unusued slot; if this exceeds the global maximum number of verbs an error will be raised.<br />
|-<br />
|$10||SO_VERB_DIMCOLOR||Sets the dim colour of the verb.<br />
|-<br />
|$11||SO_VERB_DIM||Dims this verb.<br />
|-<br />
|$12||SO_VERB_KEY||Sets the key code (maybe ASCII char?) associated with this verb.<br />
|-<br />
|$13||SO_VERB_CENTER||Centres the verb?<br />
|-<br />
|$14||SO_VERB_NAME_STR||Loads the given string resource into the verb's slot. If either the string resource or verb slot is not found (0), the verb resource is nuked.<br />
|-<br />
|$16||Assign Object||Assigns an object from the given room to the verb (if the object's image index is not already assigned to the given object).<br />
|-<br />
|$17||Set Back Colour||Sets the background colour of the verb?<br />
|}<br />
<br />
<br />
==wait ($AE)==<br />
<br />
===Encoding===<br />
opcode sub-opcode<br />
<br />
sub-opcodes:<br />
$01 actor[p8]<br />
$02 <br />
$03<br />
$04<br />
<br />
===Operation===<br />
{| border="1" cellpadding="2" width=100%<br />
|- style="background:whitesmoke"<br />
|Opcode||Meaning||Description<br />
|-<br />
|$01||SO_WAIT_FOR_ACTOR||If the given actor is moving, breaks and resumes at this instruction again.<br />
|-<br />
|$02||SO_WAIT_FOR_MESSAGE||If the global variable VAR_HAVE_MSG (Var[3]) is not zero, breaks and resumes at this instruction again.<br />
|-<br />
|$03||SO_WAIT_FOR_CAMERA||If the camera has not reached its destination x position, breaks and resumes at this instruction again.<br />
|-<br />
|$04||SO_WAIT_FOR_SENTENCE||If there is a sentence present?, breaks and resumes at this instruction again<br />
|}<br />
<br />
===Variants===<br />
In Indy3 (non-Macintosh), this opcode only acts as SO_WAIT_FOR_MESSAGE and omits the sub-opcode.<br />
opcode<br />
<br />
<br />
==walkActorTo ($1E)==<br />
<br />
===Encoding===<br />
opcode actor[p8] x[p16] y[p16]<br />
<br />
===Operation===<br />
Sets the actor to begin walking to the given position.<br />
<br />
<br />
==walkActorToActor ($0D)==<br />
<br />
===Encoding===<br />
opcode walker[p8] walkee[p8] distance[8]<br />
<br />
===Operation===<br />
Walks walker towards walkee's position by the given distance. Walker and walkee are both actors.<br />
<br />
<br />
==walkActorToObject ($36)==<br />
<br />
===Encoding===<br />
opcode actor[p8] object[p16]<br />
<br />
===Operation===<br />
Sets the actor to begin walking to the given object's position.<br />
<br />
=Variables=<br />
<br />
A number of variables are reserved for use by the SPUTM/SCUMM engine. Here is a list of known variables and their corresponding numbers, taken from the ScummVM source code.<br />
<br />
VAR_RESULT = 0; // descumm claims var 0 is the result var (for expressions)<br />
VAR_KEYPRESS = 0; // script_v5_.cpp claims var 0 is for keypresses...<br />
VAR_EGO = 1;<br />
VAR_CAMERA_POS_X = 2;<br />
VAR_HAVE_MSG = 3;<br />
VAR_ROOM = 4;<br />
VAR_OVERRIDE = 5;<br />
VAR_MACHINE_SPEED = 6;<br />
VAR_ME = 7;<br />
VAR_NUM_ACTOR = 8;<br />
VAR_CURRENT_LIGHTS = 9;<br />
VAR_CURRENTDRIVE = 10;<br />
VAR_TMR_1 = 11;<br />
VAR_TMR_2 = 12;<br />
VAR_TMR_3 = 13;<br />
VAR_MUSIC_TIMER = 14;<br />
VAR_ACTOR_RANGE_MIN = 15;<br />
VAR_ACTOR_RANGE_MAX = 16;<br />
VAR_CAMERA_MIN_X = 17;<br />
VAR_CAMERA_MAX_X = 18;<br />
VAR_TIMER_NEXT = 19;<br />
VAR_VIRT_MOUSE_X = 20;<br />
VAR_VIRT_MOUSE_Y = 21;<br />
VAR_ROOM_RESOURCE = 22;<br />
VAR_LAST_SOUND = 23;<br />
VAR_CUTSCENEEXIT_KEY = 24;<br />
VAR_TALK_ACTOR = 25;<br />
VAR_CAMERA_FAST_X = 26;<br />
VAR_SCROLL_SCRIPT = 27;<br />
VAR_ENTRY_SCRIPT = 28;<br />
VAR_ENTRY_SCRIPT2 = 29;<br />
VAR_EXIT_SCRIPT = 30;<br />
VAR_EXIT_SCRIPT2 = 31;<br />
VAR_VERB_SCRIPT = 32;<br />
VAR_SENTENCE_SCRIPT = 33;<br />
VAR_INVENTORY_SCRIPT = 34;<br />
VAR_CUTSCENE_START_SCRIPT = 35;<br />
VAR_CUTSCENE_END_SCRIPT = 36;<br />
VAR_CHARINC = 37;<br />
VAR_WALKTO_OBJ = 38;<br />
VAR_DEBUGMODE = 39;<br />
VAR_HEAPSPACE = 40;<br />
VAR_RESTART_KEY = 42;<br />
VAR_PAUSE_KEY = 43;<br />
VAR_MOUSE_X = 44;<br />
VAR_MOUSE_Y = 45;<br />
VAR_TIMER = 46;<br />
VAR_TIMER_TOTAL = 47;<br />
VAR_SOUNDCARD = 48;<br />
VAR_VIDEOMODE = 49;<br />
VAR_MAINMENU_KEY = 50;<br />
VAR_FIXEDDISK = 51;<br />
VAR_CURSORSTATE = 52;<br />
VAR_USERPUT = 53;<br />
VAR_V5_TALK_STRING_Y = 54;<br />
VAR_SOUNDRESULT = 56;<br />
VAR_TALKSTOP_KEY = 57;<br />
VAR_FADE_DELAY = 59;<br />
VAR_NOSUBTITLES = 60;<br />
VAR_SOUNDPARAM = 64;<br />
VAR_SOUNDPARAM2 = 65;<br />
VAR_SOUNDPARAM3 = 66;<br />
VAR_INPUTMODE = 67; // 1 is keyboard, 2 is joystick, 3 is mouse<br />
VAR_MEMORY_PERFORMANCE = 68;<br />
VAR_VIDEO_PERFORMANCE = 69;<br />
VAR_ROOM_FLAG = 70;<br />
VAR_GAME_LOADED = 71;<br />
VAR_NEW_ROOM = 72;<br />
<br />
<br />
=Table of Parameters=<br />
Please see the wiki page [[SCUMM/V5_opcodes/Table]].</div>Jestar jokin