<!DOCTYPE Book PUBLIC "-//Davenport//DTD DocBook V3.0//EN" [
        <!ENTITY lt "<">
        <!ENTITY gt ">">
        <!ENTITY amp "&">
	<!ENTITY kernel-functions-doc SYSTEM "sci-kernel.sgml">
	<!ENTITY freesci-doc SYSTEM "freesci.sgml">
	<!ENTITY game-list SYSTEM "game-list.sgml">
]>


<!-- (set 'font-lock-maximum-size 1024000) C-x e this in EMACS to make it possible to fontify this buffer -->

<Book>

  <Title>The Sierra Creative Interpreter</Title>

  <TitleAbbrev>SCI Documentation</TitleAbbrev>


  <BookInfo>

    <Author>
     <FirstName>Lars</firstname>
     <SurName>Skovlund</surname>
     <AuthorBlurb><Para>
      Lars Skovlund (<Email>skovmanden50@hotmail.com</Email>) contributed information about the
      SCI heap, many of the kernel functions, and wrote the description of SCI ports.
     </Para></AuthorBlurb>
    </Author>


    <Author>
     <FirstName>Christoph</firstname>
     <SurName>Reichenbach</surname>
     <AuthorBlurb><Para>
       Christoph Reichenbach (<Email>jameson@linuxgames.com</Email>)
       maintains this document and the FreeSCI interpreter.
     </Para></AuthorBlurb>
    </Author>


    <Author>
     <Firstname/Ravi/<surname/Iyengar/
      <authorblurb><para>
       Ravi (<email/ravi.i@softhome.net/), the SCI Decoding Project's sound specialist,
       contributed information about the
       sound subsystem.
      </para>
      </authorblurb>
    </author>


    <Author>
     <Firstname/Rickard/<surname/Lind/
      <authorblurb><para>
	Rickard (<email/rpl@dd.chalmers.se/) contributed information about the sound SCI01
	resources, and documented the patch.001 format. He also implemented the MT-32 to
	GM MIDI mapper used in FreeSCI.
      </para>
      </authorblurb>
    </author>


    <Author>
     <firstname/Vladimir/<surname/Gneushev/
      <authorblurb><para>
	Vladimir contributed game information, compression schemes, and the SCI1/SCI32 graphics
	format. 
      </para></authorblurb>
    </author>

    <Author>
     <firstname/Petr/<surname/Vyhnak/
      <authorblurb><para>
	Petr described the deflate-like algorithm required to decompress resources in
	SCI1.1-style games, and the general resource format.
      </para></authorblurb>
    </author>

    <Author>
     <firstname/Dark/<surname/Minister/
      <authorblurb><para>
        Dark Minister, whoever he may be, was the first one to document
        parts of the SCI instruction set, and the Said() system call.
      </para></authorblurb>
    </author>

    <Author>
     <firstname/Francois/<surname/Boyer/
      <authorblurb><para>
        Francos Boyer contributed several detailed descriptions of SCI kernel functions.
      </para></authorblurb>
    </author>

    <Othercredit>
     <FirstName>Carl</firstname>
     <SurName>Muckenhoupt</surname>
     <AuthorBlurb><Para>
      Carl Muckenhoupt (<Email>carl@wurb.com</Email>), author of the original SCI
      decoding utilities for DOS, discovered most of the decompression and graphics
      stuff (picture and view resources) described here.
     </Para></AuthorBlurb>
    </Othercredit>

    <Abstract><Para>
      This book describes the Sierra Creative Interpreter, versions 0.xxx and 1.xxx
      to the extent known to the general public, as well as the
      FreeSCI interpreter for those games.
      Please contact the author if you find that anything is being described
      incorrectly or missing.
      <warning><para>
        This version of the documentation is incomplete and covers only some parts
        of SCI0.
      </para></warning>
    </Para></Abstract>

    <ReleaseInfo/This document is still incomplete and covers almost only SCI0./

    <LegalNotice>
     <Para>
     Copyright (C) 1999, 2000, 2001, 2002 by the authors
     </Para>
     <Para>
   Permission is hereby granted, free of charge, to any person obtaining a
   copy of this documentation to deal in the Documentation without restriction,
   including without limitation the rights to use, copy, modify, merge, publish,
   distribute, sublicense, and/or sell copies of the Documentation, and to permit
   persons to whom the Documentation is furnished to do so, subject to the following
   conditions:
</Para>
<Para>
   The above copyright notice and this permission notice shall be included in
   all copies or substantial portions of the Documentation.
</Para><Para>
   THE DOCUMENTATION IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
   IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
   FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
   THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
   IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
   CONNECTION WITH THE DOCUMENTATION OR THE USE OR OTHER DEALINGS IN THE DOCUMENTATION.
     </Para><Para>
       The Sierra Creative Interpreter was originally developed by Sierra On-Line, Inc.
       "Sierra On-Line Inc. (TM)" is a registered trademark of Sierra On-Line, Inc.
       "Quest for Glory: So You Want To Be A Hero", "Quest For Glory 2: Trial By Fire"
       and "Space Quest 3: The Pirates of Pestulon" are trademarks of Sierra On-Line, Inc.
     </Para>
    </LegalNotice>

  </BookInfo>

  <Preface>
  <Title/Preface/
   <para>
    Throughout the documentation, the term SCI will be used to describe the original
    Sierra Creative Interpreter, in any version. SCI0 will refer to all games using the
    SCI version 0.xxx, except for those games who use the 'in-between' game engine
    referred to as SCI01 (such as Quest for Glory 2). SCI1 will refer to the interpreter
    version 1.xxx.
    FreeSCI will refer specifically to either implementation details of the FreeSCI
    engine or to extensions of the original SCI engine specific to FreeSCI.
   </para>
   <para>
   I would like to take this opportunity to thank the members of the FreeSCI
   and SCI Decoding Projects and their supporters, as well as Carl Muckenhoupt,
   who took the first steps of SCI decoding, for their valuable help and
   support.
   </para><para>
    Please note that some of the text contributions have been cut, reformatted or
    slightly modified in an attempt to improve the general quality of this document.
   </para>
   </Preface>


 <Chapter>
 <Title/Introduction/
<sect1>
  <Title/The basics/
    <para>
      The Sierra Creative Interpreter is a stack-based virtual machine ("P-Machine"). In addition
      to its roughly 125 basic opcodes, it provides a set of extended functions
      for displaying graphics, playing sound, receiving input, writing and reading
      data to and from the hard disk, and handling complex arithmetical and logical functions.
      In version 0.xxx of the interpreter, Sierra split the game data into nine
      different types of information:
      <simplelist>
	<member>script data: SCI scripts and local data</member>
	<member>vocab data: Parser data and debug information</member>
	<member>patch data: Information pertaining to specific audio output devices</member>
	<member>sound data: MIDI music tracks</member>
	<member>cursor data: Mouse pointer shapes</member>
	<member>view data: Sets of sets of image and hotspot information</member>
	<member>pic data: Background images and metadata</member>
	<member>font data: Bitmap fonts</member>
	<member>text data: Plain text information</member>
      </simplelist>
</para>
<para>
Each game may contain up to 1000 different elements of each data type; these
elements are referred to as "resources". The index numbers of the various
resources need not be in sequence; they are usually assigned arbitrarily.
<footnote><para>With several notable exceptions, such as script 0 and most vocab resources.</para></footnote>
</para>
</sect1>
<sect1>
<title/Resource storage/
<para>
Individual resources can be stored in one of two ways: Either in resource files
(which, surprisingly, are called something like "resource.000" or
"resource.001"), or in external patch files (not to be confused with "patch"
resources). The external files are called something like "pic.100" or
"script.000", and they take precedence over data from resource files.
</para>
<para>
There is also a file called "resource.map", which contains a lookup table for
the individual resources, and another file, "resource.cfg", which contains
configuration information; neither of those is used by FreeSCI.
</para>
<para>
Resource information stored in external patch files is not compressed and
therefore easily readable. It is, however, preceeded by two bytes:
The first byte contains the resource type ORed with 0x80, the purpose of the
second byte is unknown (but it appears to be ignored by the original SCI
version 0 engine).
</para>
<para>
As stated before, external patch files take precedence over resource resource
files. Applying those external files as patches is an option since FreeSCI
version 0.2.2.
</para>
<para>
The resource files, however, are more complicated. Each of them contains a
sequence of resources preceeded by a header; these resources may be compressed.
It is, also, quite common to find resources shared by several resource files.
The reason for this appears to be that that, back when hard disks were rare and hard
to come by, the games had to be playable from floppy disks. To prevent
unneccessary disk-jockeying, common stuff was placed in several resource files,
each of which was then stored on one disk.
</para>
</sect1>

<sect1>
<title/The individual resources: A summary/
<para>
The resource types of SCI0 can be roughly grouped into four sets:
<itemizedlist>
<ListItem><para>Graphics (pic, view, font, cursor)</para></ListItem>
<ListItem><para/Sound (patch, sound)/</ListItem>
<ListItem><para/Logic (script, vocab)/</ListItem>
<ListItem><para/Text/</ListItem>
</itemizedList>

Text resources are nothing more than a series of ASCIIZ strings; but the other
resources deserve further discussion.

</para>
<sect2>
<Title/Graphical resources summarized/
  <para>
    The screen graphics are compromised of the four graphics resources. The
    background pictures are drawn using vector-oriented commands from at least one
    pic resource (several resources may be overlaid). The fact that vector graphics
    were used for SCI0 allows for several interesting picture quality improvements.
    Pic resources also include two additional "maps": The priority map, which
    marks parts of the pictures with a certain priority, so that other things with
    less priority can be fully or partially covered by them even if they are drawn
    at a later time, and the control map, which delimits the walking area and
    some special places used by the game logic. FreeSCI uses a fourth auxiliary
    map for during drawing time (this is a heritage from Carl Muckenhoupt's
    original code).
  </para>
  <para>
    View resources contain most of the games' pixmaps (multi-color bitmaps). Each
    view contains a list of loops, and each loop contains a list of cels. The cels
    themselves contain the actual image information: RLE encoded pixmaps with
    transparency information, and relative offsets.
  </para>
  <para>
    View resources are used for foreground images as well as for background images
    (for example, the "Spielburg" sign in QfG1 (EGA) is stored in a view resource
    and added to the background picture after it is drawn).
  </para>
  <para>
    The cursor resource contains simple bitmaps for drawing the mouse pointer. It
    only allows for black, white, and transparent pixels in SCI0.
  </para>
  <para>
    The fourth graphics resource is font data. It contains bitmapped fonts which
    are used to draw most of the text in the games. Text is used in one of four
    places: Text boxes, Text input fields, the title bar menu, and occasionally
    on-screen.
  </para>
</sect2>
<sect2>
<Title/Sound resources summarized/
<para>
SCI0 uses two types of resources for sound: Patch resources, and sound
resources. Sound resources contain a rather simple header, and music data
stored in a slightly modified version of the MIDI standard.
</para>
<para>
Patch resources contain device-dependant instrument mapping information for the
instruments used in the sound resources. SCI0 sound resources do not adhere to
the General Midi (GM) standard (which was, to my knowledge, written several
years after the first SCI0 game was released), though later SCI versions may do
so.
</para>
</sect2>

<sect2>
<title/Logic resources summarized/
<para>
Whenever the parser needs to look up a word, it looks for it in one of
the vocab resources. This is not the sole purpose of the vocab resources,
though; they provide information required by the debugger, including the help
text for the debugger help menu and the names of the various SCI opcodes
and kernel functions.
</para><para>
Script resources are the heart (or, rather, the brains) of the game. Consqeuently,
they also are its most complex aspects, containing class and object information,
local data, pointer relocation tables, and, of course, SCI bytecode.
</para><para>
To run the game, scripts are loaded on the SCI stack, their pointers are relocated
appropriately, and their functions are executed by a virtual machine. They use a set of 0x7d opcodes,
which may take either 8 or 16 bit parameters (so, effectively, there is twice
the amount of commands). The functions may refer to global data, local temporary
data, local function parameter data, or object data (selectors). They may,
additionally, indirectly refer to "hunk" data, which is stored outside of the
SCI heap. Since the whole design is object oriented, functions may
re-use or overload the functions of their superclasses.
</para>
</sect2>
</sect1>

<sect1>
<title/SCI01 extensions/
<para>
  SCI01 differs only in very few respects: It uses different compression
  algorithms (all of which are supported since FreeSCI 0.2.1), and a
  different type of sound resources, which may contain digitized sound effects
  (PCM data). The basic music data, however, still resembles MIDI data.
</para>
<para>
  Also, scripts are split into two parts when loaded: A dynamic part, which
  resides in the heap as before, and a static part, which is stored externally
  to conserve heap space.
  <footnote>
    <para>
      The background for this is that heap space started running out in Quest for Glory 2.
      In order to compensate for this, changes were made to both the script library and the
      interpreter.
    </para>
  </footnote>
</para>
</sect1>


<sect1>
  <title/SCI1 extensions/
<para>
  SCI1, which is not covered by FreeSCI at the moment, introduces new concepts
  like Palettes, scaled bitmap images and several new compression algorithms.
  In SCI1.0, the resource limit was first increased to 16383
  <footnote>
    <para>
      This <emphasis>appears</emphasis> to be the limit- none of the
      SCI1.0 games I tested used resource numbers beyond 16383
    </para>
  </footnote>
  , and then to 65535 in SCI1. Because of the inherent limitations of the FAT file
  system the primary target OS of Sierra's SCI interpreter was limited to, patch
  file names were altered accordingly, with the resource number (not padded) before
  the dot and a three-letter resource ID behind it; examples are "0.scr" or "100.v56".
</para>
<para>
  The complete list of suffixes is as follows:
  <simplelist>
    <member>80: v56: 256 color views</member>
    <member>81: p56: 256 color background pictures</member>
    <member>82: scr: Scripts (static data)</member>
    <member>83: tex: Texts (apparently deprecated in favor of messages)</member>
    <member>84: snd: Sound data (MIDI music)</member>
    <member>86<footnote><para>Type 0x85 resources are 'memory' resources, which are only used internally.</para></footnote>
      :voc: Vocabulary (not used)</member>
    <member>87: fon: Fonts</member>
    <member>88: cur: Mouse cursors (deprecated in favor of v56-based cursors)</member>
    <member>89: pat: Audio patch files</member>
    <member>8a: bit: Bitmap files (purpose unknown)</member>
    <member>8b: pal: 256 color palette files</member>
    <member>8c: cda: CD Audio resources</member>
    <member>8d: aud: Audio resources (probably sound effects)</member>
    <member>8e: syn: Sync (purpose unknown)</member>
    <member>8f: msg: Message resources: Text plus metadata</member>
    <member>90: map: Map (purpose unknown)</member>
    <member>91: hep: Heap resources: Dynamic script data</member>
  </simplelist>
  Apparently, the script resource split introduced in SCI01 was incorporated into the actual resource layout
  in SCI1.
</sect1>

<sect1><title/Sierra SCI games/
  <para>
     <author><firstname/Paul David/<surname/Doherty/</author>, <author><firstname/Vladimir/<surname/Gneushev/</author>
</para><para>
  The listing here is almost certainly incomplete. Thanks to the information provided by Vladimir, game information now includes
  some features of certain versions the interpreter shipped with, they are listed below:
  <informaltable frame="all">
  <tgroup cols="2">
          <thead><row>
		<entry/Symbol/
		<entry/Meaning/
	  </row></thead>
	<tbody>
	<row>
		<entry/<emphasis>Rn</emphasis>/<entry/Resource patches identified by name (script.256)/
	</row><row>
		<entry/<emphasis>Re</emphasis>/<entry/Resource patches identified by extension (256.scr)/
	</row><row>
		<entry/<emphasis>Dd</emphasis>/<entry/Built-in debugger/
	</row><row>
		<entry/<emphasis>D*</emphasis>/<entry/Interpreter binary shipped with debug symbols/
	</row><row>
		<entry/<emphasis>Ss</emphasis>/<entry/Scripts consist of script resources only/
	</row><row>
		<entry/<emphasis>Sh</emphasis>/<entry/Scripts use heap and script resources/
	</row><row>
		<entry/<emphasis>Sc</emphasis>/<entry/Scripts use 'csc' resources/
	</row>
	</tbody>
  </tgroup>
  </informaltable>

  &game-list;

</sect1>
</chapter>

<chapter>
  <title>Resource files</title>
  <para>
  with significant contributions from <author><firstname>Petr</firstname> <surname>Vyhnak</surname></author> and <author><firstname>Vladimir</firstname> <surname>Gneushev</surname></author>
  </para><para>
    In order to allow games to be both distributeable and playable from
    several floppy disks, SCI was designed to support multi-volume data.
    The data itself could therefore be spread into separate files,
    with some of the more common resources present in more than one of
    them. The global index for these files was a "resource.map" file,
    which was read during startup and present on the same disk as the
    interpreter itself. This file contained a linear lookup table that
    mapped resource type/number tuples to a set of resource number/
    offset tuples, which they could subsequently be read from.
  </para>
  <sect1>
    <title>SCI0 resources</title>
    <sect2>
      <title>resource.map</title>
      <para>
	The SCI0 map file format is pretty simple:
	It consists of 6-byte entries, terminated by the sequence 0xffff ffff ffff.
	The first 2 bytes, interpreted as little endian 16 bit integer, encode
	resource type (high 5 bits) and number (low 11 bits). The next 4 bytes
	are a 32 bit LE integer that contains the resource file number in the high 6 bits,
	and the absolute offset within the file in the low 26 bits.
	SCI0 performs a linear search to find the resource; however, multiple entries may
	match the search, since resources may be present more than once (the inverse
	mapping is not injective).
      </para>
    </sect2>
    <sect2>
      <title>resource.&lt;nr&gt;</title>
      <para>
	SCI0 resource entries start with a four-tuple of little endian 16 bit words,
	which we will call (<literal/id/, <literal/comp_size/, <literal/decomp_size/, <literal/method/).
	<literal>id</literal> has the usual SCI0 semantics (high 5 are the resource type, low 11 are
	  its number). <literal>comp_size</literal> and <literal>decomp_size</literal> are the
	  size of the compressed and the decompressed resource, respectively. The compressed size
	  actually starts counting at the record position of <literal>decomp_size</literal>, so
	  it counts four bytes in addition to the actual content. <literal>method</literal>, finally,
	  is the compression method used to store the data.
      </para>
    </sect2>
  </sect1>
  <sect1>
    <title>SCI1 resources</title>
    <sect2>
      <title>resource.map</title>
      <para>
	The SCI1 resource.map starts with an array of 3-byte structures where the 1st 
	byte is
	the resource type (0x80 ... 0x91) and next 2 bytes (interpreted as little-endian 16 bit integer) represent the absolute offset
	of the resource's lookup table (within resource.map). This first array is terminated by a
	3-byte entry with has 0xFF as a type
	and the offset pointing to the first byte after the last resource type's lookup table.
	SCI1 first goes through this list
	to find the start of list for the correct resource type and remember this 
	offset and the offset from the next entry
	to know where it ends. The resulting interval contains a sorted list of
	6-byte structures, 
	where the first LE 16 bit integer is the resource number, and the next LE 32 bit integer
	contains the resource
	file number in its high 4 bits and the absolute resource offset (in the indicated resource file) in its low 28 bits.
	Because the list is sorted and its length is known, Sierra SCI can use binary search to locate the resource ID it is looking for.
      </para>
    </sect2>
    <sect2>
      <title>resource.&lt;nr&gt;</title>
      <para>
	Later versions of SCI1 changed the resource file structure slightly:
	The resource header now contains a byte describing the resource's type, and a four-tuple
	(<literal/res_nr/, <literal/comp_size/, <literal/decomp_size/, <literal/method/), where
	<literal>comp_size</literal>, <literal>decomp_size</literal>, and <literal>method</literal> have
	  the same meanings as before (with the exception of <literal>method</literal> referring to different algorithms),
	  while res_nr is simply the resource's number.
      </para>
    </sect2>
  </sect1>
  <sect1>
    <title>Decompression algorithms</title>
    <para>
      The decompression algorithms used in SCI are as follows:
      <table frame="all">
	<title>SCI0 compression algorithms</title>
	<tgroup cols="2">
	  <thead>
	    <row>
	      <entry>method</entry>
	      <entry>algorithm</entry>
	    </row>
	  </thead>
	  <tbody>
	    <row>
	      <entry>0</entry>
	      <entry>uncompressed</entry>
	    </row>
	    <row>
	      <entry>1</entry>
	      <entry>LZW</entry>
	    </row>
	    <row>
	      <entry>2</entry>
	      <entry>HUFFMAN</entry>
	    </row>
	  </tbody>
	</tgroup>
      </table>

      <table frame="all">
	<title>SCI01 compression algorithms</title>
	<tgroup cols="2">
	  <thead>
	    <row>
	      <entry>method</entry>
	      <entry>algorithm</entry>
	    </row>
	  </thead>
	  <tbody>
	    <row>
	      <entry>0</entry>
	      <entry>uncompressed</entry>
	    </row>
	    <row>
	      <entry>1</entry>
	      <entry>LZW</entry>
	    </row>
	    <row>
	      <entry>2</entry>
	      <entry>COMP3</entry>
	    </row>
	    <row>
	      <entry>3</entry>
	      <entry>HUFFMAN</entry>
	    </row>
	  </tbody>
	</tgroup>
      </table>


      <table frame="all">
	<title>SCI1.0 compression algorithms</title>
	<tgroup cols="2">
	  <thead>
	    <row>
	      <entry>method</entry>
	      <entry>algorithm</entry>
	    </row>
	  </thead>
	  <tbody>
	    <row>
	      <entry>0</entry>
	      <entry>uncompressed</entry>
	    </row>
	    <row>
	      <entry>1</entry>
	      <entry>LZW</entry>
	    </row>
	    <row>
	      <entry>2</entry>
	      <entry>COMP3</entry>
	    </row>
	    <row>
	      <entry>3</entry>
	      <entry>UNKNOWN-0</entry>
	    </row>
	    <row>
	      <entry>4</entry>
	      <entry>UNKNOWN-1</entry>
	    </row>
	  </tbody>
	</tgroup>
      </table>


      <table frame="all">
	<title>SCI1.1 compression algorithms</title>
	<tgroup cols="2">
	  <thead>
	    <row>
	      <entry>method</entry>
	      <entry>algorithm</entry>
	    </row>
	  </thead>
	  <tbody>
	    <row>
	      <entry>0</entry>
	      <entry>uncompressed</entry>
	    </row>
	    <row>
	      <entry>18</entry>
	      <entry>DCL-EXPLODE</entry>
	    </row>
	    <row>
	      <entry>19</entry>
	      <entry>DCL-EXPLODE</entry>
	    </row>
	    <row>
	      <entry>20</entry>
	      <entry>DCL-EXPLODE</entry>
	    </row>
	  </tbody>
	</tgroup>
      </table>

	As reported by Vladimir Gneushev, SCI32 uses STACpack (as described in RFC 1974) explicitly, determining
	whether there is a need for compression by comparing the size of the compressed
	data block with that of the uncompressed.

    </para>
    <sect2>
      <title>Decompression algorithm LZW</title>
      <para>
	The LZW algorithm itself, when used for compression or decompression in an apparatus (sic)
	designed for compression and decompression, has been patented by Unisys in Japan, Europe, and
	the United States. Fortunately, FreeSCI only needs LZW decompression, which means that it
	does not match the description of the apparatus as given above. (Further, patents on
	software are (at the time of this writing) not enforceable in Europe, where the FreeSCI
	implementation of the LZW decompressor was written).
      </para>
      <para>
	<!-- fixme -->
	  WriteMe.
      </para>
    </sect2>
    <sect2 id="decomp-huffman">
      <title>Decompression algorithm HUFFMAN</title>
      <para>
	This is an implementation of a simple huffman token decoder, which looks up tokens in a huffman tree.
	A <emphasis>huffman tree</emphasis> is a hollow binary search tree. This means that all inner nodes, usually
	including the root, are empty, and have two siblings. The tree's leaves contain the actual information.
	<programlisting>
FUNCTION get_next_bit(): Boolean;
/* This function reads the next bit from the input stream. Reading starts at the MSB. */


FUNCTION get_next_byte(): Byte
VAR
    i: Integer;
    literal: Byte;
BEGIN
    literal := 0;
    FOR i := 0 to 7 DO
        literal := (literal << 1) | get_next_bit();
    OD
    RETURN literal;
END


FUNCTION get_next_char(nodelist : Array of Nodes, index : Integer): (Char, Boolean)
VAR
    left, right: Integer;
    literal : Char;
    node : Node;
BEGIN
    Node := nodelist[index];

    IF node.siblings == 0 THEN
	RETURN (node.value, False);
    ELSE BEGIN
       left := (node.siblings & 0xf0) >> 4;
       right := (node.siblings & 0x0f);

       IF get_next_bit() THEN BEGIN
	   IF right == 0 THEN /* Literal token */
	       literal := ByteToChar(get_next_byte());

	       RETURN (literal, True);
	   ELSE
	       RETURN get_next_char(nodelist, index + right)
        END ELSE
	        RETURN get_next_char(nodelist, index + left)
    END
END
	</programlisting>
	The function get_next_char() is executed until its second return value is True (i.e.
	if a value was read directly from the input stream) while the first return value equals
	a certain terminator character, which is the first byte stored in the compressed resource:
	<informaltable frame="none">
	  <tgroup cols="3">
	    <thead>
	      <row>
		<entry>Offset</entry>
		<entry>Name</entry>
		<entry>Meaning</entry>
	      </row>
	    </thead>
	    <tbody>
	      <row>
		<entry>0</entry>
		<entry>terminator</entry>
		<entry>Terminator character</entry>
	      </row>
	      <row>
		<entry>1</entry>
		<entry>nodes</entry>
		<entry>Number of nodes</entry>
	      </row>
	      <row>
		<entry>2 + i*2</entry>
		<entry>nodelist[i].value</entry>
		<entry>Value of node #i (0 &le; i < nodes)</entry>
	      </row>
	      <row>
		<entry>3 + i*2</entry>
		<entry>nodelist[i].siblings</entry>
		<entry>Sibling nodes of node #i</entry>
	      </row>
	      <row>
		<entry>2 + nodes*2</entry>
		<entry>data[]</entry>
		<entry>The actual compressed data</entry>
	      </row>
	    </tbody>
	  </tgroup>
	</informaltable>
	where nodelist[0] is the root node.
      </para>
    </sect2>
    <sect2>
      <title>Decompression algorithm COMP3</title>
      <para>
	<!-- fixme -->
	  WriteMe.
      </para>
    </sect2>
    <sect2>
      <title>Decompression algorithm DCL-EXPLODE</title>
      <para>
	originally by <author><firstname>Petr</firstname> <surname>Vyhnak</surname></author>
      </para>
      <note><para>
	This algorithm matches one or more of the UNKNOWN algorithms.
      </para></note>
      <para>
	This algorithm is based on the Deflate algorithm described in the Internet RFC 1951 (see also
	RFC 1950 for related material).
      </para>
      <para>
	The algorithm is quite similar to the explode algorithm (ZIP method #6 - implode ) but 
	there are differences.
	<programlisting>
	/* The first 2 bytes are parameters */

P1 = ReadByte(); /* 0 or 1 */
	/* I think this means 0=binary and 1=ascii file, but in RESOURCEs I saw always 0 */

P2 = ReadByte();
	/* must be 4,5 or 6 and it is a parameter for the decompression algorithm */


/* Now, a bit stream follows, which is decoded as described below: */


LOOP:
     read 1 bit (take bits from the lowest value (LSB) to the MSB i.e. bit 0, bit 1 etc ...)
         - if the bit is 0 read 8 bits and write it to the output as it is.
         - if the bit is 1 we have here a length/distance pair:
                 - decode a number with Hufmman Tree #1; variable bit length, result is 0x00 .. 0x0F -&gt; L1
                   if L1 &lt;= 7:
                         LENGTH = L1 + 2
                   if L1 &gt; 7
                         read more (L1-7) bits -&gt; L2
                         LENGTH = L2 + M[L1-7] + 2

                 - decode another number with Hufmann Tree #2 giving result 0x00..0x3F -&gt; D1
                   if LENGTH == 2
                         D1 = D1 &lt;&lt; 2
                         read 2 bits -&gt; D2
                   else
                         D1 = D1 &lt;&lt; P2  // the parameter 2
                         read P2 bits -&gt; D2

                   DISTANCE = (D1 | D2) + 1

                 - now copy LENGTH bytes from (output_ptr-DISTANCE) to output_ptr
END LOOP

	</programlisting>
	The algorithm terminates as soon as it runs out of bits. The data structures used
	are as follows:
	</para>
	<sect3>
	  <title>M</title>
	  <para>
	    M is a constant array defined as M[0] = 7,  M[n+1] = M[n]+ 2^n.
	    That means M[1] = 8, M[2] = 0x0A, M[3] = 0x0E, M[4] = 0x16, M[5] = 0x26, etc.
	  </para>
	</sect3>

	<sect3>
	  <title>Huffman Tree #1</title>
	  <para>
	    The first huffman tree (<xref linkend="decomp-huffman">) contains the length values. It is described by the following table:

	    <informaltable>
	      <tgroup cols="2">
		<thead>
		  <row>
		    <entry>value (hex)</entry>
		    <entry>code (binary)</entry>
		  </row>
		</thead>
		<tbody>
		  <row> <entry>0</entry> <entry>101</entry> </row>
		  <row> <entry>1</entry> <entry>11</entry> </row>
		  <row> <entry>2</entry> <entry>100</entry> </row>
		  <row> <entry>3</entry> <entry>011</entry> </row>
		  <row> <entry>4</entry> <entry>0101</entry> </row>
		  <row> <entry>5</entry> <entry>0100</entry> </row>
		  <row> <entry>6</entry> <entry>0011</entry> </row>
		  <row> <entry>7</entry> <entry>0010 1</entry> </row>
		  <row> <entry>8</entry> <entry>0010 0</entry> </row>
		  <row> <entry>9</entry> <entry>0001 1</entry> </row>
		  <row> <entry>a</entry> <entry>0001 0</entry> </row>
		  <row> <entry>b</entry> <entry>0000 11</entry> </row>
		  <row> <entry>c</entry> <entry>0000 10</entry> </row>
		  <row> <entry>d</entry> <entry>0000 01</entry> </row>
		  <row> <entry>e</entry> <entry>0000 001</entry> </row>
		  <row> <entry>f</entry> <entry>0000 000</entry> </row>
		</tbody>
	      </tgroup>
	    </informaltable>
	    where bits should be read from the left to the right.
	  </para>
	</sect3>

	<sect3>
	  <title>Huffman Tree #2</title>
	  <para>
	    The second huffman code tree contains the distance values. It can be built from the following table:
	    <informaltable>
	      <tgroup cols="2">
		<thead>
		  <row>
		    <entry>value (hex)</entry>
		    <entry>code (binary)</entry>
		  </row>
		</thead>
		<tbody>
		  <row> <entry>00</entry> <entry>11</entry> </row>
		  <row> <entry>01</entry> <entry>1011</entry> </row>
		  <row> <entry>02</entry> <entry>1010</entry> </row>
		  <row> <entry>03</entry> <entry>1001 1</entry> </row>
		  <row> <entry>04</entry> <entry>1001 0</entry> </row>
		  <row> <entry>05</entry> <entry>1000 1</entry> </row>
		  <row> <entry>06</entry> <entry>1000 0</entry> </row>
		  <row> <entry>07</entry> <entry>0111 11</entry> </row>
		  <row> <entry>08</entry> <entry>0111 10</entry> </row>
		  <row> <entry>09</entry> <entry>0111 01</entry> </row>
		  <row> <entry>0a</entry> <entry>0111 00</entry> </row>
		  <row> <entry>0b</entry> <entry>0110 11</entry> </row>
		  <row> <entry>0c</entry> <entry>0110 10</entry> </row>
		  <row> <entry>0d</entry> <entry>0110 01</entry> </row>
		  <row> <entry>0e</entry> <entry>0110 00</entry> </row>
		  <row> <entry>0f</entry> <entry>0101 11</entry> </row>
		  <row> <entry>10</entry> <entry>0101 10</entry> </row>
		  <row> <entry>11</entry> <entry>0101 01</entry> </row>
		  <row> <entry>12</entry> <entry>0101 00</entry> </row>
		  <row> <entry>13</entry> <entry>0100 11</entry> </row>
		  <row> <entry>14</entry> <entry>0100 10</entry> </row>
		  <row> <entry>15</entry> <entry>0100 01</entry> </row>
		  <row> <entry>16</entry> <entry>0100 001</entry> </row>
		  <row> <entry>17</entry> <entry>0100 000</entry> </row>
		  <row> <entry>18</entry> <entry>0011 111</entry> </row>
		  <row> <entry>19</entry> <entry>0011 110</entry> </row>
		  <row> <entry>1a</entry> <entry>0011 101</entry> </row>
		  <row> <entry>1b</entry> <entry>0011 100</entry> </row>
		  <row> <entry>1c</entry> <entry>0011 011</entry> </row>
		  <row> <entry>1d</entry> <entry>0011 010</entry> </row>
		  <row> <entry>1e</entry> <entry>0011 001</entry> </row>
		  <row> <entry>1f</entry> <entry>0011 000</entry> </row>
		  <row> <entry>20</entry> <entry>0010 111</entry> </row>
		  <row> <entry>21</entry> <entry>0010 110</entry> </row>
		  <row> <entry>22</entry> <entry>0010 101</entry> </row>
		  <row> <entry>23</entry> <entry>0010 100</entry> </row>
		  <row> <entry>24</entry> <entry>0010 011</entry> </row>
		  <row> <entry>25</entry> <entry>0010 010</entry> </row>
		  <row> <entry>26</entry> <entry>0010 001</entry> </row>
		  <row> <entry>27</entry> <entry>0010 000</entry> </row>
		  <row> <entry>28</entry> <entry>0001 111</entry> </row>
		  <row> <entry>29</entry> <entry>0001 110</entry> </row>
		  <row> <entry>2a</entry> <entry>0001 101</entry> </row>
		  <row> <entry>2b</entry> <entry>0001 100</entry> </row>
		  <row> <entry>2c</entry> <entry>0001 011</entry> </row>
		  <row> <entry>2d</entry> <entry>0001 010</entry> </row>
		  <row> <entry>2e</entry> <entry>0001 001</entry> </row>
		  <row> <entry>2f</entry> <entry>0001 000</entry> </row>
		  <row> <entry>30</entry> <entry>0000 1111</entry> </row>
		  <row> <entry>31</entry> <entry>0000 1110</entry> </row>
		  <row> <entry>32</entry> <entry>0000 1101</entry> </row>
		  <row> <entry>33</entry> <entry>0000 1100</entry> </row>
		  <row> <entry>34</entry> <entry>0000 1011</entry> </row>
		  <row> <entry>35</entry> <entry>0000 1010</entry> </row>
		  <row> <entry>36</entry> <entry>0000 1001</entry> </row>
		  <row> <entry>37</entry> <entry>0000 1000</entry> </row>
		  <row> <entry>38</entry> <entry>0000 0111</entry> </row>
		  <row> <entry>39</entry> <entry>0000 0110</entry> </row>
		  <row> <entry>3a</entry> <entry>0000 0101</entry> </row>
		  <row> <entry>3b</entry> <entry>0000 0100</entry> </row>
		  <row> <entry>3c</entry> <entry>0000 0011</entry> </row>
		  <row> <entry>3d</entry> <entry>0000 0010</entry> </row>
		  <row> <entry>3e</entry> <entry>0000 0001</entry> </row>
		  <row> <entry>3f</entry> <entry>0000 0000</entry> </row>
		</tbody>
	      </tgroup>
	    </informaltable>
	    where bits should be read from the left to the right.
	  </para>
	</sect3>

      	<sect3>
	  <title>Huffman Tree #3</title>
	  <para>
	    This tree describes literal values for ASCII mode, which adds another
	    compression step to the algorithm.
	    <informaltable>
	      <tgroup cols="2">
		<thead>
		  <row>
		    <entry>value (hex)</entry>
		    <entry>code (binary)</entry>
		  </row>
		</thead>
		<tbody>
                  <row> <entry>00</entry> <entry>0000 1001 001</entry> </row>
                  <row> <entry>01</entry> <entry>0000 0111 1111 </entry> </row>
                  <row> <entry>02</entry> <entry>0000 0111 1110 </entry> </row>
                  <row> <entry>03</entry> <entry>0000 0111 1101 </entry> </row>
                  <row> <entry>04</entry> <entry>0000 0111 1100 </entry> </row>
                  <row> <entry>05</entry> <entry>0000 0111 1011 </entry> </row>
                  <row> <entry>06</entry> <entry>0000 0111 1010 </entry> </row>
                  <row> <entry>07</entry> <entry>0000 0111 1001 </entry> </row>
                  <row> <entry>08</entry> <entry>0000 0111 1000 </entry> </row>
                  <row> <entry>09</entry> <entry>0001 1101 </entry> </row>
                  <row> <entry>0a</entry> <entry>0100 011</entry> </row>
                  <row> <entry>0b</entry> <entry>0000 0111 0111 </entry> </row>
                  <row> <entry>0c</entry> <entry>0000 0111 0110 </entry> </row>
                  <row> <entry>0d</entry> <entry>0100 010</entry> </row>
                  <row> <entry>0e</entry> <entry>0000 0111 0101 </entry> </row>
                  <row> <entry>0f</entry> <entry>0000 0111 0100 </entry> </row>
                  <row> <entry>10</entry> <entry>0000 0111 0011 </entry> </row>
                  <row> <entry>11</entry> <entry>0000 0111 0010 </entry> </row>
                  <row> <entry>12</entry> <entry>0000 0111 0001 </entry> </row>
                  <row> <entry>13</entry> <entry>0000 0111 0000 </entry> </row>
                  <row> <entry>14</entry> <entry>0000 0110 1111 </entry> </row>
                  <row> <entry>15</entry> <entry>0000 0110 1110 </entry> </row>
                  <row> <entry>16</entry> <entry>0000 0110 1101 </entry> </row>
                  <row> <entry>17</entry> <entry>0000 0110 1100 </entry> </row>
                  <row> <entry>18</entry> <entry>0000 0110 1011 </entry> </row>
                  <row> <entry>19</entry> <entry>0000 0110 1010 </entry> </row>
                  <row> <entry>1a</entry> <entry>0000 0010 0100 1</entry> </row>
                  <row> <entry>1b</entry> <entry>0000 0110 1001 </entry> </row>
                  <row> <entry>1c</entry> <entry>0000 0110 1000 </entry> </row>
                  <row> <entry>1d</entry> <entry>0000 0110 0111 </entry> </row>
                  <row> <entry>1e</entry> <entry>0000 0110 0110 </entry> </row>
                  <row> <entry>1f</entry> <entry>0000 0110 0101 </entry> </row>
                  <row> <entry>20</entry> <entry>1111 </entry> </row>
                  <row> <entry>21</entry> <entry>0000 1010 01</entry> </row>
                  <row> <entry>22</entry> <entry>0001 1100 </entry> </row>
                  <row> <entry>23</entry> <entry>0000 0110 0100 </entry> </row>
                  <row> <entry>24</entry> <entry>0000 1010 00</entry> </row>
                  <row> <entry>25</entry> <entry>0000 0110 0011 </entry> </row>
                  <row> <entry>26</entry> <entry>0000 1001 11</entry> </row>
                  <row> <entry>27</entry> <entry>0001 1011 </entry> </row>
                  <row> <entry>28</entry> <entry>0100 001</entry> </row>
                  <row> <entry>29</entry> <entry>0100 000</entry> </row>
                  <row> <entry>2a</entry> <entry>0001 1010 </entry> </row>
                  <row> <entry>2b</entry> <entry>0000 1101 1</entry> </row>
                  <row> <entry>2c</entry> <entry>0011 111</entry> </row>
                  <row> <entry>2d</entry> <entry>1001 01</entry> </row>
                  <row> <entry>2e</entry> <entry>0011 110</entry> </row>
                  <row> <entry>2f</entry> <entry>0001 1001 </entry> </row>
                  <row> <entry>30</entry> <entry>0011 101</entry> </row>
                  <row> <entry>31</entry> <entry>1001 00</entry> </row>
                  <row> <entry>32</entry> <entry>0011 100</entry> </row>
                  <row> <entry>33</entry> <entry>0011 011</entry> </row>
                  <row> <entry>34</entry> <entry>0011 010</entry> </row>
                  <row> <entry>35</entry> <entry>0011 001</entry> </row>
                  <row> <entry>36</entry> <entry>0001 1000 </entry> </row>
                  <row> <entry>37</entry> <entry>0011 000</entry> </row>
                  <row> <entry>38</entry> <entry>0010 111</entry> </row>
                  <row> <entry>39</entry> <entry>0001 0111 </entry> </row>
                  <row> <entry>3a</entry> <entry>0001 0110 </entry> </row>
                  <row> <entry>3b</entry> <entry>0000 0110 0010 </entry> </row>
                  <row> <entry>3c</entry> <entry>0000 1001 000</entry> </row>
                  <row> <entry>3d</entry> <entry>0010 110</entry> </row>
                  <row> <entry>3e</entry> <entry>0000 1101 0</entry> </row>
                  <row> <entry>3f</entry> <entry>0000 1000 111</entry> </row>
                  <row> <entry>40</entry> <entry>0000 0110 0001 </entry> </row>
                  <row> <entry>41</entry> <entry>1000 11</entry> </row>
                  <row> <entry>42</entry> <entry>0010 101</entry> </row>
                  <row> <entry>43</entry> <entry>1000 10</entry> </row>
                  <row> <entry>44</entry> <entry>1000 01</entry> </row>
                  <row> <entry>45</entry> <entry>1110 1</entry> </row>
                  <row> <entry>46</entry> <entry>0010 100</entry> </row>
                  <row> <entry>47</entry> <entry>0001 0101 </entry> </row>
                  <row> <entry>48</entry> <entry>0001 0100 </entry> </row>
                  <row> <entry>49</entry> <entry>1000 00</entry> </row>
                  <row> <entry>4a</entry> <entry>0000 1000 110</entry> </row>
                  <row> <entry>4b</entry> <entry>0000 1100 1</entry> </row>
                  <row> <entry>4c</entry> <entry>0111 11</entry> </row>
                  <row> <entry>4d</entry> <entry>0010 011</entry> </row>
                  <row> <entry>4e</entry> <entry>0111 10</entry> </row>
                  <row> <entry>4f</entry> <entry>0111 01</entry> </row>
                  <row> <entry>50</entry> <entry>0010 010</entry> </row>
                  <row> <entry>51</entry> <entry>0000 1000 101</entry> </row>
                  <row> <entry>52</entry> <entry>0111 00</entry> </row>
                  <row> <entry>53</entry> <entry>0110 11</entry> </row>
                  <row> <entry>54</entry> <entry>0110 10</entry> </row>
                  <row> <entry>55</entry> <entry>0010 001</entry> </row>
                  <row> <entry>56</entry> <entry>0000 1100 0</entry> </row>
                  <row> <entry>57</entry> <entry>0001 0011 </entry> </row>
                  <row> <entry>58</entry> <entry>0000 1011 1</entry> </row>
                  <row> <entry>59</entry> <entry>0000 1011 0</entry> </row>
                  <row> <entry>5a</entry> <entry>0000 1000 100</entry> </row>
                  <row> <entry>5b</entry> <entry>0001 0010 </entry> </row>
                  <row> <entry>5c</entry> <entry>0000 1000 011</entry> </row>
                  <row> <entry>5d</entry> <entry>0000 1010 1</entry> </row>
                  <row> <entry>5e</entry> <entry>0000 0110 0000 </entry> </row>
                  <row> <entry>5f</entry> <entry>0001 0001 </entry> </row>
                  <row> <entry>60</entry> <entry>0000 0101 1111 </entry> </row>
                  <row> <entry>61</entry> <entry>1110 0</entry> </row>
                  <row> <entry>62</entry> <entry>0110 01</entry> </row>
                  <row> <entry>63</entry> <entry>0110 00</entry> </row>
                  <row> <entry>64</entry> <entry>0101 11</entry> </row>
                  <row> <entry>65</entry> <entry>1101 1</entry> </row>
                  <row> <entry>66</entry> <entry>0101 10</entry> </row>
                  <row> <entry>67</entry> <entry>0101 01</entry> </row>
                  <row> <entry>68</entry> <entry>0101 00</entry> </row>
                  <row> <entry>69</entry> <entry>1101 0</entry> </row>
                  <row> <entry>6a</entry> <entry>0000 1000 010</entry> </row>
                  <row> <entry>6b</entry> <entry>0010 000</entry> </row>
                  <row> <entry>6c</entry> <entry>1100 1</entry> </row>
                  <row> <entry>6d</entry> <entry>0100 11</entry> </row>
                  <row> <entry>6e</entry> <entry>1100 0</entry> </row>
                  <row> <entry>6f</entry> <entry>1011 1</entry> </row>
                  <row> <entry>70</entry> <entry>0100 10</entry> </row>
                  <row> <entry>71</entry> <entry>0000 1001 10</entry> </row>
                  <row> <entry>72</entry> <entry>1011 0</entry> </row>
                  <row> <entry>73</entry> <entry>1010 1</entry> </row>
                  <row> <entry>74</entry> <entry>1010 0</entry> </row>
                  <row> <entry>75</entry> <entry>1001 1</entry> </row>
                  <row> <entry>76</entry> <entry>0001 0000 </entry> </row>
                  <row> <entry>77</entry> <entry>0001 111</entry> </row>
                  <row> <entry>78</entry> <entry>0000 1111 </entry> </row>
                  <row> <entry>79</entry> <entry>0000 1110 </entry> </row>
                  <row> <entry>7a</entry> <entry>0000 1001 01</entry> </row>
                  <row> <entry>7b</entry> <entry>0000 1000 001</entry> </row>
                  <row> <entry>7c</entry> <entry>0000 1000 000</entry> </row>
                  <row> <entry>7d</entry> <entry>0000 0101 1110 </entry> </row>
                  <row> <entry>7e</entry> <entry>0000 0101 1101 </entry> </row>
                  <row> <entry>7f</entry> <entry>0000 0101 1100 </entry> </row>
                  <row> <entry>80</entry> <entry>0000 0010 0100 0</entry> </row>
                  <row> <entry>81</entry> <entry>0000 0010 0011 1</entry> </row>
                  <row> <entry>82</entry> <entry>0000 0010 0011 0</entry> </row>
                  <row> <entry>83</entry> <entry>0000 0010 0010 1</entry> </row>
                  <row> <entry>84</entry> <entry>0000 0010 0010 0</entry> </row>
                  <row> <entry>85</entry> <entry>0000 0010 0001 1</entry> </row>
                  <row> <entry>86</entry> <entry>0000 0010 0001 0</entry> </row>
                  <row> <entry>87</entry> <entry>0000 0010 0000 1</entry> </row>
                  <row> <entry>88</entry> <entry>0000 0010 0000 0</entry> </row>
                  <row> <entry>89</entry> <entry>0000 0001 1111 1</entry> </row>
                  <row> <entry>8a</entry> <entry>0000 0001 1111 0</entry> </row>
                  <row> <entry>8b</entry> <entry>0000 0001 1110 1</entry> </row>
                  <row> <entry>8c</entry> <entry>0000 0001 1110 0</entry> </row>
                  <row> <entry>8d</entry> <entry>0000 0001 1101 1</entry> </row>
                  <row> <entry>8e</entry> <entry>0000 0001 1101 0</entry> </row>
                  <row> <entry>8f</entry> <entry>0000 0001 1100 1</entry> </row>
                  <row> <entry>90</entry> <entry>0000 0001 1100 0</entry> </row>
                  <row> <entry>91</entry> <entry>0000 0001 1011 1</entry> </row>
                  <row> <entry>92</entry> <entry>0000 0001 1011 0</entry> </row>
                  <row> <entry>93</entry> <entry>0000 0001 1010 1</entry> </row>
                  <row> <entry>94</entry> <entry>0000 0001 1010 0</entry> </row>
                  <row> <entry>95</entry> <entry>0000 0001 1001 1</entry> </row>
                  <row> <entry>96</entry> <entry>0000 0001 1001 0</entry> </row>
                  <row> <entry>97</entry> <entry>0000 0001 1000 1</entry> </row>
                  <row> <entry>98</entry> <entry>0000 0001 1000 0</entry> </row>
                  <row> <entry>99</entry> <entry>0000 0001 0111 1</entry> </row>
                  <row> <entry>9a</entry> <entry>0000 0001 0111 0</entry> </row>
                  <row> <entry>9b</entry> <entry>0000 0001 0110 1</entry> </row>
                  <row> <entry>9c</entry> <entry>0000 0001 0110 0</entry> </row>
                  <row> <entry>9d</entry> <entry>0000 0001 0101 1</entry> </row>
                  <row> <entry>9e</entry> <entry>0000 0001 0101 0</entry> </row>
                  <row> <entry>9f</entry> <entry>0000 0001 0100 1</entry> </row>
                  <row> <entry>a0</entry> <entry>0000 0001 0100 0</entry> </row>
                  <row> <entry>a1</entry> <entry>0000 0001 0011 1</entry> </row>
                  <row> <entry>a2</entry> <entry>0000 0001 0011 0</entry> </row>
                  <row> <entry>a3</entry> <entry>0000 0001 0010 1</entry> </row>
                  <row> <entry>a4</entry> <entry>0000 0001 0010 0</entry> </row>
                  <row> <entry>a5</entry> <entry>0000 0001 0001 1</entry> </row>
                  <row> <entry>a6</entry> <entry>0000 0001 0001 0</entry> </row>
                  <row> <entry>a7</entry> <entry>0000 0001 0000 1</entry> </row>
                  <row> <entry>a8</entry> <entry>0000 0001 0000 0</entry> </row>
                  <row> <entry>a9</entry> <entry>0000 0000 1111 1</entry> </row>
                  <row> <entry>aa</entry> <entry>0000 0000 1111 0</entry> </row>
                  <row> <entry>ab</entry> <entry>0000 0000 1110 1</entry> </row>
                  <row> <entry>ac</entry> <entry>0000 0000 1110 0</entry> </row>
                  <row> <entry>ad</entry> <entry>0000 0000 1101 1</entry> </row>
                  <row> <entry>ae</entry> <entry>0000 0000 1101 0</entry> </row>
                  <row> <entry>af</entry> <entry>0000 0000 1100 1</entry> </row>
                  <row> <entry>b0</entry> <entry>0000 0101 1011 </entry> </row>
                  <row> <entry>b1</entry> <entry>0000 0101 1010 </entry> </row>
                  <row> <entry>b2</entry> <entry>0000 0101 1001 </entry> </row>
                  <row> <entry>b3</entry> <entry>0000 0101 1000 </entry> </row>
                  <row> <entry>b4</entry> <entry>0000 0101 0111 </entry> </row>
                  <row> <entry>b5</entry> <entry>0000 0101 0110 </entry> </row>
                  <row> <entry>b6</entry> <entry>0000 0101 0101 </entry> </row>
                  <row> <entry>b7</entry> <entry>0000 0101 0100 </entry> </row>
                  <row> <entry>b8</entry> <entry>0000 0101 0011 </entry> </row>
                  <row> <entry>b9</entry> <entry>0000 0101 0010 </entry> </row>
                  <row> <entry>ba</entry> <entry>0000 0101 0001 </entry> </row>
                  <row> <entry>bb</entry> <entry>0000 0101 0000 </entry> </row>
                  <row> <entry>bc</entry> <entry>0000 0100 1111 </entry> </row>
                  <row> <entry>bd</entry> <entry>0000 0100 1110 </entry> </row>
                  <row> <entry>be</entry> <entry>0000 0100 1101 </entry> </row>
                  <row> <entry>bf</entry> <entry>0000 0100 1100 </entry> </row>
                  <row> <entry>c0</entry> <entry>0000 0100 1011 </entry> </row>
                  <row> <entry>c1</entry> <entry>0000 0100 1010 </entry> </row>
                  <row> <entry>c2</entry> <entry>0000 0100 1001 </entry> </row>
                  <row> <entry>c3</entry> <entry>0000 0100 1000 </entry> </row>
                  <row> <entry>c4</entry> <entry>0000 0100 0111 </entry> </row>
                  <row> <entry>c5</entry> <entry>0000 0100 0110 </entry> </row>
                  <row> <entry>c6</entry> <entry>0000 0100 0101 </entry> </row>
                  <row> <entry>c7</entry> <entry>0000 0100 0100 </entry> </row>
                  <row> <entry>c8</entry> <entry>0000 0100 0011 </entry> </row>
                  <row> <entry>c9</entry> <entry>0000 0100 0010 </entry> </row>
                  <row> <entry>ca</entry> <entry>0000 0100 0001 </entry> </row>
                  <row> <entry>cb</entry> <entry>0000 0100 0000 </entry> </row>
                  <row> <entry>cc</entry> <entry>0000 0011 1111 </entry> </row>
                  <row> <entry>cd</entry> <entry>0000 0011 1110 </entry> </row>
                  <row> <entry>ce</entry> <entry>0000 0011 1101 </entry> </row>
                  <row> <entry>cf</entry> <entry>0000 0011 1100 </entry> </row>
                  <row> <entry>d0</entry> <entry>0000 0011 1011 </entry> </row>
                  <row> <entry>d1</entry> <entry>0000 0011 1010 </entry> </row>
                  <row> <entry>d2</entry> <entry>0000 0011 1001 </entry> </row>
                  <row> <entry>d3</entry> <entry>0000 0011 1000 </entry> </row>
                  <row> <entry>d4</entry> <entry>0000 0011 0111 </entry> </row>
                  <row> <entry>d5</entry> <entry>0000 0011 0110 </entry> </row>
                  <row> <entry>d6</entry> <entry>0000 0011 0101 </entry> </row>
                  <row> <entry>d7</entry> <entry>0000 0011 0100 </entry> </row>
                  <row> <entry>d8</entry> <entry>0000 0011 0011 </entry> </row>
                  <row> <entry>d9</entry> <entry>0000 0011 0010 </entry> </row>
                  <row> <entry>da</entry> <entry>0000 0011 0001 </entry> </row>
                  <row> <entry>db</entry> <entry>0000 0011 0000 </entry> </row>
                  <row> <entry>dc</entry> <entry>0000 0010 1111 </entry> </row>
                  <row> <entry>dd</entry> <entry>0000 0010 1110 </entry> </row>
                  <row> <entry>de</entry> <entry>0000 0010 1101 </entry> </row>
                  <row> <entry>df</entry> <entry>0000 0010 1100 </entry> </row>
                  <row> <entry>e0</entry> <entry>0000 0000 1100 0</entry> </row>
                  <row> <entry>e1</entry> <entry>0000 0010 1011 </entry> </row>
                  <row> <entry>e2</entry> <entry>0000 0000 1011 1</entry> </row>
                  <row> <entry>e3</entry> <entry>0000 0000 1011 0</entry> </row>
                  <row> <entry>e4</entry> <entry>0000 0000 1010 1</entry> </row>
                  <row> <entry>e5</entry> <entry>0000 0010 1010 </entry> </row>
                  <row> <entry>e6</entry> <entry>0000 0000 1010 0</entry> </row>
                  <row> <entry>e7</entry> <entry>0000 0000 1001 1</entry> </row>
                  <row> <entry>e8</entry> <entry>0000 0000 1001 0</entry> </row>
                  <row> <entry>e9</entry> <entry>0000 0010 1001 </entry> </row>
                  <row> <entry>ea</entry> <entry>0000 0000 1000 1</entry> </row>
                  <row> <entry>eb</entry> <entry>0000 0000 1000 0</entry> </row>
                  <row> <entry>ec</entry> <entry>0000 0000 0111 1</entry> </row>
                  <row> <entry>ed</entry> <entry>0000 0000 0111 0</entry> </row>
                  <row> <entry>ee</entry> <entry>0000 0010 1000 </entry> </row>
                  <row> <entry>ef</entry> <entry>0000 0000 0110 1</entry> </row>
                  <row> <entry>f0</entry> <entry>0000 0000 0110 0</entry> </row>
                  <row> <entry>f1</entry> <entry>0000 0000 0101 1</entry> </row>
                  <row> <entry>f2</entry> <entry>0000 0010 0111 </entry> </row>
                  <row> <entry>f3</entry> <entry>0000 0010 0110 </entry> </row>
                  <row> <entry>f4</entry> <entry>0000 0010 0101 </entry> </row>
                  <row> <entry>f5</entry> <entry>0000 0000 0101 0</entry> </row>
                  <row> <entry>f6</entry> <entry>0000 0000 0100 1</entry> </row>
                  <row> <entry>f7</entry> <entry>0000 0000 0100 0</entry> </row>
                  <row> <entry>f8</entry> <entry>0000 0000 0011 1</entry> </row>
                  <row> <entry>f9</entry> <entry>0000 0000 0011 0</entry> </row>
                  <row> <entry>fa</entry> <entry>0000 0000 0010 1</entry> </row>
                  <row> <entry>fb</entry> <entry>0000 0000 0010 0</entry> </row>
                  <row> <entry>fc</entry> <entry>0000 0000 0001 1</entry> </row>
                  <row> <entry>fd</entry> <entry>0000 0000 0001 0</entry> </row>
                  <row> <entry>fe</entry> <entry>0000 0000 0000 1</entry> </row>
                  <row> <entry>ff</entry> <entry>0000 0000 0000 0</entry> </row>
		</tbody>
	      </tgroup>
	    </informaltable>
	    where bits should be read from the left to the right.
	  </para>
	</sect3>

    </sect2>

    <sect2>
      <title>Decompression algorithm UNKNOWN</title>
      <para>
	The algorithms listed as UNKNOWN-x have not yet been mapped to actual algorithms but
	are known to be used by the games. For some of them, it is possible that they match
	one of the algorithms described above, but have not yet been added to FreeSCI in an
	appropriate way (refer to DCL-EXPLODE for a good example).
      </para>
    </sect2>
  </sect1>
</chapter>

<chapter>
 <Title/The Graphics subsystem/
 <sect1>
 <Title/General stuff/
 <para>
 The graphics in SCI are generated using four resource types:
 <itemizedlist>
 <listitem><para/Pic resources for background pictures/</listitem>
 <listitem><para/View resources for images/</listitem>
 <listitem><para/Font resources for drawing text/</listitem>
 <listitem><para/Cursor resources for displaying the mouse pointer/</listitem>
 </itemizedlist>
 
 Those resources are drawn on three distinct maps:
 <itemizedlist>
 <listitem><para/The visual map, used for displaying the actual pictures the player sees/</listitem>
 <listitem><para/The priority map, which keeps information about how the depth of the screen/</listitem>
 <listitem><para/The control map, which contains special information/</listitem>
 </itemizedlist>
 </para>
 </sect1>
 <sect1>
 <Title/SCI Ports/
 <para>
 <author><firstname/Lars/ <surname/Skovlund/ </author>

</para><para>
  Version 1.0,
  6. July 1999
</para><para>
 Note that the observations made in this document are
generally based on SCI version 0.000.572 (the one that comes with LSL3),
but should be valid even for SCI01 and SCI1, as well. I know already
about
some differences in the port system from SCI0 to SCI1, but I feel we
should
have an interpreter running for SCI0 before dealing with SCI1.
</para><para>
This article discusses a key data structure in SCI graphics handling;
this data structure is called a port, and it is involved in most
graphics-related
operations. The port is basically a graphics state record, storing
things
like pen color, current font, cursor position etc. Each port also has
an origin and a size. The actual port data structure has remained
absolutely
unchanged from SCI0 up to the latest versions of SCI1. 
</para><para>
The port can be viewed as a rectangle in which things are drawn. Every
drawing operation (even KDrawPic) is executed relative to the origin
coordinates of the current port (depending on the kernel function, other
parameters in the port structure are used as well), such that coordinate
(0, 0) in the "picture window" (such a thing really exists in SCI!) is
<emphasis/not/ the top of the screen, but rather the leftmost point underneath
the menu bar. The coordinate set (0,0) is called the local coordinates,
and its physical position on the screen, (0, 10), is called the global
coordinates. Kernel calls exist to ease conversion between the two
coordinate
systems, but they are, it appears, meant for event handlers to use, and
not generally usable (I think they take a pointer to an Event object as
a
parameter).
</para><para>
At least three ports are created and managed automatically by the SCI
interpreter. These are the "window manager" port, the menu port, and the
picture port (which is actually a window, see later). The latter two
should be fairly easy to understand. The menu bar is drawn in the menu
port,
and the current room is drawn in the picture port. What may be less
obvious
is that the window manager port is an "invisible" port, on which the
window
backgrounds are drawn, although the windows have a port themselves. If
you
are familiar with <Trademark>Windows</trademark>
programming, the term "client rectangle" may
ring a
bell here - SCI draws the window backgrounds, using values in the window
manager port, while the window's own port controls what is drawn inside
it.
The window manager port covers the same bounding rectangle as the
picture
window, but it is transparent so it doesn't mess up the graphics.
</para><para>
I feel compelled to mention windows for a bit here, not in depth - they
are
the subject of a later article - but just to mention that the structure
used
to manage windows is just an extension of the port structure. Whenever
an
SCI system call needs a pointer to a port structure, a pointer to a
window
structure will do. This implicates that the SysWindow class (which
implements
windows) has no "port" property. Instead, its "window" property points
to the
extended port/window structure which can safely be passed to KSetPort.
Not
surprisingly, many of KNewWindow's arguments end up in the port part of
the
window structure.
</para><para>
An SCI program can't directly instantiate a port. If a program wants to
access a specific part of the screen using ports, it has to instantiate
a
transparent window. In fact, SCI creates the picture window using
RNewWindow,
the same function that the kernel call KNewWindow ends up calling,
asking for
an untitled window with a transparent background - but more on that in a
later article.
</para><para>
It must be stressed that ports are purely internal structures. Although
a
program can select different ports to draw in, the data structures
themselves
are absolutely off-limits to SCI code. KNewWindow fills a port structure
with
user-supplied data, but there is no way of changing that data, short of
dis-
posing the window and instantiating it again. The structure is
frequently
changed by SCI itself, though.
</para><para>
Only two kernel calls deal directly with ports:
</para><para>
<simpleList>
<member>KGetPort (see <xref linkend="KGetPort">)</member>
<member>KSetPort (see <xref linkend="KSetPort">)</member>
</simplelist>
</para><para>
These two functions are often used in pairs (also internally), like:
</para><para><programlisting>
var temp;

temp=KGetPort();  /* Save the old port */
KSetPort(...);      /* Activate some other port */
..                            /* Draw some stuff */
KSetPort(temp);    /* Reactivate the old port */
</programlisting>
 </para>

</sect1>
 <sect1>
 <Title/The Cursor resource/

  <para>
  This resource stores a simple bitmap describing the shape and texture of the
  mouse pointer. All information stored herein is little endian in byte order.
  </para><para>
  <VariableList>
   <VarListEntry><Term>0x00 - 0x01
        </Term><ListItem><Para> 
        X coordinate of the mouse cursor hot spot as a 16 bit integer.
	This variable is not used in SCI0.
        </para>
   </ListItem></VarListEntry><VarListEntry><Term>0x02 - 0x03
        </Term><ListItem><Para>
        Y coordinate of the mouse cursor hot spot as a 16 bit integer.
	Only 0x03 is used in SCI0; here, if set, the hot spot is at (8,8),
	if not set, it is located at (0,0).
        </para>
   </ListItem></VarListEntry><VarListEntry><Term>0x04 - 0x23
        </Term><ListItem><Para>
        This is a list of 16 unsigned 16 bit integers constituting bitmasks for the
        mouse cursor's transparency map, with the MSB representing the leftmost
        pixel.
        </para>
   </ListItem></VarListEntry><VarListEntry><Term>0x24 - 0x43
        </Term><ListItem><Para>
        This is another list of 16 unsigned 16 bit integers. Each of them represents
        another bitmask, determining whether the mouse cursor pixel should be drawn
        in black (not set) or white (set). 
        </para>
   </ListItem></VarListEntry></VariableList>
   To determine whether or not to draw a pixel, and, if it is to be drawn, in which
   color it should be drawn in, the corresponding bits of both bitmask lists mentioned
   above have to be examined. In the table below, A represents a bit from
   the first list, and B the corresponding bit from the lower list.
   </para>
   <sect2>
         <title>Color mapping for the SCI0 mouse pointer</title>
   <para>
   <informaltable frame="all">
         <tgroup cols="2">
           <thead>
             <row>
               <entry>AB</entry>
               <entry>Result</entry>
             </row>
           </thead>
           <tbody>
             <row>
               <entry>00</entry>
               <entry>Transparent</entry>
             </row>
             <row>
               <entry>01</entry>
               <entry>Transparent</entry>
             </row>
             <row>
               <entry>10</entry>
               <entry>0x00 (Black)</entry>
             </row>
             <row>
               <entry>11</entry>
               <entry>0x0f (White)</entry>
             </row>
           </tbody>
         </tgroup>
       </InformalTable>
   </para>
   </sect2>

   <sect2>
         <title>Color mapping for the SCI1 mouse pointer</title>
   <para>
   Since this method of doing things wastes one combination, the table was changed for
   SCI01 and SCI1:

   <InformalTable frame="all">
         <tgroup cols="2">
           <thead>
             <row>
               <entry>AB</entry>
               <entry>Result</entry>
             </row>
           </thead>
           <tbody>
             <row>
               <entry>00</entry>
               <entry>Transparent</entry>
             </row>
             <row>
               <entry>01</entry>
               <entry>0x0f (White)</entry>
             </row>
             <row>
               <entry>10</entry>
               <entry>0x00 (Black)</entry>
             </row>
             <row>
               <entry>11</entry>
               <entry>0x07 (Light Gray)</entry>
             </row>
           </tbody>
         </tgroup>
       </InformalTable>
  </para>
  </sect2>
 </sect1>


<sect1>
  <Title/The SCI0 View Resource/
   <para>
    In SCI0, Views are collections of images or sprites. Each View resource
    contains a number of groups, which, in turn, contain one or more images.
    Usually, those groups contain a number of consecutive animation frames.
    It appears to be customary to store related animations or images in a
    single frame. For example, the basic movements of all protagonists (four
    or eight animation cycles (depending on the game)) are stored inside of
    a single View resource.
    Please note that the byte order of the following data is always little endian.

 </para>
 <sect2>
   <Title/The View Resource/
 <para>
 <VariableList>
   <VarListEntry><Term>0x00 - 0x01
      </Term><ListItem><para>
        The number of image groups available.
      </para>
   </ListItem></VarListEntry><VarListEntry><Term>0x02 - 0x03
      </Term><ListItem><Para>
        A bitmask containing the 'mirrored' flag for each of the groups,
        with the LSB containing the 'mirrored' flag for group 0.
      </para>
   </ListItem></VarListEntry><VarListEntry><Term>0x04 - 0x07
      </Term><ListItem><Para>
        - unknown -
      </para>
   </ListItem></VarListEntry><VarListEntry><Term>0x08...
      </Term><ListItem><Para>
        A list of indices pointing to the start of the cell list for each
        image group. The number of entries is equal to the number of cells
        as described in 0x00 - 0x01.
   </para></ListItem></VarListEntry>
 </VariableList>
 </para>
 </sect2>


 <sect2>
   <Title/Cell List/
 <para>
  <VariableList>
    <VarListEntry><Term>0x00 - 0x01
       </Term><ListItem><Para>
         The number of image cells available for this group.
       </para>
    </ListItem></VarListEntry><VarListEntry><Term>0x02 - 0x03
       </Term><ListItem><Para>
         - unknown -
       </para>
    </ListItem></VarListEntry><VarListEntry><Term>0x04...
       </Term><ListItem><Para>
         A list of 16 bit pointers indexing the start of the image cell
         structure for each image cell. The pointers are relative to the
         beginning of the resource data.
    </para></ListItem></VarListEntry>
  </VariableList>
 </para>
 </sect2>


 <sect2><Title/Image Cell/
 <para>
 <VariableList>
   <VarListEntry><Term>0x00 - 0x01
      </Term><ListItem><Para>
        The horizontal (X) size of the image.
      </para>
   </ListItem></VarListEntry><VarListEntry><Term>0x02 - 0x03
      </Term><ListItem><Para>
        The vertical (Y) size of the image.
      </para>
   </ListItem></VarListEntry><VarListEntry><Term>0x04
      </Term><ListItem><Para>
        The x placement modifier. This signed value determines the number of pixels a
        view cell is moved to the right before it is drawn.
      </para>
   </ListItem></VarListEntry><VarListEntry><Term>0x05
      </Term><ListItem><Para>
        The y placement modifier. This signed value determines the number of pixels a
        view cell is moved downwards before it is drawn.
      </para>
   </ListItem></VarListEntry><VarListEntry><Term>0x06
      </Term><ListItem><Para>
        The color key, i.e. the color number used for transparency in
        this cell.
      </para>
   </ListItem></VarListEntry><VarListEntry><Term>0x07...
      </Term><ListItem><Para>
        A list of combined color/repeat count entries. Each byte contains
        a color entry (low nibble) and a repeat count (high nibble).
        If the color is equal to the color key from index 0x06, then
        no drawing should be performed, although [repeat] pixels still need
        to be skipped. It is not known whether this list is terminated;
        the FreeSCI drawing algorithm stops drawing as soon as the rectangle
        defined in the first two cell entries has been filled.
   </para></ListItem></VarListEntry>
 </VariableList>
 </para>
 </sect2>
</sect1>
<sect1>
  <title>The SCI font resource</title>
  <para>
    SCI font resources remained unchanged during the SCI revisions and were still
    used in SCI32. Their format is relatively straightforward and completely
    sufficient for any 8 or even 16 bit character table:
  </para>
  <para>
    <table frame="all">
      <title>The SCI font resource data structure</title>
      <tgroup cols="2">
	<thead>
	  <row>
	    <entry>Offset</entry>
	    <entry>Type</entry>
	    <entry>Meaning</entry>
	  </row>
	</thead>
	<tbody>
	  <row>
	    <entry>0</entry>
	    <entry>16 bit integer, little endian encoding</entry>
	    <entry>Always zero (?)</entry>
	  </row>
	  <row>
	    <entry>2</entry>
	    <entry>16 bit integer, little endian encoding</entry>
	    <entry>NUMCHAR: Number of characters</entry>
	  </row>
	  <row>
	    <entry>4</entry>
	    <entry>16 bit integer, little endian encoding</entry>
	    <entry>HEIGHT: Number of pixel lines per text line</entry>
	  </row>
	  <row>
	    <entry>6 + NR * 2</entry>
	    <entry>16 bit integer, little endian encoding</entry>
	    <entry>Absolute offset of the character #NR, where 0 &lt;= NR &lt NUMCHAR</entry>
	  </row>
	</tbody>
      </tgroup>
    </table>
  </para>
  <para>
    HEIGHT does not affect the height of a character, though- it only tells the
    interpreter how far to move downwards when displaying a line of text. The
    characters referenced to starting at offset 6 are encoded as follows:
    <table frame="all">
      <title>The SCI font resource character data structure</title>
      <tgroup cols="2">
	<thead>
	  <row>
	    <entry>Offset</entry>
	    <entry>Type</entry>
	    <entry>Meaning</entry>
	  </row>
	</thead>
	<tbody>
	  <row>
	    <entry>0</entry>
	    <entry>unsigned 8 bit integer</entry>
	    <entry>character HEIGHT</entry>
	  </row>
	  <row>
	    <entry>1</entry>
	    <entry>unsigned 8 bit integer</entry>
	    <entry>character WIDTH</entry>
	  </row>
	  <row>
	    <entry>2...</entry>
	    <entry>bitmask, size HEIGHT * round_up(WIDTH / 8)</entry>
	    <entry>Bitmask for the character</entry>
	  </row>
	</tbody>
      </tgroup>
    </table>
    The bitmap consists of HEIGHT lines of n bytes, where n equals the number
    of bytes required for storing WIDTH bits. Data is stored with the MSB first,
    in little-endian encoding (first byte describes the 8 leftmost pixels), where
    a pixel is drawn iff the bit it corresponds to is set.
  </para>
</sect1>
<sect1>
  <title>The SCI0 and SCI01 pic resource</title>
  <para>
    The pic (background picture) resource format used in SCI0 is rather complex in comparison
    to the other graphical resource formats. It is best described as a sequence of drawing
    operations on a set of four 320x200 canvases, three of which are later used in the game
    (visual, priority, and control), and one of which is used during the drawing process for
    auxiliary purposes<footnote><para>
    Due to the vector graphics nature of these drawing operations, they are inherently more scaleable
    than pixmaps.
    </para></footnote>
  </para>
  <para>
    In order to describe the process, we will first need to define a set of operations
    we base them on:
    <programlisting>
FUNCTION peek_input(): Byte; /* returns the byte pointed to by the input pointer */
FUNCTION get_input(): Byte; /* works like peek_input(), but also increminates the 
                            ** input pointer  */
FUNCTION skip_input(x): Byte; /* skips x input bytes */
      </programlisting>
      Using these pre-defined functions, we will now define additional helper functions used for reading
      specifically encoded data tuples:
      <programlisting>
FUNCTION GetAbsCoordinates(): (Integer, Integer)
VAR
	x, y, coordinate_prefix : Integer;
BEGIN
	coordinate_prefix := get_input();
	x := get_input();
	y := get_input();
	x |= (coordinate_prefix & 0xf0) << 4;
	y |= (coordinate_prefix & 0x0f) << 8;

	RETURN (x,y)
END


FUNCTION GetRelCoordinates(x : Integer, y: Integer): (Integer, Integer)
VAR
	input : Integer;
BEGIN
	input := get_input();
	IF (input & 0x80) THEN
	        x -= (input >> 4);
	ELSE
		x += (input >> 4);
	FI

	IF (input & 0x08) THEN
		y -= (input & 0x7);
	ELSE
		y += (input & 0x7);
	FI

	RETURN (x,y)
END

      </programlisting>
      We also need some data types based on EGACOLOR and PRIORITY, which can be thought of as integers:
      <programlisting>
TYPE Palette = ARRAY[0..39] of EGACOLOR[0..1]
TYPE Priority_Table = ARRAY[0..39] of PRIORITY

Palette default_palette =
     &lt;(0,0), (1,1), (2,2), (3,3), (4,4), (5,5), (6,6), (7,7),
      (8,8), (9,9), (a,a), (b,b), (c,c), (d,d), (e,e), (8,8),
      (8,8), (0,1), (0,2), (0,3), (0,4), (0,5), (0,6), (8,8),
      (8,8), (f,9), (f,a), (f,b), (f,c), (f,d), (f,e), (f,f),
      (0,8), (9,1), (2,a), (3,b), (4,c), (5,d), (6,e), (8,8)&gt;;

#define DRAW_ENABLE_VISUAL   1
#define DRAW_ENABLE_PRIORITY 2
#define DRAW_ENABLE_CONTROL  4

#define PATTERN_FLAG_RECTANGLE 0x10
#define PATTERN_FLAG_USE_PATTERN 0x20
      </programlisting>
      And now for the actual algorithm:
      <programlisting>
FUNCTION DrawPic (cumulative, fill_in_black : Boolean; default_palette: Integer; visual_map, priority_map, control_map, aux_map : Map): Map^4
VAR
	palette : Array [0..3] of Palette;
	drawenable, priority, col1, col2, pattern_nr, pattern_code : Integer;
BEGIN
	palette := (default_palette × 4);
	drawenable := DRAW_ENABLE_VISUAL | DRAW_ENABLE_PRIORITY
	priority := 0;
	col1 := col2 := 0;
	pattern_nr := 0;
	pattern_code := 0;

	IF (!cumulative) THEN BEGIN
		visual_map := (0xf × 320 × 200);
		map control := map priority := map aux := (0 × 320 × 200);
	END

	FOREVER DO BEGIN

		opcode := get_input();

		COND opcode:
			0xf0 &rarr; /* PIC_OP_SET_COLOR */
				code := get_input();
				(col1, col2) := palette[default_palette + (code / 40)][code % 40];
				drawenable |= DRAW_ENABLE_VISUAL;

			0xf1 &rarr; /* PIC_OP_DISABLE_VISUAL */
				drawenable &= ~DRAW_ENABLE_VISUAL;

			0xf2 &rarr; /* PIC_OP_SET_PRIORITY */
				code := get_input();
				priority := code & 0xf;
				drawenable |= DRAW_ENABLE_PRIORITY;

			0xf3 &rarr; /* PIC_OP_DISABLE_PRIORITY */
				drawenable &= ~DRAW_ENABLE_PRIORITY;

			0xf4 &rarr; /* PIC_OP_RELATIVE_PATTERNS */
				IF (pattern_code & PATTERN_FLAG_USE_PATTERN) THEN
					pattern_nr := (get_input() &gt;&gt; 1) & 0x7f
				FI

				(x,y) := GetAbsCoordinates();

				DrawPattern(x, y, col1, col2, priority, control, drawenable,
						 pattern_code & PATTERN_FLAG_USE_PATTERN,
						 pattern_size, pattern_nr, pattern_code & PATTERN_FLAG_RECTANGLE);

				WHILE (peek_input() < 0xf0) DO BEGIN
					IF (pattern_code & PATTERN_FLAG_USE_PATTERN) THEN
						pattern_nr := (get_input() &gt;&gt; 1) & 0x7f
					FI
					(x,y) =  GetRelCoordinates(x,y);
					DrawPattern(x, y, col1, col2, priority, control, drawenable,
							 pattern_code & PATTERN_FLAG_USE_PATTERN,
							 pattern_size, pattern_nr, pattern_code & PATTERN_FLAG_RECTANGLE);
				END

			0xf5 &rarr; /* PIC_OP_RELATIVE_MEDIUM_LINES */
				(oldx, oldy) := GetAbsCoordinates();
				WHILE (peek_input() &lt; 0xf0) DO BEGIN
					temp := get_input();
					IF (temp & 0x80) THEN
						y := oldy - (temp & 0x7f)
					ELSE
						y := oldy + temp
					FI
					x = oldx + get_input();
					 DitherLine(oldx, oldy, x, y, col1, col2, priority, special, drawenable);
					(oldx, oldy) := (x, y);
				END

			0xf6 &rarr; /* PIC_OP_RELATIVE_LONG_LINES */
				(oldx, oldy) :=  GetAbsCoordinates()
				WHILE (peek_input() &lt; 0xf0) DO BEGIN
					(x, y) := GetAbsCoordinates();
					DitherLine(oldx, oldy, x, y, col1, col2, priority, special, drawenable);
					(oldx, oldy) := (x, y);
				END

			0xf7 &rarr; /* PIC_OP_RELATIVE_SHORT_LINES */
				(oldx, oldy) =  GetAbsCoordinates()
				WHILE (peek_input() &lt; 0xf0) DO BEGIN
					(x, y) := GetRelCoordinates(oldx, oldy);
					DitherLine(oldx, oldy, x, y, col1, col2, priority, special, drawenable);
					(oldx, oldy) := (x, y);
				END

			0xf8 &rarr; /* PIC_OP_FILL */
				IF (fill_in_black) THEN
					(oldc1, oldc2) := (c1, c2);
				FI

				WHILE (peek_unput() &lt; 0xf0) DO BEGIN
					(x, y) := GetAbsCoordinates();
					DitherFill(x, y, col1, col2, priority, special, drawenable);
				END

				IF (fill_in_black) THEN
					(c1, c2) := (oldc1, oldc2);
				FI

			0xf9 &rarr; /* PIC_OP_SET_PATTERN */
				pattern_code := get_input() & 0x37;
				pattern_size := pattern_code & 0x7;

			0xfa &rarr; /* PIC_OP_ABSOLUTE_PATTERNS */
				WHILE (peek_input() &lt; 0xf0) DO
					IF (pattern_code & PATTERN_FLAG_USE_PATTERN)
						pattern_nr := (get_input() >> 1) & 0x7f
					FI
					(x, y) := GetAbsCoordinates();
					DrawPattern(x, y, col1, col2, priority, control, drawenable,
							 pattern_code & PATTERN_FLAG_USE_PATTERN,
							 pattern_size, pattern_nr, pattern_code & PATTERN_FLAG_RECTANGLE);
					END

			0xfb &rarr; /* PIC_OP_SET_CONTROL */
				control := get_input() & 0x0f;
				drawenable |= DRAW_ENABLE_CONTROL;

			0xfc &rarr; /* PIC_OP_DISABLE_CONTROL */
				drawenable &= ~DRAW_ENABLE_CONTROL;

			0xfd &rarr; /* PIC_OP_RELATIVE_MEDIUM_PATTERNS */
				IF (pattern_code & PATTERN_FLAG_USE_PATTERN) THEN
					pattern_nr := (get_input() &gt;&gt; 1) & 0x7f;
				FI

				(oldx, oldy) := GetAbsCoordinates();

				DrawPattern(x, y, col1, col2, priority, control, drawenable,
						 pattern_code & PATTERN_FLAG_USE_PATTERN,
						 pattern_size, pattern_nr, pattern_code & PATTERN_FLAG_RECTANGLE);

				WHILE (peek_input() &lt; 0xf0) DO BEGIN
					IF (pattern_code & PATTERN_FLAG_USE_PATTERN) THEN
						pattern_nr := (get_input() &gt;&gt; 1) & 0x7f;
					FI
			
					temp := get_input();
					IF (temp & 0x80)
						y := oldy - (temp & 0x7f)
					ELSE
						y := oldy + temp
					FI
					x := oldx + get_input();
					DrawPattern(x, y, col1, col2, priority, control, drawenable,
							 pattern_code & PATTERN_FLAG_USE_PATTERN,
							 pattern_size, pattern_nr, pattern_code & PATTERN_FLAG_RECTANGLE);
				END

			0xfd &rarr; /* PIC_OP_OPX */
				COND get_input():
					0x00 &rarr; /* PIC_OPX_SET_PALETTE_ENTRY */
						WHILE peek_input() &lt; 0xf0 DO BEGIN
							index := get_input();
							color := get_input();
							palette[index / 40][color % 40] := color;
						END

					0x01 &rarr; /* PIC_OPX_SET_PALETTE */
						palette_number := get_input();
						FOR i := 0 TO 39 DO
							palette[palette_number][i] := get_input();
						OD

					0x02 &rarr; /* PIC_OPX_MONO0 */
						skip_input(41);

					0x03 &rarr; /* PIC_OPX_MONO1 */
						skip_input(1);

					0x04 &rarr; /* PIC_OPX_MONO2 */
					0x05 &rarr; /* PIC_OPX_MONO3 */
						skip_input(1);

					0x06 &rarr; /* PIC_OPX_MONO4 */
					0x07 &rarr; /* PIC_OPX_EMBEDDED_VIEW */ /* SCI01 operation */
					0x08 &rarr; /* PIC_OPX_SET_PRIORITY_TABLE */ /* SCI01 operation */

			0xff &rarr; return (visual, control, priority, aux);
		END OF COND
      END
END
      </programlisting>
      This algorithm uses three auxiliary algorithms, DrawPattern, DitherLine, and DitherFill, which are sketched below. All of
      these functions are supposed to take the four maps as implicit parameters.
      <programlisting>
PROCEDURE DrawPattern(x, y, col1, col2, priority, control, drawenable : Integer;  solid : Boolean ;  pattern_size, pattern_nr : Integer; rectangle : Boolean)

Alters (x,y) so that 0 &lt;= (x - pattern_size), 319 &gt;= (x + pattern_size), 189 &gt;= (y + pattern_size) and
0 &lt;= (y - pattern_size), then draws a rectangle or a circle filled with col1, col2, priority, control,
as determined by drawenable.
If rectangle is not set, it will draw a rectangle, otherwise a circle of size pattern_size.
pattern_nr is used to specify the start index in the random bit table (256 random bits)



PROCEDURE DitherLine(x, y, xend, yend, color1, color2, priority, control, drawenable : Integer)

Draws a dithered line between (x, y+10) and (xend, yend+10). If the appropriate drawenable flags
are set, it draws 'priority' to the priority map, 'control' to the control map, and 'color1' and 'color2'
(alternating) to the visual map. The auxiliary map is bitwise-or'd with the drawenable flag while this is
done.



PROCEDURE DitherFill(x, y, col0, col1, priority, control, drawenable : Integer)
Fills all layers for which drawenable is set with the appropriate content.
Diagonal filling is not allowed.
Boundaries are determined as follows:
x&lt;0, x&gt;319, y&lt;10, y&gt;199 are hard boundaries. We now determine the
'boundary map' bound_map and the allowed color legal_color.
If bound_map[coordinates] = legal_color, then the pixel may be filled.

IF (drawenable & DRAW_ENABLE_VISUAL)
	bound_map = visual;
	legal_color = 0xf;
ELSIF (drawenable & DRAW_ENABLE_PRIORITY)
	bound_map = priority;
	legal_color = 0;
ELSIF (drawenable & DRAW_ENABLE_CONTROL)
	bound_map = control;
	legal_color = 0;
ELSE
	return;
FI
      </programlisting>


</sect1>
<sect1 ID="LarsWindows">
<Title/Windows, Dialogs and Controls/
<para>
by <Author><firstname/Lars/<surname/Skovlund/</Author></para><para>
Version 1.0, 7. July 1999
</para><para>
I am going to start by mentioning the menus. It has nothing to do with the
material I deal with in this essay. They use different kernel calls, and
such things as port management are handled internally by the kernel 
routines.
The SCI program just sets up a menu structure using the kernel calls.
Since they are irrelevant to the subject of this essay, I will not spend 
more
time on them.
</para><para>
The Rect structure is important (also to ports) since it is the basis for
passing a screen position to the interpreter. It looks like this:
</para><para>
<programlisting>
typedef struct
{
  short top, left, bottom, right;
}
</programlisting>
</para><para>
It will be seen from this that rectangle coordinates in SCI are not normally
 represented in the usual (x,y,width,height) fashion. So pay close attention
 to this structure! Also, it is not passed as a pointer, but rather as
the four values in order. This is particularly true of SCI objects, where
the property names nsTop etc. actually form a Rect structure which can be
used directly by the interpreter.
</para><para>
Windows are created using the KNewWindow kernel function. Each window has
six attributes which are passed from the script to the kernel function:
</para><para>
<simplelist>
<member/Bounding rectangle/
<member/Title/
<member/Type/
<member/Priority/
<member/Foreground color/
<member/Background color/
</simplelist>
</para><para>
Of these, the type and priority are the most interesting, because they 
decide
the appearance of the window. The type is a bit field:
</para><para>
<simplelist>
<member/bit 0 - transparency/
<member/bit 1 - window does _not_ have a frame/
<member/bit 2 - the window has a title/
<member/bit 3-6 - unused/
<member/bit 7 - see below/
</simplelist>
</para><para>
Bit 0 specifies a transparent window. KNewWindow does not save the image
behind the created window - it stays on the screen until the pic is redrawn,
so windows with this style definitely can't be used as message boxes. It 
does
have some special uses, though. If this bit is not set, KNewWindow draws
a rectangle in the specified background color using the bounding rectangle
coordinates (using the WM port). When this bit is set,
</para><para>
Bit 1 specifies a window without a frame. The frame is the black shading you
can see in the corner of a message box.
</para><para>
Bit 2 tells KNewWindow to draw a grey title bar with a title printed in
white. In the version I have used for this essay, it is not possible to
change the title bar colors. Note that the bounding rectangle is always
specified as if the window had no title bar. If this bit is set, ten pixels
are reserved above the coordinates specified. Although this bit is set,
the Title parameter may still be NULL. If this is the case, an empty title
bar is drawn.
</para><para>
Bit 7 has a special meaning; it is used only in window type 0x81, and is not
tested in any other way. When this style is chosen, KNewWindow does not
draw anything at all. It is the caller's responsibility to draw a
window frame on the WM port. CB1 uses this style for its ornate windows,
and draws the frame manually.
</para><para>
The picture window which I mentioned in the last article is created using
style 3 (that is, TRANSPARENT | NOFRAME). The normal message box styles used
in LSL3 are 0 and 4.
</para><para>
I have not been able to investigate the priority property yet, so the fol-
lowing is based on suppositions. It is only used when drawing transparent
windows. In this case, if priority is not -1 (which means not used), the
window is drawn onto the priority map (with the specified priority value) as
well as the screen.
</para><para>
There is a class called SysWindow which is just a simple wrapper around the
following two kernel calls. Try breaking on SysWindow::open, then type c
to inspect the current object. You can change all the parameters to KNewWin-
dow (the Rect is split in its fields, to nsTop, nsLeft etc.)
</para><para>
To create a window structure, use KNewWindow (see <XREF LINKEND="KNewWindow">);
to remove it again, apply KDisposeWindow (see <XREF LINKEND="KDisposeWindow">) on
it.
</para><para>
So how do we put stuff inside these windows? That question is a little com-
plicated to answer, because it is really a shared effort between the inter-
preter and the object hierarchy, and this is one case where the interpreter
actually interacts with the objects itself. I will start by explaining the
classes involved.
</para><para>
All control types are descendants of a common class (I do not know its name,
since it appears to have an invalid name property). Among other things, this
common class contains a type number and a state. The type number is the only
thing that distinguishes the control types from each other inside the
interpreter - if a wrong type is set, the interpreter might try to change
a non-existent property.
</para><para>
The type numbers are laid out as follows:
<simplelist>
<member/  1 - Button control/
<member/  2 - Text control/
<member/  3 - Edit control/
<member/  4 - Icon control/
<member/  5 - not used/
<member/  6 - Selector control (as in the Save and Restore boxes)/
</simplelist>
The gauge "controls" are not really controls. I don't know how they work
(yet).
</para><para>
Each control also has a state value. These are laid out as follows:
<simplelist>
<member/bit 0 - selectable. If this bit is set, the control can be selected using 
the
Tab key. Except for the text and icon controls, all controls are selectable./
<member/bit 1 - unknown. Always set, except for the text and icon controls/
<member/bit 2 - disabled. When this bit is set, a button is grayed out. No other
control types are affected./
<member/bit 3 - selected. When this bit is set, a frame is drawn around the control./
</simplelist>
Note that state 3 is by far the most common.
With that explained, I'll move on to the kernel functions. There are three
functions associated with controls - KDrawControl (see <XREF LINKEND="KDrawControl">),
KHiliteControl (see <XREF LINKEND="KHiliteControl">) and
KEditControl (see <XREF LINKEND="KEditControl">).
 Note that there is a KOnControl kernel call which is entirely
unrelated to window management.
</para><para>
The dialogs are implemented using not one, but two classes - Dialog and
Window. While the Window class maintains the window (It is derived from
SysWindow), the Dialog class is just a list of controls. It is derived from
the List class, but has extended functionality to tell its members to redraw
etc. There is a special function, located in script 255, which allows
scripts to push information about the dialog on the stack instead of 
creating
the Dialog object manually.
</para><note><para>
Note that the internal debugger uses the same window calls as the SCI 
script.
That is why the screen messes up if you step through drawing code - the debugger has
 activated the Debug window port, and "forgets" to switch back
while stepping across instructions. Thus, all graphics commands are
redirected to the debug window port. Not a pretty sight.

</para></note>
</sect1>
<sect1 ID="LARSPICSANDMOVEMENT">
  <Title/Pictures and movement control/
   <para>By<author><firstname/Lars/<surname/Skovlund/</author></para>
   <para/Version 1.0, 24. July 1999/
   <para>
A pic in SCI consists of three layers (called maps - they are unrelated to
the map resources found in SCI1 games). The visual map, used for the
picture which appears on the user's screen. The priority map which tells the
interpreter which things go in front of which in the three-dimensional room.
Without the priority map, a room would just be a flat, painted surface.
The control map decides where game characters (called actors) can walk and
where special events occur. These special events are triggered by a game
character walking on a particular spot. Where the visual map is almost
always very complex and using dithered fills etc., the latter two consist of
large areas of solid color.
</para><para>
Many functions which need to access these maps do so by using a bit-field.
The bits are laid out as follows (but don't set more than one at a time!)
<simplelist>
<member/bit 0 - Visual/
<member/bit 1 - Priority/
<member/bit 2 - Control/
</simplelist>
</para><para>
It is important to understand that, although being represented as colors on
the screen, a priority/control "color" should be considered a number.
The colors map to values according to the standard EGA color values.
</para><para>
Every animated object in SCI has a priority. As the object moves, its pri-
ority changes according to the so-called priority bands, explained next
(it is, however, possible for a script to lock the priority of a view).
The picture window is divided vertically into 16 priority bands. The
priority of an animated object is determined by the position of its
"base rectangle" in one of these bands. Things are drawn in order of
ascending priority, so objects with priority 15 are guaranteed to be in 
front
of everything else. The default priority mapping gives priority 0 a fairly
large space, the 42 topmost rows (including the menu bar which AFAIK is 10) 
in the picture. All other priority
bands have the same size. A script can choose to alter this mapping,
specifying the amount of space to assign to priority 0, and the number of 
the
last row to include in the mapping calculation.
</para><para>
In most rooms, it is desirable to limit actor movement, confining the
actor to a specific part of the screen. In other cases, special events
are triggered by movement into a specific screen area. On some occasions,
even room switches are implemented using control polygons. While the meaning
of priorities is determined by the kernel, the meaning of control values
is entirely up to the script. It is more or less a standard, however, that
actors can't walk on white control areas.
</para><para>
As the control map is not consulted by the interpreter itself (except in a
few cases), scripts need a way to do so. That way is called OnControl, and
it is a kernel call. Supplied with a point or a rectangle, it returns a bit
mask containing the control values of all the pixels in the desired region.
If a specific control value is encountered, it is used as a bit number, and
that bit is set in the output mask.
</para><para>
This bit mask system is also used in another place, namely the illegalBits
selector of the Act (actor) class. The illegalBits selector determines in
which areas the actor may not walk.
</para><para>
The OnControl() system call is explained in <XREF LINKEND="KONCONTROL">.
</para>
</sect1>
</chapter>

<Chapter>
  <Title/The Sound subsystem/
   <sect1>
     <Title/The SCI0 Sound Resource Format/
     <para> by <author><firstname/Ravi/<surname/Iyengar/</author>
     </para><para>
	Revision 10, Mar. 11, 2002
	</para>
	<sect2><Title/Preface/
	<para>
	   Sierra's SCI0 sound resources contain the music and sound effects played
	   during the game. With the introduction of SCI, the company took advantage of
	   new sound hardware which allowed for far better music than the traditional
	   PC speaker could ever create. Sierra chose two devices to specifically
	   target: the MT-32, and the Adlib. The MT-32 is a MIDI synth while the
	   Adlib is a less expensive card based around the OPL2, a non-MIDI chip.
	   Anyone interested in Sierra music and its history can find information at
	   the Sierra Soundtrack Series (http://www.queststudios.com).
	</para><para>
	   Music is stored as a series of MIDI events, and the sound resource is
	   basically just a MIDI file. The MIDI standard and device implementations
	   are not covered here in detail, but specifications should be readily
	   available elsewhere.
	</para><para>
	   SCI0 Sound resources can also contain digital samples, although an SCI
	   remake of KQ1 is the only DOS game I know of that includes them. These files
	   still contain MIDI data, but the wave data is appended at the end. The MIDI
	   data is an approximation of the sound effect for hardware that can't play
	   digital sound.
	</para><para>
	   Some people prefer the one-based numbering system for channel and program
	   numbers. I personally prefer the zero-based system, and use it here. If
	   you're familiar with channels 1-16, be aware that I will call them 0-15.
	   My intention is not to be deviant from other programs but to be more
	   accurate in representing the way information gets stored. The same is true
	   for programs 0-127 as opposed to 1-128. For whatever reason, convention
	   already holds that controls be numbered 0-127, so nothing in my treatment
	   of them should be abnormal.
	</para><para>
	   Sierra changed its sound file format in the switch to SCI1. I refer only
	   to SCI0 sound files in this specification. Hybrid interpreters such as
	   the one used for Quest for Glory II are also excluded. Finally, SCI games
	   written for non-DOS systems may have different formats. This document
	   applies to Sierra's IBM games.
	</para><para>
	   Please post comments or questions to the SCI webboard:
	      http://pub48.bravenet.com/forum/show.asp?usernum=4071584210
	</para><para>
	   You can contact me personally at ravi.i@softhome.net, but I would prefer
	   that SCI messages be posted on the webboard so everyone can see them.
	</para>
	</sect2><sect2><Title/Sound Devices/
	<para>
	   A gamer's sound hardware greatly affects how music will sound. Devices
	   used by SCI0 can be broken into general categories:
	<variablelist>
		<varlistentry><term>MIDI Synths</term><listitem><para>
		   These will generally give the best sound quality. MIDI
                   synths are polyphonic with definable instruments through
                   patch files and full support for MIDI controls. The
                   General MIDI standard had not been written when Sierra
                   began writing SCI games, and as far as I know no SCI0 game
                   uses a GM driver or includes a GM track. This means that
                   synths had to be individually supported.
		</para></listitem></varlistentry>

		<varlistentry><term>Non-MIDI Synths</term><listitem><para>
		   Generally not as good as MIDI synths, but also less
                   expensive. The OPLx family of chips are still very common
                   among home PC users thanks to the Adlib and SoundBlaster
                   cards. Synths are polyphonic with definable instruments
                   through patch files, but drivers must be written to
                   interpret MIDI events and turn them into commands the
                   hardware will recognize. Support for most sound controls
                   gets lost in the process. Furthermore, drivers must map
                   logical, polyphonic MIDI channels to physical, monophonic
                   hardware channels. A control (4Bh) was introduced for this
                   purpose and will be discussed later.
		</para></listitem></varlistentry>

		<varlistentry><term>Beepers</term><listitem><para>
		   Beepers produce very poor music and don't support instrument
                   definitions, but all PC users have one so supporting them
                   covers people without special sound hardware. The most
                   common device is the PC speaker, which is monophonic.
                   Another is the Tandy speaker with 3 channels. Drivers must
                   interpret MIDI events, but need only concern themselves
                   with basic functionality. Interpreting the MIDI events is
                   also made easier because each channel is monophonic. To
                   play a chord on the Tandy, for example, each voice must be
                   put in a separate MIDI channel.
		</para></listitem></varlistentry>

		<varlistentry><term>Wave Devices</term><listitem><para>Wave devices play digital sound data. Sierra's versions of
                   SCI never used them to play music, but they could be used in
                   conjunction with one of the above devices to add special
                   sound effects to a game.
		</para></listitem></varlistentry>

	</variablelist>
	</para><para>
	   With such a diverse group of devices to support, Sierra put a lot of the
	   work on the shoulders of the drivers. Functions for loading patch files,
	   handling events, pausing, etc. are all in the drivers. The interpreter
	   calls them as needed but does not concern itself at all with how they
	   get implemented.
	</para><para>
	   Listed here are devices supported by the SCI0 interpreter with a little
	   information about each. There could very well be other hardware not listed
	   here, so please send in any missing information.
	  </para><para>
	   <informaltable frame="all">
	    <tgroup cols="5">
	     <thead><row>
	      <entry/Device Name/
	      <entry/Driver/
	      <entry/Patch/
	      <entry/Poly/
	      <entry/Flag/
	     </row></thead>
	     <tbody>
	      <row>
	      <entry/    Roland MT-32      /<entry/  mt32    /<entry/   001   /<entry/   32   / <entry/01h/
	     </row><row>
	      <entry/        Adlib         /<entry/  adl     /<entry/   003   /<entry/   9    /<entry/04h/
	     </row><row>
	      <entry/     PC Speaker       /<entry/  std     /<entry/    *    /<entry/   1    /<entry/20h/
	     </row><row>
	      <entry/  Tandy 1000 or PCJr   /<entry/  jr      /<entry/    *    /<entry/   3    /<entry/10h/
	     </row><row>
	      <entry/  Tandy 1000 SL, TL   /<entry/  tandy   /<entry/    *    /<entry/   3    /<entry/10h/
	     </row><row>
	      <entry/  IBM Music Feature   /<entry/  imf     /<entry/   002   /<entry/   8    /<entry/+/
	     </row><row>
	      <entry/    Yamaha FB-01      /<entry/  fb01    /<entry/   002   /<entry/   8    /<entry/02h/
	     </row><row>
	      <entry/  CMS or Game Blaster  /<entry/  cms     /<entry/   101   /<entry/   12   /<entry/04h/
	     </row><row>
	      <entry/  Casio MT540 or CT460   /<entry/  mt540   /<entry/   004   /<entry/   10   /<entry/08h/
	     </row><row>
	      <entry/     Casio CSM-1      /<entry/          /<entry/   007   /<entry/        /<entry//
	     </row><row>
	      <entry/  Roland D110,D10,D20   /<entry/          /<entry/   000   /<entry/        /<entry//
	     </row><row>
	      <entry/  PAULA (Amiga)   /<entry/          /<entry/      /<entry/        /<entry/40h/
	      </row>
	     </tbody>
	    </tgroup>
	   </informaltable>
	              (thanks to Shane T. for providing some of this).
	              Blank fields are unknown, not unused.
	   <simplelist>
	            <member/*  when asked which patch to load, the PC and Tandy
	                  speaker drivers return FFFFh, which is a signal
	                  that they do not use patches/
	            <member/+ the imf driver almost certainly uses 02h for the play
                  flag, but I haven't confirmed this/

	   </simplelist>
	</para><para>
	  The driver column holds the file name of each driver without the .drv
	  extension. The patch column specifies which patch resource each driver
	  requests. The poly column is the maximum number of voices which can be
	  played at once according to the driver. The flag column gives each
	  device's play flag. Play flags, explained in the header section, determine
	  which channels a device will play.
	</para>
	</sect2><sect2><Title/File Format/
	<para>
	   Sound files follow the same format as all extracted SCI0 resources. The
	   first two bytes of the file contain a magic number identifying the
	   resource type. The rest of the file contains a dump of the uncompressed
	   data. The identifier is the resource type (04h for sound) OR-ed with 80h
	   and stored as a word. The result will be 84h 00h in extracted sound files.
	</para><para>
	   The sound resource data itself is a header with channel initialization
	   followed by a series of MIDI events.
	</para>
	<sect3><Title/Header/
		<para>
		   The header provides the sound driver with 2 pieces of information about
		   each channel. The first is a byte which specifies how many voices each
		   logical MIDI channel will be playing. For MIDI synths, this information is
		   not really necessary and is probably ignored. The same goes for beepers.
		   This byte is only useful for non-MIDI synths which must know how many
		   hardware channels each logical MIDI channel will need. This value is only
		   an initial setting. Sound files can request changes to the mapping later
		   with control changes. Requesting more hardware channels than are actually
		   available can cause errors on some drivers.
		</para><para>
		   The second byte describes how the user's sound hardware should treat the
		   channel. It is the combination of bit flags which may be OR-ed together.
		   If the appropriate bit is set for the currently selected sound device, the
		   channel will be played. If it is not, the channel will be silent. The
		   driver decides which bit it will use as the play flag, and the table under
		   Sound Devices lists the flag used by each driver. Drivers ignore the first
		   byte (used to request hardware channels) on MIDI channels they don't play.
		</para><para>
		   The MT-32 always plays channel 9, the MIDI percussion channel, regardless
		   of whether or not the channel is flagged for the device. Other MIDI
		   devices may also do this.
		</para><para>
		   A byte at the beginning of the file, before channel initialization,
		   specifies whether the resource contains a digital sample or not. A value of
		   0 means that there is only MIDI data. A value of 2 means that there is a
		   digital sample at the end of the file. In this case, only the first 15 MIDI
		   channels have header bytes. The two header bytes for the last channel is
		   replaced with an offset to the digital sound effect. The offset is stored
		   in big-endian order in the resource. If present, it points to the last byte
		   before the digital sample header. If the offset is 0, the file must be
		   searched for the status FCh, and the digital sample header will come next.
		   There may be two FCh bytes in a row, in which case both will come before
		   the digital sample header. The digital sample header is discussed in more
		   detail in the digial sample section.
		</para><para>
		   The header format:
		   <simplelist>
		      <member/1 byte  - digital sample flag (0 or 2)/
		      <member/2 bytes - initialization for channel 0/
		      <member/2 bytes - initialization for channel 1/
		      <member/./
		      <member/./
		      <member/./
		      <member/2 bytes - initialization for channel 15 OR offset to digital sample/
		    </simplelist>
		</para><para>
		   The header is always 33 bytes long.
		</para></sect3><sect3><title/Events/
		<para>
		   The actual music is stored in a series of events. The generic form for an
		   event is:
		<simplelist>
			<member/&lt;delta time&gt; [byte - status] [byte - p1 [p2]]/
		</simplelist>
		</para><para>
		   Delta time is the number of ticks to wait after executing the previous
		  event before executing this event. Ticks occur at 60 Hz. The delta time
		  value is usually a single byte. However, longer delays can be produced by
		  using F8h any number of times before the delta time value. Each F8h byte
		  causes a delay of 240 ticks before continuing playback. For example, the
		  sequence F8 F8 78 FC waits 600 ticks then stops the sequence because of
		  the FCh status. The fact that F8h waits F0h ticks makes me think that E9h
		  is the largest technically allowable delta time.
		</para><para>
		  The delta time must be present in most events. The only exception is when
		  FCh is the status, because FCh is a real-time message. Sierra's resources
		  seem to have always provided a delta time, though. Note also that FCh
		  cannot be used as a delta time value - it will be interpreted as a stop
		  sequence status.
		</para><para>
		   The status byte is basically a command. The most significant bit is always
		   set. This feature is important because the status byte will not always be
		  present. A missing status byte is known as running status mode and the
		  last status gets repreated with the new parameters. Parameters will never
		  have their most significant bits set.
		</para><para>
		  The generic form for a status byte is (in bits) 1xxxcccc. The lower nibble
		  usually specifies a channel. The upper specifies a status.
		</para>
		</sect3><sect3><title/Status Reference/
		<para>
		<variablelist>
			<varlistentry><term/8x n v/<listitem><para/
			    Note off: Stop playing note n on channel x, releasing the key
		            with velocity v. If a hold pedal is pressed, the note will
		            continue to play after this status is received and end when the
		            pedal is released.
			</listitem></varlistentry>

			<varlistentry><term/9x n v/<listitem><para/
			    Note on: Play note n on with velocity v on channel x. Playing a
		            note with velocity 0 is a way of turning the note off./
			</listitem></varlistentry>

			<varlistentry><term/Ax n p/<listitem><para/
			    Key pressure (after-touch): Set key pressure to p for note n on
		            channel x. This is to modify key pressure for a note that is
		            already playing./
			</listitem></varlistentry>

			<varlistentry><term/Bx c s /<listitem><para>
			    Control: Set control c to s on channel x. This can be confusing
		            because there isn't just one meaning. Changing the settings on
		            different controls will, of course, have different outcomes.
			</para><para>
		            Controls which handle any value are continuous controllers. They
		            have a continuous range. Controls which are only on/off are
			    switches. Their defined values are 01h (OFF) and 7Fh (ON).
			</para><para>
		            Listed in this reference are the non-standard MIDI controls I've
		            found in Sierra SCI0 sound files. Standard controls are not
			    listed here. Not all drivers support all controls.
			</para><para>
		            Control Reference
			<variablelist>
				<varlistentry><term/4Bh/<listitem><para/
					Channel mapping: When a channel sets this control, it
		                        tells the driver how many notes it will be playing
		                        at once, and therefore how many hardware channels it
		                        occupies./
				</listitem></varlistentry>

				<varlistentry><term/4Ch/<listitem><para>
					Reset on PauseSound: An on/off switch where a value of
		                        zero is off and a non-zero value is on. Note that
		                        this is not the same as for standard MIDI control
		                        switches. When this control is on, calling the sound
		                        driver's PauseSound subfunction will reset the sound
		                        position to the beginning. The initial value is set
		                        to off when a sound gets loaded.</para>
				</listitem></varlistentry>

               			<varlistentry><term/4Eh/<listitem><para/
					Unknown: Experiments in setting and clearing it show
		                        that a value of 0 will cause notes to be played
		                        without regard for the velocity paramater while a
		                        value of 1 will enable velocities./
				</listitem></varlistentry>

				<varlistentry><term/50h/<listitem><para>
				  Reverb: I know little about this myself. Rickard Lind
				  reports that it exists in the MT-32 driver and
				  supports parameter values 0-10 (possibly 0-16?).
				</para></listitem></varlistentry>

               			<varlistentry><term/60h/<listitem><para/
					Cumulative cue: The interpreter can get cues from the
		                        sound file, which sets the Sound object's signal
		                        property. When a sound gets loaded, the initial cue is
		                        set to 127. When a CC60 occurs, the new control value
		                        is added to the current cue. If the cue were 130, for
		                        example, a CC60 5 on any channel would make the new
		                        cumulative cue equal 135./
				</listitem></varlistentry>
			</variablelist>
			</para></listitem></varlistentry>

			<varlistentry><term/Cx p/<listitem><para>
				  Program change: Set program (patch / instrument / ect.) to p for
				  channel x. This is a simple instrument change.
			</para><para>
			  Channel 15, however, includes two special cases of this status. The
			  first relates to communication with the game interpreter. If p is
			  less than 127 then the signal property for the game interpreter's
			  Sound object gets set to p, triggering a non-cumulative cue.
			</para><para>
			  If p is equal to 127, then the current position within the sound
			  resource is remembered as the loop point. Normally the driver
			  loops to the beginning of the sound when the sequence ends. If an
			  explicit loop point is set, the sound will be replayed from the
			  marked point instead.
			</para><para>
			          The actual time of the loop point is better explained with a short
			          diagram:
				<simplelist>
				      <member/0x10 0x91 0x20 0x20      play a note on channel 1/
			              <member/0x05 0x91 0x20 0x00      stop the previous note/
			              <member/0x00 0x92 0x30 0x10      play a note on channel 2/
			              <member/  [restart here]/
			              <member/0x00 0xCF 0x7F           set loop point/
			              <member/0x00 0xC8 0x05           change to program 5 on channel 8/
			              <member/0x00 0xCF 0x13           set signal to 19/
			              <member/0x20 0xFC                end of file, loop to marked location/
				</simplelist>
			</para><para>
			          In both situations (p < 127 and p = 127), no actual program change
			          takes place. Channel 15 is used for control, not playing music.
			</para></listitem></varlistentry>

   			<varlistentry><term/Dx p/<listitem><para/
				  Pressure (after-touch): Set key pressure to p on channel x. This is
			          similar to Ax but differs in its scope. Message Ax is applied on a
			          per-note basis while message Dx is applied to an entire channel./
			</listitem></varlistentry>

			<varlistentry><term/Ex t b/<listitem><para/
				    Pitch wheel: Set the pitch wheel to tb. The setting is actually
			            a 14 bit number with the least significant 7 bits stored in b
			            and the most significant 7 bits stored in t. The range of values
			  	    is 0000h to 3FFFh. A value of 2000h means that the pitch wheel is
			            centered. Larger values raise pitch and smaller values lower it./
			</listitem></varlistentry>

			<varlistentry><term/F0/<listitem><para>
				Begin SysEx: Starts a system exclusive data block. The block must
			        terminate with F7h.</para>
			</listitem></varlistentry>

			<varlistentry><term/F7/<listitem><para>
				End SysEx: Ends a system exclusive data block. Normal sound data
			        resumes at this point.</para>
			</listitem></varlistentry>

			<varlistentry><term/FC/<listitem><para>
				Stop Sequence: This is a system real-time message which tells the
			        sound driver to stop the current sound. The sound object's signal
			        property gets set to FFFFh and the position moves to the loop point,
			        which defaults to the beginning. Drivers allow this message to occur
			        without a delta time, but I haven't seen any examples.</para>
			</listitem></varlistentry>
		</variablelist>
		</para>
	</sect3>
	</sect2><sect2><title/Digial Samples/
		<para>
	   The digital sample header is 44 bytes long. Offset 14 in the header contains
	   the frequency as a short integer. Offset 32 contains the sample length, also
	   as a short integer. Other fields in the header are unknown (to me) at the
	   time of writing, but aren't critical to playback.
		</para><para>
	   The wave data comes immediately after the header, stored in unsigned 8 bit
	   PCM format.
		</para>
	</sect2><sect2><title/Revision history/
  <para>
  <variablelist>
   <varlistentry><term/Revision 10 - Mar. 11, 2002/
	<listitem><para><itemizedlist>
      <listitem><para>Added section on digital samples (thanks to the FreeSCI developers,
        Rickard Lind especially)</para></listitem>
      <listitem><para>Added wave devices to the hardware category list</para></listitem>
      <listitem><para>Updated header section to cover the header for PCM resources</para></listitem>
      <listitem><para>Added more play flags to the sound driver table</para></listitem>
      <listitem><para>Fixed a typo in the sound driver table where I accidentally called the
        "Yamaha FB-01" the "Yamaha FM-01"</para></listitem>
      </itemizedlist></para></listitem>
    </varlistentry>
    <varlistentry><term/Revision 9 - Jul. 4, 2001/
      <listitem><para><itemizedlist>
	<listitem><para>Changed StopSound to PauseSound for control 4Ch</para></listitem>
	<listitem><para>Updated URL for SCI messageboard</para></listitem>
	<listitem><para>Added web links for more SCI information<footnote>
	  <para>Editor's note: These are not included in the FreeSCI documentation version
	  </para></footnote></para></listitem>
	<listitem><para>Did a little proofreading and editing</para></listitem>
      </itemizedlist></para></listitem>
    </varlistentry>
    <varlistentry><term/Revision 8 - Dec. 21, 2000/
      <listitem><para><itemizedlist>
	<listitem><para>Added suggested limit on delta time values</para></listitem>
	<listitem><para> Fixed hex notation (sometimes listed NNh, sometimes 0xNN)</para></listitem>
	<listitem><para> Removed notice about early revisions' mistake describing the header's
	  channel mapping byte</para></listitem>
	<listitem><para> Added note about control 50h (thanks to Rickard Lind)</para></listitem>
	<listitem><para> Listed MT-32 play flag</para></listitem>
	<listitem><para> Added notice about the special case of channel 9 to the header
	  section</para></listitem></itemizedlist>
   <varlistentry><term/Revision 7 - Jan. 7, 2000/
	<listitem><para><itemizedlist>
	      	<listitem><para/Added information about F8h delta times (thanks to Rickard Lind for
			bringing these to my attention)/</listitem>
      		<listitem><para/Reorganized Fx status information/</listitem>
      		<listitem><para/Fixed major error in description of loop points (sorry)/</listitem>
      		<listitem><para/Fixed typos/</listitem>
     </itemizedlist></para></listitem></varlistentry>

   <varlistentry><term/Revision 6 - Sep. 17, 1999/
	<listitem><para><itemizedlist>
	      	<listitem><para/Added information about cues/</listitem>
	      	<listitem><para/Updated control 60h information/</listitem>
	      	<listitem><para/Added information about loop points/</listitem>
	      	<listitem><para/Updated control 4Ch information/</listitem>
	      	<listitem><para/Cleaned up control reference introduction/</listitem>
     </itemizedlist></para></listitem></varlistentry>

   <varlistentry><term/Revision 5 - Jul. 5, 1999/
     <listitem><para><itemizedlist>
      <listitem><para/Rewrote much of the specification, trying to focus less on explaining
        MIDI and more on explaining sound resources/</listitem>
      <listitem><para/Removed information about standard MIDI controls/</listitem>
      <listitem><para/Added driver table/</listitem>
      <listitem><para/Expanded sound device section/</listitem>
      <listitem><para/Completed header information/</listitem>
     </itemizedlist></para></listitem></varlistentry>

   <varlistentry><term/Revision 4 - Jun. 19, 1999/
     <listitem><para><itemizedlist>
      <listitem><para/Fixed the list of changes in Revision 3 (was incomplete)/</listitem>
      <listitem><para/Expanded the introductory blurb about controls/</listitem>
      <listitem><para/I began working with a disassembly of ADL.DRV, and am hoping to use
        it to complete this specification. The next revision should be more
        interesting than this one./</listitem>
     </itemizedlist></para></listitem></varlistentry>

   <varlistentry><term/Revision 3 - May 4, 1999/
     <listitem><para><itemizedlist>
      <listitem><para/Removed the "compatible games" list. I haven't found a non-compatible
        SCI0 game yet, which makes the list quite useless./</listitem>
      <listitem><para/Verified that SCI1 sound resources are different./</listitem>
      <listitem><para/Tidied the "About the output medium" section. Does that term "output
        medium" sound wordy or unclear? I don't really like it, but I didn't
        want to beat "sound device" to death./</listitem>
      <listitem><para/More information about the header/</listitem>
      <listitem><para/Modified the explanation for message FCh./</listitem>
      <listitem><para/Changed most references to status bytes as "commands" with "messges"
        to stay more consistent with MIDI terminology./</listitem>
      <listitem><para/Added midi.org as a source for more MIDI information/</listitem>
      <listitem><para/Removed labels like "tentative" and "incomplete" as things become
        more concrete -- not complete yet, but getting there./</listitem>
      <listitem><para/More information about controls/</listitem>
     </itemizedlist></para></listitem></varlistentry>

   <varlistentry><term/Revision 2 - Jan. 16, 1999/
     <listitem><para><itemizedlist>
      <listitem><para/Got rid of the HTML. I originally intented to post this as a message
        on the webboard, but ended up distributing the file. If I'm going to
        distribute it as a file, there's no need to bother with the HTML
        since I can do all my formatting as plain text./</listitem>
      <listitem><para/I found refrences to command 8x in the 1988 Christmas Card, so my
        comment about not seeing one got removed. To date, I haven't seen any
        examples of commands Ax or Dx./</listitem>
      <listitem><para/Expanded the header section./</listitem>
      <listitem><para/Added information about controls./</listitem>
      <listitem><para/Added information about the output mediums./</listitem>
      <listitem><para/Tried to be more consistent with terminology/</listitem>
     </itemizedlist></para></listitem></varlistentry>

   <varlistentry><term/Revision 1 - Dec. 29, 1998/
     <listitem><para><itemizedlist>
      <listitem><para/First release of the specification/</listitem>
     </itemizedlist></para></listitem></varlistentry>
  </variablelist>
  </para>
 </sect2>
</sect1>

   <sect1>
    <title/Mapping instruments in FreeSCI/
    <sect2><Title/The Patch.002 resource/
     <para>
       As Ravi describes in his description of the patch resources (which have not been included
       here), one of the major problems with SCI sound support is the lack of General Midi (GM)
       support in the earlier games. Since those were written before GM was conceived, this
       can hardly be considered to be Sierra's fault; but this fact doesn't help when it comes
       to supporting the games in a portable manner.
     </para><para>
       Unfortunately, almost every SCI0 game uses an individual instrument mapping scheme. This
       means that there are only two options to generate GM music from the original SCI sound
       resources: Either create a manual mapping for each game, or abuse existing data from the
       game for this purpose. Obviously, the latter way would be either impossible or much
       easier.
     </para><para>
       So, the solution would be to use an existing instrument mapping scheme. Those mapping schemes
       are stored in the patch resources, and, as such, easily accessible to an SCI engine.
       As those patch files are driver dependant (which, in turn, are hardware dependant), most
       of the patch data is unusable. The Adlib data, for example, will only work for an OPL-2
       FM synthesizer chip or one of its successors, the MT-32 data (which consists of one massive
       sysex block) won't help anyone without an MT-32 or LAPC-1, and so on. So, to recycle
       this hardware-dependant data, two new possibilities remain: Either extract and interpret
       the patch data using a portable software synthesizer (such as timidity), or extract
       instrument names and map those to GM instruments. The first approach would, of course,
       yield the better results (at the cost of computation power); but the only software emulator
       for a specific sound system I've seen so far was an OPL-2 emulator. So the alternative,
       extracting a text ID of each instrument and using it to map this instrument to a GM instrument,
       looks much more promising.
     </para><para>
       Now, most SCI0 games come with a patch.002 resource, which is used by the IBM Music Feature card
       and Yamaha FM-01 sound synthesizers (both of which appear to use frequency modulation).
       This is the only patch file that includes text descriptions of most of its instruments. Note
       this, not all instruments have name representation. This means that some of them can't be
       mapped and have to be silenced; but those instruments are either used for sound effects only
       or not used at all, so this isn't critical.
     </para><para>
       Using those 7-letter instrument names, it is now possible to build a small database of
       instruments, which, subseqently, can be mapped to GM instruments.
     </para><para>
       The file structure is relatively simple (for this purpose): Every patch.002 consists of
       either one or two instrument banks carrying 48 instruments each. Every instrument has a
       fixed block size of 0x40 bytes; each block starts with the 7-letter description of the
       instrument or seven blanks if none is available.
     </para><para>
       If two banks are present, the second bank is separated from the first one by a two-byte
       sequence (0xab, 0xcd). Keeping this in mind, it is trivial to extract the instrument names
       of the 48 or 96 instruments.
     </para>
    </sect2>
    <sect2><title/Percussion instruments/
     <para>
       Percussion instruments are treated specially in the MIDI standard. MIDI channel 10 (or 9,
       if you count from 0 to 15 like most people do) is reserved for percussions and some
       special effects; each key for this channel represents either nothing or one
       fixed percussion instrument.
     </para><para>
       At first glance, this might lead to an additional problem of mapping those percussion
       instruments. Fortunately, the General Midi standard extends on the MT-32 percussion mappings,
       which are used in SCI0, so that channel 9 can be left completely untouched in the process
       of instrument mapping.
     </para>
    </sect2>
   </sect1>
</chapter>


<Chapter>
 <Title/The SCI virtual machine/
  <sect1>
  <Title/Introduction/
   <sect2>
   <Title/Script resources/
    <para>
      Like any processor, the SCI virtual machine is virtually useless without code to execute.
      This code is provided by script resources, which constitute the logic behind any
      SCI game.
    </para><para>
      In order to operate on the script resource, those first have to be loaded to the heap.
      The heap is the only memory space that the VM can work on directly (with some restrictions); all
      other memory spaces have to be used implicitly or explicitly by using kernel calls.
      The heap also contains a stack, which is heavily used by SCI bytecode.
    </para><para>
      Each script resource may contain one or several of various script objects, listed here:
      <simplelist>
       <member/Type 1: Object/
       <member/Type 2: Code/
       <member/Type 3: Synonym word lists/
       <member/Type 4: Said specs/
       <member/Type 5: Strings/
       <member/Type 6: Class/
       <member/Type 7: Exports/
       <member/Type 8: Relocation table/
       <member/Type 9: Preload text (a flag, rather than a real section)/
       <member/Type 10: Local variables/
      </simplelist>
      </para><para>
	Standard SCI0 scripts (of post-0.000.396 SCI0, approximately) consist of a four-byte
	header, followed by a list of bytes:
	<simplelist>
	  <member><literal>[00][01]</literal>: Block type as LE 16 bit value, or 0 to terminate script resource</member>
	  <member><literal>[02][03]</literal>: Block size as LE 16 bit value; includes header size</member>
	  <member><literal>[04]...</literal>: Data</member>
	</simplelist>
      </para><para>
       The code blocks contain the SCI bytecode that actually gets executed. The export block
       (of which there may be only one (or none at all)) contains script-relative pointers to
       exported functions, which can be called by the SCI operations <function/calle/ and
       <function/callb/. The local variables block, which stores one of the four variable types,
       is used to share variables among the objects and classes of one script.
      </para><para>
       But the most important script members are Objects and Classes. As in the usual OOP terms,
       Classes refer to object prototypes, and Objects are instantiated Classes. However, unlike
       most OOP languages, SCI treats the base class very similar to objects, so that they may
       actually get called by the SCI bytecode. Therefore, they also have their own space for
       selectors (see below). Also, each object or class knows which class it inherits from and
       which class it was instantiated from (in the case of objects).
      </para><para>
	Note that all script segments are optional and 16 bit aligned; they are described in more detail below:
      </para><para>
    </para>
      <sect3><title>Object segments</title>
      <para>
	Objects look like this (LE 16 bit values):
	<simplelist>
	  <member><literal>[00][01]</literal>: Magic number 0x1234</member>
	  <member><literal>[02][03]</literal>: Local variable offset (filled in at run-time)</member>
	  <member><literal>[04][05]</literal>: Offset of the function selector list, relative to its own position</member>
	  <member><literal>[06][07]</literal>: Number of variable selectors (= #vs)</member>
	  <member><literal>[08][09]</literal>: The 'species' selector</member>
	  <member><literal>[0a][0b]</literal>: The 'superClass' selector</member>
	  <member><literal>[0c][0d]</literal>: The '--info--' selector</member>
	  <member><literal>[0e][0f]</literal>: The 'name' selector (object/class name)</member>
	  <member><literal>[10]...</literal>: (#vs-4) more variable selectors</member>
	  <member><literal>[08+ #vs*2][09+ #vs*2]</literal>: Number of function selectors (= #fs)</member>
	  <member><literal>[0a+ #vs*2]...</literal>: Selector IDs for the functions</member>
	  <member><literal>[08+ #vs*2 + #fs*2][09+ #vs*2 + #fs*2]</literal>zero</member>
	  <member><literal>[0a+ #vs*2 + #fs*2]...</literal>: Function selector code pointers</member>
	</simplelist>
	For objects, the selectors are simply values for the selector IDs specified in their species
	class (which is either present by its offset (in-memory) or class ID (in-script)- the same
	for the species' superclass (superClass selector)). Info typically has one of the following
	values (although this does not appear to be relevant for SCI):
	<simplelist>
	  <member><literal>0x0000</literal>: Normal (statical) object</member>
	  <member><literal>0x0001</literal>: Clone</member>
	  <member><literal>0x8000</literal>: Class</member>
	</simplelist>
	Other values are used, but do not appear to be of relevance<footnote><para>See SQ3's inventory objects for an example</para></footnote>.
      </para>
      <sect3><title>Code segments</title>
      <para>
	Code segments contain free-form SCI bytecode. Pointers into this code are held by objects, classes,
	and export entries; these entries are, in turn, referenced in the export segment.
      </para>
      <sect3><title>Synonym word list segments</title>
      <para>
	Inside these, synonyms for certain words may be found. A synonym is a tuple
	(a, b), where both a and b are word groups, and b is the replacement for a
	if this synonym is in use. They are stored as 16 bit LE values in sequence
	(first a, then b).
	Synonyms must be set explicitly by the kernel function SetSynonyms() (as described
	<xref linkend="kfunct-set-synonyms">). It is not possible to select
	  synonyms selectively.
      </para>
      <sect3><title>Said spec segments</title>
      <para>
	This section contains said specs (explained in <xref linkend="CRSaidSpec" />), tightly grouped.
      </para>
      <sect3><title>String segments</title>
      <para>
	This segment contains a sequence of asciiz strings describing class and object names, debug information,
	and (occasionally) game text.
      </para>
      <sect3><title>Class segments</title>
      <para>
	Classes look similar to objects:
	<simplelist>
	  <member><literal>[00][01]</literal>: Magic number 0x1234</member>
	  <member><literal>[02][03]</literal>: Local variable offset (filled in at run-time)</member>
	  <member><literal>[04][05]</literal>: Offset of the function selector list, relative to its own position</member>
	  <member><literal>[06][07]</literal>: Number of variable selectors (= #vs)</member>
	  <member><literal>[08][09]</literal>: The 'species' selector</member>
	  <member><literal>[0a][0b]</literal>: The 'superClass' selector</member>
	  <member><literal>[0c][0d]</literal>: The '--info--' selector</member>
	  <member><literal>[0e][0f]</literal>: The 'name' selector (object/class name)</member>
	  <member><literal>[10]...</literal>: (#vs-4) more variable selectors</member>
	  <member><literal>[08+ #vs*2][09+ #vs*2]</literal>: Selector ID of the first varselector (0)</member>
	  <member><literal>[0a+ #vs*2]...</literal>: Selector ID of the second etc. varselectors</member>
	  <member><literal>[08+ #vs*4][09+ #vs*4]</literal>: Number of function selectors (#fs)</member>
	  <member><literal>[0a+ #vs*4]...</literal>: Function selector code pointers</member>
	  <member><literal>[08+ #vs*4 + #fs*2][09+ #vs*4 + #fs*2]</literal>: 0</member>
	  <member><literal>[0a+ #vs*4 + #fs*2]...</literal>: Selector ID of the first etc. funcselectors</member>
	</simplelist>
	Simply put, they look like objects with each selector section followed by a list of selector IDs.
      </para>
      <sect3><title>Export segments</title>
      <para>
	External symbols are contained herein, the number of which is described by the first
	(16 bit LE) value in the segment. All the values that follow point to addresses that
	the program counter will jump to when a <literal>calle</literal>
	operation is invoked. An exception is script 0, entry 0, which points to the first object
	whose 'play' method should be invoked during startup (a magical entry point like C's 'main())' function).
      </para>
      <sect3><title>Relocation tables</title>
      <para>
	This section contains script-relative pointers pointing to pointers inside the script.
	These refer to script-relative addresses and need to be relocated when the script is
	loaded to the heap; this is done by adding the offset of the first byte of the script
	on the heap to each of the values referenced in this section
	<footnote><para/Thanks to Francois Boyer for this information/</footnote>.
      </para><para>
	The section itself starts with a 16 bit LE value containing the number of pointers that
	follow, with each of the script-relative 16 bit pointers beyond having semantics as
	described above
      </para>
      <sect3><title>The Preload Text flag</title>
      <para>
	This is an actual script section, although it is always of size 4 (i.e. only consists of the
	script header). It is only checked for presence; if <literal>script.x</literal> is loaded and contains this
	section, the <literal>text.x</literal> resource is also loaded implicitly along with it
	<footnote><para>This is ignored by FreeSCI ATM, since all resources are present in memory all the time.</para></footnote>
      </para>
      <sect3><title>Local variable segments</title>
      <para>
	This section contains the script's local variable segment, which consists of a sequence of
	16 bit little-endian values.
      </para>
   </sect2>
   <sect2>
   <Title/Selectors/
    <para>
       Selectors are very important in SCI. They can be either methods or object/class-relative
       variables, and this makes the interpretation of SCI operations like <function/send/
       a bit tricky.
    </para><para>
       Each class comes with two two-dimensional tables. The first table contains selector values
       and selector indices<footnote><para>Those can be used as an index into vocab.997, where
       the selector names are stored as strings.</para></footnote> for each variable selector. The
       second table contains selector indices and script-relative method offsets. Objects look
       nearly identical, but they do not contain the list of selector indices for variable selectors,
       since those can be looked up at the class they were instantiated from (their "species", which
       happens to be one of the variable selectors).
    </para><para>
       Now, whenever a selector is sent for, the engine has to determine the right action to take.
       FreeSCI first determines whether the selector is a variable selector, by looking for it in
       the list of variable selector indices of the species class of the object that the
       "<function/send/" was sent to (classes use their own class number as their species class)
       <footnote><para/In practice, send looks up the heap position of the requested class in a
       global class table./</footnote>. If it is, the selector value is either read (if no parameter
       was provided to the <function/send/ call) or set (if one parameter was provided). If the
       selector was not part of the variable selectors of the specified object, the object's methods
       are checked for this selector index. If they don't contain the selector index, either, then
       FreeSCI recurses into checking the method selectors of the object's superclasses. If it finds
       the selector value there, it calls the heap address corresponding to the selector index.
    </para>
   </sect2>
   <sect2>
   <Title/Function invocation/
    <para>
       SCI provides three distinct ways for invocating a function<footnote><para/Of course, "manual"
       invocation (using push and jump operations) could also be used, but there are no special
       provisions for it, and it does not appear to be used in the existing SCI bytecode./</footnote>:
       <simplelist>
        <member>Calling exported functions (<function/calle/, <function/callb/)</member>
        <member>Calling selector methods (<function/send/, <function/self/, <function/super/)</member>
        <member>Calling PC-relative addresses (<function/call/)</member>
       </simplelist>
    </para><para>
       Exported functions are called by providing a script number and an exported function number
       (which is then looked up in the script's Type 7 block). They use the object they were called
       from to look up local variables and selectors for <function/self/ and <function/super/.
     </para><para>
       Selector methods are called by providing an object and a selector index. The selector index
       gets looked up in the object's selector tables, and, if it is used for a method, this method
       gets invocated. The provided object is used for local references.
     </para><para>
       PC-relative calls only make sense inside scripts, since they jump to a position relative
       to the <function/call/ opcode. The calling object is used for local references.
    </para>
   </sect2>
   <sect2>
   <Title/Variable types/
    <para>
       SCI bytecode can address four types of variables (not counting the variable selectors).
       Those variable types are:
       <variablelist>
         <varlistentry>
          <term/Local variables/
           <listitem><para>
              These are the variables stored in Type 10 script blocks. They are shared between
              the objects and classes of each script.
           </para></listitem>
         </varlistentry>
         <varlistentry>
          <term/Global variables/
           <listitem><para>
              These variables are the local variables of script 0.
           </para></listitem>
         </varlistentry>
         <varlistentry>
          <term/Temporary variables/
           <listitem><para>
              Those variables are stored on the stack. They are relative to the stack frame of
              the current method, so space for them must be allocated before they can be used.
              This is commonly done by using the <function/link/ operation.
           </para></listitem>
         </varlistentry>
         <varlistentry>
          <term/Parameters/
           <listitem><para>
              Parameters are stored on the stack below the current stack frame, as they technically
              belong to the calling function. They can be modified, if neccessary.
              <footnote><para/Obviously, SCI uses a call-by-value model for primitives and call-by-reference for objects/</footnote>
           </para></listitem>
         </varlistentry>
       </variablelist>
    </para>
   </sect2>
  </sect1>
  <sect1 ID="LSExecLoop">
  <title/Interpreter initialization and the main execution loop/
  <para>
By <author><firstname/Lars/<surname/Skovlund/</author>
Version 1.0, 7. July 1999
</para><para>
When the interpreter initializes, it sets up a timer for 60 hertz (one that
"ticks" 60 times per second). This timer does two things: it lets
the so-called servers execute (most notably, the sound player and input
manager) and it "feeds" the internal game clock. This 60 hz. "systick" is
used all over the place. For example, it is accessible using the KGetTime
kernel function. Some graphic effects depend on it, for example the
"shake screen" effect. In SCI1, it is also used for timing in the palette
fades. And naturally, it is used in the KWait kernel call.
</para><para>
Basically, the initialization proceeds as follows:
<simplelist>
<member/   Initialize the heap and hunk./
<member/   Parse the config file and the command line./
<member/   Load the drivers specified in the config file/
<member/   Initialize the graphics subsystem./
<member/   Initialize the event manager/
<member/   Initialize the window manager/
<member/   Initialize the text parser (i.e. load the vocabulary files)/
<member/   Initialize the music player/
<member>   Save the machine state for restarting the game later on
  <footnote><para>This is quite interesting, the KRestartGame kernel call is implemented
  using a simple setjmp/longjmp pair.</para></footnote></member>
<member/   Allocate the PMachine stack on the heap./
<member/   Get a pointer to the game object/
<member/   And run, by executing the play or replay method./
</simplelist>
</para><para>
The right game object is found by looking in the "dispatch table" of script
0. The dispatch table has block type 7, and is an array of words. The first
entry is a pointer (script relative) to the game object, for instance SQ3.
If the game was restarted, the interpreter executes the replay method, play
otherwise.
</para><para>
After looking up the address of the method in the object block, execution is
started. It can be viewed as a huge switch statement, which executes con-
tinuously. When the last ret statement (in the play or replay method) is
met, the interpreter terminates.
</para><para>
The ExecuteCode function, which contains the mentioned switch statement,
is called recursively. It lets other subroutines handle the object
complexity, all the ExecuteCode function has is a pointer to the next in-
struction. Thus, it is easy to terminate the interpreter; just return from
all running instances of ExecuteCode.
</para><para>
So, how does an SCI program execute? Well, the play method is defined in the
Game class, and it is never overridden. It consists of a huge loop which
calls Game::doit continuously, followed by a pause according to the selected
animation speed. That is, the script, not the interpreter, handles animation
speed. Notice how the debugger very often shows the statement sag $12 upon
entering the debugger? This instruction resides in Game::play, and the break
occurs here because of a KWait kernel call which is executed right before
that instruction. This wait takes the most execution time, so therefore the
debug break is most likely to be
A game programmer would then override Game::doit and place the game
specific main loop here (still, Game::doit is almost identical from game to
game). Execution of the Game::play main loop stops when an event causes
global variable 4 to be non-zero. The last ret instruction is met, and the
interpreter terminates.
</para>
  </sect1>

  <sect1>
   <Title/The SCI Heap/
    <para>
     SCI0 (and probably SCI1 as well) uses a heap consisting of 0xffff bytes of
     memory; this size corresponds to the size of one i386 real-mode memory segment
     minus one.
     <Footnote><para/
     This appears to be the maximum size; the games generally require less heap
     space./
     </Footnote>
    </para>

     <sect2>
     <Title/Heap structure/
     <para>
      The original heap starts with 200 separate entries with a size of four bytes.
      Each of those entries appears to be a pointer to "hunk" memory, which is
      separate from the heap and not covered here. The actual heap base pointer
      points to the first byte that is not part of these pointers.
     </para>
     </sect2>

     <sect2>
      <Title/Memory handles/
      <para>
      A memory handle consists of two consecutive unsigned 16 bit integers:
      <itemizedlist>
       <listitem><para>The memory block size</para></listitem>
       <listitem><para>The heap address of the next memory handle</para></listitem>
      </itemizedlist>
      in this sequence.
      </para><para>
      Memory handles are stored inside of the heap; they delimit the holes in the
      heap by indexing each other, with the exception of the last handle, which
      points to zero.
     </para>
     </sect2>


     <sect2>
     <Title/Initialization/
     <para>
      The list is initialized to 0. Memory handle #0 is set to contain 0xffff minus
      the size required by the memory handles (800 bytes) to a total of 0xfcdf,
      the pointer to the next free index is set to 0x0.
     </para>
     </sect2>

     <sect2>
     <Title/Memory allocation/
     <para>
      The memory allocation function takes one parameter; this is the requested allocation
      block size. If it is 0, the function aborts. Otherwise, the size is increased by 2
      (and then again by 1, if it is odd, for alignment purposes).
     </para><para>
      After the memory allocation algorithm finds a sufficiently large memory hole, it
      allocates its memory by splitting the memory hole and allocating the lower part
      (or by swallowing the upper part if its size would be less than four). It adjusts the
      previous memory handle (which used to point to the start of the now allocated part
      of the heap) to point to the next hole, and then goes on to write its size to the first
      two bytes of its newly allocated home.
     </para><para>
      If no sufficiently large memory hole can be found, the function returns 0; otherwise,
      it returns a heap pointer to the start of the allocated block (i.e. to the two bytes
      that carry the block's size).
     </para>
     <para>
      Memory deallocation does this process in reverse; it also merges adjacent memory holes
      to prevent memory fragmentation.
     </para>
     </sect2>
  </sect1>

  <sect1 ID="VM">
    <Title/The Sierra PMachine/
      <para>
        <author><firstname/Lars/ <surname/Skovlund/ </author>,
        <author><firstname/Dark/ <surname/Minister/ </author> and
        <author><firstname/Christoph/ <surname/Reichenbach/ </author>
      </para><para>
         Version 1.0, 6. July 1999 </para>
      <para>
This document describes thee design of the Sierra PMachine (the virtual CPU
used for executing SCI programs). It is a special CPU, in the sense that it
is designed for object oriented programs.
</para><para>
There are three kinds of memory in SCI: Variables, objects, and stack space.
The stack space is used in a Last-In-First-Out manner, and is primarily used
for temporary space in a routine, as well as passing data from one routine
to another. Note that the stack space is used bottom-up by the original in-
terpreter, instead of the more usual top-down. I don't know if this has any
significance for us.
</para><para>
Scripts are loaded into the PMachine by creating a memory imagee of it on 
the
heap. For this reason, the script file format may seem a bit obscure at
times. It is optimized for in-memory performance, not readability. It should
be mentioned here that a lot of fixup stuff is done by the interpreter.
In the script files, all addresses are specified as script-relative. These
are converted to absolute offsets. The species and superClass fields of all
objects are converted into pointers to the actual class etc.
</para><para>
There are four types of variables. These are called global, local, 
temporary,
and parameter. All four types are simple arrays of 16-bit words. A pointer 
is
kept for each type, pointing to the list that is currently active. In fact,
only the global variable list is constant in memory. The other pointers are
changed frequently, as scripts are loaded/unloaded, routines called, etc.
The variables are always referenced as an index into the variable list.
I'll explain the four types below - the names in parantheses will be used
occasionally in the rest of the text:
</para>
<sect2><Title/Local variables (LocalVar)/
<para>
This variable type is called "local" because it belongs to a specific 
script.
Each script may have its own set of local variables, defined by script block
type 10. As long as the code from a specific script is running, the local
variables for that script are "active" (pointed to by the mentioned 
pointer).
</para></sect2>
<sect2><Title/Global variables/
<para>
These, like the local variables, reside in script space (in fact, they are
the local variables of script 0!). But the pointer to them remains constant
for the whole duration of the program.
</para></sect2>
<sect2><Title/Temporary variables/
<para>
These are allocated by specific subroutines in a script. They reside on the
PMachine stack and are allocated by the link opcode. The temp variables are
automatically discarded when the subroutine returns.
</para></sect2>
<sect2><Title/Parameter variables/
<para>
These variables also reside on the stack. They contain information passed
from one routine to another. Any routine in SCI is capable of taking a
variable number of parameters, if need be. This is possible because a list
size is pushed as the first thing before calling a routine. In addition to
this, a frame size is passed to the call* functions.
</para></sect2>
<sect2><Title/Objects/
<para>
While two adjacent variables may be entirely unrelated, the contents of an
object is always related to one task. The object, like the variable tables,
provides storage space. This storage space is called properties. Depending
on the instructions used, a property can be referred to by index into the
object structure, or by property IDs (PIDs). For instance, the name property
has the PID 17h, but the offset 6. The property IDs are assigned by the SCI
compiler, and it is the "compatible" way of accessing object data. Whereas
the offset method is used only internally by an object to access its own
data, the PID method is used externally by objects to read/write the data
fields of other objects. The PID method is also used to call methods in an
object, either by the object itself, by another object, or by the SCI inter-
preter. Yes, this really happens sometimes.
</para></sect2>
<sect2><Title/The PMachine "registers"/
<para>
The PMachine can be said to have a number of registers, although none of 
them
can be accessed explicitly by script code. They are used/changed implicitly
by the script opcodes:
<simplelist>
  <member/Acc - the accumulator. Used for result storage and input for a number of
  opcodes./
  <member>IP - the instruction pointer.<Footnote><para/FreeSCI calls this the "Program Counter"
          or PC, which is the more general term./</footnote>
          Points to the currently executing instruction</member>
  <member/Vars - an array of 4 values, pointing to the current variables of each
  mentioned type/
  <member/Object - points to the currently executing object./
  <member/SP - the current stack pointer. Note that the stack in the original SCI
  interpreter is used bottom-up instead of the more usual top-down./
</simplelist>
</para><para>
The PMachine, apart from the actual instruction pointer, keeps a record of
which object is currently executing.
</para></sect2>
<sect2><title/The instruction set/
<para>
The PMachine CPU potentially has 128 instructions (however, a couple of 
these
are invalid and generate an error). Some of these instructions have a flag
which specify whether the opcode has byte- or word-sized operands (I will
refer to this as variably-sized parameters, as opposed to constant
parameters). Other instructions have only one calling form. These
instructions simply disregard the operand size flag. Ideally, however, all
script instructions should be prepared to take variably-sized operands.
Yet another group of instructions take both a constant parameter and a
variably-sized parameter. The format of an opcode byte is as follows:
<informaltable frame="all">
 <tgroup cols="2">
  <tbody>
   <row>
    <entry/bit 7-1/<entry/        opcode number/
   </row><row>
    <entry/bit 0/<entry/            operand size flag/
   </row>
  </tbody>
 </tgroup>
</informaltable>
</para>
<sect3><title/Relative addresses/
<para>
Certain instructions (in particular, branching ones) take relative addresses
as a parameter. The actual address is calculated based on the instruction
after the branching instruction itself. In this example, the bnt
instruction, if the branch is made, jumps over the ldi instruction.
<programlisting>
        eq?
        bnt +2
        ldi byte 2
        push
</programlisting>
<note><para/Relative addresses are signed values./</note>
</para></sect3>
<sect3><title/Dispatch addresses/
<para>
The callb and calle instructions take a so-called dispatch index as a
parameter. This index is used to look up an actual script address, using the
so-called dispatch table. The dispatch table is located in script block type
7 in the script file. It is a series of words - the first one, as in so many
other places in the script file, is the number of entries.
</para></sect3>
<sect3><title/Frame sizes/
<para>
In every call instruction, a value is included which determines the size of
the parameter list, as an offset into the stack. This value discounts the
list size pushed by the SCI code. For instance, consider this example from
real SCI code:

<programlisting>
     pushi 3 ; three parameters passed
     pushi 4 ; the screen flag
     pTos x ; push the x property
     pTos y ; push the y property
     callk OnControl, 6
</programlisting>

Notice that, although the callk line specifies 6 bytes of parameters, the
kernel routine has access to the list size (which is at offset 8)!
</para></sect3>
<sect3><title/PErrors/
<para>
These are internal errors in the interpreter. They are usually caused by
buggy script code. The PErrors end up displaying an "Oops!" box in the
original interpreter (it is interesting to see how Sierra likes to believe
that PErrors are caused by the user - judging by the message "You did
something we weren't expecting"!). In the original interpreter, specifying
-d on the command line causes it to give more detailed information about
PErrors, as well as activating the internal debugger if one occurs.
</para></sect3>
<sect3><Title/Class numbers and adresses/
<para>
The key to finding a specific class lies in the class table. This class
table resides in VOCAB.996, and contains the numbers of scripts that carry
classes. If a script has more than one class defintion, the script number
is repeated as necessary. Notice how each script number is followed by a
zero word? When the interpreter loads a script, it checks to see if the
script has classes. If it does, a pointer to the object structure is put in
this empty space.
</para></sect3>
<sect3><title/The instructions/
<para>
The instructions are described below. I have used Dark Minister's text on
the subject as a starting point, but many things have changed; stuff
explained more thoroughly, errors corrected, etc. The first 23 instructions
(up to, but not including, bt) take no parameters.
      </para><para>
         These functions are used in the pseudocode explanations:
         <simplelist>
           <member/pop(): sp -= 2; return *sp;/
           <member/push(x): *sp = x; sp += 2; return x;/
         </simplelist>
         The following rules apply to opcodes:
         <simplelist>
           <member/Parameters are signed, unless stated otherwise. Sign extension is performed./
           <member/Jumps are relative to the posisition of the next operation./
           <member/*TOS refers to the TOS (Top Of Stack) element./
           <member/"tmp" refers to a temporary register that is used for explanation purposes only./
         </simplelist>
      </para>
          <itemizedlist>
           <listitem><para>
              <simplelist>
                <member>op 0x00: bnot  (1 byte)</member>
                <member>op 0x01: bnot  (1 byte)</member>
              </simplelist>
              Binary not:
                 <programlisting/acc ^= 0xffff;/

           </para></listitem>
           <listitem><para>
              <simplelist>
                <member>op 0x02: add  (1 byte)</member>
                <member>op 0x03: add  (1 byte)</member>
              </simplelist>
              Addition:
                 <programlisting/acc += pop();/

           </para></listitem>
           <listitem><para>
              <simplelist>
                <member>op 0x04: sub  (1 byte)</member>
                <member>op 0x05: sub  (1 byte)</member>
              </simplelist>
              Subtraction: 
                 <programlisting/acc = pop() - acc;/

           </para></listitem>
           <listitem><para>
              <simplelist>
                <member>op 0x06: mul  (1 byte)</member>
                <member>op 0x07: mul  (1 byte)</member>
              </simplelist>
              Multiplication:
                 <programlisting/acc *= pop();/

           </para></listitem>
           <listitem><para>
              <simplelist>
                <member>op 0x08: div  (1 byte)</member>
                <member>op 0x09: div  (1 byte)</member>
              </simplelist>
              Division:
                 <programlisting>acc = pop() / acc;</programlisting>

              Division by zero is caught => acc = 0.
           </para></listitem>
           <listitem><para>
              <simplelist>
                <member>op 0x0a: mod  (1 byte)</member>
                <member>op 0x0b: mod  (1 byte)</member>
              </simplelist>
              Modulo:
                 <programlisting/acc = pop() % acc;/

              Modulo by zero is caught => acc = 0.
           </para></listitem>
           <listitem><para>
              <simplelist>
                <member>op 0x0c: shr  (1 byte)</member>
                <member>op 0x0d: shr  (1 byte)</member>
              </simplelist>
              Shift Right logical:
                 <programlisting/acc = pop() >> acc;/

           </para></listitem>
           <listitem><para>
              <simplelist>
                <member>op 0x0e: shl  (1 byte)</member>
                <member>op 0x0f: shl  (1 byte)</member>
              </simplelist>
              Shift Left logical:
                 <programlisting/acc = pop() << acc;/

           </para></listitem>
           <listitem><para>
              <simplelist>
                <member>op 0x10: xor  (1 byte)</member>
                <member>op 0x11: xor  (1 byte)</member>
              </simplelist>
              Exclusive or:
                 <programlisting/acc ^= pop();/

           </para></listitem>
           <listitem><para>
              <simplelist>
                <member>op 0x12: and  (1 byte)</member>
                <member>op 0x13: and  (1 byte)</member>
              </simplelist>
              Logical and:
                 <programlisting/acc &= pop();/

           </para></listitem>
           <listitem><para>
              <simplelist>
                <member>op 0x14: or  (1 byte)</member>
                <member>op 0x15: or  (1 byte)</member>
              </simplelist>
              Logical or:
                 <programlisting/acc |= pop();/

           </para></listitem>
           <listitem><para>
              <simplelist>
                <member>op 0x16: neg  (1 byte)</member>
                <member>op 0x17: neg  (1 byte)</member>
              </simplelist>
              Sign negation:
                 <programlisting/acc = -acc;/

           </para></listitem>
           <listitem><para>
              <simplelist>
                <member>op 0x18: not  (1 byte)</member>
                <member>op 0x19: not  (1 byte)</member>
              </simplelist>
              Boolean not:
                 <programlisting/acc = !acc;/

           </para></listitem>
           <listitem><para>
              <simplelist>
                <member>op 0x1a: eq?  (1 byte)</member>
                <member>op 0x1b: eq?  (1 byte)</member>
              </simplelist>
              Equals?:
                 <programlisting/prev = acc;
                                 acc = (acc == pop());/

           </para></listitem>
           <listitem><para>
              <simplelist>
                <member>op 0x1c: ne?  (1 byte)</member>
                <member>op 0x1d: ne?  (1 byte)</member>
              </simplelist>
              Is not equal to?
                 <programlisting/prev = acc;
                                 acc = !(acc == pop());/

           </para></listitem>
           <listitem><para>
              <simplelist>
                <member>op 0x1e: gt?  (1 byte)</member>
                <member>op 0x1f: gt?  (1 byte)</member>
              </simplelist>
              Greater than?
                 <programlisting/prev = acc;
                                 acc = (pop() > acc);/

           </para></listitem>
           <listitem><para>
              <simplelist>
                <member>op 0x20: ge?  (1 byte)</member>
                <member>op 0x21: ge?  (1 byte)</member>
              </simplelist>
              Greater than or equal to?
                 <programlisting/prev = acc;
                                 acc = (pop() >= acc);/

           </para></listitem>
           <listitem><para>
              <simplelist>
                <member>op 0x22: lt?  (1 byte)</member>
                <member>op 0x23: lt?  (1 byte)</member>
              </simplelist>
              Less than?
                 <programlisting/prev = acc;
                                 acc = (pop() < acc);/

           </para></listitem>
           <listitem><para>
              <simplelist>
                <member>op 0x24: le?  (1 byte)</member>
                <member>op 0x25: le?  (1 byte)</member>
              </simplelist>
              Less than or equal to?
                 <programlisting/prev = acc;
                                 acc = (pop() <= acc);/

           </para></listitem>
           <listitem><para>
              <simplelist>
                <member>op 0x26: ugt?  (1 byte)</member>
                <member>op 0x27: ugt?  (1 byte)</member>
              </simplelist>
              Unsigned: Greater than?
                 <programlisting/acc = (pop() > acc);/

           </para></listitem>
           <listitem><para>
              <simplelist>
                <member>op 0x28: uge?  (1 byte)</member>
                <member>op 0x29: uge?  (1 byte)</member>
              </simplelist>
              Unsigned: Greather than or equal to?  
                 <programlisting/acc = (pop() >= acc);/

           </para></listitem>
           <listitem><para>
              <simplelist>
                <member>op 0x2a: ult?  (1 byte)</member>
                <member>op 0x2b: ult?  (1 byte)</member>
              </simplelist>
              Unsigned: Less than?
                 <programlisting/acc = (pop() < acc);/

           </para></listitem>
           <listitem><para>
              <simplelist>
                <member>op 0x2c: ule?  (1 byte)</member>
                <member>op 0x2d: ule?  (1 byte)</member>
              </simplelist>
              Unsigned: Less than or equal to?
                 <programlisting/acc = (pop() <= acc);/

           </para></listitem>
           <listitem><para>
              <simplelist>
                <member>op 0x2e: bt W relpos  (3 bytes)</member>
                <member>op 0x2f: bt B relpos  (2 bytes)</member>
              </simplelist>
              Branch relative if true
                 <programlisting/if (acc) pc += relpos;/

           </para></listitem>
           <listitem><para>
              <simplelist>
                <member>op 0x30: bnt W relpos  (3 bytes)</member>
                <member>op 0x31: bnt B relpos  (2 bytes)</member>
              </simplelist>
              Branch relative if not true
                 <programlisting/if (!acc) pc += relpos;/

           </para></listitem>
           <listitem><para>
              <simplelist>
                <member>op 0x32: jmp W relpos  (3 bytes)</member>
                <member>op 0x33: jmp B relpos  (2 bytes)</member>
              </simplelist>
              Jump
                 <programlisting/pc += relpos;/

           </para></listitem>
           <listitem><para>
              <simplelist>
                <member>op 0x34: ldi W data  (3 bytes)</member>
                <member>op 0x35: ldi B data  (2 bytes)</member>
              </simplelist>
              Load data immediate
                 <programlisting/acc = data;/
              Sign extension is done for 0x35 if required.

           </para></listitem>
           <listitem><para>
              <simplelist>
                <member>op 0x36: push  (1 byte)</member>
                <member>op 0x37: push  (1 byte)</member>
              </simplelist>
              Push to stack
                 <programlisting/push(acc)/

           </para></listitem>
           <listitem><para>
              <simplelist>
                <member>op 0x38: pushi W data  (3 bytes)</member>
                <member>op 0x39: pushi B data  (2 bytes)</member>
              </simplelist>
              Push immediate
                 <programlisting/push(data)/
              Sign extension for 0x39 is performed where required.

           </para></listitem>
           <listitem><para>
              <simplelist>
                <member>op 0x3a: toss  (1 byte)</member>
                <member>op 0x3b: toss  (1 byte)</member>
              </simplelist>
              TOS subtract
                 <programlisting/pop();/
              For confirmation: Yes, this simply tosses the TOS value away.

           </para></listitem>
           <listitem><para>
              <simplelist>
                <member>op 0x3c: dup  (1 byte)</member>
                <member>op 0x3d: dup  (1 byte)</member>
              </simplelist>
              Duplicate TOS element
                 <programlisting/push(*TOS);/

           </para></listitem>
           <listitem><para>
              <simplelist>
                <member>op 0x3e: link W size  (3 bytes)</member>
                <member>op 0x3f: link B size  (2 bytes)</member>
              </simplelist>
                 <programlisting/sp += (size * 2);/

           </para></listitem>
           <listitem><para>
              <simplelist>
                <member>op 0x40: call W relpos, B framesize  (4 bytes)</member>
                <member>op 0x41: call B relpos, B framesize  (3 bytes)</member>
              </simplelist>
              Call inside script.
              <programlisting/(See description below)
                              sp -= (framesize + 2 + &amp;rest_modifier);
                              &amp;rest_modifier = 0;/
              This calls a script subroutine at the relative position
              <parameter/relpos/, setting up the ParmVar pointer first.
              ParmVar points to sp-<parameter/framesize/ (but see also the &amp;rest operation).
              The number of parameters is stored at word offset -1 relative to ParmVar.

           </para></listitem>
           <listitem><para>
              <simplelist>
                <member>op 0x42: callk W kfunct, B kparams  (4 bytes)</member>
                <member>op 0x43: callk B kfunct, B kparams  (3 bytes)</member>
              </simplelist>
              Call kernel function (see <XREF LINKEND="Kfunctions">)
                 <programlisting/sp -= (kparams + 2 + &amp;rest_modifier);
                                 &amp;rest_modifier = 0;
                                 (call kernel function <parameter/kfunct/)/

           </para></listitem>
           <listitem><para>
              <simplelist>
                <member>op 0x44: callb W dispindex, B framesize  (4 bytes)</member>
                <member>op 0x45: callb B dispindex, B framesize  (3 bytes)</member>
              </simplelist>
              Call base script
                 <programlisting/(See description below)
                              sp -= (framesize + 2 + &amp;rest_modifier);
                              &amp;rest_modifier = 0;/
              This operation starts a new execution loop at the beginning of script 0, public
              method <parameter/dispindex/ (Each script comes with a dispatcher list (type 7) that
              identifies public methods). Parameters are handled as in the call operation.

           </para></listitem>
           <listitem><para id="op-calle">
              <simplelist>
                <member>op 0x46: calle W script, W dispindex, B framesize  (5 bytes)</member>
                <member>op 0x47: calle B script, B dispindex, B framesize  (4 bytes)</member>
              </simplelist>
              Call external script
                 <programlisting/(See description below)
                              sp -= (framesize + 2 + &amp;rest_modifier);
                              &amp;rest_modifier = 0;/
              This operation starts a new execution loop at the beginning of script
              <parameter/script/s public method <parameter/dispindex/. The dispatcher list
              (the script's type 7 object) is used to dereference the requested method.
              Parameters are handled as described for the call operation.

           </para></listitem>
           <listitem><para>
              <simplelist>
                <member>op 0x48: ret  (1 byte)</member>
                <member>op 0x49: ret  (1 byte)</member>
              </simplelist>
              Return: returns from an execution loop started by call, calle, callb, send, self or
              super.
              

           </para></listitem>
           <listitem><para>
              <simplelist>
                <member>op 0x4a: send B framesize (2 bytes)</member> <!-- Brian: 0x4a is disallowed in SCI1 -->
                <member>op 0x4b: send B framesize (2 bytes)</member>
              </simplelist>
              Send for one or more selectors. This is the most complex SCI operation (together with
              self and class).
            </para><para>
              Send looks up the supplied selector(s) in the object pointed to by the accumulator.
              If the selector is a variable selector, it is read (to the accumulator) if it was sent
              for with zero parameters. If a parameter was supplied, this selector is set to that
              parameter. Method selectors are called with the specified parameters.
            </para><para>
              The selector(s) and parameters are retreived from the stack frame. Send first looks up
              the selector ID at the bottom of the frame, then retreives the number of parameters,
              and, eventually, the parameters themselves. This algorithm is iterated until all of
              the stack frame has been "used up". Example:
            <programlisting/; This is an example for usage of the SCI send operation
                            pushi x      ; push the selector ID of x
                            push1        ; 1 parameter: x is supposed to be set
                            pushi 42     ; That's the value x will get set to
                            pushi moveTo ; In this example, moveTo is a method selector.
                            push2        ; It will get called with two parameters-
                            push         ; The accumulator...
                            lofss 17     ; ...and PC-relative address 17.
                            pushi foo    ; Let's assume that foo is another variable selector.
                            push0        ; This will read foo and return the value in acc.
                            send 12      ; This operation does three quite different things./
                            

           </para></listitem>
           <listitem><para>
              <simplelist>
                <member>op 0x4c</member>
                <member>op 0x4d</member>
                <member>op 0x4e</member>
                <member>op 0x4f</member>
              </simplelist>
              These opcodes don't exist in SCI.

           </para></listitem>
           <listitem><para>
              <simplelist>
                <member>op 0x50: class W function  (3 bytes)</member>
                <member>op 0x51: class B function  (2 bytes)</member>
              </simplelist>
              Get class address.
              Sets the accumulator to the memory address of the specified <parameter/function/
              of the current object.

           </para></listitem>
           <listitem><para>
              <simplelist>
                <member>op 0x52</member>
                <member>op 0x53</member>
              </simplelist>
              These opcodes don't exist in SCI.

           </para></listitem>
           <listitem><para>
              <simplelist>
                <member>op 0x54: self B stackframe (2 bytes)</member>
                <member>op 0x55: self B stackframe (2 bytes)</member>
              </simplelist>
              Send to self. This operation is the same as the send operation, except that it
              sends to the current object instead of the object pointed to by the accumulator.

           </para></listitem>
           <listitem><para>
              <simplelist>
                <member>op 0x56: super W class, B stackframe (4 bytes)</member>
                <member>op 0x57: super B class, B stackframe (3 bytes)</member>
              </simplelist>
              Send to any class. This operation is the same as the send operation, except that it
              sends to an arbitrary <parameter/class/.

           </para></listitem>
           <listitem><para>
              <simplelist>
                <member>op 0x58: &amp;rest W paramindex  (3 bytes)</member>
                <member>op 0x59: &amp;rest B paramindex  (2 bytes)</member>
              </simplelist>
    Pushes all or part of the ParmVar list on the stack. The number specifies
    the first parameter variable to be pushed.
    I'll give a small example. Suppose we have two functions:
</para><para>
    function a(y,z)
    and
    function b(x,y,z)
</para><para>
    function b wants to call function a with its own y and z parameters. Easy
    job, using the the normal lsp instruction. Now suppose that both function
    a and b are designed to take a variable number of parameters:
</para><para>
    function a(y,z,...)
    and
    function b(x,y,z,...)
</para><para>
    Since lsp does not support register indirection, we can't just push the
    variables in a loop (as we would in C). Instead this function is used.
    In this case, the instruction would be &amp;rest 2, since we want the copying
    to start from y (inclusive), the second parameter.
</para><para>
    Note that the values are copied to the stack <emphasis>immediately</emphasis>.
    The <literal>&amp;rest_modifier</literal> is set to the number of variables pushed
    afterwards.


           </para></listitem>
           <listitem><para>
              <simplelist>
                <member>op 0x5a: lea W type, W index ( bytes)</member>
                <member>op 0x5b: lea B type, B index ( bytes)</member>
              </simplelist>
              Load Effective Address
</para><para>
    The variable type is a bit-field used as follows:
  <variablelist>
   <varlistentry><term/bit 0/<listitem><para/      unused/</listitem></varlistentry>
   <varlistentry><term/bit 1-2/<listitem><para>  the number of the variable list to use
           <simplelist>
                       <member/       0 - globalVar/
                       <member/       2 - localVar/
                       <member/       4 - tempVar/
                       <member/       6 - parmVar/
           </simplelist>
         </para></listitem></varlistentry>
  <varlistentry><term/bit 3/<listitem><para/      unused/</listitem></varlistentry>
  <varlistentry><term/bit 4/<listitem><para/      set if the accumulator is to be used as additional index/</listitem></varlistentry>
  </variablelist>
Because it is so hard to explain, I have made a transcription of it here:

<programlisting>
< <![CDATA[
short *vars[4];

int acc;

int lea(int vt, int vi)
{
  return &((vars[(vt >> 1) & 3])[vt & 0x10 ? vi+acc : vi]);
}
]]>
</programlisting>

           </para></listitem>
           <listitem><para>
              <simplelist>
                <member>op 0x5c: selfID  (1 bytes)</member>
                <member>op 0x5d: selfID  (1 bytes)</member>
              </simplelist>
              Get 'self' identity: SCI uses heap pointers to identify objects, so this operation
              sets the accumulator to the address of the current object.
                 <programlisting/acc = object/

           </para></listitem>
           <listitem><para>
              <simplelist>
                <member>op 0x5e</member>
                <member>op 0x5f</member>
              </simplelist>
              These opcodes don't exist in SCI.

           </para></listitem>
           <listitem><para>
              <simplelist>
                <member>op 0x60: pprev  (1 bytes)</member>
                <member>op 0x61: pprev  (1 bytes)</member>
              </simplelist>
              Push prev: Pushes the value of the prev register, set by the last comparison
              bytecode (eq?, lt?, etc.), on the stack.
                 <programlisting/push(prev)/

           </para></listitem>
           <listitem><para>
              <simplelist>
                <member>op 0x62: pToa W offset  (3 bytes)</member>
                <member>op 0x63: pToa B offset  (2 bytes)</member>
              </simplelist>
              Property To Accumulator:
    Copies the value of the specified property (in the current object) to the
    accumulator. The property is specified as an offset into the object 
structure.

           </para></listitem>
           <listitem><para>
              <simplelist>
                <member>op 0x64: aTop W offset  (3 bytes)</member>
                <member>op 0x65: aTop B offset  (2 bytes)</member>
              </simplelist>
              Accumulator To Property:
    Copies the value of the accumulator into the specified property (in the
    current object). The property number is specified as an offset into the
    object structure.

           </para></listitem>
           <listitem><para>
              <simplelist>
                <member>op 0x66: pTos W offset  (3 bytes)</member>
                <member>op 0x67: pTos B offset  (2 bytes)</member>
              </simplelist>
              Property To Stack:
    Same as pToa, but pushes the property value on the stack instead.

           </para></listitem>
           <listitem><para>
              <simplelist>
                <member>op 0x68: sTop W offset  (3 bytes)</member>
                <member>op 0x69: sTop B offset  (2 bytes)</member>
              </simplelist>
              Stack To Property:
    Same as aTop, but gets the new property value from the stack instead.

           </para></listitem>
           <listitem><para>
              <simplelist>
                <member>op 0x6a: ipToa W offset  (3 bytes)</member>
                <member>op 0x6b: ipToa B offset  (2 bytes)</member>
              </simplelist>
              Incement Property and copy To Accumulator:
    Increments the value of the specified property of the current object
    and copies it into the accumulator. The property number is specified as
    an offset into the object structure.

           </para></listitem>
           <listitem><para>
              <simplelist>
                <member>op 0x6c: dpToa W offset  (3 bytes)</member>
                <member>op 0x6d: dpToa B offset  (2 bytes)</member>
              </simplelist>
              Decrepent Property and copy to Accumulator:
    Decrements the value of the specified property of the current object
    and copies it into the accumulator. The property number is specified as
    an offset into the object structure.

           </para></listitem>
           <listitem><para>
              <simplelist>
                <member>op 0x6e: ipTos W offset  (3 bytes)</member>
                <member>op 0x6f: ipTos B offset  (2 bytes)</member>
              </simplelist>
              Increment Property and push to Stack
    Same as ipToa, but pushes the result on the stack instead.

           </para></listitem>
           <listitem><para>
              <simplelist>
                <member>op 0x70: dpTos W offset  (3 bytes)</member>
                <member>op 0x71: dpTos B offset  (2 bytes)</member>
              </simplelist>
              Decrement Property and push to stack:
    Same as dpToa, but pushes the result on the stack instead.

           </para></listitem>
           <listitem><para>
              <simplelist>
                <member>op 0x72: lofsa W offset  (3 bytes)</member>
                <member>op 0x73: lofsa B offset  (2 bytes)</member>
              </simplelist>
              Load Offset to Accumulator:
              <programlisting>acc = pc + <parameter>offset</parameter></programlisting>
              Adds a value to the post-operation pc and stores the result in the accumulator.
             

           </para></listitem>
           <listitem><para>
              <simplelist>
                <member>op 0x74: lofss W offset  (3 bytes)</member>
                <member>op 0x75: lofss B offset  (2 bytes)</member>
              </simplelist>
              Load Offset to Stack:
              <programlisting>push(pc + <parameter>offset</parameter>)</programlisting>
              Adds a value to the post-operation pc and pushes the result on the stack.

           </para></listitem>
           <listitem><para>
              <simplelist>
                <member>op 0x76: push0  (1 bytes)</member>
                <member>op 0x77: push0  (1 bytes)</member>
              </simplelist>
              Push 0:
                 <programlisting/push(0)/

           </para></listitem>
           <listitem><para>
              <simplelist>
                <member>op 0x78: push1  (1 bytes)</member>
                <member>op 0x79: push1  (1 bytes)</member>
              </simplelist>
              Push 1:
                 <programlisting/push(1)/

           </para></listitem>
           <listitem><para>
              <simplelist>
                <member>op 0x7a: push2  (1 bytes)</member>
                <member>op 0x7b: push2  (1 bytes)</member>
              </simplelist>
              Push 2:
                 <programlisting/push(2)/

           </para></listitem>
           <listitem><para>
              <simplelist>
                <member>op 0x7c: pushSelf  (1 bytes)</member>
                <member>op 0x7d: pushSelf  (1 bytes)</member>
              </simplelist>
              Push self:
                 <programlisting/push(object)/

           </para></listitem>
           <listitem><para>
              <simplelist>
                <member>op 0x7e</member>
                <member>op 0x7f</member>
              </simplelist>
              These operations don't exist in SCI.

           </para></listitem>
           <listitem><para>
              <simplelist>
                <member>op 0x80 - 0xfe: [ls+-][as][gltp]i? W index  (3 bytes)</member>
                <member>op 0x81 - 0xff: [ls+-][as][gltp]i? B index  (2 bytes)</member>
              </simplelist>
              The remaining SCI operations work on one of the four variable types. The variable
              index is retreived by taking the heap pointer for the specified variable type, adding
              the <parameter/index/ and possibly the accumulator, and executing the operation according
              to the following table:
              <variablelist>
                <varlistentry>
                 <term/Bit 0/
                 <listitem><para>
                   Used as with all other opcodes with variably-sized parameters:
                   <simplelist>
                    <member/0: 16 bit parameter/
                    <member/1: 8 bit parameter/
                   </simplelist>
                 </para></listitem>
                </varlistentry>
                <varlistentry>
                 <term/Bits 1,2/
                 <listitem><para>
                   The type of variable to operate on:
                   <simplelist>
                    <member/0: Global/
                    <member/1: Local/
                    <member/2: Temporary/
                    <member/3: Parameter/
                   </simplelist>
                 </para></listitem>
                </varlistentry>
                <varlistentry>
                 <term/ Bit 3/
                 <listitem><para>
                   Whether to use the accumulator or the stack for operations:
                   <simplelist>
                    <member/0: Accumulator/
                    <member/1: Stack/
                   </simplelist>
                 </para></listitem>
                </varlistentry>
                <varlistentry>
                 <term/Bit 4/
                 <listitem><para>
                   Whether to use the accumulator as a modifier to the supplied index:
                   <simplelist>
                    <member/0: Don't use accumulator as an additional index/
                    <member/1: Use the accumulator as an additional index/
                   </simplelist>
                 </para></listitem>
                </varlistentry>
                <varlistentry>
                 <term/Bits 5,6/
                 <listitem><para>
                   The type of execution to perform:
                   <simplelist>
                    <member/0: Load the variable to the accumulator or stack/
                    <member/1: Store the accumulator or stack in the variable/
                    <member/2: Increment the variable, then load it into acc or on the stack/
                    <member/3: Decrement the variable, then load it into acc or on the stack/
                   </simplelist>
                 </para></listitem>
                </varlistentry>
                <varlistentry>
                 <term/Bit 7/
                 <listitem><para>
                   Always 1 (identifier for these opcodes)
                 </para></listitem>
                </varlistentry>
              </variablelist>
              Example: "sagi 2" would Store the Accumulator in the Global variable indexed with
              2 plus the current accumulator value (this rarely makes sense, obviously). "+sp 6"
              would increment the parameter at offset 6 (the third parameter, not counting the
              argument counter), and push it on the stack.

           </para></listitem>
          </itemizedlist>
         </sect3>
     </sect2>
  </sect1>

  <sect1 ID="Kfunctions">
   <Title/Kernel functions/
<note><para/Thanks to Lars Skovlund, Francois Boyer and Jeremy Tartaglia for additional information!/</note>
<para>
In SCI0, calls to the SCI kernel are initiated by using the <function>callk</function> opcode.
<function>callk</function> has the opcode <literal>0x42</literal>
or <literal>0x43</literal>; <literal>0x42</literal> takes one 16 bit little endian and
one 8 bit paramter, <literal/0x43/ takes two 8 bit parameters.
The first parameter is the number of the kernel function to be called, the
second number undetermined (as of yet).
</para><para>
Opcode summary:
</para><para>
<simplelist>
<member>op 0x42: callk W kfunct, B kparams  (4 bytes)</member>
<member>op 0x43: callk B kfunct, B kparams  (3 bytes)</member>
</simplelist>
</para><para>
The number of parameters passed to the kernel function are determined
by kparam. A total number of (kparams+2) bytes are removed from the local
stack and passed on to the kernel function.
The first two of those bytes are apparently always created by pushing
the number of following bytes.
For example, if Load(view, 10) is called, then we've got two word
parameters, "view" (0x0080) and "10" (0x000a). So the callk function would
have kparams set to 4; this value would be pushed to the stack first,
followed by the two parameters.
So the stack would look like this (left means lower address, byte ordering
little endian):
</para><para>

<literal/02 00  80 00  0a 00/
</para><para>
before calling Load().

</para><para>

Return values are returned into the accumulator, unless stated otherwise.
If return type is stated as (void), then the accumulator is not modified.
</para>


<sect2>
<Title/Parameter types/
<para>
SCI0 uses only little endian 16 bit integer values for parameters. However, this document
distinguishes between different uses of those integers by defining the following variable
types:
<simplelist>
<member><Type/(word)/: 16 bit signed little endian integer</member>
<member><Type/(HeapPtr)/: As <Type/(word)/; interpreted as a pointer to a heap address</member>
<member><Type/(DblList)/: As <Type/(HeapPtr)/; interpreted as offset of a doubly linked list</member>
<member><Type/(Node)/: As <Type/(HeapPtr)/; interpreted as offset of a list node</member>
<member><Type/(&amp;FarPtr)/: As <Type/(HeapPtr)/; interpreted as the 32 bit pointer stored at
           the referenced heap address</member>
<member><Type/(Point)/: A sequence of two <Type/(word)/s to describe a point on the screen, with
the y coordinate being the first in the sequence.</member>
<member><Type/(Rect)/: A sequence of four <Type/(word)/s describing a rectangle. If you read
"(Rect) foo", think "(word) foo_ymin, (word) foo_xmin, (word) foo_ymax, (word) foo_xmax" instead.
</member>
<member><Type/(String)/: If greater than or equal to 1000, this is the heap address of a text string.
If less than 1000, it is the number of a text resource, and immediately followed by another word
that contains the number of the string inside the text resource.</member>
</simplelist>
</para><para>
Parameters in brackets (like "[foo]") are optional.
</para><para>
Most functions exit gracefully if either a NULL HeapPtr or DblList is
provided.
</para></sect2>

  &kernel-functions-doc; <!-- include external kfunction description -->

</sect1>

</Chapter>


<Chapter>
  <Title/SCI in action/
  <sect1 ID="LarsEvents">
   <Title/Event handling in SCI/
    <para>
     By <Author><FirstName/Lars/<SurName/Skovlund/</author>
    </para><para/Version 1.0, 12. July 1999/
<para>
This article will deal with the event manager in SCI. Like several other
key parts of the interpreter, this one actively communicates with the SCI
application. It directly writes to objects of the Event class, but more on
that later.
</para><para>
The different input devices are polled differently:
<itemizedlist>
<listitem><para>The keyboard is typically polled at each timer tick (which is 60 hz).</para>
</listitem>
<listitem><para>SCI sets up a callback for the PC mouse driver, meaning that
the mouse driver "polls itself" and sends information to the interpreter.
On non-MS-DOS platforms, this would probably be done in the timer handler.
<footnote><para>The default FreeSCI event mechanism uses libgii, which is completely
event-based.</para></footnote></para></listitem>
<listitem><para>The joystick is only polled when the script wants to.</para></listitem>
</itemizedlist>
</para><para>
Some parts of the event mechanism (in particular, keyboard management) are
very PC specific, and a conversion will no doubt have to take place on other
platforms.
</para>
 <sect2>
  <title/Event types and modifiers/
   <para>
There are three types of events, distinguished by their "type" property.
The possible values are listed below; they are laid out as a bitfield to
allow for selective event retrieval, see later.
<simplelist>
  <member/0x00 - Null event/
  <member/0x01 - Mouse button event/
  <member/0x02 - Mouse button release event/
  <member/0x04 - Keyboard event/
  <member/0x40 - Movement (joystick) event/
</simplelist>
</para><para>
This type is returned to the SCI event managers by the input device drivers
along with a "message" and a set of "modifiers". This is the basic event
structure, although some event types contain extra information. The latter
field is a direct copy of the BIOS shift flags, laid out as follows:
</para><para>
<simplelist>
<member/bit 7 - Insert active/
<member/bit 6 - Caps lock active/
<member/bit 5 - Num lock active/
<member/bit 4 - Scroll lock active/
<member/bit 3 - Alt key pressed/
<member/bit 2 - Ctrl key pressed/
<member/bit 1 - Left shift key pressed/
<member/bit 0 - Right shift key pressed/
</simplelist>
</para><para>
It is obvious, then, that these keys by themselves don't generate any
keyboard events. They can, however, be combined with other keys or mouse
clicks to produce "shift-click" events, for instance.
</para>
<sect3><title/The null events/
<para>
These are generated when a script wants to see an event, but there isn't one
to give. The current tick count and mouse position. The tick count, as 
explained in
another document, is the time passed since the interpreter started, measured
in 1/60ths of a second. It doesn't seem to be copied into the event object,
however.
</para>
</sect3>

<sect3>
 <title/The mouse events/
<para>
The mouse position is returned in extra fields in the event record.
</para><para>
If the middle or right button is pressed, this is reflected by the 
modifiers,
in addition to the mouse event. The middle button is translated to the Ctrl
key (i.e. set modifiers bit 2), the right button "holds down" both shift 
keys
(setting bits 1 and 0). Every SCI interpreter (at least from 0.000.572 and
up) does this, but to my knowledge it is used only in QfG2, where either
a shift-click or a right-click is equivalent to typing "look ...".
</para></sect3>

<sect3><title/The keyboard event/
<para>
The keyboard driver also generates events. When a key is pressed, a keyboard
event is generated, with the message field set to the scan code of the
pressed key. It should be simple enough, right? Not quite so. The script may
want to know if a direction key was pressed, and if so, which. It may call
the KMapKeyToDir kernel function for this. KMapKeyToDir takes a keyboard
event as input and converts it to a movement event, which is described next.
</para>
</sect3>

<sect3>
<title/The movement event/
<para>
The movement event is only generated by the joystick driver. However, on
request, the keyboard driver can convert keyboard events into movement 
events
as described above. The message field is just a direction code, mapped as
follows:
<informaltable frame="all">
    <tgroup cols="3">
     <tbody>
       <row>
        <entry/8/
        <entry/1/
        <entry/2/
       </row>
       <row>
        <entry/7/
        <entry/Center/
        <entry/3/
       </row>
       <row>
        <entry/6/
        <entry/5/
        <entry/4/
       </row>
     </tbody>
    </tgroup>
   </informaltable>
</para><para>
That is, the direction code starts at straight up (code 1), increasing
with clockwise movement.
</para>
</sect3>

</sect2>
  </sect1>
  <sect1 ID="LarsDMParser">
     <Title/The Parser/
        <sect2>
          <Title/Vocabulary file formats/
             <para>By <author><firstname/Lars/<surname/Skovlund/</author>
</para><para>
Version 1.0, 30. July 1999
</para>
<sect3><title/The main vocabulary (VOCAB.000)/
<para>
The file begins with a list of 26 offsets. Each index corresponds to a 
letter
in the (English) alphabet, and points to the first word starting with that
letter. The offset is set to 0 if no words start with that letter.
If an input word starts with an alphabetical letter, this table is
used to speed up the vocabulary searching - though not strictly necessary,
this speeds up the lookup process somewhat.
</para><para>
After the offset table are the actual words. A word defition consists of
two parts: The actual text of the word, compressed in a special way, and a
24-bit (yes, three bytes) ID. The ID divided in 2 12-bit quantities, a
word class (grammatically speaking) mask, and a group number.
The class mask is used, among other things, for throwing away unnecessary
words. "Take book", for instance, is a valid sentence in parser'ese, while 
it
isn't in English.
</para><para>
The possible values are arranged as a bit field to allow for
class masks, see later. Only one bit is actually tested by the interpreter.
If a word class equals to 0xff ("anyword"), the word is excluded (allowing for
parser'ese). The values go like this:
<simplelist>
<member/0x001 - number (not found in the vocabulary, set internally)/
<member/0x002 - special/
<member/0x004 - special/
<member>0x008 - special<footnote><para>The three special classes are apparently used for words
with very specific semantics, such as "if", "not", "and" etc. It is unknown as of yet whether they
receive special treatment by the parser.</para></footnote></member>
<member/0x010 - preposition/
<member/0x020 - article/
<member/0x040 - qualifying adjective/
<member/0x080 - relative pronoun/
<member/0x100 - noun/
<member/0x200 - indicative verb (such as "is", "went" as opposed to _do_ this or
that, which is imperative)/
<member/0x400 - adverb/
<member/0x800 - imperative verb/
</simplelist>
</para><para>
The group number is used to implement synonyms (words with the same
meaning), as well as by the Said instruction to identify words. There is 
also
a way of using synonyms in code, see the appropriate document.
</para><para>
The compression works in this way: Each string starts with a byte-sized copy
count. This many characters are retained from the previous string. The
actual text comes after, in normal low-ascii. The last character in the text
has its high bit set (no null termination!).
</para><para>
Here is an example of the compression scheme:
<simplelist>
<member/  apple - 0,appl\0xE5/
</simplelist>
</para><para>
The byte count is 0 because we assume that "apple" is the first word
beginning with an a (not likely, though!). 0xE5 is 0x65 (the ascii value
for 'e') | 0x80. Watch now the next word:
<simplelist>
<member/  athlete - 1,thlet\0xE5/
</simplelist>
</para><para>
Here, the initial letter is identical to that of its predecessor, so the
copy count is 1. Another example:
<simplelist>
<member/  atrocious - 2,rociou\0xF3/
</simplelist>
</para>
</sect3>
<sect3>
<Title/The suffix vocabulary (VOCAB.901)/
<note><para/
Note: You may need to consult a grammar book to fully understand the
following discussion./</note>
<para>
The suffix vocabulary is structurally much simpler. It consists of
variably-sized records with this layout:
<informaltable frame="all">
    <tgroup cols="2">
     <tbody>
       <row>
        <entry/NULL-TERMINATED/
        <entry/Suffix string/
       </row>
       <row>
        <entry/WORD/
        <entry/The class mask for the suffix/
       </row>
       <row>
        <entry/NULL-TERMINATED/
        <entry/Reduced string/
       </row>
       <row>
        <entry/WORD/
        <entry/The output word class/
       </row>
     </tbody>
    </tgroup>
</informaltable>
</para><para>
The suffix vocabulary is used by the interpreter in order to parse compound
words, and other words which consist of more than one part. For
instance, a simple plural noun like "enemies" is reduced to its singular
form "enemy", "stunning" is converted to "stun" etc. The point is that the
interpreter gets a second chance at figuring out the meaning if the word
can not be identified as entered. A word which changes its class does
might end up as a different word class, the correct class is always 
retained.
Thus, "carefully", an adverb, is reduced to its adjectival form "careful",
and found in the vocabulary as such, but it is still marked as an adverb.
</para><para>
The suffix vocabulary consists of variably-sized records with this layout:
<informaltable frame="all">
    <tgroup cols="2">
     <tbody>
       <row>
         <entry/NULL-TERMINATED/
         <entry/Suffix string/
       </row>
       <row>
         <entry/WORD/
         <entry/The output word class/
       </row>
       <row>
         <entry/NULL-TERMINATED/
         <entry/Reduced string/
       </row>
       <row>
         <entry/WORD/
         <entry/The allowed class mask for the reduced word/
       </row>
     </tbody>
    </tgroup>
</informaltable>
</para><para>
An asterisk (*) represents the word stem. Taking the above example with
"enemies", the interpreter finds this record:
<simplelist>
<member/  *ies/
<member/  0x100/
<member/  *y/
<member/  0x100/
</simplelist>
word class 0x100 being a noun.
</para><para>
The interpreter then tries to replace "enemies" with "enemy" and finds that
word in the vocabulary. "Enemy" is a noun (class 1), which it is also
supposed to be, according to the suffix vocabulary. Since we succeeded,
the word class is set to the output value (which is, incidentally, also 1).
</para>
<sect4><Title/Numbers/
<para>
If the word turns out to be a number (written with numbers, that is), and
that number is not listed explicitly in the vocabulary, it gets an ID of
0xFFD, and a word class of 0x100.
</para>
</sect4>
</sect3>
<sect3><Title/The tree vocabulary (VOCAB.900)/
<para>
This vocabulary is used solely for building parse trees. It consists of a
series of word values which end up in the data nodes on the tree. It doesn't 
make much
sense without the original parsing code.
</para>
</sect3>   
    </sect2>
    <sect2><Title/The black box: The magic behind Sierra's text parser/
    <para>By <author><firstname/Lars/<surname/Skovlund/</author>
</para><para>
Version 0.1, 30. July 1999. Incomplete!
</para><para>
This document describes the process of parsing user input and relating it
to game actions. This document does not describe the process of the user
typing his command; only the "behind-the-scenes" work is described, hence
the title.
</para><para>
The process of parsing is two-fold, mainly for speed reasons. The Parse
kernel function takes the actual input string and generates a special
"said" event (type 0x80) from it. This function is only called once per
line. Parse can either accept or reject the input. <note><para/A rejection can only
occur if Parse fails to identify a word in the sentence./</note> Even if Parse
accepts the sentence, it does not need to make sense. Still, syntax checks
are made - see later.
</para><para>
Assuming that the parsing succeeded, the User object (which encapsulates the
parser) then goes on to call the relevant event handlers. These event hand-
lerrs in turn call the Said kernel function. This function is potentially
called hundreds or even thousands of times, so it must execute as quickly
as possible. Said simply determines from the pre-parsed input line whether
or not a specific command is desired.
</para><para>
The Parse function must always work on an internal copy of the actual 
string,
because the user must be able to recall his exact last input using the F3
key. The parser's first step is to convert the input line to pure lower 
case.
This is because the vocabulary words are entered in lower case. The parser
then searches the main vocabulary (VOCAB.000), hoping to find the word.
</para><para>
This doesn't necessarily happen yet. Consider, for example, the meaning of
the word "carefully", which does not appear in the vocabulary, but is found
anyway. This is due to the so-called suffix vocabulary, which is discussed
in another document.
</para><para>
If the word still can't be found, the interpreter copies the failing word
into a buffer temporarily allocated on the heap (remember, the interpreter
operates on its own local buffers). It then calls the Game::wordFail method
which prints an appropriate message. The interpreter then deallocates the
buffer and exits (it does, however, still return an event. The claimed
property of that event is set to TRUE to indicate that the event has already
been responded to (error message printed)).
</para><para>
If the interpreter succeeds in identifying all the words, it then goes on to
check the syntax of the sentence - it builds a parse tree. See the appropri-
ate document.
</para><para>
If the syntax of the sentence is invalid, the interpreter calls
Game::syntaxFail, passing the entire input line. As for the error situation,
the event is claimed.
</para><para>
As mentioned in the beginning of this text, this function generates an
event. This event, apart from its type id, does not contain any data. 
Rather,
all pertinent data is kept in the interpreter.
</para><para>
The Said kernel function is called for each command which the game might 
respond to at any given time. Its only parameter is a pointer to a said 
information block which resides in script space. This block is described below
(see <XREF LINKEND="CRSaidSpec">).
</para><para>
The Said function first does some sanity checking on the event pointer which
Parse stored earlier. It must be a said event (type property), and it must
not have been handled by an earlier call to Said (claimed property).
</para><para>
It then word-extends the passed said block into a temporary buffer
(command codes are byte-sized, remember?). This is supposedly just for
convenience/speed, and not really needed.
</para>
   </sect2>
	<sect2><Title/The Parse tree/
		<para>
			<note><para/This and the two following sections borrow some ideas and structures from abstract
			language theory. Readers might want to consider related literature./
			  <para>Most of the information explained here was gathered by Lars Skovlund, and, before that, Dark Minister.</para></note>
		</para>
		<para>
		  After tokenizing, looking up, and finally aliasing the data found in the
		  parsed input string, the interpreter proceeds to build a parse tree T<subscript/&Pi;/
		  from the input tokens
		  <blockquote><para>
		    I := w<subscript/0/, w<subscript/1/, w<subscript/2/ ... w<subscript/n-1/
		  </para></blockquote>
		  where
		  <blockquote><para>
		    w<subscript>j</subscript> &isin; W
		    &gamma;<subscript>j</subscript> &isin; &Gamma;
		    &mu;<subscript>j</subscript> &isin; 2<superscript>C</superscript>
		    w<subscript>j</subscript> := (&gamma;<subscript>j</subscript>, &mu;<subscript>j</subscript>)
		  </para></blockquote>
		  with W being the set of all words, &Gamma being the set of all word groups, C being the set of all class masks {1, 2, 4, 8, 10, 20, 40, 80, 100},
		  &gamma;<subscript>j</subscript> being the word group w<subscript>j</subscript> belongs to, and
		  &mu;<subscript>j</subscript> being its class mask, as described above.
		</para>
		<para>
		  For the following sections, we will define
		  <blockquote><para>
		    group: W &rarr; &Gamma;
		    	group((&gamma;, &mu;)) := &gamma;

		    classes: W &rarr; C
		    	classes((&gamma;, &mu;)) := &mu;

		    C<subscript>x</subscript> := { w | w &isin; W. x &isin; class(w) }
		  </para></blockquote>
			To do that, it uses the class masks M as input for a pushdown automaton (PDA) A
			built from a parser grammar; if M was accepted by A, the parse tree T<subscript/&Pi;/ will
			be built from the matching syntax tree to represent the semantics.
		</para>
		<para>
			The PDA is defined by a grammar G=(V, &Sigma, P, s), most of which, along with its semantics, is
			stored in vocab.900. This resource contains a parser rule at every 20 bytes, starting with a
			non-terminal symbol v (one word) and a null-terminated list of up to five tuples (&sigma;<subscript/i/, m<subscript/i/), both of which
			are words. In these tuples, m<subscript/i/ is a terminal or non-terminal symbol (determined by &sigma;<subscript/i/), and
			&sigma;<subscript/i/ is the meaning of m<subscript/i/:
			<informaltable frame="all">
				<tgroup cols="2">
					<thead>
						<row>
							<entry>&sigma;<subscript/i/</entry>
							<entry/Type/
							<entry/Meaning/
						</row>
					</thead>
					<tbody>
						<row>
							<entry/0x141/
							<entry/Non-terminal/
							<entry/Predicate part: This identifies the first part of a sentence/
						</row>
						<row>
							<entry/0x142/
							<entry/Non-terminal/
							<entry/Subject part: This identifies the second part of a sentence/
						</row>
						<row>
							<entry/0x143/
							<entry/Non-terminal/
							<entry/Suffix part: This identifies the third and last part of a sentence/
						</row>
						<row>
							<entry/0x144/
							<entry/Non-terminal/
							<entry/Reference part: This identifies words that reference another word in the same sentence part/
						</row>
						<row>
							<entry/0x146/
							<entry/Terminal/
							<entry>Match on class mask: Matches if (m<subscript/i/ &isin; classes(w<subscript/j/))</entry>
						</row>
						<row>
							<entry/0x14d/
							<entry/Terminal/
							<entry>Match on word group: Matches if (m<subscript/i/ = group(w<subscript/j/))</entry>
						</row>
						<row>
							<entry/0x154/
							<entry/Terminal/
							<entry/"Force storage": Apparently, this was only used for debugging./
						</row>
					</tbody>
				</tgroup>
			</informaltable>
			With the notable exception of the first rule, these rules constitute P.  V := { x | &exist;R, R &isin; P. x &isin; R }; typically,
			V := {0x12f ... 0x13f}. s := m<subscript/0/ of the first rule encountered; in all games observed, it was set to 0x13c. &Sigma contains
			all word groups and class masks. For the sake of simplicity, we will consider rules matching composite class masks to be several rules.
			Here is a simplified example of what such a grammar might look like (the hexadecimal prefix '0x' is omitted for brevity):
			<example>
			  <title>Parse grammar example</title>
			  <blockquote><para>
	    G := ({12f ... 13e}, {C<subscript/1/, C<subscript/2/, C<subscript/4/ ... C<subscript/100/}, P, 13c)
	    P := {
	  	13c &rarr; 13b 134
	  	13c &rarr; 13b 13d 133
	  	13c &rarr; 13b 13d
	  	13c &rarr; 13b
	  	13c &rarr; 13b 13d 13b 13d
	    	13b &rarr; 131 134
	    	13b &rarr; 131 13d 13d
		13b &rarr; 131
		13d &rarr; 134
	    	131 &rarr; C<subscript/80/
	    	133 &rarr; C<subscript/20/
	    	134 &rarr; C<subscript/10/
	    }
			  </para></blockquote>
			</example>
			In addition to this grammar, each right-hand non-terminal m<subscript/i/ carries its semantic value &rho;<subscript>i</subscript>, which is
			not relevant for constructing a syntax tree, but must be considered for the semantic tree T<subscript>&Pi;</subscript>. These values were omitted
			in the example above.
			As in the example above, the grammar is a context-free (type 2) grammar, almost in Chomsky Normal Form (<acronym>CNF</acronym>) in SCI; constructing a
			grammar with CNF rules from it would be trivial.
			<footnote><para>FreeSCI constructs a <acronym>GNF</acronym> (Greibach Normal Form) representation from these rules for parsing.</para></footnote>
			<example><title>Parser example</title>
			  <para>
			    Parse is called with "open door".
			    <blockquote><para>
	      "open" &isin; (842, {C<subscript>80</subscript>}) (an imperative word of the word group 0x842)
	      "door" &isin; (917, {C<subscript>10</subscript>}) (a substantive of the word group 0x917)

	      I := (842, {C<subscript>80</subscript>}), (917, (C<subscript>10</subscript>)
			    </para></blockquote>
			    I is clearly accepted by automatons based on the grammar described above. Here are two possible derivations:
			    <blockquote><para>
	      D<subscript>0</subscript>:
	      13c
			      (13c &rarr; 13b 134)
	      |- 13b 134
			      (13b &rarr; 131)
	      |- 131 134
			      (131 &rarr; C<subscript>80</subscript>)
	      |- C<subscript>80</subscript> 134
			      (134 &rarr; C<subscript>10</subscript>)
	      |- C<subscript>80</subscript> C<subscript>10</subscript>


	      D<subscript>1</subscript>:
	      13c
			      (13c &rarr; 13b)
	      |- 13b
			      (13b &rarr; 131 134)
	      |- 131 134
			      (131 &rarr; C<subscript>80</subscript>)
	      |- C<subscript>80</subscript> 134
			      (134 &rarr; C<subscript>10</subscript>)
	      |- C<subscript>80</subscript> C<subscript>10</subscript>
			    </para></blockquote>
			  </para>
			</example>
			Obviously, G is an ambiguous grammar. In SCI, rule precedence is implied by rule order, so the resulting left derivation tree is well-defined
			(in the example, it would be defined by D<subscript>0</subscript>)
			<footnote><para>In FreeSCI, you can use the "parse" console command to retreive all possible left derivation trees</para></footnote>.
			</para>
			<sect3>
			  <title>Semantics</title>
			  <para>
			    This is important, since the parser does much more than just accept or discard input. Using the semantic tags applied to each non-terminal
			    on the right-hand side of a rule, it constructs what I will call the semantic parse tree T<subscript>&Pi;</subscript>, which attempts to
			    describe what the input means. For each non-terminal rule
			    <blockquote><para>
			      r := v<subscript>0</subscript> &rarr; v<subscript>1</subscript> v<subscript>2</subscript> ... v<subscript>n</subscript>
			    </para></blockquote>
			    there are semantic tags &sigma;<subscript>r,1</subscript>, &sigma;<subscript>r,2</subscript> ... &sigma;<subscript>r,n</subscript> &isin; S, as explained above.
			    T<subscript>&Pi;</subscript> is now constructed from the resulting derivation and the semantic tags assiociated with each non-terminal of the rule used. The construction
			    algorithm is explained below with T<subscript>&Pi;</subscript> being constructed from nodes, which have the following structure:
			    <blockquote><para>
			      Nodes := {&diams;} &cup; S × V × (Nodes &cup; &Gamma;)&lowast;
			    </para></blockquote>
			    Where S is the set of possible semantic values, and V is the set of non-terminals as defined in the grammar. We will also use the sequence
			    &gamma;<subscript>0</subscript>, &gamma;<subscript>1</subscript>, &gamma;<subscript>2</subscript> ... &gamma;<subscript>k-1</subscript>, which will represent the word groups the input tokens
			    belonged to (in the exact order they were accepted), and the sequence r<subscript>0</subscript>, r<subscript>1</subscript>, r<subscript>2</subscript> ... r<subscript>l-1</subscript>,
			    which will be the list of rules used to create the left derivation tree as described in the previous section.
			    <programlisting>
	      Helper function sci_said_recursive: S × V × (V &cup; &Sigma;)&lowast &rarr; Node
	      Parameters: s &isin S, Rule r &isin; V × (V &cup; &Sigma;): v<subscript>0</subscript> &rarr; v<subscript>1</subscript> v<subscript>2</subscript> ... v<subscript>i</subscript>
	      cn<subscript>mr</subscript> = cn<subscript>r</subscript>
	      Node n := s, v<subscript/0/
	      FOR j := 1 TO i
	      		IF (v<subscript/j/ &isin; &Sigma;) THEN
	      			n := n, &gamma;<subscript>cn<subscript>&gamma;</subscript></subscript>
	      			cn<subscript>&gamma;</subscript> := cn<subscript>&gamma;</subscript> + 1
	      		ELSE
	      			cn<subscript>oldr</subscript> := cn<subscript>r</subscript>
	      			cn<subscript>r</subscript> := cn<subscript>r</subscript> + 1
	      			n := n, sci_said_recursive(&sigma;<subscript>r<subscript>mr</subscript>,j</subscript>, r<subscript>cn<subscript>oldr</subscript></subscript>)
	      		FI
	      ROF
	      RETURN (n)


	      Helper function get_children: Node &rarr; Nodes&lowast;
			      get_children((s, v, n<subscript>0</subscript>, n<subscript>1</subscript> ... n<subscript>m</subscript>)) := n<subscript>0</subscript>, n<subscript>1</subscript> ... n<subscript>m</subscript>


	      Algorithm SCI-SAID-TREE
	      cn<subscript>&gamma;</subscript> := 0;
	      cn<subscript>r</subscript> := 1;
	      n<subscript>temp</subscript> := n<subscript>temp</subscript>, SCI-SAID-RECURSIVE(0, r<subscript>0</subscript>)
	      root(T<subscript>&Pi;</subscript>) := (141, 13f, get_children(n<subscript>temp</subscript>))
			    </programlisting>
			    Here is an example, based on the previous one:
			    <example><title/Semantic tree example/<blockquote><para>
	      k = 2:
	      &gamma;<subscript>0</subscript> = 842, &gamma;<subscript>1</subscript> = 917

	      l = 4
	      r<subscript>0</subscript> = 13c &rarr; 13b 134
	      &sigma;<subscript>r<subscript/0/,1</subscript> = 141, &sigma;<subscript>r<subscript/0/,2</subscript> = 142
	      r<subscript>1</subscript> = 13b &rarr; 131
	      &sigma;<subscript>r<subscript/1/,1</subscript> = 141
	      r<subscript>2</subscript> = 131 &rarr; C<subscript>80</subscript>
	      r<subscript>3</subscript> = 134 &rarr; C<subscript>10</subscript>

	      The resulting tree would look like this:

	      	(141 13f
	      		(141 13b
	      			(141 131 842)
	      		)
	      		(142 134 917)
	      	)
			    </para></blockquote></example>
			  </para>
			</sect3>
	</sect2>
	<sect2 ID="CRSaidSpec"><Title/Said specs/
		<para>
		  To test what the player wanted to say, SCI compares T<subscript>&Pi;</subscript> with a second tree, T<subscript>&Sigma;</subscript>, which is built
		  from a so-called Said spec. A Said spec is a variable-sized block in SCI memory which consists of a set of byte-sized operators and special tokens
		  (stored in the range 0xf0 to 0xf9) and word groups (in big-endian notation, so that they don't conflict with the operators); it is terminated by
		  the speial token 0xff. The meanings of the operators and special tokens are as follows:
		  <informaltable frame="all">
		    <tgroup cols="3">
		      <thead>
			<row>
			  <entry>Operator</entry>
			  <entry>Byte representation</entry>
			  <entry>Meaning</entry>
			</row>
		      </thead>
		      <tbody>
			<row>
			  <entry>,</entry>
			  <entry>f0</entry>
			  <entry>"OR". Used to specify alternatives to words, such as "take , get".</entry>
			</row>
			<row>
			  <entry>&amp;</entry>
			  <entry>f1</entry>
			  <entry>Unknown. Probably used for debugging.</entry>
			</row>
			<row>
			  <entry>/</entry>
			  <entry>f2</entry>
			  <entry>Sentence part separator. Only two of these tokens may be used, since sentences are split into a maximum of three parts.</entry>
			</row>
			<row>
			  <entry>(</entry>
			  <entry>f3</entry>
			  <entry>Used together with ')' for grouping</entry>
			</row>
			<row>
			  <entry>)</entry>
			  <entry>f4</entry>
			  <entry>See '('</entry>
			</row>
			<row>
			  <entry>[</entry>
			  <entry>f5</entry>
			  <entry>Used together with '[' for optional grouping. "[ a ]" means "either a or nothing"</entry>
			</row>
			<row>
			  <entry>]</entry>
			  <entry>f6</entry>
			  <entry>See '['.</entry>
			</row>
			<row>
			  <entry>#</entry>
			  <entry>f7</entry>
			  <entry>Unknown. Assumed to have been used exclusively for debugging, if at all.</entry>
			</row>
			<row>
			  <entry>&lt;</entry>
			  <entry>f8</entry>
			  <entry>Semantic reference operator (as in "get < up").</entry>
			</row>
			<row>
			  <entry>&gt;</entry>
			  <entry>f9</entry>
			  <entry>Instructs Said() not to claim the event passed to the previous Parse() call on a match. Used for successive matching.</entry>
			</row>
		      </tbody>
		    </tgroup>
		  </informaltable>
		</para>
		<para>
		  This sequence of operators and word groups is now used to build the Said tree T<subscript>&Sigma;</subscript>.
		  I will describe the algorithm used to generate T<subscript>&Sigma</subscript> by providing a grammar G<subscript>&Sigma;</subscript>, with
		  L(G<subscript>&Sigma;</subscript>) containing all valid Said specs. The semantics will be provided under each rule with a double arrow:
		  <programlisting>
	G<subscript>&Sigma;</subscript> = ({saidspec, optcont, leftspec, midspec, rightspec, word, cwordset, wordset, expr, cwordrefset, wordrefset, recref}, &Gamma;, P, saidspec)

	P := {
	  saidspec &rarr;	 leftspec optcont
				&rArr; (141 13f leftspec optcont)
			| leftspec midspec optcont
				&rArr; (141 13f leftspec midspec optcont)
			| leftspec midspec rightspec optcont
				&rArr; (141 13f leftspec midspec rightspec optcont)



	  optcont &rarr;	e
				&rArr;
			| >
				&rArr; (14b f900 f900)



	  leftspec &rarr;	e
				&rArr;
			| expr
				&rArr; (141 149 expr)



	  midspec &rarr;	 / expr
				&rArr; (142 14a expr)
			| [ / expr ]
				&rArr; (152 142 (142 14a expr))
			| /
				&rArr;



	  rightspec &rarr;	 / expr
				&rArr; (143 14a expr)
			| [ / expr ]
				&rArr; (152 143 (143 14a expr))
			| /
				&rArr;


	  word &rarr;	 &gamma; &isin; &Gamma;
				&rArr; (141 153 &gamma)


	  cwordset &rarr;	 wordset
				&rArr; (141 14f wordset)
			| [ wordset ]
				&rArr; (141 14f (152 14c (141 14f wordset)))


	  wordset &rarr;	 word
				&rArr; word
			| ( expr )
				&rArr; (141 14c expr)
			| wordset , wordset
				&rArr; wordset wordset
			| wordset , [ wordset ]
				&rArr; wordset wordset


	  expr &rarr;		 cwordset cwordrefset
				&rArr; cwordset cwordrefset
			| cwordset
				&rArr; cwordset
			| cwordrefset
				&rArr; cwordrefset
	

	  cwordrefset &rarr;	 wordrefset
				&rArr; wordrefset
			| [ wordrefset ]
				&rArr; (152 144 wordrefset)


	  wordrefset &rarr;	< wordset recref
				&rArr; (144 14f word) recref
			| < wordset
				&rArr; (144 14f word)
		        | < [ wordset ]
		                &rArr; (152 144 (144 14f wordset))


	  recref &rarr;	< wordset recref
				&rArr; (141 144 (144 14f wordset) recref)
			| < wordset
				&rArr; (141 144 (144 14f wordset))
	}
		  </programlisting>
		</para>
	</sect2>
	<sect2><title/Matching the trees/
		<para>
		  The exact algorithm used to compare T<subscript>&Pi;</subscript> to T<subscript>&Sigma;</subscript> is not known yet. The one described here is based
		  on the approximation used in FreeSCI, which is very similar to the original SCI one.
		</para>
		<para>
		  First, we need to describe a set of functions for traversing the nodes of T<subscript>&Sigma;</subscript> and T<subscript>&Pi;</subscript>, and doing
		  some work. They will be
		  operating on the sets N := { 0, i | (i - 1) &isin N } (all non-negative integral numbers), B := {tt, ff} (the boolean lattice with two elements), and
		  Nodes (which we defined earlier).
		  <blockquote><para>
	first: Node &rarr; S
		    first((s, v, n<subscript>0</subscript>, n<subscript/1/ ... n<subscript/i/)) := s
	    </para><para>

	second : Node &rarr; V
		    second((s, v, n<subscript>0</subscript>, n<subscript/1/ ... n<subscript/i/)) := v
	    </para><para>

	word : Node &rarr; &Gamma;
		    word((s, v, &gamma)) := &gamma;
	    </para><para>

	children : Node &rarr; Node&lowast;
		    children((s, v, n<subscript>0</subscript>, n<subscript/1/ ... n<subscript/i/)) := { m | &forall;m.m&isin;{ n<subscript>0</subscript>, n<subscript>1</subscript> ... n<subscript>i</subscript> } &and; m&isin;Node }
	    </para><para>

	all_children : Node &rarr; Node&lowast;
		    all_children(n) := children(n) &cup; { m | &exist;l.l&isin;all_children(n).m&isin;l }
	    </para><para>

	is_word : Node &rarr; B
		    is_word((s, v, n<subscript>0</subscript>, n<subscript/1/ ... n<subscript/i/) = tt &hArr; (i = 0) &and; n<subscript>0</subscript> &isin; &Gamma;
	    </para><para>

	contains_word : Node × S × &Gamma; &rarr; B
		    contains_word(n, s, &gamma;) = tt &gamma = 0xfff<footnote><para>This is the so-called "anyword". Words with
	      a word group of 0xfff match any other word.</para></footnote> &or; (&hArr; &exist;m.m&isin;all_children(n).(s = second(m)) &and (is_word(m) &and; (word(m) = &gamma)))
	    </para><para>

	verify_sentence_part_elements : Node × Node &rarr; B
		    verify_sentence_part_elements(n<subscript/p/, n<subscript/s/) = tt &hArr;
		    	(first(n<subscript/s/ = 152)
				&and; ((&forall;m.m &isin; Node.verify_sentence_part_elements(m, n<subscript/s/) &hArr; { w | &exist;t.t &isin; all_children(m).w = word(t)} = &empty;)
		    			&or; &exist;m &isin; children(n<subscript/s/).verify_sentence_part_elements(m, n<subscript/s/))
		    	) &or; ((second(n<subscript/s/) = 153)
				&and; (&exist;m.m &isin; children(n<subscript/s/).(&exist;o &isin; all_children(n<subscript/s/).(first(o) = first(n<subscript/p/)) &and word(o) = word(m)))
			) &or; ((second(n<subscript/s/) &isin; {144, 14c})
				&and; (&exist;m.m &isin; children(n<subscript/s/).verify_sentence_part(m, n<subscript/s/)))
	    </para><para>

	verify_sentence_part : Node × Node &rarr; B
		    verify_sentence_part(n<subscript/p/, n<subscript/s/) = tt &hArr; &forall;n.n &isin; children(n<subscript/s/):&exist;m.m&isin;children(n<subscript/p/).(first(m) = first(n)) &and; verify_sentence_part_elements(n, m)
	    </para><para>

	verify_sentence_part_brackets : Node × Node &rarr; B
		    verify_sentence_part_brackets(n<subscript/p/, n<subscript/s/) = tt &hArr;
				(first(n<subscript/p/) = 152 &and;
					 (&forall;m.m&isin;Node.(first(m) = first(n<subscript/s/)) &and (second(m) = second(n<subscript/s/)).
						verify_sentence_part(n<subscript/p/, m) &hArr; { w | &exist;t.t &isin; all_children(m).w = word(t)} = &empty;))
				&or; ((first(n<subscript/p/) &isin; {141, 142, 143}) &and; verify_sentence_part(n<subscript/p/, n<subscript/s/))

		  </para></blockquote>
		  With these functions, we can now define an algorithm for augmenting T<subscript>&Pi;</subscript> and T<subscript>&Sigma;</subscript>:
		  <blockquote><para>
	Algorithm SCI-AUGMENT

	matched := tt
	claim_on_match := tt

	FOREACH n &isin; root(T<subscript>&Sigma</subscript>)
		IF ((first(n) = 14b) &and; (second(n) = f900)) THEN claim_on_match := ff
		ELSE IF &not;verify_sentence_part_brackets(n, root(T<subscript>&Pi;</subscript>)) THEN
			matched := ff
	HCAEROF

		  </para></blockquote>
		  Augmenting succeeded if matched = tt; in this case, T<subscript>&Pi;</subscript> is one of the trees accepted by the description provided by T<subscript>&Sigma</subscript>.
		  In this case, Said() will return 1. It will also claim the event previously provided to Parse(), unless claim_on_match = ff.
		</para>
	</sect2>


  </sect1>
  <sect1 ID="LarsAnim"><title/Views and animation in SCI/
    <para>by <author><firstname/Lars/<surname/Skovlund/</author>
</para><para>
Version 0.2, 4. January 2002, with notes by Christoph Reichenbach
</para><para>
This chapter deals with a rather complex subject within SCI. The subsystem
described here is one of the "bad boys" in SCI, since it calls functions in
user space, as well as changing the value of various selectors. This
document is not necessarily complete. There are several things I have not
covered - because they are better off in a separate document, or simply
because I haven't yet figured that part out. IOW, this stuff is incomplete.
Things may change.
</para><para>
After drawing a pic on the screen (which is DrawPic's job, that doesn't
surprise now, does it?), some views have to be added to it. There are two
ways of doing this; the AddToPic and the Animate call. While AddToPic is
used for static views, Animate lets each animated view in the cast list
perform an "animation cycle".
</para><para>
An animation cycle is done entirely in SCI code (with the aid of some kernel
calls). It involves two other objects; the mover and the cycler. The mover
is responsible for controlling the motion of an actor towards a specific
point, while the cycler changes the image of the actor, making him appear to
walk, for instance.
</para><para>
The behaviour of a view is controlled by its signal property. This property
contains a bitfield which describes a lot of animation-related stuff. The
bits can be roughly divided into two groups; the script and interpreter bits
(I had called them Option and State bits at first, but that is not entirely
accurate). The first group allows the script to influence the drawing pro-
cess somewhat, the other are used internally by the interpreter. The two
groups overlap a bit, though.

	<table frame="all">
	  <title>SCI and FreeSCI signal bits</title>
	  <tgroup cols="4">
	    <thead>
	      <row>
		<entry>Bit #</entry>
		<entry>Name</entry>
		<entry>FreeSCI constant</entry>
		<entry>Meaning</entry>
	      </row>
	    </thead>
	    <tbody>
	      <row>
		<entry>0</entry>
		<entry></entry>
		<entry>_K_VIEW_SIG_FLAG_STOP_UPDATE</entry>
		<entry>A view updating process has ended</entry>
	      </row>
	      <row>
		<entry>1</entry>
		<entry></entry>
		<entry>_K_VIEW_SIG_FLAG_UPDATED</entry>
		<entry>The view object is being updated</entry>
	      </row>
	      <row>
		<entry>2</entry>
		<entry>noUpd</entry>
		<entry>_K_VIEW_SIG_FLAG_NO_UPDATE</entry>
		<entry>Don't actually draw the view</entry>
	      </row>
	      <row>
		<entry>3</entry>
		<entry></entry>
		<entry>_K_VIEW_SIG_FLAG_HIDDEN</entry>
		<entry>The view is hidden from sight. Often, if an actor is supposed to
		  enter and exit a room (such as the guards in the plazas in QfG2), this bit 
		  is used. When he's supposed to enter the room, bit 3 in his signal is cleared.
		  When he leaves, bit 3 is set, but his SCI object is not deleted.
		</entry>
	      </row>
	      <row>
		<entry>4</entry>
		<entry>fixPriOn</entry>
		<entry>_K_VIEW_SIG_FLAG_FIX_PRI_ON</entry>
		<entry>if this bit is set, the priority of the view never
		  changes (if it isn't, the interpreter recalculates the priority
		  automagically).
		</entry>
	      </row>
	      <row>
		<entry>5</entry>
		<entry></entry>
		<entry>_K_VIEW_SIG_FLAG_ALWAYS_UPDATE</entry>
		<entry></entry>
	      </row>
	      <row>
		<entry>6</entry>
		<entry></entry>
		<entry>_K_VIEW_SIG_FLAG_FORCE_UPDATE</entry>
		<entry></entry>
	      </row>
	      <row>
		<entry>7</entry>
		<entry></entry>
		<entry>_K_VIEW_SIG_FLAG_REMOVE</entry>
		<entry>The view should be removed from the screen (an interpreter bit -
		  its corresponding script bit is bit 3). If bit 3 isn't set as well, the
		  view reappears on the next frame.
		</entry>
	      </row>
	      <row>
		<entry>8</entry>
		<entry></entry>
		<entry>_K_VIEW_SIG_FLAG_FROZEN</entry>
		<entry>Deactivates the mover object of the view (it is "frozen" - the view
		  can still turn, however).
		</entry>
	      </row>
	      <row>
		<entry>9</entry>
		<entry>isExtra</entry>
		<entry>_K_VIEW_SIG_FLAG_IS_EXTRA</entry>
		<entry></entry>
	      </row>
	      <row>
		<entry>10</entry>
		<entry></entry>
		<entry>_K_VIEW_SIG_FLAG_HIT_OBSTACLE</entry>
		<entry>The view hit an obstacle on the last animation cycle</entry>
	      </row>
	      <row>
		<entry>11</entry>
		<entry></entry>
		<entry>_K_VIEW_SIG_FLAG_DOESNT_TURN</entry>
		<entry>Meaningful for actors only. Means that the actor does not turn, 
		  even though he is walking the "wrong way".
		</entry>
	      </row>
	      <row>
		<entry>12</entry>
		<entry></entry>
		<entry>_K_VIEW_SIG_FLAG_NO_CYCLER</entry>
		<entry>The view cycler is disabled. This makes the view float instead of walk.</entry>
	      </row>
	      <row>
		<entry>13</entry>
		<entry>ignoreHorizon</entry>
		<entry>_K_VIEW_SIG_FLAG_IGNORE_HORIZON</entry>
		<entry></entry>
	      </row>
	      <row>
		<entry>14</entry>
		<entry>ignrAct</entry>
		<entry>_K_VIEW_SIG_FLAG_IGNORE_ACTOR</entry>
		<entry>Actors can walk in the rectangle occupied by the view.
		  The behaviour of this bit is odd, and best expressed by example. The Guild
		  Master in QfG1 has his bit 14 set. This means that ego (or someone else) can
		  walk all the way to his chair (try sneaking in on him from behind). If we
		  clear this bit, we can't sneak in on him.
		</entry>
	      </row>
	      <row>
		<entry>15</entry>
		<entry></entry>
		<entry>_K_VIEW_SIG_FLAG_DISPOSE_ME</entry>
		<entry>The view should be disposed</entry>
	      </row>
	      <row>
		<entry>
		  <footnote id="animate-flags-freesci">
		    <para>
		      This flag is used internally in FreeSCI; it can't be found in the view
		      objects, only in their copies in the dynview widget list.
		    </para>
		  </footnote>
		</entry>
		<entry></entry>
		<entry>_K_VIEW_SIG_FLAG_FREESCI_PRIVATE</entry>
		<entry>Used as an intermediate result by the interpreter; marks
		  views that are going to have their nsRect/lsRect regions redrawn
		  (for the test in the main draw algorithm's step 17.1., below)
		</entry>
	      </row>
	      <row>
		<entry><footnoteref linkend="animate-flags-freesci"></entry>
		<entry></entry>
		<entry>_K_VIEW_SIG_FLAG_FRESCI_STOPUPD</entry>
		<entry>View has been 'stopupdated'. This flag is set whenever
		  the view has the STOP_UPDATE bit set, and cleared as soon as
		  it moves again. Stopupdated views are collided against differently
		  than normal views.</entry>
	      </row>
	    </tbody>
	  </tgroup>
	</table>
		

The unlisted bits are probably all interpreter bits. They don't seem to have
an effect when set. Many bits seem to be involved in the decision whether to
display a view or not. I have not completely figured this out.
<footnote><para>
The bit names I have written come from some debug information I got from
QfG2 - type "suck blue frog" then Ctrl-W to save the cast list!</para></footnote>
</para>
<para>
Animate (see <XREF LINKEND="KAnimate">) can be called in two ways:
<simplelist>
<member/Animate(DblList cast, bool cycle)/
<member/Animate()/
</simplelist>
If the second syntax is used, the two parameters are assumed to be zero.
</para><para>
The cast list is just a list of the views to draw. Animate creates a backup
of this list for updating purposes. However, this backup cast list isn't 
just
a normal copy. The interpreter copies some selectors from the view
(view, loop, cel, nsRect) and places them in a special data structure. This
indicates to me that there is a possibility that the view objects may be
deleted even though an update is anticipated.
</para><para>
The general pseudocode for Animate goes as follows:
<programlisting>
0. Backup PicNotValid: PicNotValid' := PicNotValid
1. If we don't have a new cast:
    1.1. if PicNotValid is set:
        1.1.1. Redraw picture with opening animation
    1.2. exit
2. For each view in the cast list:
    2.1. If view is not frozen:
	2.1.1. call view::doit(), performing an animation cycle
3. Prepare a list of y coordinates by traversing the cast list
4. For each view in the cast list:
    4.1. If the view resource view::view has not been loaded yet:
	4.1.1. Load view.nr, where nr=view::view
5. For each view in the cast list:
    5.1. If view::loop is invalid, set view::loop := 0
    5.2. If view::cel is invalid, set view::cel := 0
6. Sort the cast list, first by y, then by z
7. For each view in the cast list: Update view::nsRect (SetNowSeen())
8. For each view in the cast list: Unless the views' priority is fixed, recalculate it
9. For each view in the cast list:
    9.1. If NO_UPDATE is set for the view:
	9.1.1. If the following holds:
            9.1.1.1.     (VIEW_UPDATED || FORCE_UPDATE)
            9.1.1.2.  || (!(VIEW_UPDATED || FORCE_UPDATE) && !IS_HIDDEN && REMOVE_VIEW)
            9.1.1.3.  || (!(VIEW_UPDATED || FORCE_UPDATE) && !IS_HIDDEN && !REMOVE_VIEW && ALWAYS_UPDATE)
            9.1.1.4.  || (!(VIEW_UPDATED || FORCE_UPDATE) && IS_HIDDEN && ALWAYS_UPDATE)
	    9.1.1.5. then increase PicNotValid by one.
	9.1.2. Clear the STOP_UPDATE flag
    9.2. otherwise:
	9.2.1. If (STOP_UPDATE and !ALWAYS_UPDATE) or (!STOP_UPDATE and ALWAYS_UPDATE)
            9.2.1.1. Increase PicNotValid by one
	9.2.2. Clear the FORCE_UPDATE flag
10. If PicNotValid is now greater than zero, call the sub-algorithm described separately
11. For each view: If NO_UPDATE, IS_HIDDEN and ALWAYS_UPDATE are not set:
    11.1. [12] Save the area covered by the view's nsRect, store the handle in view::underBits
    11.2. [13] Draw the view object
    11.3. [14] If the view IS_HIDDEN, clear the REMOVE_VIEW bit (don't need to hide it twice)
    11.4. [15] Insert the view into the backup cast list
16. If PicNotValid', our copy of the initial value of PicNotValid, is non-zero:
    16.1. Refresh entire screen with opening animation
    16.2. PicNotValid := 0
17. For each view in the cast list:
    17.1. [18] If the view was changed in step 10 and neither REMOVE_VIEW nor NO_UPDATE is set:
        17.1.1. [19] Redraw the nsRect and lsRect areas
        17.1.2. [20] Copy the nsRect to the lsRect
        17.1.3. [21] If IS_HIDDEN, set REMOVE_VIEW as well
22. For each view in the reverse cast list:
    22.1. [23] If neither NO_UPDATE nor REMOVE_VIEW is set:
        22.1.1. Restore the underbits
        22.1.2. Clear the underbits
    22.2. [24] if DISPOSE_ME is set, call view::dispose to dispose it
</programlisting>

With the sub-algorithm being:

<programlisting>
1. For each view from the cast list:
    1.1. [2] If NO_UPDATE is set:
        1.1.1. [3] If REMOVE_VIEW is set:
            1.1.1.1. If PicNotValid is 0, restore the area covered by view::underBits
            1.1.1.2. Free view::underBits
        1.1.2. [4] Clear FORCE_UPDATE
        1.1.3. [5] If VIEW_UPDATED is set: Clear VIEW_UPDATED and NO_UPDATE
    1.2. otherwise (if NO_UPDATE is not set):
        1.2.1. Clear STOP_UPDATE
        1.2.2. Set NO_UPDATE
6. For each view from the cast list:
    6.1. [7] Draw the view
    6.2. [8] If ALWAYS_UPDATE, clear STOP_UPDATE, VIEW_UPDATED, NO_UPDATE, FORCE_UPDATE
    6.3. [9] Clip the nsRect against the boundaries of the "natural" priority band of the view
    6.4. [10] If IGNORE_ACTOR is clear, fill the area found in 6.3. with 0xf on the control map
11. For each view from the view list:
    11.1. if NO_UPDATE is set:
        11.1.1. [12] If IS_HIDDEN, then set REMOVE_VIEW, otherwise:
            11.1.1.1. clear REMOVE_VIEW
            11.1.1.2. [13] Save the area covered by the nsRect in the underBits
14. For each view from the cast list:
    14.1. If NO_UPDATE is set and IS_HIDDEN is clear:
        14.1.1. [15] Draw the view
</programlisting>

</para>
<note><para>
The ReAnimate subfunction (0x0D) of the Graph kernel call redraws parts of
the maps using the cast list created by Animate, whereas the ShowBits call
(0x0C) copies parts of the active map to the physical screen.
</para></note>

  </sect1>
</Chapter>

  &freesci-doc; <!-- Include freesci-specific documentation -->

</Book>
