<?xml version="1.0"?>
<feed xmlns="http://www.w3.org/2005/Atom" xml:lang="en">
	<id>http://sciwiki.sierrahelp.com/api.php?action=feedcontributions&amp;feedformat=atom&amp;user=Jeremiah+Nellis</id>
	<title>SCI Wiki - User contributions [en]</title>
	<link rel="self" type="application/atom+xml" href="http://sciwiki.sierrahelp.com/api.php?action=feedcontributions&amp;feedformat=atom&amp;user=Jeremiah+Nellis"/>
	<link rel="alternate" type="text/html" href="http://sciwiki.sierrahelp.com/index.php/Special:Contributions/Jeremiah_Nellis"/>
	<updated>2026-08-27T11:13:44Z</updated>
	<subtitle>User contributions</subtitle>
	<generator>MediaWiki 1.35.9</generator>
	<entry>
		<id>http://sciwiki.sierrahelp.com/index.php?title=SciAudio&amp;diff=14658</id>
		<title>SciAudio</title>
		<link rel="alternate" type="text/html" href="http://sciwiki.sierrahelp.com/index.php?title=SciAudio&amp;diff=14658"/>
		<updated>2020-07-12T20:09:46Z</updated>

		<summary type="html">&lt;p&gt;Jeremiah Nellis: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{SCISoftwareInfobox&lt;br /&gt;
| Software = sciAudio&lt;br /&gt;
| image = [[Image:SciAudio.png|200px]]&amp;lt;br /&amp;gt;&lt;br /&gt;
&amp;#039;&amp;#039;sciAudio Example&amp;#039;&amp;#039;&lt;br /&gt;
| Version = 1.1&lt;br /&gt;
| ReleaseDate = Oct. 20, 2012&lt;br /&gt;
| Developers = {{JeremiahNellisToolDev}}&lt;br /&gt;
| ProgLanguage = C#&lt;br /&gt;
| Platform = {{WinTool}}&lt;br /&gt;
| Type = {{ModTool}}&lt;br /&gt;
| Localization = English&lt;br /&gt;
| Website = &lt;br /&gt;
}} &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div align=&amp;quot;center&amp;quot;&amp;gt;&amp;lt;span style=&amp;quot;font-size: 22pt&amp;quot;&amp;gt;sciAudio&amp;lt;/span&amp;gt;&amp;lt;br /&amp;gt;&lt;br /&gt;
Version 1.1&amp;lt;br /&amp;gt;&lt;br /&gt;
&amp;#039;&amp;#039;Developer: [[Gumby]]&amp;#039;&amp;#039;&amp;lt;/div&amp;gt;&lt;br /&gt;
&amp;lt;br /&amp;gt;&lt;br /&gt;
==&amp;lt;br /&amp;gt;&amp;lt;br /&amp;gt; Description ==&lt;br /&gt;
&lt;br /&gt;
&amp;lt;blockquote&amp;gt;&lt;br /&gt;
sciAudio is here!  Check out the &amp;quot;LockerGnome Quest Redux&amp;quot; demo game to see it in action!&lt;br /&gt;
&lt;br /&gt;
Announcement here: http://sciprogramming.com/community/index.php?topic=634.0&lt;br /&gt;
&amp;lt;/blockquote&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==&amp;lt;br /&amp;gt; Features ==&lt;br /&gt;
&lt;br /&gt;
* Playback of WAV and MP3 files&lt;br /&gt;
* Unlimited number of sounds playing simultaneously&lt;br /&gt;
* Fade in/out, looping and volume control&lt;br /&gt;
* Classification of sounds for playback management&lt;br /&gt;
* Multiple commands may be issued simultaneously to the &amp;#039;controller&amp;#039; file&lt;br /&gt;
* Multiple controller files to avoid resource contention&lt;br /&gt;
* Runs hidden in background &amp;amp; will terminate itself shortly upon game close&lt;br /&gt;
* Calls to sciAudio are performed very similarly to the built-in SCI sound calls&lt;br /&gt;
* Poor man&amp;#039;s encryption (MP3&amp;#039;s only) - simply rename your .MP3 to be .sciAudio&lt;br /&gt;
* Log file for troubleshooting sound playback (&amp;#039;sciAudio.log&amp;#039; located in same directory as sciAudio.exe)&lt;br /&gt;
&lt;br /&gt;
&amp;amp;nbsp;&lt;br /&gt;
&lt;br /&gt;
== Limitations ==&lt;br /&gt;
&lt;br /&gt;
&amp;lt;blockquote&amp;gt;&lt;br /&gt;
Works only in Windows (requires .NET framework)&lt;br /&gt;
&amp;lt;/blockquote&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==&amp;lt;br /&amp;gt; Usage ==&lt;br /&gt;
&lt;br /&gt;
&amp;lt;blockquote&amp;gt;&lt;br /&gt;
===&amp;lt;br /&amp;gt;Setup ===&lt;br /&gt;
&lt;br /&gt;
# Place the 2 nAudio DLLs &amp;amp; executable into a subfolder within your game named &amp;#039;sciAudio&amp;#039;&lt;br /&gt;
# Create subfolders within sciAudio for your playback files.  Something like this&amp;lt;blockquote&amp;gt;&amp;lt;gamedir&amp;gt;\sciAudio\effects&amp;lt;br /&amp;gt;&amp;lt;gamedir&amp;gt;\sciAudio\music&amp;lt;/blockquote&amp;gt;&lt;br /&gt;
# Include the sciAudio.sc script &amp;amp; &amp;#039;use&amp;#039; it in any script you wish to have sciAudio playback in&lt;br /&gt;
&lt;br /&gt;
===&amp;lt;br /&amp;gt; Available commands ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;blockquote&amp;gt;&lt;br /&gt;
command &amp;lt;playback command&amp;gt;&lt;br /&gt;
&amp;lt;blockquote&amp;gt;&lt;br /&gt;
play&amp;lt;blockquote&amp;gt;&lt;br /&gt;
        Begins playback of a sound&amp;lt;/blockquote&amp;gt;&lt;br /&gt;
&lt;br /&gt;
stop&amp;lt;blockquote&amp;gt;&lt;br /&gt;
        Stops playback of a sound&amp;lt;/blockquote&amp;gt;&lt;br /&gt;
&lt;br /&gt;
change&amp;lt;blockquote&amp;gt;&lt;br /&gt;
Changes playback of a sound.  Used primarily for volume &amp;amp; loop control, very limited usefulness.&amp;lt;/blockquote&amp;gt;&lt;br /&gt;
&lt;br /&gt;
playx (play exclusively based on sound class)&amp;lt;blockquote&amp;gt;&lt;br /&gt;
This behaves just like the &amp;#039;play&amp;#039; command, but will stop any currently playing sounds with the same sound class as the specified class.&amp;lt;/blockquote&amp;gt;&lt;br /&gt;
&amp;lt;/blockquote&amp;gt;&lt;br /&gt;
fileName&lt;br /&gt;
&amp;lt;blockquote&amp;gt;Filename to playback, including the path.&amp;lt;/blockquote&amp;gt;&lt;br /&gt;
      &lt;br /&gt;
soundClass&lt;br /&gt;
&amp;lt;blockquote&amp;gt;Sound class to assign this sound.  This is simply a string to assign to the playback for the purpose of potentially changing or terminating all sounds with the same sound class at a later time.&lt;br /&gt;
   &lt;br /&gt;
For example, you might have several sound effects playing simultaneously in a room. Upon leaving the room, you want to stop all the sound effects.  To to this you would issue a stop &amp;lt;soundclass&amp;gt; command, which would stop all currently playing sounds with the specified sound class.&lt;br /&gt;
      &lt;br /&gt;
If no sound class is specified, a default sound class of &amp;quot;noClass&amp;quot; will be used&amp;lt;/blockquote&amp;gt;&lt;br /&gt;
&lt;br /&gt;
volume&lt;br /&gt;
&amp;lt;blockquote&amp;gt;Playback volume of sample.  Default is 100 (100% volume of sample).  Range: 0 to ~300?&amp;lt;/blockquote&amp;gt;&lt;br /&gt;
      &lt;br /&gt;
fadeInMillisecs&lt;br /&gt;
&amp;lt;blockquote&amp;gt;Number of milliseconds to fade in the sample&lt;br /&gt;
      &lt;br /&gt;
fadeOutMillisecs&lt;br /&gt;
&amp;lt;blockquote&amp;gt;Number of milliseconds to fade out a sample.  Can be issued with a play or stop command&amp;lt;/blockquote&amp;gt;&lt;br /&gt;
      &lt;br /&gt;
loopFadeInMillisecs&lt;br /&gt;
&amp;lt;blockquote&amp;gt;Number of milliseconds to fade in a sample between loops.&amp;lt;/blockquote&amp;gt;  &lt;br /&gt;
      &lt;br /&gt;
loopFadeOutMillisecs&lt;br /&gt;
&amp;lt;blockquote&amp;gt;Number of milliseconds to fade out a sample between loops.&amp;lt;/blockquote&amp;gt;&lt;br /&gt;
      &lt;br /&gt;
loopCount&lt;br /&gt;
&amp;lt;blockquote&amp;gt;Number of times to loop the sample.  Default is 0, -1 is infinite&amp;lt;/blockquote&amp;gt;&lt;br /&gt;
      &lt;br /&gt;
conductorFile&lt;br /&gt;
&amp;lt;blockquote&amp;gt;&amp;#039;Conductor&amp;#039; file name used to place commands into.  This is how commands are passed between the SCI virtual machine &amp;amp; the sciAudio application.  The sciAudio application constantly polls all conductor files, looking for changes &amp;amp; executes them.  These files must have extension of .con.&lt;br /&gt;
&lt;br /&gt;
The default value for this parameter is command.con.&lt;br /&gt;
&lt;br /&gt;
Utilization of this parameter is useful in the event you have many near-simultaneous playback commands issued from within your game.  Multiple different conductor files can mitigate the issue of potential file contention of just using a single file.  Most game developers will probably not need to use this option.&amp;lt;/blockquote&amp;gt;&lt;br /&gt;
&lt;br /&gt;
playXFadeOutMillisecs&lt;br /&gt;
&amp;lt;blockquote&amp;gt;Only used for the &amp;#039;playx&amp;#039; command.  Upon terminating any currently playing sounds for a sound class, this value will be used for the fade out.&lt;br /&gt;
&amp;lt;/blockquote&amp;gt;&lt;br /&gt;
&amp;lt;/blockquote&amp;gt;&lt;br /&gt;
&amp;lt;/blockquote&amp;gt;&lt;br /&gt;
&amp;lt;/blockquote&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==&amp;lt;br /&amp;gt; Examples ==&lt;br /&gt;
&lt;br /&gt;
&amp;lt;blockquote&amp;gt;&lt;br /&gt;
&amp;lt;div class=&amp;quot;CodeBlockHeader&amp;quot;&amp;gt;Code:&amp;lt;/div&amp;gt;&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;sci&amp;quot;&amp;gt;&lt;br /&gt;
(use &amp;quot;sciAudio&amp;quot;)&lt;br /&gt;
&lt;br /&gt;
(local&lt;br /&gt;
    snd&lt;br /&gt;
)&lt;br /&gt;
&lt;br /&gt;
(instance aud of sciAudio&lt;br /&gt;
   (properties)&lt;br /&gt;
   (method (init)&lt;br /&gt;
      (super:init())&lt;br /&gt;
   )&lt;br /&gt;
)&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div class=&amp;quot;CodeBlockHeader&amp;quot;&amp;gt;Code:&amp;lt;/div&amp;gt;&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;sci&amp;quot;&amp;gt;&lt;br /&gt;
// basic playback&lt;br /&gt;
(send snd:&lt;br /&gt;
   command(&amp;quot;play&amp;quot;)&lt;br /&gt;
   fileName(&amp;quot;effects\\score.sciAudio&amp;quot;)   // important: note the two backslashes in path name!&lt;br /&gt;
   volume(&amp;quot;35&amp;quot;)&lt;br /&gt;
   loopCount(&amp;quot;0&amp;quot;)&lt;br /&gt;
   fadeInMillisecs(&amp;quot;3000&amp;quot;)   // fade in beginning by 3 secs&lt;br /&gt;
   fadeOutMillisecs(&amp;quot;2000&amp;quot;)  // fade out ending by 2 secs&lt;br /&gt;
   init()&lt;br /&gt;
)&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div class=&amp;quot;CodeBlockHeader&amp;quot;&amp;gt;Code:&amp;lt;/div&amp;gt;&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;sci&amp;quot;&amp;gt;&lt;br /&gt;
// looping playback example&lt;br /&gt;
(send snd:&lt;br /&gt;
    command(&amp;quot;play&amp;quot;)&lt;br /&gt;
    fileName(&amp;quot;effects\\loopedSound.sciAudio&amp;quot;)&lt;br /&gt;
    volume(&amp;quot;100&amp;quot;)&lt;br /&gt;
    loopFadeInMillisecs(&amp;quot;2000&amp;quot;)&lt;br /&gt;
    loopFadeOutMillisecs(&amp;quot;2000&amp;quot;)&lt;br /&gt;
    loopCount(&amp;quot;-1&amp;quot;)  // loop forever&lt;br /&gt;
    init()&lt;br /&gt;
)&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div class=&amp;quot;CodeBlockHeader&amp;quot;&amp;gt;Code:&amp;lt;/div&amp;gt;&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;sci&amp;quot;&amp;gt;&lt;br /&gt;
// stop with 5 second fade out&lt;br /&gt;
(send snd:&lt;br /&gt;
   command(&amp;quot;stop&amp;quot;)&lt;br /&gt;
   fileName(&amp;quot;music\\introMusic.sciAudio&amp;quot;)&lt;br /&gt;
   fadeOutMillisecs(&amp;quot;5000&amp;quot;)&lt;br /&gt;
   loopCount(&amp;quot;0&amp;quot;)&lt;br /&gt;
   init()&lt;br /&gt;
)&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div class=&amp;quot;CodeBlockHeader&amp;quot;&amp;gt;Code:&amp;lt;/div&amp;gt;&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;sci&amp;quot;&amp;gt;&lt;br /&gt;
// change currently playing volume for a sound class&lt;br /&gt;
(send snd:&lt;br /&gt;
   command(&amp;quot;change&amp;quot;)&lt;br /&gt;
   soundClass(&amp;quot;myMusicSoundClass&amp;quot;)&lt;br /&gt;
   volume(&amp;quot;50&amp;quot;)   // set playback to 50% volume&lt;br /&gt;
   init()&lt;br /&gt;
)&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div class=&amp;quot;CodeBlockHeader&amp;quot;&amp;gt;Code:&amp;lt;/div&amp;gt;&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;sci&amp;quot;&amp;gt;&lt;br /&gt;
// stop looping a particular sound file&lt;br /&gt;
(send snd:&lt;br /&gt;
   command(&amp;quot;change&amp;quot;)&lt;br /&gt;
   soundClass(&amp;quot;music\\introMusic.sciAudio&amp;quot;)&lt;br /&gt;
   loopCount(&amp;quot;0&amp;quot;)  // stop looping&lt;br /&gt;
   init()&lt;br /&gt;
)&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div class=&amp;quot;CodeBlockHeader&amp;quot;&amp;gt;Code:&amp;lt;/div&amp;gt;&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;sci&amp;quot;&amp;gt;&lt;br /&gt;
// exclusive playback (starts new playback of sound&lt;br /&gt;
// &amp;amp; stops any already playing sounds (with fadeout) for same soundClass&lt;br /&gt;
(send snd:&lt;br /&gt;
   command(&amp;quot;playx&amp;quot;)&lt;br /&gt;
   soundClass(&amp;quot;narration&amp;quot;)&lt;br /&gt;
   conductorFile(&amp;quot;speech\\narrate.con&amp;quot;)&lt;br /&gt;
   fileName(&amp;quot;speech\\newNarration.sciAudio&amp;quot;)&lt;br /&gt;
   playXFadeOutMillisecs(&amp;quot;1500&amp;quot;) // will fade currently playing &amp;quot;narration&amp;quot; sound class sounds&lt;br /&gt;
   volume(&amp;quot;200&amp;quot;)&lt;br /&gt;
   init()&lt;br /&gt;
)&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&amp;lt;/blockquote&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==&amp;lt;br /&amp;gt;&amp;lt;br /&amp;gt; Version 1.2/1.2.1 ==&lt;br /&gt;
&lt;br /&gt;
New version attached here and also put all this code into a git repo, apparently it wasn&amp;#039;t before:  https://bitbucket.org/nellisjp/sciaudio/&lt;br /&gt;
&lt;br /&gt;
Now there is an sciAudio.ini file (needs to be in the sciAudio subdirectory of your game) that is read in and used for monitoring a list of (5) possible applications to monitor to determine when to kill sciAudio.  It&amp;#039;s a bit hacky, and 5 applications might be overkill but it gives a little flexibility and is backward-compatible with the previous versions which monitored either &amp;#039;RUN&amp;#039;, &amp;#039;DosBox&amp;#039; or &amp;#039;ntvdm&amp;#039;.  I also improved the logging around all of this so it&amp;#039;s a bit easier to troubleshoot.&lt;br /&gt;
&lt;br /&gt;
Here&amp;#039;s what the included INI file looks like, modify it to suit your needs:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div class=&amp;quot;CodeBlockHeader&amp;quot;&amp;gt;Code:&amp;lt;/div&amp;gt;&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;sci&amp;quot;&amp;gt;&lt;br /&gt;
[sciAudio]&lt;br /&gt;
GameExecutableName1=RUN&lt;br /&gt;
GameExecutableName2=DOSBox&lt;br /&gt;
GameExecutableName3=ntvdm&lt;br /&gt;
GameExecutableName4=&lt;br /&gt;
GameExecutableName5=&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Version 1.2.1 includes a fix that was causing the application to not work reliably because it was checking for the game application &amp;#039;too soon&amp;#039; and would abruptly exit.  Fix consists of a 5 second delay before watching currently running processes.&lt;br /&gt;
&lt;br /&gt;
==&amp;lt;br /&amp;gt; Notes ==&lt;br /&gt;
&lt;br /&gt;
If you decide to re-use the same sound instance for multiple sounds, it&amp;#039;s up to you to reset any previously specified properties, otherwise they will be carried over into the next command&lt;br /&gt;
&lt;br /&gt;
Use the sciAudio.log file (located in the same directory as executable) for troubleshooting sound playback.&lt;br /&gt;
&lt;br /&gt;
==&amp;lt;br /&amp;gt; Download ==&lt;br /&gt;
&lt;br /&gt;
&amp;lt;blockquote&amp;gt;&lt;br /&gt;
Download from here (source included):&lt;br /&gt;
* [[Image:ZIP.PNG|ZIP File]] [[scidl:AudioUtilities/SciAudio_v1.2.1.zip|sciAudio 1.2.1]]&amp;lt;span class=&amp;quot;DLInfo&amp;quot;&amp;gt; (ZIP file) [193 KB]&amp;lt;/span&amp;gt;&lt;br /&gt;
* [[Image:ZIP.PNG|ZIP File]] [[scidl:AudioUtilities/sciAudio10_wSRC.zip|sciAudio 1.0]]&amp;lt;span class=&amp;quot;DLInfo&amp;quot;&amp;gt; (ZIP file) [200 KB]&amp;lt;/span&amp;gt;&lt;br /&gt;
&amp;lt;/blockquote&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==&amp;lt;br /&amp;gt; Also See ==&lt;br /&gt;
&lt;br /&gt;
*&lt;/div&gt;</summary>
		<author><name>Jeremiah Nellis</name></author>
	</entry>
	<entry>
		<id>http://sciwiki.sierrahelp.com/index.php?title=SciAudio&amp;diff=14657</id>
		<title>SciAudio</title>
		<link rel="alternate" type="text/html" href="http://sciwiki.sierrahelp.com/index.php?title=SciAudio&amp;diff=14657"/>
		<updated>2020-07-12T20:07:25Z</updated>

		<summary type="html">&lt;p&gt;Jeremiah Nellis: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{SCISoftwareInfobox&lt;br /&gt;
| Software = sciAudio&lt;br /&gt;
| image = [[Image:SciAudio.png|200px]]&amp;lt;br /&amp;gt;&lt;br /&gt;
&amp;#039;&amp;#039;sciAudio Example&amp;#039;&amp;#039;&lt;br /&gt;
| Version = 1.1&lt;br /&gt;
| ReleaseDate = Oct. 20, 2012&lt;br /&gt;
| Developers = {{JeremiahNellisToolDev}}&lt;br /&gt;
| ProgLanguage = C#&lt;br /&gt;
| Platform = {{WinTool}}&lt;br /&gt;
| Type = {{ModTool}}&lt;br /&gt;
| Localization = English&lt;br /&gt;
| Website = &lt;br /&gt;
}} &lt;br /&gt;
&lt;br /&gt;
&amp;lt;div align=&amp;quot;center&amp;quot;&amp;gt;&amp;lt;span style=&amp;quot;font-size: 22pt&amp;quot;&amp;gt;sciAudio&amp;lt;/span&amp;gt;&amp;lt;br /&amp;gt;&lt;br /&gt;
Version 1.1&amp;lt;br /&amp;gt;&lt;br /&gt;
&amp;#039;&amp;#039;Developer: [[Gumby]]&amp;#039;&amp;#039;&amp;lt;/div&amp;gt;&lt;br /&gt;
&amp;lt;br /&amp;gt;&lt;br /&gt;
==&amp;lt;br /&amp;gt;&amp;lt;br /&amp;gt; Description ==&lt;br /&gt;
&lt;br /&gt;
&amp;lt;blockquote&amp;gt;&lt;br /&gt;
sciAudio is here!  Check out the &amp;quot;LockerGnome Quest Redux&amp;quot; demo game to see it in action!&lt;br /&gt;
&lt;br /&gt;
Announcement here: http://sciprogramming.com/community/index.php?topic=634.0&lt;br /&gt;
&amp;lt;/blockquote&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==&amp;lt;br /&amp;gt; Features ==&lt;br /&gt;
&lt;br /&gt;
* Playback of WAV and MP3 files&lt;br /&gt;
* Unlimited number of sounds playing simultaneously&lt;br /&gt;
* Fade in/out, looping and volume control&lt;br /&gt;
* Classification of sounds for playback management&lt;br /&gt;
* Multiple commands may be issued simultaneously to the &amp;#039;controller&amp;#039; file&lt;br /&gt;
* Multiple controller files to avoid resource contention&lt;br /&gt;
* Runs hidden in background &amp;amp; will terminate itself shortly upon game close&lt;br /&gt;
* Calls to sciAudio are performed very similarly to the built-in SCI sound calls&lt;br /&gt;
* Poor man&amp;#039;s encryption (MP3&amp;#039;s only) - simply rename your .MP3 to be .sciAudio&lt;br /&gt;
* Log file for troubleshooting sound playback (&amp;#039;sciAudio.log&amp;#039; located in same directory as sciAudio.exe)&lt;br /&gt;
&lt;br /&gt;
&amp;amp;nbsp;&lt;br /&gt;
&lt;br /&gt;
== Limitations ==&lt;br /&gt;
&lt;br /&gt;
&amp;lt;blockquote&amp;gt;&lt;br /&gt;
Works only in Windows (requires .NET framework)&lt;br /&gt;
&amp;lt;/blockquote&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==&amp;lt;br /&amp;gt; Usage ==&lt;br /&gt;
&lt;br /&gt;
&amp;lt;blockquote&amp;gt;&lt;br /&gt;
===&amp;lt;br /&amp;gt;Setup ===&lt;br /&gt;
&lt;br /&gt;
# Place the 2 nAudio DLLs &amp;amp; executable into a subfolder within your game named &amp;#039;sciAudio&amp;#039;&lt;br /&gt;
# Create subfolders within sciAudio for your playback files.  Something like this&amp;lt;blockquote&amp;gt;&amp;lt;gamedir&amp;gt;\sciAudio\effects&amp;lt;br /&amp;gt;&amp;lt;gamedir&amp;gt;\sciAudio\music&amp;lt;/blockquote&amp;gt;&lt;br /&gt;
# Include the sciAudio.sc script &amp;amp; &amp;#039;use&amp;#039; it in any script you wish to have sciAudio playback in&lt;br /&gt;
&lt;br /&gt;
===&amp;lt;br /&amp;gt; Available commands ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;blockquote&amp;gt;&lt;br /&gt;
command &amp;lt;playback command&amp;gt;&lt;br /&gt;
&amp;lt;blockquote&amp;gt;&lt;br /&gt;
play&amp;lt;blockquote&amp;gt;&lt;br /&gt;
        Begins playback of a sound&amp;lt;/blockquote&amp;gt;&lt;br /&gt;
&lt;br /&gt;
stop&amp;lt;blockquote&amp;gt;&lt;br /&gt;
        Stops playback of a sound&amp;lt;/blockquote&amp;gt;&lt;br /&gt;
&lt;br /&gt;
change&amp;lt;blockquote&amp;gt;&lt;br /&gt;
Changes playback of a sound.  Used primarily for volume &amp;amp; loop control, very limited usefulness.&amp;lt;/blockquote&amp;gt;&lt;br /&gt;
&lt;br /&gt;
playx (play exclusively based on sound class)&amp;lt;blockquote&amp;gt;&lt;br /&gt;
This behaves just like the &amp;#039;play&amp;#039; command, but will stop any currently playing sounds with the same sound class as the specified class.&amp;lt;/blockquote&amp;gt;&lt;br /&gt;
&amp;lt;/blockquote&amp;gt;&lt;br /&gt;
fileName&lt;br /&gt;
&amp;lt;blockquote&amp;gt;Filename to playback, including the path.&amp;lt;/blockquote&amp;gt;&lt;br /&gt;
      &lt;br /&gt;
soundClass&lt;br /&gt;
&amp;lt;blockquote&amp;gt;Sound class to assign this sound.  This is simply a string to assign to the playback for the purpose of potentially changing or terminating all sounds with the same sound class at a later time.&lt;br /&gt;
   &lt;br /&gt;
For example, you might have several sound effects playing simultaneously in a room. Upon leaving the room, you want to stop all the sound effects.  To to this you would issue a stop &amp;lt;soundclass&amp;gt; command, which would stop all currently playing sounds with the specified sound class.&lt;br /&gt;
      &lt;br /&gt;
If no sound class is specified, a default sound class of &amp;quot;noClass&amp;quot; will be used&amp;lt;/blockquote&amp;gt;&lt;br /&gt;
&lt;br /&gt;
volume&lt;br /&gt;
&amp;lt;blockquote&amp;gt;Playback volume of sample.  Default is 100 (100% volume of sample).  Range: 0 to ~300?&amp;lt;/blockquote&amp;gt;&lt;br /&gt;
      &lt;br /&gt;
fadeInMillisecs&lt;br /&gt;
&amp;lt;blockquote&amp;gt;Number of milliseconds to fade in the sample&lt;br /&gt;
      &lt;br /&gt;
fadeOutMillisecs&lt;br /&gt;
&amp;lt;blockquote&amp;gt;Number of milliseconds to fade out a sample.  Can be issued with a play or stop command&amp;lt;/blockquote&amp;gt;&lt;br /&gt;
      &lt;br /&gt;
loopFadeInMillisecs&lt;br /&gt;
&amp;lt;blockquote&amp;gt;Number of milliseconds to fade in a sample between loops.&amp;lt;/blockquote&amp;gt;  &lt;br /&gt;
      &lt;br /&gt;
loopFadeOutMillisecs&lt;br /&gt;
&amp;lt;blockquote&amp;gt;Number of milliseconds to fade out a sample between loops.&amp;lt;/blockquote&amp;gt;&lt;br /&gt;
      &lt;br /&gt;
loopCount&lt;br /&gt;
&amp;lt;blockquote&amp;gt;Number of times to loop the sample.  Default is 0, -1 is infinite&amp;lt;/blockquote&amp;gt;&lt;br /&gt;
      &lt;br /&gt;
conductorFile&lt;br /&gt;
&amp;lt;blockquote&amp;gt;&amp;#039;Conductor&amp;#039; file name used to place commands into.  This is how commands are passed between the SCI virtual machine &amp;amp; the sciAudio application.  The sciAudio application constantly polls all conductor files, looking for changes &amp;amp; executes them.  These files must have extension of .con.&lt;br /&gt;
&lt;br /&gt;
The default value for this parameter is command.con.&lt;br /&gt;
&lt;br /&gt;
Utilization of this parameter is useful in the event you have many near-simultaneous playback commands issued from within your game.  Multiple different conductor files can mitigate the issue of potential file contention of just using a single file.  Most game developers will probably not need to use this option.&amp;lt;/blockquote&amp;gt;&lt;br /&gt;
&lt;br /&gt;
playXFadeOutMillisecs&lt;br /&gt;
&amp;lt;blockquote&amp;gt;Only used for the &amp;#039;playx&amp;#039; command.  Upon terminating any currently playing sounds for a sound class, this value will be used for the fade out.&lt;br /&gt;
&amp;lt;/blockquote&amp;gt;&lt;br /&gt;
&amp;lt;/blockquote&amp;gt;&lt;br /&gt;
&amp;lt;/blockquote&amp;gt;&lt;br /&gt;
&amp;lt;/blockquote&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==&amp;lt;br /&amp;gt; Examples ==&lt;br /&gt;
&lt;br /&gt;
&amp;lt;blockquote&amp;gt;&lt;br /&gt;
&amp;lt;div class=&amp;quot;CodeBlockHeader&amp;quot;&amp;gt;Code:&amp;lt;/div&amp;gt;&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;sci&amp;quot;&amp;gt;&lt;br /&gt;
(use &amp;quot;sciAudio&amp;quot;)&lt;br /&gt;
&lt;br /&gt;
(local&lt;br /&gt;
    snd&lt;br /&gt;
)&lt;br /&gt;
&lt;br /&gt;
(instance aud of sciAudio&lt;br /&gt;
   (properties)&lt;br /&gt;
   (method (init)&lt;br /&gt;
      (super:init())&lt;br /&gt;
   )&lt;br /&gt;
)&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div class=&amp;quot;CodeBlockHeader&amp;quot;&amp;gt;Code:&amp;lt;/div&amp;gt;&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;sci&amp;quot;&amp;gt;&lt;br /&gt;
// basic playback&lt;br /&gt;
(send snd:&lt;br /&gt;
   command(&amp;quot;play&amp;quot;)&lt;br /&gt;
   fileName(&amp;quot;effects\\score.sciAudio&amp;quot;)   // important: note the two backslashes in path name!&lt;br /&gt;
   volume(&amp;quot;35&amp;quot;)&lt;br /&gt;
   loopCount(&amp;quot;0&amp;quot;)&lt;br /&gt;
   fadeInMillisecs(&amp;quot;3000&amp;quot;)   // fade in beginning by 3 secs&lt;br /&gt;
   fadeOutMillisecs(&amp;quot;2000&amp;quot;)  // fade out ending by 2 secs&lt;br /&gt;
   init()&lt;br /&gt;
)&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div class=&amp;quot;CodeBlockHeader&amp;quot;&amp;gt;Code:&amp;lt;/div&amp;gt;&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;sci&amp;quot;&amp;gt;&lt;br /&gt;
// looping playback example&lt;br /&gt;
(send snd:&lt;br /&gt;
    command(&amp;quot;play&amp;quot;)&lt;br /&gt;
    fileName(&amp;quot;effects\\loopedSound.sciAudio&amp;quot;)&lt;br /&gt;
    volume(&amp;quot;100&amp;quot;)&lt;br /&gt;
    loopFadeInMillisecs(&amp;quot;2000&amp;quot;)&lt;br /&gt;
    loopFadeOutMillisecs(&amp;quot;2000&amp;quot;)&lt;br /&gt;
    loopCount(&amp;quot;-1&amp;quot;)  // loop forever&lt;br /&gt;
    init()&lt;br /&gt;
)&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div class=&amp;quot;CodeBlockHeader&amp;quot;&amp;gt;Code:&amp;lt;/div&amp;gt;&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;sci&amp;quot;&amp;gt;&lt;br /&gt;
// stop with 5 second fade out&lt;br /&gt;
(send snd:&lt;br /&gt;
   command(&amp;quot;stop&amp;quot;)&lt;br /&gt;
   fileName(&amp;quot;music\\introMusic.sciAudio&amp;quot;)&lt;br /&gt;
   fadeOutMillisecs(&amp;quot;5000&amp;quot;)&lt;br /&gt;
   loopCount(&amp;quot;0&amp;quot;)&lt;br /&gt;
   init()&lt;br /&gt;
)&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div class=&amp;quot;CodeBlockHeader&amp;quot;&amp;gt;Code:&amp;lt;/div&amp;gt;&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;sci&amp;quot;&amp;gt;&lt;br /&gt;
// change currently playing volume for a sound class&lt;br /&gt;
(send snd:&lt;br /&gt;
   command(&amp;quot;change&amp;quot;)&lt;br /&gt;
   soundClass(&amp;quot;myMusicSoundClass&amp;quot;)&lt;br /&gt;
   volume(&amp;quot;50&amp;quot;)   // set playback to 50% volume&lt;br /&gt;
   init()&lt;br /&gt;
)&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div class=&amp;quot;CodeBlockHeader&amp;quot;&amp;gt;Code:&amp;lt;/div&amp;gt;&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;sci&amp;quot;&amp;gt;&lt;br /&gt;
// stop looping a particular sound file&lt;br /&gt;
(send snd:&lt;br /&gt;
   command(&amp;quot;change&amp;quot;)&lt;br /&gt;
   soundClass(&amp;quot;music\\introMusic.sciAudio&amp;quot;)&lt;br /&gt;
   loopCount(&amp;quot;0&amp;quot;)  // stop looping&lt;br /&gt;
   init()&lt;br /&gt;
)&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div class=&amp;quot;CodeBlockHeader&amp;quot;&amp;gt;Code:&amp;lt;/div&amp;gt;&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;sci&amp;quot;&amp;gt;&lt;br /&gt;
// exclusive playback (starts new playback of sound&lt;br /&gt;
// &amp;amp; stops any already playing sounds (with fadeout) for same soundClass&lt;br /&gt;
(send snd:&lt;br /&gt;
   command(&amp;quot;playx&amp;quot;)&lt;br /&gt;
   soundClass(&amp;quot;narration&amp;quot;)&lt;br /&gt;
   conductorFile(&amp;quot;speech\\narrate.con&amp;quot;)&lt;br /&gt;
   fileName(&amp;quot;speech\\newNarration.sciAudio&amp;quot;)&lt;br /&gt;
   playXFadeOutMillisecs(&amp;quot;1500&amp;quot;) // will fade currently playing &amp;quot;narration&amp;quot; sound class sounds&lt;br /&gt;
   volume(&amp;quot;200&amp;quot;)&lt;br /&gt;
   init()&lt;br /&gt;
)&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&amp;lt;/blockquote&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==&amp;lt;br /&amp;gt;&amp;lt;br /&amp;gt; Version 1.2.1 ==&lt;br /&gt;
&lt;br /&gt;
New version attached here and also put all this code into a git repo, apparently it wasn&amp;#039;t before:  https://bitbucket.org/nellisjp/sciaudio/&lt;br /&gt;
&lt;br /&gt;
Now there is an sciAudio.ini file (needs to be in the sciAudio subdirectory of your game) that is read in and used for monitoring a list of (5) possible applications to monitor to determine when to kill sciAudio.  It&amp;#039;s a bit hacky, and 5 applications might be overkill but it gives a little flexibility and is backward-compatible with the previous versions which monitored either &amp;#039;RUN&amp;#039;, &amp;#039;DosBox&amp;#039; or &amp;#039;ntvdm&amp;#039;.  I also improved the logging around all of this so it&amp;#039;s a bit easier to troubleshoot.&lt;br /&gt;
&lt;br /&gt;
Here&amp;#039;s what the included INI file looks like, modify it to suit your needs:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div class=&amp;quot;CodeBlockHeader&amp;quot;&amp;gt;Code:&amp;lt;/div&amp;gt;&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;sci&amp;quot;&amp;gt;&lt;br /&gt;
[sciAudio]&lt;br /&gt;
GameExecutableName1=RUN&lt;br /&gt;
GameExecutableName2=DOSBox&lt;br /&gt;
GameExecutableName3=ntvdm&lt;br /&gt;
GameExecutableName4=&lt;br /&gt;
GameExecutableName5=&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==&amp;lt;br /&amp;gt; Notes ==&lt;br /&gt;
&lt;br /&gt;
If you decide to re-use the same sound instance for multiple sounds, it&amp;#039;s up to you to reset any previously specified properties, otherwise they will be carried over into the next command&lt;br /&gt;
&lt;br /&gt;
Use the sciAudio.log file (located in the same directory as executable) for troubleshooting sound playback.&lt;br /&gt;
&lt;br /&gt;
==&amp;lt;br /&amp;gt; Download ==&lt;br /&gt;
&lt;br /&gt;
&amp;lt;blockquote&amp;gt;&lt;br /&gt;
Download from here (source included):&lt;br /&gt;
* [[Image:ZIP.PNG|ZIP File]] [[scidl:AudioUtilities/SciAudio_v1.2.1.zip|sciAudio 1.2.1]]&amp;lt;span class=&amp;quot;DLInfo&amp;quot;&amp;gt; (ZIP file) [193 KB]&amp;lt;/span&amp;gt;&lt;br /&gt;
* [[Image:ZIP.PNG|ZIP File]] [[scidl:AudioUtilities/sciAudio10_wSRC.zip|sciAudio 1.0]]&amp;lt;span class=&amp;quot;DLInfo&amp;quot;&amp;gt; (ZIP file) [200 KB]&amp;lt;/span&amp;gt;&lt;br /&gt;
&amp;lt;/blockquote&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==&amp;lt;br /&amp;gt; Also See ==&lt;br /&gt;
&lt;br /&gt;
*&lt;/div&gt;</summary>
		<author><name>Jeremiah Nellis</name></author>
	</entry>
	<entry>
		<id>http://sciwiki.sierrahelp.com/index.php?title=File:SciAudio_v.1.2.1.zip&amp;diff=14656</id>
		<title>File:SciAudio v.1.2.1.zip</title>
		<link rel="alternate" type="text/html" href="http://sciwiki.sierrahelp.com/index.php?title=File:SciAudio_v.1.2.1.zip&amp;diff=14656"/>
		<updated>2020-07-12T19:47:09Z</updated>

		<summary type="html">&lt;p&gt;Jeremiah Nellis: sciAudio version 1.2.1 - Added 5 second delay before checking running processes for the game executable&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;sciAudio version 1.2.1 - Added 5 second delay before checking running processes for the game executable&lt;/div&gt;</summary>
		<author><name>Jeremiah Nellis</name></author>
	</entry>
	<entry>
		<id>http://sciwiki.sierrahelp.com/index.php?title=SCI_Specifications:_Chapter_3_-_The_Graphics_subsystem&amp;diff=9347</id>
		<title>SCI Specifications: Chapter 3 - The Graphics subsystem</title>
		<link rel="alternate" type="text/html" href="http://sciwiki.sierrahelp.com/index.php?title=SCI_Specifications:_Chapter_3_-_The_Graphics_subsystem&amp;diff=9347"/>
		<updated>2016-02-02T11:44:01Z</updated>

		<summary type="html">&lt;p&gt;Jeremiah Nellis: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;==General stuff==&lt;br /&gt;
The graphics in SCI are generated using four resource types:&lt;br /&gt;
&lt;br /&gt;
* Pic resources for background pictures&lt;br /&gt;
* View resources for images&lt;br /&gt;
* Font resources for drawing text&lt;br /&gt;
* Cursor resources for displaying the mouse pointer&lt;br /&gt;
&lt;br /&gt;
Those resources are drawn on three distinct maps:&lt;br /&gt;
&lt;br /&gt;
* The visual map, used for displaying the actual pictures the player sees&lt;br /&gt;
* The priority map, which keeps information about how the depth of the screen&lt;br /&gt;
* The control map, which contains special information&lt;br /&gt;
&lt;br /&gt;
==SCI Ports==&lt;br /&gt;
&lt;br /&gt;
&amp;#039;&amp;#039;&amp;#039;Lars Skovlund&amp;#039;&amp;#039;&amp;#039;&lt;br /&gt;
&lt;br /&gt;
Version 1.0, 6. July 1999&lt;br /&gt;
&lt;br /&gt;
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.&lt;br /&gt;
&lt;br /&gt;
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.&lt;br /&gt;
&lt;br /&gt;
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 &amp;quot;picture window&amp;quot; (such a thing really exists in SCI!) is 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).&lt;br /&gt;
&lt;br /&gt;
At least three ports are created and managed automatically by the SCI interpreter. These are the &amp;quot;window manager&amp;quot; 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 &amp;quot;invisible&amp;quot; port, on which the window backgrounds are drawn, although the windows have a port themselves. If you are familiar with Windows™ programming, the term &amp;quot;client rectangle&amp;quot; may ring a bell here - SCI draws the window backgrounds, using values in the window manager port, while the window&amp;#039;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&amp;#039;t mess up the graphics.&lt;br /&gt;
&lt;br /&gt;
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 &amp;quot;port&amp;quot; property. Instead, its &amp;quot;window&amp;quot; property points to the extended port/window structure which can safely be passed to KSetPort. Not surprisingly, many of KNewWindow&amp;#039;s arguments end up in the port part of the window structure.&lt;br /&gt;
&lt;br /&gt;
An SCI program can&amp;#039;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.&lt;br /&gt;
&lt;br /&gt;
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.&lt;br /&gt;
&lt;br /&gt;
Only two kernel calls deal directly with ports:&lt;br /&gt;
&lt;br /&gt;
KGetPort (see [[SCI_Specifications:_Chapter_5_(cont.)_-_Kernel_functions#Kernel_function_0x14:_GetPort.28.29|the Section called Kernel function 0x14: GetPort() in Chapter 5]])&amp;lt;br&amp;gt;&lt;br /&gt;
KSetPort (see [[SCI_Specifications:_Chapter_5_(cont.)_-_Kernel_functions#Kernel_function_0x15:_SetPort.28.29|the Section called Kernel function 0x15: SetPort() in Chapter 5]])&lt;br /&gt;
&lt;br /&gt;
These two functions are often used in pairs (also internally), like:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;var temp;&lt;br /&gt;
&lt;br /&gt;
temp=KGetPort();  /* Save the old port */&lt;br /&gt;
KSetPort(...);      /* Activate some other port */&lt;br /&gt;
..                            /* Draw some stuff */&lt;br /&gt;
KSetPort(temp);    /* Reactivate the old port */&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==The Cursor resource==&lt;br /&gt;
&lt;br /&gt;
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.&lt;br /&gt;
&lt;br /&gt;
0x00 - 0x01&lt;br /&gt;
&lt;br /&gt;
:: X coordinate of the mouse cursor hot spot as a 16 bit integer. This variable is not used in SCI0. &lt;br /&gt;
&lt;br /&gt;
0x02 - 0x03&lt;br /&gt;
&lt;br /&gt;
:: 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). &lt;br /&gt;
&lt;br /&gt;
0x04 - 0x23&lt;br /&gt;
&lt;br /&gt;
:: This is a list of 16 unsigned 16 bit integers constituting bitmasks for the mouse cursor&amp;#039;s transparency map, with the MSB representing the leftmost pixel. &lt;br /&gt;
&lt;br /&gt;
0x24 - 0x43&lt;br /&gt;
&lt;br /&gt;
:: 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). &lt;br /&gt;
&lt;br /&gt;
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.&lt;br /&gt;
&lt;br /&gt;
&amp;amp;nbsp;&lt;br /&gt;
&lt;br /&gt;
===Color mapping for the SCI0 mouse pointer===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;blockquote&amp;gt;&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot; width=&amp;quot;150&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! align=&amp;quot;center&amp;quot; width=&amp;quot;25&amp;quot; | AB&lt;br /&gt;
! width=&amp;quot;120&amp;quot; | Result&lt;br /&gt;
|-&lt;br /&gt;
| align=&amp;quot;center&amp;quot; width=&amp;quot;25&amp;quot; | 00&lt;br /&gt;
| width=&amp;quot;120&amp;quot; | Transparent&lt;br /&gt;
|-&lt;br /&gt;
| align=&amp;quot;center&amp;quot; width=&amp;quot;25&amp;quot; | 01&lt;br /&gt;
| width=&amp;quot;120&amp;quot; | Transparent&lt;br /&gt;
|-&lt;br /&gt;
| align=&amp;quot;center&amp;quot; width=&amp;quot;25&amp;quot; | 10&lt;br /&gt;
| width=&amp;quot;120&amp;quot; | 0x00 (Black)&lt;br /&gt;
|-&lt;br /&gt;
| align=&amp;quot;center&amp;quot; width=&amp;quot;25&amp;quot; | 11&lt;br /&gt;
| width=&amp;quot;120&amp;quot; | 0x0f (White)&lt;br /&gt;
|}&lt;br /&gt;
&amp;lt;/blockquote&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;amp;nbsp;&lt;br /&gt;
&lt;br /&gt;
===Color mapping for the SCI1 mouse pointer===&lt;br /&gt;
&lt;br /&gt;
Since this method of doing things wastes one combination, the table was changed for SCI01 and SCI1:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;blockquote&amp;gt;&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot; width=&amp;quot;150&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! align=&amp;quot;center&amp;quot; width=&amp;quot;25&amp;quot; | AB&lt;br /&gt;
! width=&amp;quot;120&amp;quot; | Result&lt;br /&gt;
|-&lt;br /&gt;
| align=&amp;quot;center&amp;quot; width=&amp;quot;25&amp;quot; | 00&lt;br /&gt;
| width=&amp;quot;120&amp;quot; | Transparent&lt;br /&gt;
|-&lt;br /&gt;
| align=&amp;quot;center&amp;quot; width=&amp;quot;25&amp;quot; | 01&lt;br /&gt;
| width=&amp;quot;120&amp;quot; | 0x0f (White)&lt;br /&gt;
|-&lt;br /&gt;
| align=&amp;quot;center&amp;quot; width=&amp;quot;25&amp;quot; | 10&lt;br /&gt;
| width=&amp;quot;120&amp;quot; | 0x00 (Black)&lt;br /&gt;
|-&lt;br /&gt;
| align=&amp;quot;center&amp;quot; width=&amp;quot;25&amp;quot; | 11&lt;br /&gt;
| width=&amp;quot;120&amp;quot; | 0x07 (Light Gray)&lt;br /&gt;
|}&lt;br /&gt;
&amp;lt;/blockquote&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;amp;nbsp;&lt;br /&gt;
&lt;br /&gt;
==The SCI0 View Resource==&lt;br /&gt;
&lt;br /&gt;
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.&lt;br /&gt;
&lt;br /&gt;
===The View Resource===&lt;br /&gt;
&lt;br /&gt;
0x00 - 0x01&lt;br /&gt;
&lt;br /&gt;
:: The number of image groups available. &lt;br /&gt;
&lt;br /&gt;
0x02 - 0x03&lt;br /&gt;
&lt;br /&gt;
:: A bitmask containing the &amp;#039;mirrored&amp;#039; flag for each of the groups, with the LSB containing the &amp;#039;mirrored&amp;#039; flag for group 0. &lt;br /&gt;
&lt;br /&gt;
0x04 - 0x07&lt;br /&gt;
&lt;br /&gt;
:: - unknown - &lt;br /&gt;
&lt;br /&gt;
0x08...&lt;br /&gt;
&lt;br /&gt;
:: 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 - &lt;br /&gt;
&lt;br /&gt;
0x01. &lt;br /&gt;
&lt;br /&gt;
===Cell List===&lt;br /&gt;
&lt;br /&gt;
0x00 - 0x01&lt;br /&gt;
&lt;br /&gt;
:: The number of image cells available for this group.&lt;br /&gt;
&lt;br /&gt;
0x02 - 0x03&lt;br /&gt;
&lt;br /&gt;
:: - unknown -&lt;br /&gt;
&lt;br /&gt;
0x04...&lt;br /&gt;
&lt;br /&gt;
:: 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. &lt;br /&gt;
&lt;br /&gt;
===Image Cell===&lt;br /&gt;
&lt;br /&gt;
0x00 - 0x01&lt;br /&gt;
&lt;br /&gt;
:: The horizontal (X) size of the image.&lt;br /&gt;
&lt;br /&gt;
0x02 - 0x03&lt;br /&gt;
&lt;br /&gt;
:: The vertical (Y) size of the image.&lt;br /&gt;
&lt;br /&gt;
0x04&lt;br /&gt;
&lt;br /&gt;
:: The x placement modifier. This signed value determines the number of pixels a view cell is moved to the right before it is drawn.&lt;br /&gt;
&lt;br /&gt;
0x05&lt;br /&gt;
&lt;br /&gt;
:: The y placement modifier. This signed value determines the number of pixels a view cell is moved downwards before it is drawn.&lt;br /&gt;
&lt;br /&gt;
0x06&lt;br /&gt;
&lt;br /&gt;
:: The color key, i.e. the color number used for transparency in this cell.&lt;br /&gt;
&lt;br /&gt;
0x07...&lt;br /&gt;
&lt;br /&gt;
:: 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.&lt;br /&gt;
&lt;br /&gt;
==The SCI font resource==&lt;br /&gt;
&lt;br /&gt;
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:&lt;br /&gt;
&amp;lt;div id=&amp;quot;AEN2349&amp;quot;&amp;gt;&amp;lt;/div&amp;gt;&lt;br /&gt;
&amp;#039;&amp;#039;&amp;#039;Table 3-1. The SCI font resource data structure&amp;#039;&amp;#039;&amp;#039;&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot; width=&amp;quot;760&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! width=&amp;quot;85&amp;quot; align=&amp;quot;center&amp;quot; | Offset&lt;br /&gt;
! width=&amp;quot;235&amp;quot; | Type&lt;br /&gt;
! width=&amp;quot;440&amp;quot; | Meaning&lt;br /&gt;
|-&lt;br /&gt;
| width=&amp;quot;85&amp;quot; align=&amp;quot;center&amp;quot; | 0&lt;br /&gt;
| width=&amp;quot;235&amp;quot; | 16 bit integer, little endian encoding&lt;br /&gt;
| width=&amp;quot;440&amp;quot; | Always zero (?)&lt;br /&gt;
|-&lt;br /&gt;
| width=&amp;quot;85&amp;quot; align=&amp;quot;center&amp;quot; | 2&lt;br /&gt;
| width=&amp;quot;235&amp;quot; | 16 bit integer, little endian encoding&lt;br /&gt;
| width=&amp;quot;440&amp;quot; | NUMCHAR: Number of characters&lt;br /&gt;
|-&lt;br /&gt;
| width=&amp;quot;85&amp;quot; align=&amp;quot;center&amp;quot; | 4&lt;br /&gt;
| width=&amp;quot;235&amp;quot; | 16 bit integer, little endian encoding&lt;br /&gt;
| width=&amp;quot;440&amp;quot; | HEIGHT: Number of pixel lines per text line&lt;br /&gt;
|-&lt;br /&gt;
| width=&amp;quot;85&amp;quot; align=&amp;quot;center&amp;quot; | 6 + NR * 2&lt;br /&gt;
| width=&amp;quot;235&amp;quot; | 16 bit integer, little endian encoding&lt;br /&gt;
| width=&amp;quot;440&amp;quot; | Absolute offset of the character #NR, where 0 &amp;amp;lt;= NR &amp;amp;lt; NUMCHAR&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
 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:&lt;br /&gt;
&amp;lt;div id=&amp;quot;AEN2375&amp;quot;&amp;gt;&amp;lt;/div&amp;gt;&lt;br /&gt;
&amp;#039;&amp;#039;&amp;#039;Table 3-2. The SCI font resource character data structure&amp;#039;&amp;#039;&amp;#039;&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot; width=&amp;quot;760&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! width=&amp;quot;85&amp;quot; align=&amp;quot;center&amp;quot; | Offset&lt;br /&gt;
! width=&amp;quot;235&amp;quot; | Type&lt;br /&gt;
! width=&amp;quot;440&amp;quot; | Meaning&lt;br /&gt;
|-&lt;br /&gt;
| width=&amp;quot;85&amp;quot; align=&amp;quot;center&amp;quot; | 0&lt;br /&gt;
| width=&amp;quot;235&amp;quot; | unsigned 8 bit integer&lt;br /&gt;
| width=&amp;quot;440&amp;quot; | character &amp;lt;span style=&amp;quot;color: red; text-decoration: line-through;&amp;quot;&amp;gt;HEIGHT&amp;lt;/span&amp;gt; WIDTH&lt;br /&gt;
|-&lt;br /&gt;
| width=&amp;quot;85&amp;quot; align=&amp;quot;center&amp;quot; | 1&lt;br /&gt;
| width=&amp;quot;235&amp;quot; | unsigned 8 bit integer&lt;br /&gt;
| width=&amp;quot;440&amp;quot; | character &amp;lt;span style=&amp;quot;color: red; text-decoration: line-through;&amp;quot;&amp;gt;WIDTH&amp;lt;/span&amp;gt; HEIGHT&lt;br /&gt;
|-&lt;br /&gt;
| width=&amp;quot;85&amp;quot; align=&amp;quot;center&amp;quot; | 2...&lt;br /&gt;
| width=&amp;quot;235&amp;quot; | bitmask, size HEIGHT * round_up(WIDTH / 8)&lt;br /&gt;
| width=&amp;quot;440&amp;quot; | Bitmask for the character&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
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.&lt;br /&gt;
&lt;br /&gt;
==The SCI0 and SCI01 pic resource==&lt;br /&gt;
&lt;br /&gt;
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&amp;lt;ref group=Note&amp;gt;Due to the vector graphics nature of these drawing operations, they are inherently more scaleable than pixmaps.&amp;lt;/ref&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Note hereIn order to describe the process, we will first need to define a set of operations we base them on:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;FUNCTION peek_input(): Byte; /* returns the byte pointed to by the input pointer */&lt;br /&gt;
FUNCTION get_input(): Byte; /* works like peek_input(), but also increminates the &lt;br /&gt;
                            ** input pointer  */&lt;br /&gt;
FUNCTION skip_input(x): Byte; /* skips x input bytes */&amp;lt;/pre&amp;gt;&lt;br /&gt;
      &lt;br /&gt;
&lt;br /&gt;
Using these pre-defined functions, we will now define additional helper functions used for reading specifically encoded data tuples:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;FUNCTION GetAbsCoordinates(): (Integer, Integer)&lt;br /&gt;
VAR&lt;br /&gt;
    x, y, coordinate_prefix : Integer;&lt;br /&gt;
BEGIN&lt;br /&gt;
    coordinate_prefix := get_input();&lt;br /&gt;
    x := get_input();&lt;br /&gt;
    y := get_input();&lt;br /&gt;
    x |= (coordinate_prefix &amp;amp; 0xf0) &amp;lt;&amp;lt; 4;&lt;br /&gt;
    y |= (coordinate_prefix &amp;amp; 0x0f) &amp;lt;&amp;lt; 8;&lt;br /&gt;
&lt;br /&gt;
    RETURN (x,y)&lt;br /&gt;
END&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
FUNCTION GetRelCoordinates(x : Integer, y: Integer): (Integer, Integer)&lt;br /&gt;
VAR&lt;br /&gt;
    input : Integer;&lt;br /&gt;
BEGIN&lt;br /&gt;
    input := get_input();&lt;br /&gt;
&lt;br /&gt;
    &amp;#039;&amp;#039;The below code for x is inaccurate. The left-most bit is used to indicate sign, so before doing the bitshift it is necessary to remove the left-most bit&amp;#039;&amp;#039;&lt;br /&gt;
    IF (input &amp;amp; 0x80) THEN&lt;br /&gt;
            x -= (input &amp;gt;&amp;gt; 4);&lt;br /&gt;
    ELSE&lt;br /&gt;
        x += (input &amp;gt;&amp;gt; 4);&lt;br /&gt;
    FI&lt;br /&gt;
&lt;br /&gt;
    IF (input &amp;amp; 0x08) THEN&lt;br /&gt;
        y -= (input &amp;amp; 0x7);&lt;br /&gt;
    ELSE&lt;br /&gt;
        y += (input &amp;amp; 0x7);&lt;br /&gt;
    FI&lt;br /&gt;
&lt;br /&gt;
    RETURN (x,y)&lt;br /&gt;
END&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
We also need some data types based on EGACOLOR and PRIORITY, which can be thought of as integers:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;TYPE Palette = ARRAY[0..39] of EGACOLOR[0..1]&lt;br /&gt;
TYPE Priority_Table = ARRAY[0..39] of PRIORITY&lt;br /&gt;
&lt;br /&gt;
Palette default_palette =&lt;br /&gt;
     &amp;lt;(0,0), (1,1), (2,2), (3,3), (4,4), (5,5), (6,6), (7,7),&lt;br /&gt;
      (8,8), (9,9), (a,a), (b,b), (c,c), (d,d), (e,e), (8,8),&lt;br /&gt;
      (8,8), (0,1), (0,2), (0,3), (0,4), (0,5), (0,6), (8,8),&lt;br /&gt;
      (8,8), (f,9), (f,a), (f,b), (f,c), (f,d), (f,e), (f,f),&lt;br /&gt;
      (0,8), (9,1), (2,a), (3,b), (4,c), (5,d), (6,e), (8,8)&amp;gt;;&lt;br /&gt;
&lt;br /&gt;
#define DRAW_ENABLE_VISUAL   1&lt;br /&gt;
#define DRAW_ENABLE_PRIORITY 2&lt;br /&gt;
#define DRAW_ENABLE_CONTROL  4&lt;br /&gt;
&lt;br /&gt;
#define PATTERN_FLAG_RECTANGLE 0x10&lt;br /&gt;
#define PATTERN_FLAG_USE_PATTERN 0x20&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
And now for the actual algorithm:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;FUNCTION DrawPic (cumulative, fill_in_black : Boolean; default_palette: Integer; visual_map, priority_map, control_map, aux_map : Map): Map^4&lt;br /&gt;
VAR&lt;br /&gt;
    palette : Array [0..3] of Palette;&lt;br /&gt;
    drawenable, priority, col1, col2, pattern_nr, pattern_code : Integer;&lt;br /&gt;
BEGIN&lt;br /&gt;
    palette := (default_palette × 4);&lt;br /&gt;
    drawenable := DRAW_ENABLE_VISUAL | DRAW_ENABLE_PRIORITY&lt;br /&gt;
    priority := 0;&lt;br /&gt;
    col1 := col2 := 0;&lt;br /&gt;
    pattern_nr := 0;&lt;br /&gt;
    pattern_code := 0;&lt;br /&gt;
&lt;br /&gt;
    IF (!cumulative) THEN BEGIN&lt;br /&gt;
        visual_map := (0xf × 320 × 200);&lt;br /&gt;
        map control := map priority := map aux := (0 × 320 × 200);&lt;br /&gt;
    END&lt;br /&gt;
&lt;br /&gt;
    FOREVER DO BEGIN&lt;br /&gt;
&lt;br /&gt;
        opcode := get_input();&lt;br /&gt;
&lt;br /&gt;
        COND opcode:&lt;br /&gt;
            0xf0 → /* PIC_OP_SET_COLOR */&lt;br /&gt;
                code := get_input();&lt;br /&gt;
                (col1, col2) := palette[default_palette + (code / 40)][code % 40];&lt;br /&gt;
                drawenable |= DRAW_ENABLE_VISUAL;&lt;br /&gt;
&lt;br /&gt;
            0xf1 → /* PIC_OP_DISABLE_VISUAL */&lt;br /&gt;
                drawenable &amp;amp;= ~DRAW_ENABLE_VISUAL;&lt;br /&gt;
&lt;br /&gt;
            0xf2 → /* PIC_OP_SET_PRIORITY */&lt;br /&gt;
                code := get_input();&lt;br /&gt;
                priority := code &amp;amp; 0xf;&lt;br /&gt;
                drawenable |= DRAW_ENABLE_PRIORITY;&lt;br /&gt;
&lt;br /&gt;
            0xf3 → /* PIC_OP_DISABLE_PRIORITY */&lt;br /&gt;
                drawenable &amp;amp;= ~DRAW_ENABLE_PRIORITY;&lt;br /&gt;
&lt;br /&gt;
            0xf4 → /* PIC_OP_RELATIVE_PATTERNS */&lt;br /&gt;
                IF (pattern_code &amp;amp; PATTERN_FLAG_USE_PATTERN) THEN&lt;br /&gt;
                    pattern_nr := (get_input() &amp;gt;&amp;gt; 1) &amp;amp; 0x7f&lt;br /&gt;
                FI&lt;br /&gt;
&lt;br /&gt;
                (x,y) := GetAbsCoordinates();&lt;br /&gt;
&lt;br /&gt;
                DrawPattern(x, y, col1, col2, priority, control, drawenable,&lt;br /&gt;
                         pattern_code &amp;amp; PATTERN_FLAG_USE_PATTERN,&lt;br /&gt;
                         pattern_size, pattern_nr, pattern_code &amp;amp; PATTERN_FLAG_RECTANGLE);&lt;br /&gt;
&lt;br /&gt;
                WHILE (peek_input() &amp;lt; 0xf0) DO BEGIN&lt;br /&gt;
                    IF (pattern_code &amp;amp; PATTERN_FLAG_USE_PATTERN) THEN&lt;br /&gt;
                        pattern_nr := (get_input() &amp;gt;&amp;gt; 1) &amp;amp; 0x7f&lt;br /&gt;
                    FI&lt;br /&gt;
                    (x,y) =  GetRelCoordinates(x,y);&lt;br /&gt;
                    DrawPattern(x, y, col1, col2, priority, control, drawenable,&lt;br /&gt;
                             pattern_code &amp;amp; PATTERN_FLAG_USE_PATTERN,&lt;br /&gt;
                             pattern_size, pattern_nr, pattern_code &amp;amp; PATTERN_FLAG_RECTANGLE);&lt;br /&gt;
                END&lt;br /&gt;
&lt;br /&gt;
            0xf5 → /* PIC_OP_RELATIVE_MEDIUM_LINES */&lt;br /&gt;
                (oldx, oldy) := GetAbsCoordinates();&lt;br /&gt;
                WHILE (peek_input() &amp;lt; 0xf0) DO BEGIN&lt;br /&gt;
                    temp := get_input();&lt;br /&gt;
                    IF (temp &amp;amp; 0x80) THEN&lt;br /&gt;
                        y := oldy - (temp &amp;amp; 0x7f)&lt;br /&gt;
                    ELSE&lt;br /&gt;
                        y := oldy + temp&lt;br /&gt;
                    FI&lt;br /&gt;
                    x = oldx + get_input();&lt;br /&gt;
                     DitherLine(oldx, oldy, x, y, col1, col2, priority, special, drawenable);&lt;br /&gt;
                    (oldx, oldy) := (x, y);&lt;br /&gt;
                END&lt;br /&gt;
&lt;br /&gt;
            0xf6 → /* PIC_OP_RELATIVE_LONG_LINES */&lt;br /&gt;
                (oldx, oldy) :=  GetAbsCoordinates()&lt;br /&gt;
                WHILE (peek_input() &amp;lt; 0xf0) DO BEGIN&lt;br /&gt;
                    (x, y) := GetAbsCoordinates();&lt;br /&gt;
                    DitherLine(oldx, oldy, x, y, col1, col2, priority, special, drawenable);&lt;br /&gt;
                    (oldx, oldy) := (x, y);&lt;br /&gt;
                END&lt;br /&gt;
&lt;br /&gt;
            0xf7 → /* PIC_OP_RELATIVE_SHORT_LINES */&lt;br /&gt;
                (oldx, oldy) =  GetAbsCoordinates()&lt;br /&gt;
                WHILE (peek_input() &amp;lt; 0xf0) DO BEGIN&lt;br /&gt;
                    (x, y) := GetRelCoordinates(oldx, oldy);&lt;br /&gt;
                    DitherLine(oldx, oldy, x, y, col1, col2, priority, special, drawenable);&lt;br /&gt;
                    (oldx, oldy) := (x, y);&lt;br /&gt;
                END&lt;br /&gt;
&lt;br /&gt;
            0xf8 → /* PIC_OP_FILL */&lt;br /&gt;
                IF (fill_in_black) THEN&lt;br /&gt;
                    (oldc1, oldc2) := (c1, c2);&lt;br /&gt;
                FI&lt;br /&gt;
&lt;br /&gt;
                WHILE (peek_unput() &amp;lt; 0xf0) DO BEGIN&lt;br /&gt;
                    (x, y) := GetAbsCoordinates();&lt;br /&gt;
                    DitherFill(x, y, col1, col2, priority, special, drawenable);&lt;br /&gt;
                END&lt;br /&gt;
&lt;br /&gt;
                IF (fill_in_black) THEN&lt;br /&gt;
                    (c1, c2) := (oldc1, oldc2);&lt;br /&gt;
                FI&lt;br /&gt;
&lt;br /&gt;
            0xf9 → /* PIC_OP_SET_PATTERN */&lt;br /&gt;
                pattern_code := get_input() &amp;amp; 0x37;&lt;br /&gt;
                pattern_size := pattern_code &amp;amp; 0x7;&lt;br /&gt;
&lt;br /&gt;
            0xfa → /* PIC_OP_ABSOLUTE_PATTERNS */&lt;br /&gt;
                WHILE (peek_input() &amp;lt; 0xf0) DO&lt;br /&gt;
                    IF (pattern_code &amp;amp; PATTERN_FLAG_USE_PATTERN)&lt;br /&gt;
                        pattern_nr := (get_input() &amp;gt;&amp;gt; 1) &amp;amp; 0x7f&lt;br /&gt;
                    FI&lt;br /&gt;
                    (x, y) := GetAbsCoordinates();&lt;br /&gt;
                    DrawPattern(x, y, col1, col2, priority, control, drawenable,&lt;br /&gt;
                             pattern_code &amp;amp; PATTERN_FLAG_USE_PATTERN,&lt;br /&gt;
                             pattern_size, pattern_nr, pattern_code &amp;amp; PATTERN_FLAG_RECTANGLE);&lt;br /&gt;
                    END&lt;br /&gt;
&lt;br /&gt;
            0xfb → /* PIC_OP_SET_CONTROL */&lt;br /&gt;
                control := get_input() &amp;amp; 0x0f;&lt;br /&gt;
                drawenable |= DRAW_ENABLE_CONTROL;&lt;br /&gt;
&lt;br /&gt;
            0xfc → /* PIC_OP_DISABLE_CONTROL */&lt;br /&gt;
                drawenable &amp;amp;= ~DRAW_ENABLE_CONTROL;&lt;br /&gt;
&lt;br /&gt;
            0xfd → /* PIC_OP_RELATIVE_MEDIUM_PATTERNS */&lt;br /&gt;
                IF (pattern_code &amp;amp; PATTERN_FLAG_USE_PATTERN) THEN&lt;br /&gt;
                    pattern_nr := (get_input() &amp;gt;&amp;gt; 1) &amp;amp; 0x7f;&lt;br /&gt;
                FI&lt;br /&gt;
&lt;br /&gt;
                (oldx, oldy) := GetAbsCoordinates();&lt;br /&gt;
&lt;br /&gt;
                DrawPattern(x, y, col1, col2, priority, control, drawenable,&lt;br /&gt;
                         pattern_code &amp;amp; PATTERN_FLAG_USE_PATTERN,&lt;br /&gt;
                         pattern_size, pattern_nr, pattern_code &amp;amp; PATTERN_FLAG_RECTANGLE);&lt;br /&gt;
&lt;br /&gt;
                WHILE (peek_input() &amp;lt; 0xf0) DO BEGIN&lt;br /&gt;
                    IF (pattern_code &amp;amp; PATTERN_FLAG_USE_PATTERN) THEN&lt;br /&gt;
                        pattern_nr := (get_input() &amp;gt;&amp;gt; 1) &amp;amp; 0x7f;&lt;br /&gt;
                    FI&lt;br /&gt;
            &lt;br /&gt;
                    temp := get_input();&lt;br /&gt;
                    IF (temp &amp;amp; 0x80)&lt;br /&gt;
                        y := oldy - (temp &amp;amp; 0x7f)&lt;br /&gt;
                    ELSE&lt;br /&gt;
                        y := oldy + temp&lt;br /&gt;
                    FI&lt;br /&gt;
                    x := oldx + get_input();&lt;br /&gt;
                    DrawPattern(x, y, col1, col2, priority, control, drawenable,&lt;br /&gt;
                             pattern_code &amp;amp; PATTERN_FLAG_USE_PATTERN,&lt;br /&gt;
                             pattern_size, pattern_nr, pattern_code &amp;amp; PATTERN_FLAG_RECTANGLE);&lt;br /&gt;
                END&lt;br /&gt;
&lt;br /&gt;
            0xfd → /* PIC_OP_OPX */&lt;br /&gt;
                COND get_input():&lt;br /&gt;
                    0x00 → /* PIC_OPX_SET_PALETTE_ENTRY */&lt;br /&gt;
                        WHILE peek_input() &amp;lt; 0xf0 DO BEGIN&lt;br /&gt;
                            index := get_input();&lt;br /&gt;
                            color := get_input();&lt;br /&gt;
                            palette[index / 40][color % 40] := color;&lt;br /&gt;
                        END&lt;br /&gt;
&lt;br /&gt;
                    0x01 → /* PIC_OPX_SET_PALETTE */&lt;br /&gt;
                        palette_number := get_input();&lt;br /&gt;
                        FOR i := 0 TO 39 DO&lt;br /&gt;
                            palette[palette_number][i] := get_input();&lt;br /&gt;
                        OD&lt;br /&gt;
&lt;br /&gt;
                    0x02 → /* PIC_OPX_MONO0 */&lt;br /&gt;
                        skip_input(41);&lt;br /&gt;
&lt;br /&gt;
                    0x03 → /* PIC_OPX_MONO1 */&lt;br /&gt;
                        skip_input(1);&lt;br /&gt;
&lt;br /&gt;
                    0x04 → /* PIC_OPX_MONO2 */&lt;br /&gt;
                    0x05 → /* PIC_OPX_MONO3 */&lt;br /&gt;
                        skip_input(1);&lt;br /&gt;
&lt;br /&gt;
                    0x06 → /* PIC_OPX_MONO4 */&lt;br /&gt;
                    0x07 → /* PIC_OPX_EMBEDDED_VIEW */ /* SCI01 operation */&lt;br /&gt;
                    0x08 → /* PIC_OPX_SET_PRIORITY_TABLE */ /* SCI01 operation */&lt;br /&gt;
&lt;br /&gt;
            0xff → return (visual, control, priority, aux);&lt;br /&gt;
        END OF COND&lt;br /&gt;
      END&lt;br /&gt;
END&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;#039;&amp;#039;&amp;#039;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.&amp;#039;&amp;#039;&amp;#039;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;PROCEDURE DrawPattern(x, y, col1, col2, priority, control, drawenable : Integer;  solid : Boolean ;  pattern_size, pattern_nr : Integer; rectangle : Boolean)&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Alters (x,y) so that 0 &amp;lt;= (x - pattern_size), 319 &amp;gt;= (x + pattern_size), 189 &amp;gt;= (y + pattern_size) and 0 &amp;lt;= (y - pattern_size), then draws a rectangle or a circle filled with col1, col2, priority, control, as determined by drawenable.&lt;br /&gt;
&lt;br /&gt;
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)&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;PROCEDURE DitherLine(x, y, xend, yend, color1, color2, priority, control, drawenable : Integer)&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Draws a dithered line between (x, y+10) and (xend, yend+10). If the appropriate drawenable flags&lt;br /&gt;
are set, it draws &amp;#039;priority&amp;#039; to the priority map, &amp;#039;control&amp;#039; to the control map, and &amp;#039;color1&amp;#039; and &amp;#039;color2&amp;#039;&lt;br /&gt;
(alternating) to the visual map. The auxiliary map is bitwise-or&amp;#039;d with the drawenable flag while this is&lt;br /&gt;
done.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;PROCEDURE DitherFill(x, y, col0, col1, priority, control, drawenable : Integer)&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Fills all layers for which drawenable is set with the appropriate content. Diagonal filling is not allowed. Boundaries are determined as follows:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;x&amp;lt;0, x&amp;gt;319, y&amp;lt;10, y&amp;gt;199 are hard boundaries. We now determine the &amp;#039;boundary map&amp;#039; bound_map and the allowed color legal_color. If bound_map[coordinates] = legal_color, then the pixel may be filled.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;IF (drawenable &amp;amp; DRAW_ENABLE_VISUAL)&lt;br /&gt;
    bound_map = visual;&lt;br /&gt;
    legal_color = 0xf;&lt;br /&gt;
ELSIF (drawenable &amp;amp; DRAW_ENABLE_PRIORITY)&lt;br /&gt;
    bound_map = priority;&lt;br /&gt;
    legal_color = 0;&lt;br /&gt;
ELSIF (drawenable &amp;amp; DRAW_ENABLE_CONTROL)&lt;br /&gt;
    bound_map = control;&lt;br /&gt;
    legal_color = 0;&lt;br /&gt;
ELSE&lt;br /&gt;
    return;&lt;br /&gt;
FI&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==Windows, Dialogs and Controls==&lt;br /&gt;
&lt;br /&gt;
&amp;#039;&amp;#039;&amp;#039;by Lars Skovlund&amp;#039;&amp;#039;&amp;#039;&lt;br /&gt;
&lt;br /&gt;
Version 1.0, 7. July 1999&lt;br /&gt;
&lt;br /&gt;
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.&lt;br /&gt;
&lt;br /&gt;
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:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;typedef struct&lt;br /&gt;
{&lt;br /&gt;
  short top, left, bottom, right;&lt;br /&gt;
}&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
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.&lt;br /&gt;
&lt;br /&gt;
Windows are created using the KNewWindow kernel function. Each window has six attributes which are passed from the script to the kernel function:&lt;br /&gt;
&lt;br /&gt;
Bounding rectangle&amp;lt;br&amp;gt;&lt;br /&gt;
Title&amp;lt;br&amp;gt;&lt;br /&gt;
Type&amp;lt;br&amp;gt;&lt;br /&gt;
Priority&amp;lt;br&amp;gt;&lt;br /&gt;
Foreground color&amp;lt;br&amp;gt;&lt;br /&gt;
Background color&lt;br /&gt;
&lt;br /&gt;
Of these, the type and priority are the most interesting, because they decide the appearance of the window. The type is a bit field:&lt;br /&gt;
&lt;br /&gt;
bit 0 - transparency&amp;lt;br&amp;gt;&lt;br /&gt;
bit 1 - window does _not_ have a frame&amp;lt;br&amp;gt;&lt;br /&gt;
bit 2 - the window has a title&amp;lt;br&amp;gt;&lt;br /&gt;
bit 3-6 - unused&amp;lt;br&amp;gt;&lt;br /&gt;
bit 7 - see below&lt;br /&gt;
&lt;br /&gt;
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&amp;#039;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,&lt;br /&gt;
&lt;br /&gt;
Bit 1 specifies a window without a frame. The frame is the black shading you can see in the corner of a message box.&lt;br /&gt;
&lt;br /&gt;
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.&lt;br /&gt;
&lt;br /&gt;
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&amp;#039;s responsibility to draw a window frame on the WM port. CB1 uses this style for its ornate windows, and draws the frame manually.&lt;br /&gt;
&lt;br /&gt;
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.&lt;br /&gt;
&lt;br /&gt;
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.&lt;br /&gt;
&lt;br /&gt;
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 KNewWindow (the Rect is split in its fields, to nsTop, nsLeft etc.)&lt;br /&gt;
&lt;br /&gt;
To create a window structure, use KNewWindow (see [[SCI_Specifications:_Chapter_5_(cont.)_-_Kernel_functions#Kernel_function_0x13:_NewWindow.28Rect.2C_HeapPtr.2C_word.2C_word.2C_word.2C_word.29|the Section called Kernel function 0x13: NewWindow(Rect, HeapPtr, word, word, word, word) in Chapter 5]]); to remove it again, apply KDisposeWindow (see [[SCI_Specifications:_Chapter_5_(cont.)_-_Kernel_functions#Kernel_function_0x16:_DisposeWindow.28HeapPtr_Window.29|the Section called Kernel function 0x16: DisposeWindow(HeapPtr Window) in Chapter 5]]) on it.&lt;br /&gt;
&lt;br /&gt;
So how do we put stuff inside these windows? That question is a little complicated to answer, because it is really a shared effort between the interpreter 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.&lt;br /&gt;
&lt;br /&gt;
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.&lt;br /&gt;
&lt;br /&gt;
The type numbers are laid out as follows:&lt;br /&gt;
&lt;br /&gt;
# - Button control&lt;br /&gt;
# - Text control&lt;br /&gt;
# - Edit control&lt;br /&gt;
# - Icon control&lt;br /&gt;
# - not used&lt;br /&gt;
# - Selector control (as in the Save and Restore boxes)&lt;br /&gt;
&lt;br /&gt;
The gauge &amp;quot;controls&amp;quot; are not really controls. I don&amp;#039;t know how they work (yet).&lt;br /&gt;
&lt;br /&gt;
Each control also has a state value. These are laid out as follows:&lt;br /&gt;
&lt;br /&gt;
: 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.&amp;lt;br&amp;gt;&lt;br /&gt;
: bit 1 - unknown. Always set, except for the text and icon controls&amp;lt;br&amp;gt;&lt;br /&gt;
: bit 2 - disabled. When this bit is set, a button is grayed out. No other control types are affected.&amp;lt;br&amp;gt;&lt;br /&gt;
: bit 3 - selected. When this bit is set, a frame is drawn around the control.&lt;br /&gt;
&lt;br /&gt;
Note that state 3 is by far the most common. With that explained, I&amp;#039;ll move on to the kernel functions. There are three functions associated with controls - KDrawControl (see [[SCI_Specifications:_Chapter_5_(cont.)_-_Kernel_functions#Kernel_function_0x17:_DrawControl.28HeapPtr.29|the Section called Kernel function 0x17: DrawControl(HeapPtr) in Chapter 5]]), KHiliteControl (see [[SCI_Specifications:_Chapter_5_(cont.)_-_Kernel_functions#Kernel_function_0x18:_HiliteControl.28HeapPtr.29|the Section called Kernel function 0x18: HiliteControl(HeapPtr) in Chapter 5]]) and KEditControl (see [[SCI_Specifications:_Chapter_5_(cont.)_-_Kernel_functions#Kernel_function_0x19:_EditControl.28HeapPtr.29|the Section called Kernel function 0x19: EditControl(HeapPtr) in Chapter 5]]). Note that there is a KOnControl kernel call which is entirely unrelated to window management.&lt;br /&gt;
&lt;br /&gt;
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.&lt;br /&gt;
&lt;br /&gt;
:: &amp;#039;&amp;#039;&amp;#039;&amp;#039;&amp;#039;Note&amp;#039;&amp;#039;&amp;#039; 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 &amp;quot;forgets&amp;quot; to switch back while stepping across instructions. Thus, all graphics commands are redirected to the debug window port. Not a pretty sight.&amp;#039;&amp;#039;&lt;br /&gt;
&lt;br /&gt;
==Pictures and movement control==&lt;br /&gt;
&lt;br /&gt;
&amp;#039;&amp;#039;&amp;#039;By Lars Skovlund&amp;#039;&amp;#039;&amp;#039;&lt;br /&gt;
&lt;br /&gt;
Version 1.0, 24. July 1999&lt;br /&gt;
&lt;br /&gt;
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&amp;#039;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.&lt;br /&gt;
&lt;br /&gt;
Many functions which need to access these maps do so by using a bit-field. The bits are laid out as follows (but don&amp;#039;t set more than one at a time!)&lt;br /&gt;
&lt;br /&gt;
bit 0 - Visual&amp;lt;br&amp;gt;&lt;br /&gt;
bit 1 - Priority&amp;lt;br&amp;gt;&lt;br /&gt;
bit 2 - Control&lt;br /&gt;
&lt;br /&gt;
It is important to understand that, although being represented as colors on the screen, a priority/control &amp;quot;color&amp;quot; should be considered a number. The colors map to values according to the standard EGA color values.&lt;br /&gt;
&lt;br /&gt;
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 &amp;quot;base rectangle&amp;quot; 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.&lt;br /&gt;
&lt;br /&gt;
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&amp;#039;t walk on white control areas.&lt;br /&gt;
&lt;br /&gt;
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.&lt;br /&gt;
&lt;br /&gt;
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.&lt;br /&gt;
&lt;br /&gt;
The OnControl() system call is explained in [[SCI_Specifications:_Chapter_5_(cont.)_-_Kernel_functions#Kernel_function_0x52:_OnControl.28word.2C_Point_.7C_Rect.29|the Section called Kernel function 0x52: OnControl(word, Point | Rect) in Chapter 5]].&lt;br /&gt;
&lt;br /&gt;
;Notes&lt;br /&gt;
&amp;lt;references group=Note/&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;amp;nbsp;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span style=&amp;quot;float: left&amp;quot;&amp;gt;[[SCI Specifications: Chapter_2_-_Resource_files|&amp;amp;lt; Previous: Chapter 2 - Resource files]]&amp;lt;/span&amp;gt;&amp;lt;span style=&amp;quot;float: right&amp;quot;&amp;gt;[[SCI Specifications: Chapter_4_-_The_Sound_subsystem|Next: Chapter 4 - The Sound subsystem &amp;amp;gt;]]&amp;lt;/span&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;amp;nbsp;&lt;br /&gt;
&lt;br /&gt;
[[Category:SCI Documentation]]&lt;br /&gt;
[[Category:Sierra Creative Interpreter Specifications]]&lt;br /&gt;
[[Category:SCI Resources]]&lt;br /&gt;
[[Category:Control Areas]]&lt;/div&gt;</summary>
		<author><name>Jeremiah Nellis</name></author>
	</entry>
	<entry>
		<id>http://sciwiki.sierrahelp.com/index.php?title=Leveraging_The_Text_Resources_Further&amp;diff=7317</id>
		<title>Leveraging The Text Resources Further</title>
		<link rel="alternate" type="text/html" href="http://sciwiki.sierrahelp.com/index.php?title=Leveraging_The_Text_Resources_Further&amp;diff=7317"/>
		<updated>2013-12-10T23:28:47Z</updated>

		<summary type="html">&lt;p&gt;Jeremiah Nellis: Created page with &amp;quot;You can move all your #title &amp;amp; #button text descriptions used in Print() statements:  In controls.sc, in the Print() procedure change the &amp;#039;(case #button&amp;#039; section: &amp;lt;div class=&amp;quot;...&amp;quot;&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;You can move all your #title &amp;amp; #button text descriptions used in Print() statements:&lt;br /&gt;
&lt;br /&gt;
In controls.sc, in the Print() procedure change the &amp;#039;(case #button&amp;#039; section:&lt;br /&gt;
&amp;lt;div class=&amp;quot;CodeBlockHeader&amp;quot;&amp;gt;Code:&amp;lt;/div&amp;gt;&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;sci&amp;quot; class=&amp;quot;cs&amp;quot;&amp;gt;&lt;br /&gt;
			(case #button&lt;br /&gt;
		    	= hButtons[buttonCnt] (DButton:new())&lt;br /&gt;
		    	&lt;br /&gt;
				(if(&amp;gt;= Abs(params[+ paramCnt 1]) 0 and &amp;lt;= Abs(params[+ paramCnt 1]) 999)	&lt;br /&gt;
					(send hButtons[buttonCnt]:&lt;br /&gt;
						text(Format(&amp;quot;%s&amp;quot; params[+ paramCnt 1] params[+ paramCnt 2]))&lt;br /&gt;
						value(params[+ paramCnt 3])&lt;br /&gt;
						setSize()&lt;br /&gt;
			    	)	&lt;br /&gt;
					= paramCnt + paramCnt 3&lt;br /&gt;
				)(else&lt;br /&gt;
					(send hButtons[buttonCnt]:&lt;br /&gt;
						text(params[++paramCnt])&lt;br /&gt;
						value(params[++paramCnt])&lt;br /&gt;
						setSize()&lt;br /&gt;
			    	)&lt;br /&gt;
				)		    	&lt;br /&gt;
		    	= btnsWidth (+ btnsWidth (+ (send hButtons[buttonCnt]:nsRight) 4))&lt;br /&gt;
		    	++buttonCnt&lt;br /&gt;
			)&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
And the &amp;#039;(case #title&amp;#039; section:&lt;br /&gt;
&amp;lt;div class=&amp;quot;CodeBlockHeader&amp;quot;&amp;gt;Code:&amp;lt;/div&amp;gt;&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;sci&amp;quot; class=&amp;quot;cs&amp;quot;&amp;gt;&lt;br /&gt;
			(case #title&lt;br /&gt;
				++paramCnt&lt;br /&gt;
&lt;br /&gt;
				(if(&amp;gt;= Abs(params[paramCnt]) 0 and &amp;lt;= Abs(params[paramCnt]) 999)&lt;br /&gt;
					Format(&amp;quot;%s&amp;quot; params[paramCnt] params[+ paramCnt 1])&lt;br /&gt;
					++paramCnt&lt;br /&gt;
				)(else&lt;br /&gt;
					(send hDialog:text(params[paramCnt]))&lt;br /&gt;
			       )&lt;br /&gt;
			)&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
Now, you can use either technique - specify a static string or a text resource like this:&lt;br /&gt;
&amp;lt;div class=&amp;quot;CodeBlockHeader&amp;quot;&amp;gt;Code:&amp;lt;/div&amp;gt;&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;sci&amp;quot; class=&amp;quot;cs&amp;quot;&amp;gt;&lt;br /&gt;
   Print(&amp;quot;Hello there&amp;quot; #title 999 1)    //  999 is the text resource holding our title text&lt;br /&gt;
   Print(&amp;quot;Hello there&amp;quot; #title &amp;quot;Greetings&amp;quot;)   // the original way of specifying a title still works too&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
Same with buttons:&lt;br /&gt;
&amp;lt;div class=&amp;quot;CodeBlockHeader&amp;quot;&amp;gt;Code:&amp;lt;/div&amp;gt;&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;sci&amp;quot; class=&amp;quot;cs&amp;quot;&amp;gt;&lt;br /&gt;
   Print(&amp;quot;Make a selection&amp;quot; #button 888 2)   // 888 is the text resource holding our button text&lt;br /&gt;
   Print(&amp;quot;Make a selection&amp;quot; #button &amp;quot;OK&amp;quot;)    // the original way of specifying text for buttons still works&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
Of course, if you are this heap-bound, you&amp;#039;d have the actual text of your Print statement to be in a text resource too, so a more realistic example would be something like this:&lt;br /&gt;
&amp;lt;div class=&amp;quot;CodeBlockHeader&amp;quot;&amp;gt;Code:&amp;lt;/div&amp;gt;&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;sci&amp;quot; class=&amp;quot;cs&amp;quot;&amp;gt;&lt;br /&gt;
  Print(0 15 #title 999 1)&lt;br /&gt;
  Print(0 22 #button 888 1)&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
[[Category:TemplateGameFixes]]&lt;br /&gt;
[[Category:Syntax]]&lt;/div&gt;</summary>
		<author><name>Jeremiah Nellis</name></author>
	</entry>
	<entry>
		<id>http://sciwiki.sierrahelp.com/index.php?title=Graphical_health_meter&amp;diff=7012</id>
		<title>Graphical health meter</title>
		<link rel="alternate" type="text/html" href="http://sciwiki.sierrahelp.com/index.php?title=Graphical_health_meter&amp;diff=7012"/>
		<updated>2013-11-02T03:11:05Z</updated>

		<summary type="html">&lt;p&gt;Jeremiah Nellis: Created page with &amp;quot;&amp;#039;&amp;#039;Originally posted on the SCI Programming Forums by Gumby.&amp;#039;&amp;#039;    Here&amp;#039;s a really simple solution to accomplish this.  First, the laborious part; y...&amp;quot;&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&amp;#039;&amp;#039;Originally posted on the [[scipf:topic,667.html|SCI Programming Forums]] by [[Gumby]].&amp;#039;&amp;#039;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Here&amp;#039;s a really simple solution to accomplish this.  First, the laborious part; you need to make a view starting with a health bar at &amp;#039;full strength&amp;#039;, and then in each frame remove one &amp;#039;line&amp;#039; of heath.  My implementation used a health meter with a length of roughly 100 pixels (so 100 cells in the view).  We will instantiate this as our &amp;#039;lifeMeter&amp;#039; view.&lt;br /&gt;
&lt;br /&gt;
Once you have your view created, add this code to your room script:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div class=&amp;quot;CodeBlockHeader&amp;quot;&amp;gt;Code:&amp;lt;/div&amp;gt;&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;sci&amp;quot;&amp;gt;&lt;br /&gt;
   (local&lt;br /&gt;
        flag&lt;br /&gt;
    )&lt;br /&gt;
&lt;br /&gt;
    (instance public rm001 of Rm&lt;br /&gt;
       (method (init)&lt;br /&gt;
           ...&lt;br /&gt;
           (lifeMeter:init())      // display the life meter on the screen&lt;br /&gt;
           = flag FALSE            // init the flag variable&lt;br /&gt;
       )&lt;br /&gt;
&lt;br /&gt;
       (method (doit)&lt;br /&gt;
           (super:doit)&lt;br /&gt;
                // when we hit particular cells in the view, display messages to the user&lt;br /&gt;
		(switch (lifeMeter:cel())&lt;br /&gt;
		   (case 35&lt;br /&gt;
		   	   (if (not flag)&lt;br /&gt;
		   	      Print(&amp;quot;You don&amp;#039;t feel so well.&amp;quot;)&lt;br /&gt;
		   	      = flag TRUE&lt;br /&gt;
			   )&lt;br /&gt;
		   )&lt;br /&gt;
		   (case 70&lt;br /&gt;
		   	   (if (not flag)&lt;br /&gt;
		   	      Print(&amp;quot;You are doubling over in pain.&amp;quot;)&lt;br /&gt;
		   	      = flag TRUE&lt;br /&gt;
			   )&lt;br /&gt;
		   )&lt;br /&gt;
		   (case 95&lt;br /&gt;
		   	   (if (not flag)&lt;br /&gt;
		   	      Print(&amp;quot;Death is imminent.&amp;quot;)&lt;br /&gt;
		   	      = flag TRUE&lt;br /&gt;
			   )&lt;br /&gt;
		   )&lt;br /&gt;
		   (case 100&lt;br /&gt;
		   	   (if (not flag)&lt;br /&gt;
		   	      Print(&amp;quot;You are dead.&amp;quot;)&lt;br /&gt;
		   	      = flag TRUE&lt;br /&gt;
			   )&lt;br /&gt;
		   )&lt;br /&gt;
		   (default               // need this so that for the 10 seconds that this cell is active&lt;br /&gt;
		   	   = flag FALSE   // for the states specified in the switch above that the message is&lt;br /&gt;
                                          // only displayed once&lt;br /&gt;
		   )&lt;br /&gt;
		)&lt;br /&gt;
        )			&lt;br /&gt;
    )&lt;br /&gt;
&lt;br /&gt;
    (instance RoomScript of Script&lt;br /&gt;
      (method (changeState mainState)&lt;br /&gt;
           (var currentCel)&lt;br /&gt;
           = seconds 10  // wait 10 seconds&lt;br /&gt;
           = currentCel (lifeMeter:cel())   // get the current cell of the health meter view&lt;br /&gt;
           (lifeMeter:setCel(+ currentCel 1))  // advance to the next view in the cell, life meter is now shorter&lt;br /&gt;
      )&lt;br /&gt;
    )&lt;br /&gt;
&lt;br /&gt;
    (instance lifeMeter of Prop (properties y 8 x 165 view 11))  // meter located top-center of screen&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&amp;amp;nbsp;&lt;br /&gt;
&lt;br /&gt;
Basically, the changeState() method runs continuously, every 10 seconds it shortens the health bar by advancing the view to the next cell.  The doit() method waits for the view to hit certain cells, and when it does it alerts the user of their failing heath.&lt;br /&gt;
&lt;br /&gt;
Obviously, this is a really simple implementation, suitable perhaps if the ego is poisoned and steadily losing health, or maybe dying from starvation.  If you wanted something that was more &amp;#039;event-driven&amp;#039;, you could go without the changeState() entirely, and handle the changing of the lifeMeter view through specific events in your game (monster attack, ego touches a particular control color, etc).&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;#039;&amp;#039;&amp;#039;With regard to heap/hunk space consumption:&amp;#039;&amp;#039;&amp;#039;&amp;lt;br&amp;gt;&lt;br /&gt;
Looks like it loads the whole view into &amp;#039;hunk space&amp;#039; upon init.  Which in my case consumed 31K (which is the size of the view reported by Companion), but I still have plenty of hunk left (128K) and that&amp;#039;s with lots of other views already init()ed.  Doesn&amp;#039;t seem to matter whether the view cycles or doesn&amp;#039;t, no change there.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
To see a full implementation (with source code) of the health meter described here, see [[120_Degrees_Below_Zero|120 Degrees Below Zero]]&lt;br /&gt;
&lt;br /&gt;
[[Category:Examples]]&lt;/div&gt;</summary>
		<author><name>Jeremiah Nellis</name></author>
	</entry>
	<entry>
		<id>http://sciwiki.sierrahelp.com/index.php?title=SCI_Logging&amp;diff=7011</id>
		<title>SCI Logging</title>
		<link rel="alternate" type="text/html" href="http://sciwiki.sierrahelp.com/index.php?title=SCI_Logging&amp;diff=7011"/>
		<updated>2013-11-02T02:58:00Z</updated>

		<summary type="html">&lt;p&gt;Jeremiah Nellis: Created page with &amp;quot;&amp;#039;&amp;#039;Originally posted on the SCI Programming Forums by Gumby.&amp;#039;&amp;#039;    I&amp;#039;m pleased to announce that the first version of [[SCI Logging Demo|SCI Logging]...&amp;quot;&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&amp;#039;&amp;#039;Originally posted on the [[scipf:topic,718.html|SCI Programming Forums]] by [[Gumby]].&amp;#039;&amp;#039;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
I&amp;#039;m pleased to announce that the first version of [[SCI Logging Demo|SCI Logging]] has been hacked together &amp;amp; uploaded to the fan games page.&lt;br /&gt;
&lt;br /&gt;
It essentially logs all the necessary events (all user interaction) that is required for a &amp;#039;automated replay&amp;#039; of a game.  Useful for testing &amp;amp; troubleshooting and should hopefully work for an automated walkthrough of a game.  Ultimately, I&amp;#039;d like to create automated testing functionality where a recorded log file could be coupled with a file containing expected responses from the game.&lt;br /&gt;
&lt;br /&gt;
Unfortunately I had to make extensive changes to the template game to make this work, too many to list here but here&amp;#039;s an overview.  I created a new script (LogEvent.sc) which is responsible for the heavy lifting, reading and writing events to/from a log file.   For logging events, the calls are pretty much all wired into the User.sc and Controls.sc script.  For replaying logs, the replay command is called in the doit() method in the Main.sc.  Logging is enable/disabled in the init() method of the Main.sc script.  Please see the commented/uncommented sections, you&amp;#039;ll be able to spot them pretty easily.&lt;br /&gt;
&lt;br /&gt;
Here&amp;#039;s the included log file in the game (poorly formatted - it&amp;#039;s a fixed width of 115 characters or so):&lt;br /&gt;
&lt;br /&gt;
Ticks: 00000051 Event: gameLClick X: 201 Y: 083 Key:       Msg:&amp;lt;br&amp;gt;                                                   &lt;br /&gt;
Ticks: 00000054 Event: openPrint  X:     Y:     Key:       Msg: Initial Print&amp;lt;br&amp;gt;                                   &lt;br /&gt;
Ticks: 00000202 Event: closePrint X:     Y:     Key:       Msg:&amp;lt;br&amp;gt;                                      &lt;br /&gt;
Ticks: 00000202 Event: openPrint  X:     Y:     Key:       Msg: Print #2&amp;lt;br&amp;gt;                                          &lt;br /&gt;
Ticks: 00000349 Event: closePrint X:     Y:     Key:       Msg:&amp;lt;br&amp;gt;                                                   &lt;br /&gt;
Ticks: 00000409 Event: keyMove    X:     Y:     Key: $4d00 Msg:&amp;lt;br&amp;gt;                                                   &lt;br /&gt;
Ticks: 00000529 Event: parseOpen  X:     Y:     Key:       Msg: Enter Input:&amp;lt;br&amp;gt;                                      &lt;br /&gt;
Ticks: 00000607 Event: parseClose X:     Y:     Key:       Msg: look&amp;lt;br&amp;gt;                                              &lt;br /&gt;
Ticks: 00000608 Event: openPrint  X:     Y:     Key:       Msg: I see nothing&amp;lt;br&amp;gt;                                    &lt;br /&gt;
Ticks: 00000882 Event: closePrint X:     Y:     Key:       Msg:&amp;lt;br&amp;gt;                                                   &lt;br /&gt;
Ticks: 00000990 Event: keyMove    X:     Y:     Key: $4800 Msg:&amp;lt;br&amp;gt;                                                   &lt;br /&gt;
Ticks: 00001242 Event: keyMove    X:     Y:     Key: $4800 Msg:&amp;lt;br&amp;gt;                                                   &lt;br /&gt;
Ticks: 00001260 Event: leftClick  X: 160 Y: 100 Key:       Msg:&amp;lt;br&amp;gt;   &lt;br /&gt;
&lt;br /&gt;
Initial tests are very promising.  The only thing of concern is to make sure that your game runs quickly enough to log &amp;amp; replay the events at the correct tick count.  If your game is laggy (like 120 Below Zero), you&amp;#039;ll need to change your DosBox speed settings to address this.  Tick counts are the Achilles Heel of this entire project.  Right now it does not perform a &amp;#039;perfect replay&amp;#039;, but it is quite close - within one or two ticks.&lt;br /&gt;
&lt;br /&gt;
I&amp;#039;m pretty happy with the result, though I&amp;#039;m sure it needs additional testing &amp;amp; feedback.  I learned a lot about event handling, especially with regard to the print and parser events.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Okay, here&amp;#039;s a stab at how you need to modify your own game to support log/replay functionality.  First, download the [[SCI Logging Demo|SCI Logging]] demo game and put the LogEvent.sc script into your game /src directory.  Then modify the following files accordingly. &lt;br /&gt;
&lt;br /&gt;
------------------------------------------------------------------------&lt;br /&gt;
game.sh&lt;br /&gt;
------------------------------------------------------------------------&lt;br /&gt;
&amp;lt;div class=&amp;quot;CodeBlockHeader&amp;quot;&amp;gt;Code:&amp;lt;/div&amp;gt;&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;sci&amp;quot;&amp;gt;&lt;br /&gt;
// Add the following defines&lt;br /&gt;
(define LOGEVENT_SCRIPT     970)&lt;br /&gt;
&lt;br /&gt;
// all the different possible log events&lt;br /&gt;
(define EVENT_LEFTCLICK  0)&lt;br /&gt;
(define EVENT_RIGHTCLICK 1)&lt;br /&gt;
(define EVENT_KEYMOVE    2)&lt;br /&gt;
(define EVENT_PARSEOPEN 3)&lt;br /&gt;
(define EVENT_CLOSEPRINT 4)&lt;br /&gt;
(define EVENT_OPENPRINT  5)&lt;br /&gt;
(define EVENT_GAMEKEY    6)&lt;br /&gt;
(define EVENT_GAMELEFTCLICK 7)&lt;br /&gt;
(define EVENT_GAMERIGHTCLICK 8)&lt;br /&gt;
(define EVENT_PARSECLOSE 9)&lt;br /&gt;
&lt;br /&gt;
// the 3 log actions&lt;br /&gt;
(define NO_LOG                 0)&lt;br /&gt;
(define SAVE_LOG               1)&lt;br /&gt;
(define REPLAY_LOG             2)&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&amp;amp;nbsp;&lt;br /&gt;
------------------------------------------------------------------------&lt;br /&gt;
Controls.sc&lt;br /&gt;
------------------------------------------------------------------------&lt;br /&gt;
&amp;lt;div class=&amp;quot;CodeBlockHeader&amp;quot;&amp;gt;Code:&amp;lt;/div&amp;gt;&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;sci&amp;quot;&amp;gt;&lt;br /&gt;
// Include the LogEvent script near the top:&lt;br /&gt;
(use &amp;quot;logevent&amp;quot;)&lt;br /&gt;
&lt;br /&gt;
// Change your Dialog class doit() method to be this (changes highlighted):&lt;br /&gt;
&lt;br /&gt;
   (method (doit pItem)&lt;br /&gt;
      (var hEvent, isClaimed, editControl)&lt;br /&gt;
      = busy TRUE&lt;br /&gt;
        = editControl FALSE&lt;br /&gt;
&lt;br /&gt;
      (self:eachElementDo(#init))&lt;br /&gt;
      (if(theItem)&lt;br /&gt;
         (send theItem:select(FALSE))&lt;br /&gt;
      )&lt;br /&gt;
      (if(paramTotal and pItem)&lt;br /&gt;
          = theItem pItem&lt;br /&gt;
      )(else&lt;br /&gt;
         = theItem (self:firstTrue(#checkState TRUE))&lt;br /&gt;
      )&lt;br /&gt;
      (if(theItem)&lt;br /&gt;
          (send theItem:select(TRUE))&lt;br /&gt;
      )&lt;br /&gt;
      = isClaimed FALSE&lt;br /&gt;
&lt;br /&gt;
      (while((not isClaimed))&lt;br /&gt;
&lt;br /&gt;
           (if (== gLogAction REPLAY_LOG)&lt;br /&gt;
            // Queue up events until we get a parser close or close print event (should just be the next event in the log)&lt;br /&gt;
               (if (&amp;lt;&amp;gt; gEventEvent EVENT_PARSECLOSE and &amp;lt;&amp;gt; gEventEvent EVENT_CLOSEPRINT)&lt;br /&gt;
                   = gEventClaimed TRUE&lt;br /&gt;
                   QueueEvent()&lt;br /&gt;
               )&lt;br /&gt;
            // wait until we should close this window&lt;br /&gt;
               (if (&amp;gt;= GetTime() gEventTicks)&lt;br /&gt;
              // it&amp;#039;s been closed, get out of the loop&lt;br /&gt;
                 = isClaimed TRUE&lt;br /&gt;
                 break&lt;br /&gt;
               )&lt;br /&gt;
            )&lt;br /&gt;
&lt;br /&gt;
          (self:eachElementDo(#cycle))&lt;br /&gt;
         = hEvent (Event:new())&lt;br /&gt;
          GlobalToLocal(hEvent)&lt;br /&gt;
           = isClaimed (self:handleEvent(hEvent))&lt;br /&gt;
         (send hEvent:dispose())&lt;br /&gt;
         (self:check)&lt;br /&gt;
         (if( (== isClaimed -1) or (not busy) )&lt;br /&gt;
             = isClaimed FALSE&lt;br /&gt;
                = editControl TRUE&lt;br /&gt;
             EditControl(theItem 0)&lt;br /&gt;
             break&lt;br /&gt;
          )&lt;br /&gt;
            Wait(1)&lt;br /&gt;
      )&lt;br /&gt;
      = busy FALSE&lt;br /&gt;
  &lt;br /&gt;
       // Log the close print event, as long as this is not an EditPrint window&lt;br /&gt;
        (if (== gLogAction SAVE_LOG and == editControl TRUE)&lt;br /&gt;
           LogEvent(hEvent &amp;quot;closePrint&amp;quot; )&lt;br /&gt;
        )&lt;br /&gt;
&lt;br /&gt;
      return(isClaimed)&lt;br /&gt;
   )&lt;br /&gt;
&lt;br /&gt;
// Make the Dialog class dispose method look like this:&lt;br /&gt;
&lt;br /&gt;
   (method (dispose)&lt;br /&gt;
      (if(== self gPrintDlg)&lt;br /&gt;
         SetPort(gOldPort)&lt;br /&gt;
         = gPrintDlg NULL&lt;br /&gt;
         = gOldPort NULL&lt;br /&gt;
      )&lt;br /&gt;
      (if(window)&lt;br /&gt;
         (send window:dispose())&lt;br /&gt;
      )&lt;br /&gt;
      = window  NULL&lt;br /&gt;
      = theItem NULL&lt;br /&gt;
      (super:dispose())&lt;br /&gt;
         &lt;br /&gt;
      // When the print window is destroyed, load up the next event&lt;br /&gt;
        (if (== gLogAction REPLAY_LOG)&lt;br /&gt;
            = gEventClaimed TRUE&lt;br /&gt;
            QueueEvent()&lt;br /&gt;
        )&lt;br /&gt;
&lt;br /&gt;
   )&lt;br /&gt;
   &lt;br /&gt;
// Add this code before the send to hDText in the Print() procedure&lt;br /&gt;
&lt;br /&gt;
   // Logs when either the parser window is opened or a print dialog is opened&lt;br /&gt;
    (if (== gLogAction SAVE_LOG)&lt;br /&gt;
      (= dummyEvent Event:new())&lt;br /&gt;
       (if(== STRINGS_EQUAL StrCmp(@msgBuf &amp;quot;Enter Input:&amp;quot;))&lt;br /&gt;
         LogEvent(dummyEvent &amp;quot;parseOpen&amp;quot; @msgBuf)&lt;br /&gt;
       )(else&lt;br /&gt;
          LogEvent(dummyEvent &amp;quot;openPrint&amp;quot; @msgBuf)&lt;br /&gt;
       )&lt;br /&gt;
   )&lt;br /&gt;
&lt;br /&gt;
   (send hDText:&lt;br /&gt;
      text(@msgBuf)&lt;br /&gt;
      moveTo(4 4)&lt;br /&gt;
      font(gDefaultFont)&lt;br /&gt;
      setSize()&lt;br /&gt;
   )&lt;br /&gt;
&lt;br /&gt;
// Further down in the Print() procedure, before the open call:&lt;br /&gt;
&lt;br /&gt;
   // Queue up the next event (which should be a CLOSEPRINT event)&lt;br /&gt;
    (if (== gLogAction REPLAY_LOG and == gEventEvent EVENT_OPENPRINT)&lt;br /&gt;
       = gEventClaimed TRUE&lt;br /&gt;
       QueueEvent()&lt;br /&gt;
    )&lt;br /&gt;
 &lt;br /&gt;
   (send hDialog:open(moveToX moveToY))&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&amp;amp;nbsp;&lt;br /&gt;
------------------------------------------------------------------------   &lt;br /&gt;
User.sc&lt;br /&gt;
------------------------------------------------------------------------&lt;br /&gt;
&amp;lt;div class=&amp;quot;CodeBlockHeader&amp;quot;&amp;gt;Code:&amp;lt;/div&amp;gt;&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;sci&amp;quot;&amp;gt;&lt;br /&gt;
// Again, include the LogEvent script&lt;br /&gt;
(use &amp;quot;logevent&amp;quot;)&lt;br /&gt;
&lt;br /&gt;
// Change the getinput method to look like this:&lt;br /&gt;
&lt;br /&gt;
   (method (getInput pEvent)&lt;br /&gt;
      (var prevSound, strLen)&lt;br /&gt;
      (if(&amp;lt;&amp;gt; (send pEvent:type) evKEYBOARD)&lt;br /&gt;
          = inputStr 0&lt;br /&gt;
      )&lt;br /&gt;
  &lt;br /&gt;
       // this allows for replaying the typed text into the input window&lt;br /&gt;
        (if (== gEventEvent EVENT_PARSEOPEN and == gLogAction REPLAY_LOG)&lt;br /&gt;
             = gEventClaimed TRUE&lt;br /&gt;
             QueueEvent()  // parser close&lt;br /&gt;
             StrCpy(@inputStr @gEventMsg)&lt;br /&gt;
             (send pEvent:message(@gEventMsg))  // set the input in input box (from parser close event)&lt;br /&gt;
        )(else&lt;br /&gt;
         (if(&amp;lt;&amp;gt; (send pEvent:message) echo)&lt;br /&gt;
             Format(@inputStr &amp;quot;%c&amp;quot; (send pEvent:message))&lt;br /&gt;
         )&lt;br /&gt;
        )&lt;br /&gt;
      = prevSound (Sound:pause(blocks))&lt;br /&gt;
      = strLen EditPrint(@inputStr maxInputLen prompt #at x y)&lt;br /&gt;
&lt;br /&gt;
      (Sound:pause(prevSound))&lt;br /&gt;
      return(strLen)&lt;br /&gt;
   )&lt;br /&gt;
&lt;br /&gt;
// And the handleEvent method:&lt;br /&gt;
&lt;br /&gt;
   (method (handleEvent pEvent)&lt;br /&gt;
      (var evType, origKey)&lt;br /&gt;
      (if(send pEvent:type)&lt;br /&gt;
         = gUserEvent pEvent&lt;br /&gt;
         = evType (send pEvent:type)&lt;br /&gt;
&lt;br /&gt;
           = origKey (send pEvent:message)   // get the original key input, prior to it being manipulated in mapKeyToDir&lt;br /&gt;
&lt;br /&gt;
         (if(mapKeyToDir)&lt;br /&gt;
            MapKeyToDir(pEvent)&lt;br /&gt;
         )&lt;br /&gt;
         (if(TheMenuBar)&lt;br /&gt;
            (TheMenuBar:handleEvent(pEvent evType))&lt;br /&gt;
         )&lt;br /&gt;
   &lt;br /&gt;
          GlobalToLocal(pEvent)&lt;br /&gt;
&lt;br /&gt;
         (if(not (send pEvent:claimed))&lt;br /&gt;
            (send gGame:handleEvent(pEvent evType))&lt;br /&gt;
         )&lt;br /&gt;
   &lt;br /&gt;
          (if(controls and (not (send pEvent:claimed))&lt;br /&gt;
            and (send gCast:contains(alterEgo)))&lt;br /&gt;
             (send alterEgo:handleEvent(pEvent))&lt;br /&gt;
          )&lt;br /&gt;
&lt;br /&gt;
         // logs ego events (mouse clicks and keyboard movements&lt;br /&gt;
            (if((send pEvent:claimed) and == gLogAction SAVE_LOG)&lt;br /&gt;
              (send pEvent:message(origKey))&lt;br /&gt;
              LogEvent(pEvent &amp;quot;ego&amp;quot;)&lt;br /&gt;
            )&lt;br /&gt;
   &lt;br /&gt;
            (if(canInput and not(send pEvent:claimed))&lt;br /&gt;
            (if( (== (send pEvent:message) echo) or (&amp;lt;= $20 (send pEvent:message)) and (&amp;lt;= (send pEvent:message) 255))&lt;br /&gt;
                        (if( (self:getInput(pEvent)))&lt;br /&gt;
      &lt;br /&gt;
                             // logs the closing of the parser&lt;br /&gt;
                              (if (== gLogAction SAVE_LOG)&lt;br /&gt;
                                 LogEvent(pEvent &amp;quot;parseClose&amp;quot; @inputStr)&lt;br /&gt;
                              )&lt;br /&gt;
                           &lt;br /&gt;
                              (if(Parse(@inputStr pEvent))&lt;br /&gt;
                              (send pEvent:type(evSAID))&lt;br /&gt;
                           (self:said(pEvent))&lt;br /&gt;
                              )&lt;br /&gt;
                        )&lt;br /&gt;
                )&lt;br /&gt;
                &lt;br /&gt;
            )&lt;br /&gt;
           // for handling the titlescreen events&lt;br /&gt;
            (if (== canInput FALSE and not(send pEvent:claimed) and == gLogAction SAVE_LOG)&lt;br /&gt;
               LogEvent(pEvent &amp;quot;game&amp;quot;)&lt;br /&gt;
          )&lt;br /&gt;
            &lt;br /&gt;
      )&lt;br /&gt;
        = gUserEvent NULL&lt;br /&gt;
   )   &lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&amp;amp;nbsp;&lt;br /&gt;
------------------------------------------------------------------------   &lt;br /&gt;
Main.sc&lt;br /&gt;
------------------------------------------------------------------------&lt;br /&gt;
&amp;lt;div class=&amp;quot;CodeBlockHeader&amp;quot;&amp;gt;Code:&amp;lt;/div&amp;gt;&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;sci&amp;quot;&amp;gt;&lt;br /&gt;
// Include logevent again:&lt;br /&gt;
(use &amp;quot;logevent&amp;quot;)&lt;br /&gt;
&lt;br /&gt;
// Add these local variables:&lt;br /&gt;
    // Logging variables&lt;br /&gt;
    gLogLineSize = 116     &lt;br /&gt;
    gLogAction = NO_LOG &lt;br /&gt;
    gLogFileName[50]&lt;br /&gt;
    gEventTicks&lt;br /&gt;
    gEventEvent&lt;br /&gt;
    gEventX&lt;br /&gt;
    gEventY&lt;br /&gt;
    gEventKey&lt;br /&gt;
    gEventMsg[51]&lt;br /&gt;
    gLogFileHandle&lt;br /&gt;
    gEventClaimed = TRUE&lt;br /&gt;
&lt;br /&gt;
// At the bottom of the init() method in the Game instance, add ONE of the following code blocks,&lt;br /&gt;
// depending whether you want to log events or replay a log file:&lt;br /&gt;
&lt;br /&gt;
       //  for logging events&lt;br /&gt;
       = gLogAction SAVE_LOG&lt;br /&gt;
       Format(@gLogFileName &amp;quot;logs\\log%d&amp;quot; Abs(GetTime(gtTIME_OF_DAY)))&lt;br /&gt;
       = gLogFileHandle FOpen(@gLogFileName fOPENFAIL)&lt;br /&gt;
&lt;br /&gt;
       // for replaying events&lt;br /&gt;
       = gLogAction REPLAY_LOG&lt;br /&gt;
       StrCpy(@gLogFileName &amp;quot;logs\\LOG19736&amp;quot;)   // change this to the log file of your choice&lt;br /&gt;
        = gLogFileHandle FOpen(@gLogFileName fOPENCREATE)&lt;br /&gt;
        = gEventEvent -1&lt;br /&gt;
        = gEventTicks -1&lt;br /&gt;
&lt;br /&gt;
   &lt;br /&gt;
   &lt;br /&gt;
// At the bottom of the doit() in your Game instance, add this:&lt;br /&gt;
&lt;br /&gt;
        // enables replaying of the log&lt;br /&gt;
        (if (== gLogAction REPLAY_LOG)&lt;br /&gt;
           ReplayLog()&lt;br /&gt;
        )&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&amp;amp;nbsp;&lt;br /&gt;
&lt;br /&gt;
[[Category:Examples]]&lt;/div&gt;</summary>
		<author><name>Jeremiah Nellis</name></author>
	</entry>
	<entry>
		<id>http://sciwiki.sierrahelp.com/index.php?title=Timing_change_for_death_handler_script_(Dying.sc)&amp;diff=7010</id>
		<title>Timing change for death handler script (Dying.sc)</title>
		<link rel="alternate" type="text/html" href="http://sciwiki.sierrahelp.com/index.php?title=Timing_change_for_death_handler_script_(Dying.sc)&amp;diff=7010"/>
		<updated>2013-11-02T02:44:02Z</updated>

		<summary type="html">&lt;p&gt;Jeremiah Nellis: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&amp;#039;&amp;#039;Originally posted on the [[scipf:topic,665.html|SCI Programming Forums]] by [[Gumby]].&amp;#039;&amp;#039;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
I just utilized the dying.sc script for the first time and I immediately noticed that there is a significant delay between calling the the script and the death &amp;#039;screen&amp;#039; popping up.&lt;br /&gt;
&lt;br /&gt;
This is by design, but I didn&amp;#039;t like the fact that the delay length was hard-coded into script.  Making a few modifications, I exposed the delay property for the script:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div class=&amp;quot;CodeBlockHeader&amp;quot;&amp;gt;Code:&amp;lt;/div&amp;gt;&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;sci&amp;quot;&amp;gt;&lt;br /&gt;
(instance public DyingScript of Script&lt;br /&gt;
	(properties&lt;br /&gt;
	    seconds 3	     //  Exposed this property (just by adding it here), &lt;br /&gt;
        )                    //  which is inherited from the Script class &amp;amp; set the default to 3&lt;br /&gt;
	&lt;br /&gt;
	(method (changeState newState)&lt;br /&gt;
		(var mbResult, message)&lt;br /&gt;
		= state newState&lt;br /&gt;
		(if(== state 0)&lt;br /&gt;
			ProgramControl()&lt;br /&gt;
			(send gTheMusic:fade())&lt;br /&gt;
			(send gRoom:setScript(0))&lt;br /&gt;
			Load(rsSOUND 2)&lt;br /&gt;
			//= seconds 3     // Commented out this line, which set the delay to 3 seconds&lt;br /&gt;
		)(else&lt;br /&gt;
  			(if(== state 1)&lt;br /&gt;
                ...&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&amp;amp;nbsp;&lt;br /&gt;
&lt;br /&gt;
So now, when I call the dying script, I can specify seconds like so:&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div class=&amp;quot;CodeBlockHeader&amp;quot;&amp;gt;Code:&amp;lt;/div&amp;gt;&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;sci&amp;quot;&amp;gt;&lt;br /&gt;
  (send dyingScript:&lt;br /&gt;
       caller(802)&lt;br /&gt;
       seconds(1)   //  You can set this to however long you wish, based on your animation length&lt;br /&gt;
       register(&amp;quot;You are dead.&amp;quot;)&lt;br /&gt;
   )&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&amp;amp;nbsp;&lt;br /&gt;
If you need more granularity than seconds, it would be simple to expose the &amp;#039;cycles&amp;#039; property instead of the &amp;#039;seconds&amp;#039; property in the Script class, then change the dying script to use cycles instead of seconds.&lt;br /&gt;
&lt;br /&gt;
[[Category:Examples]]&lt;/div&gt;</summary>
		<author><name>Jeremiah Nellis</name></author>
	</entry>
	<entry>
		<id>http://sciwiki.sierrahelp.com/index.php?title=Timing_change_for_death_handler_script_(Dying.sc)&amp;diff=7009</id>
		<title>Timing change for death handler script (Dying.sc)</title>
		<link rel="alternate" type="text/html" href="http://sciwiki.sierrahelp.com/index.php?title=Timing_change_for_death_handler_script_(Dying.sc)&amp;diff=7009"/>
		<updated>2013-11-02T02:41:22Z</updated>

		<summary type="html">&lt;p&gt;Jeremiah Nellis: Created page with &amp;quot;&amp;#039;&amp;#039;Originally posted on the SCI Programming Forums by Gumby.&amp;#039;&amp;#039;    I just utilized the dying.sc script for the first time and I immediately noticed ...&amp;quot;&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&amp;#039;&amp;#039;Originally posted on the [[scipf:topic,665.html|SCI Programming Forums]] by [[Gumby]].&amp;#039;&amp;#039;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
I just utilized the dying.sc script for the first time and I immediately noticed that there is a significant delay between calling the the script and the death &amp;#039;screen&amp;#039; popping up.&lt;br /&gt;
&lt;br /&gt;
This is by design, but I didn&amp;#039;t like the fact that the delay length was hard-coded into script.  Making a few modifications, I exposed the delay property for the script:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div class=&amp;quot;CodeBlockHeader&amp;quot;&amp;gt;Code:&amp;lt;/div&amp;gt;&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;sci&amp;quot;&amp;gt;&lt;br /&gt;
(instance public DyingScript of Script&lt;br /&gt;
	(properties&lt;br /&gt;
	    seconds 3	     //  Exposed this property (just by adding it here), &lt;br /&gt;
        )                    //  which is inherited from the Script class &amp;amp; set the default to 3&lt;br /&gt;
	&lt;br /&gt;
	(method (changeState newState)&lt;br /&gt;
		(var mbResult, message)&lt;br /&gt;
		= state newState&lt;br /&gt;
		(if(== state 0)&lt;br /&gt;
			ProgramControl()&lt;br /&gt;
			(send gTheMusic:fade())&lt;br /&gt;
			(send gRoom:setScript(0))&lt;br /&gt;
			Load(rsSOUND 2)&lt;br /&gt;
			//= seconds 3     // Commented out this line, which set the delay to 3 seconds&lt;br /&gt;
		)(else&lt;br /&gt;
  			(if(== state 1)&lt;br /&gt;
                ...&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&amp;amp;nbsp;&lt;br /&gt;
&lt;br /&gt;
So now, when I call the dying script, I can specify seconds like so:&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div class=&amp;quot;CodeBlockHeader&amp;quot;&amp;gt;Code:&amp;lt;/div&amp;gt;&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;sci&amp;quot;&amp;gt;&lt;br /&gt;
  (send dyingScript:&lt;br /&gt;
       caller(802)&lt;br /&gt;
       seconds(1)   //  You can set this to however long you wish, based on your animation length&lt;br /&gt;
       register(&amp;quot;You are dead.&amp;quot;)&lt;br /&gt;
   )&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&amp;amp;nbsp;&lt;br /&gt;
If you need more granularity than seconds, it would be simple to expose the &amp;#039;cycles&amp;#039; property instead of the &amp;#039;seconds&amp;#039; property in the Script class, then change the dying script to use cycles instead of seconds.&lt;/div&gt;</summary>
		<author><name>Jeremiah Nellis</name></author>
	</entry>
	<entry>
		<id>http://sciwiki.sierrahelp.com/index.php?title=SCI_Specifications:_Chapter_3_-_The_Graphics_subsystem&amp;diff=280</id>
		<title>SCI Specifications: Chapter 3 - The Graphics subsystem</title>
		<link rel="alternate" type="text/html" href="http://sciwiki.sierrahelp.com/index.php?title=SCI_Specifications:_Chapter_3_-_The_Graphics_subsystem&amp;diff=280"/>
		<updated>2013-06-22T23:57:24Z</updated>

		<summary type="html">&lt;p&gt;Jeremiah Nellis: /* The SCI font resource */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;==General stuff==&lt;br /&gt;
The graphics in SCI are generated using four resource types:&lt;br /&gt;
&lt;br /&gt;
* Pic resources for background pictures&lt;br /&gt;
* View resources for images&lt;br /&gt;
* Font resources for drawing text&lt;br /&gt;
* Cursor resources for displaying the mouse pointer&lt;br /&gt;
&lt;br /&gt;
Those resources are drawn on three distinct maps:&lt;br /&gt;
&lt;br /&gt;
* The visual map, used for displaying the actual pictures the player sees&lt;br /&gt;
* The priority map, which keeps information about how the depth of the screen&lt;br /&gt;
* The control map, which contains special information&lt;br /&gt;
&lt;br /&gt;
==SCI Ports==&lt;br /&gt;
&lt;br /&gt;
&amp;#039;&amp;#039;&amp;#039;Lars Skovlund&amp;#039;&amp;#039;&amp;#039;&lt;br /&gt;
&lt;br /&gt;
Version 1.0, 6. July 1999&lt;br /&gt;
&lt;br /&gt;
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.&lt;br /&gt;
&lt;br /&gt;
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.&lt;br /&gt;
&lt;br /&gt;
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 &amp;quot;picture window&amp;quot; (such a thing really exists in SCI!) is 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).&lt;br /&gt;
&lt;br /&gt;
At least three ports are created and managed automatically by the SCI interpreter. These are the &amp;quot;window manager&amp;quot; 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 &amp;quot;invisible&amp;quot; port, on which the window backgrounds are drawn, although the windows have a port themselves. If you are familiar with Windows™ programming, the term &amp;quot;client rectangle&amp;quot; may ring a bell here - SCI draws the window backgrounds, using values in the window manager port, while the window&amp;#039;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&amp;#039;t mess up the graphics.&lt;br /&gt;
&lt;br /&gt;
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 &amp;quot;port&amp;quot; property. Instead, its &amp;quot;window&amp;quot; property points to the extended port/window structure which can safely be passed to KSetPort. Not surprisingly, many of KNewWindow&amp;#039;s arguments end up in the port part of the window structure.&lt;br /&gt;
&lt;br /&gt;
An SCI program can&amp;#039;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.&lt;br /&gt;
&lt;br /&gt;
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.&lt;br /&gt;
&lt;br /&gt;
Only two kernel calls deal directly with ports:&lt;br /&gt;
&lt;br /&gt;
KGetPort (see [[SCI_Specifications:_Chapter_5_(cont.)_-_Kernel_functions#Kernel_function_0x14:_GetPort.28.29|the Section called Kernel function 0x14: GetPort() in Chapter 5]])&amp;lt;br&amp;gt;&lt;br /&gt;
KSetPort (see [[SCI_Specifications:_Chapter_5_(cont.)_-_Kernel_functions#Kernel_function_0x15:_SetPort.28.29|the Section called Kernel function 0x15: SetPort() in Chapter 5]])&lt;br /&gt;
&lt;br /&gt;
These two functions are often used in pairs (also internally), like:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;var temp;&lt;br /&gt;
&lt;br /&gt;
temp=KGetPort();  /* Save the old port */&lt;br /&gt;
KSetPort(...);      /* Activate some other port */&lt;br /&gt;
..                            /* Draw some stuff */&lt;br /&gt;
KSetPort(temp);    /* Reactivate the old port */&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==The Cursor resource==&lt;br /&gt;
&lt;br /&gt;
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.&lt;br /&gt;
&lt;br /&gt;
0x00 - 0x01&lt;br /&gt;
&lt;br /&gt;
:: X coordinate of the mouse cursor hot spot as a 16 bit integer. This variable is not used in SCI0. &lt;br /&gt;
&lt;br /&gt;
0x02 - 0x03&lt;br /&gt;
&lt;br /&gt;
:: 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). &lt;br /&gt;
&lt;br /&gt;
0x04 - 0x23&lt;br /&gt;
&lt;br /&gt;
:: This is a list of 16 unsigned 16 bit integers constituting bitmasks for the mouse cursor&amp;#039;s transparency map, with the MSB representing the leftmost pixel. &lt;br /&gt;
&lt;br /&gt;
0x24 - 0x43&lt;br /&gt;
&lt;br /&gt;
:: 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). &lt;br /&gt;
&lt;br /&gt;
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.&lt;br /&gt;
&lt;br /&gt;
&amp;amp;nbsp;&lt;br /&gt;
&lt;br /&gt;
===Color mapping for the SCI0 mouse pointer===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;blockquote&amp;gt;&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot; width=&amp;quot;150&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! align=&amp;quot;center&amp;quot; width=&amp;quot;25&amp;quot; | AB&lt;br /&gt;
! width=&amp;quot;120&amp;quot; | Result&lt;br /&gt;
|-&lt;br /&gt;
| align=&amp;quot;center&amp;quot; width=&amp;quot;25&amp;quot; | 00&lt;br /&gt;
| width=&amp;quot;120&amp;quot; | Transparent&lt;br /&gt;
|-&lt;br /&gt;
| align=&amp;quot;center&amp;quot; width=&amp;quot;25&amp;quot; | 01&lt;br /&gt;
| width=&amp;quot;120&amp;quot; | Transparent&lt;br /&gt;
|-&lt;br /&gt;
| align=&amp;quot;center&amp;quot; width=&amp;quot;25&amp;quot; | 10&lt;br /&gt;
| width=&amp;quot;120&amp;quot; | 0x00 (Black)&lt;br /&gt;
|-&lt;br /&gt;
| align=&amp;quot;center&amp;quot; width=&amp;quot;25&amp;quot; | 11&lt;br /&gt;
| width=&amp;quot;120&amp;quot; | 0x0f (White)&lt;br /&gt;
|}&lt;br /&gt;
&amp;lt;/blockquote&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;amp;nbsp;&lt;br /&gt;
&lt;br /&gt;
===Color mapping for the SCI1 mouse pointer===&lt;br /&gt;
&lt;br /&gt;
Since this method of doing things wastes one combination, the table was changed for SCI01 and SCI1:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;blockquote&amp;gt;&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot; width=&amp;quot;150&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! align=&amp;quot;center&amp;quot; width=&amp;quot;25&amp;quot; | AB&lt;br /&gt;
! width=&amp;quot;120&amp;quot; | Result&lt;br /&gt;
|-&lt;br /&gt;
| align=&amp;quot;center&amp;quot; width=&amp;quot;25&amp;quot; | 00&lt;br /&gt;
| width=&amp;quot;120&amp;quot; | Transparent&lt;br /&gt;
|-&lt;br /&gt;
| align=&amp;quot;center&amp;quot; width=&amp;quot;25&amp;quot; | 01&lt;br /&gt;
| width=&amp;quot;120&amp;quot; | 0x0f (White)&lt;br /&gt;
|-&lt;br /&gt;
| align=&amp;quot;center&amp;quot; width=&amp;quot;25&amp;quot; | 10&lt;br /&gt;
| width=&amp;quot;120&amp;quot; | 0x00 (Black)&lt;br /&gt;
|-&lt;br /&gt;
| align=&amp;quot;center&amp;quot; width=&amp;quot;25&amp;quot; | 11&lt;br /&gt;
| width=&amp;quot;120&amp;quot; | 0x07 (Light Gray)&lt;br /&gt;
|}&lt;br /&gt;
&amp;lt;/blockquote&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;amp;nbsp;&lt;br /&gt;
&lt;br /&gt;
==The SCI0 View Resource==&lt;br /&gt;
&lt;br /&gt;
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.&lt;br /&gt;
&lt;br /&gt;
===The View Resource===&lt;br /&gt;
&lt;br /&gt;
0x00 - 0x01&lt;br /&gt;
&lt;br /&gt;
:: The number of image groups available. &lt;br /&gt;
&lt;br /&gt;
0x02 - 0x03&lt;br /&gt;
&lt;br /&gt;
:: A bitmask containing the &amp;#039;mirrored&amp;#039; flag for each of the groups, with the LSB containing the &amp;#039;mirrored&amp;#039; flag for group 0. &lt;br /&gt;
&lt;br /&gt;
0x04 - 0x07&lt;br /&gt;
&lt;br /&gt;
:: - unknown - &lt;br /&gt;
&lt;br /&gt;
0x08...&lt;br /&gt;
&lt;br /&gt;
:: 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 - &lt;br /&gt;
&lt;br /&gt;
0x01. &lt;br /&gt;
&lt;br /&gt;
===Cell List===&lt;br /&gt;
&lt;br /&gt;
0x00 - 0x01&lt;br /&gt;
&lt;br /&gt;
:: The number of image cells available for this group.&lt;br /&gt;
&lt;br /&gt;
0x02 - 0x03&lt;br /&gt;
&lt;br /&gt;
:: - unknown -&lt;br /&gt;
&lt;br /&gt;
0x04...&lt;br /&gt;
&lt;br /&gt;
:: 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. &lt;br /&gt;
&lt;br /&gt;
===Image Cell===&lt;br /&gt;
&lt;br /&gt;
0x00 - 0x01&lt;br /&gt;
&lt;br /&gt;
:: The horizontal (X) size of the image.&lt;br /&gt;
&lt;br /&gt;
0x02 - 0x03&lt;br /&gt;
&lt;br /&gt;
:: The vertical (Y) size of the image.&lt;br /&gt;
&lt;br /&gt;
0x04&lt;br /&gt;
&lt;br /&gt;
:: The x placement modifier. This signed value determines the number of pixels a view cell is moved to the right before it is drawn.&lt;br /&gt;
&lt;br /&gt;
0x05&lt;br /&gt;
&lt;br /&gt;
:: The y placement modifier. This signed value determines the number of pixels a view cell is moved downwards before it is drawn.&lt;br /&gt;
&lt;br /&gt;
0x06&lt;br /&gt;
&lt;br /&gt;
:: The color key, i.e. the color number used for transparency in this cell.&lt;br /&gt;
&lt;br /&gt;
0x07...&lt;br /&gt;
&lt;br /&gt;
:: 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.&lt;br /&gt;
&lt;br /&gt;
==The SCI font resource==&lt;br /&gt;
&lt;br /&gt;
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:&lt;br /&gt;
&amp;lt;div id=&amp;quot;AEN2349&amp;quot;&amp;gt;&amp;lt;/div&amp;gt;&lt;br /&gt;
&amp;#039;&amp;#039;&amp;#039;Table 3-1. The SCI font resource data structure&amp;#039;&amp;#039;&amp;#039;&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot; width=&amp;quot;760&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! width=&amp;quot;85&amp;quot; align=&amp;quot;center&amp;quot; | Offset&lt;br /&gt;
! width=&amp;quot;235&amp;quot; | Type&lt;br /&gt;
! width=&amp;quot;440&amp;quot; | Meaning&lt;br /&gt;
|-&lt;br /&gt;
| width=&amp;quot;85&amp;quot; align=&amp;quot;center&amp;quot; | 0&lt;br /&gt;
| width=&amp;quot;235&amp;quot; | 16 bit integer, little endian encoding&lt;br /&gt;
| width=&amp;quot;440&amp;quot; | Always zero (?)&lt;br /&gt;
|-&lt;br /&gt;
| width=&amp;quot;85&amp;quot; align=&amp;quot;center&amp;quot; | 2&lt;br /&gt;
| width=&amp;quot;235&amp;quot; | 16 bit integer, little endian encoding&lt;br /&gt;
| width=&amp;quot;440&amp;quot; | NUMCHAR: Number of characters&lt;br /&gt;
|-&lt;br /&gt;
| width=&amp;quot;85&amp;quot; align=&amp;quot;center&amp;quot; | 4&lt;br /&gt;
| width=&amp;quot;235&amp;quot; | 16 bit integer, little endian encoding&lt;br /&gt;
| width=&amp;quot;440&amp;quot; | HEIGHT: Number of pixel lines per text line&lt;br /&gt;
|-&lt;br /&gt;
| width=&amp;quot;85&amp;quot; align=&amp;quot;center&amp;quot; | 6 + NR * 2&lt;br /&gt;
| width=&amp;quot;235&amp;quot; | 16 bit integer, little endian encoding&lt;br /&gt;
| width=&amp;quot;440&amp;quot; | Absolute offset of the character #NR, where 0 &amp;amp;lt;= NR &amp;amp;lt; NUMCHAR&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
 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:&lt;br /&gt;
&amp;lt;div id=&amp;quot;AEN2375&amp;quot;&amp;gt;&amp;lt;/div&amp;gt;&lt;br /&gt;
&amp;#039;&amp;#039;&amp;#039;Table 3-2. The SCI font resource character data structure&amp;#039;&amp;#039;&amp;#039;&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot; width=&amp;quot;760&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! width=&amp;quot;85&amp;quot; align=&amp;quot;center&amp;quot; | Offset&lt;br /&gt;
! width=&amp;quot;235&amp;quot; | Type&lt;br /&gt;
! width=&amp;quot;440&amp;quot; | Meaning&lt;br /&gt;
|-&lt;br /&gt;
| width=&amp;quot;85&amp;quot; align=&amp;quot;center&amp;quot; | 0&lt;br /&gt;
| width=&amp;quot;235&amp;quot; | unsigned 8 bit integer&lt;br /&gt;
| width=&amp;quot;440&amp;quot; | character &amp;lt;span style=&amp;quot;color: red; text-decoration: line-through;&amp;quot;&amp;gt;HEIGHT&amp;lt;/span&amp;gt; WIDTH&lt;br /&gt;
|-&lt;br /&gt;
| width=&amp;quot;85&amp;quot; align=&amp;quot;center&amp;quot; | 1&lt;br /&gt;
| width=&amp;quot;235&amp;quot; | unsigned 8 bit integer&lt;br /&gt;
| width=&amp;quot;440&amp;quot; | character &amp;lt;span style=&amp;quot;color: red; text-decoration: line-through;&amp;quot;&amp;gt;WIDTH&amp;lt;/span&amp;gt; HEIGHT&lt;br /&gt;
|-&lt;br /&gt;
| width=&amp;quot;85&amp;quot; align=&amp;quot;center&amp;quot; | 2...&lt;br /&gt;
| width=&amp;quot;235&amp;quot; | bitmask, size HEIGHT * round_up(WIDTH / 8)&lt;br /&gt;
| width=&amp;quot;440&amp;quot; | Bitmask for the character&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
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.&lt;br /&gt;
&lt;br /&gt;
==The SCI0 and SCI01 pic resource==&lt;br /&gt;
&lt;br /&gt;
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&amp;lt;ref group=Note&amp;gt;Due to the vector graphics nature of these drawing operations, they are inherently more scaleable than pixmaps.&amp;lt;/ref&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Note hereIn order to describe the process, we will first need to define a set of operations we base them on:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;FUNCTION peek_input(): Byte; /* returns the byte pointed to by the input pointer */&lt;br /&gt;
FUNCTION get_input(): Byte; /* works like peek_input(), but also increminates the &lt;br /&gt;
                            ** input pointer  */&lt;br /&gt;
FUNCTION skip_input(x): Byte; /* skips x input bytes */&amp;lt;/pre&amp;gt;&lt;br /&gt;
      &lt;br /&gt;
&lt;br /&gt;
Using these pre-defined functions, we will now define additional helper functions used for reading specifically encoded data tuples:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;FUNCTION GetAbsCoordinates(): (Integer, Integer)&lt;br /&gt;
VAR&lt;br /&gt;
    x, y, coordinate_prefix : Integer;&lt;br /&gt;
BEGIN&lt;br /&gt;
    coordinate_prefix := get_input();&lt;br /&gt;
    x := get_input();&lt;br /&gt;
    y := get_input();&lt;br /&gt;
    x |= (coordinate_prefix &amp;amp; 0xf0) &amp;lt;&amp;lt; 4;&lt;br /&gt;
    y |= (coordinate_prefix &amp;amp; 0x0f) &amp;lt;&amp;lt; 8;&lt;br /&gt;
&lt;br /&gt;
    RETURN (x,y)&lt;br /&gt;
END&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
FUNCTION GetRelCoordinates(x : Integer, y: Integer): (Integer, Integer)&lt;br /&gt;
VAR&lt;br /&gt;
    input : Integer;&lt;br /&gt;
BEGIN&lt;br /&gt;
    input := get_input();&lt;br /&gt;
    IF (input &amp;amp; 0x80) THEN&lt;br /&gt;
            x -= (input &amp;gt;&amp;gt; 4);&lt;br /&gt;
    ELSE&lt;br /&gt;
        x += (input &amp;gt;&amp;gt; 4);&lt;br /&gt;
    FI&lt;br /&gt;
&lt;br /&gt;
    IF (input &amp;amp; 0x08) THEN&lt;br /&gt;
        y -= (input &amp;amp; 0x7);&lt;br /&gt;
    ELSE&lt;br /&gt;
        y += (input &amp;amp; 0x7);&lt;br /&gt;
    FI&lt;br /&gt;
&lt;br /&gt;
    RETURN (x,y)&lt;br /&gt;
END&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
We also need some data types based on EGACOLOR and PRIORITY, which can be thought of as integers:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;TYPE Palette = ARRAY[0..39] of EGACOLOR[0..1]&lt;br /&gt;
TYPE Priority_Table = ARRAY[0..39] of PRIORITY&lt;br /&gt;
&lt;br /&gt;
Palette default_palette =&lt;br /&gt;
     &amp;lt;(0,0), (1,1), (2,2), (3,3), (4,4), (5,5), (6,6), (7,7),&lt;br /&gt;
      (8,8), (9,9), (a,a), (b,b), (c,c), (d,d), (e,e), (8,8),&lt;br /&gt;
      (8,8), (0,1), (0,2), (0,3), (0,4), (0,5), (0,6), (8,8),&lt;br /&gt;
      (8,8), (f,9), (f,a), (f,b), (f,c), (f,d), (f,e), (f,f),&lt;br /&gt;
      (0,8), (9,1), (2,a), (3,b), (4,c), (5,d), (6,e), (8,8)&amp;gt;;&lt;br /&gt;
&lt;br /&gt;
#define DRAW_ENABLE_VISUAL   1&lt;br /&gt;
#define DRAW_ENABLE_PRIORITY 2&lt;br /&gt;
#define DRAW_ENABLE_CONTROL  4&lt;br /&gt;
&lt;br /&gt;
#define PATTERN_FLAG_RECTANGLE 0x10&lt;br /&gt;
#define PATTERN_FLAG_USE_PATTERN 0x20&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
And now for the actual algorithm:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;FUNCTION DrawPic (cumulative, fill_in_black : Boolean; default_palette: Integer; visual_map, priority_map, control_map, aux_map : Map): Map^4&lt;br /&gt;
VAR&lt;br /&gt;
    palette : Array [0..3] of Palette;&lt;br /&gt;
    drawenable, priority, col1, col2, pattern_nr, pattern_code : Integer;&lt;br /&gt;
BEGIN&lt;br /&gt;
    palette := (default_palette × 4);&lt;br /&gt;
    drawenable := DRAW_ENABLE_VISUAL | DRAW_ENABLE_PRIORITY&lt;br /&gt;
    priority := 0;&lt;br /&gt;
    col1 := col2 := 0;&lt;br /&gt;
    pattern_nr := 0;&lt;br /&gt;
    pattern_code := 0;&lt;br /&gt;
&lt;br /&gt;
    IF (!cumulative) THEN BEGIN&lt;br /&gt;
        visual_map := (0xf × 320 × 200);&lt;br /&gt;
        map control := map priority := map aux := (0 × 320 × 200);&lt;br /&gt;
    END&lt;br /&gt;
&lt;br /&gt;
    FOREVER DO BEGIN&lt;br /&gt;
&lt;br /&gt;
        opcode := get_input();&lt;br /&gt;
&lt;br /&gt;
        COND opcode:&lt;br /&gt;
            0xf0 → /* PIC_OP_SET_COLOR */&lt;br /&gt;
                code := get_input();&lt;br /&gt;
                (col1, col2) := palette[default_palette + (code / 40)][code % 40];&lt;br /&gt;
                drawenable |= DRAW_ENABLE_VISUAL;&lt;br /&gt;
&lt;br /&gt;
            0xf1 → /* PIC_OP_DISABLE_VISUAL */&lt;br /&gt;
                drawenable &amp;amp;= ~DRAW_ENABLE_VISUAL;&lt;br /&gt;
&lt;br /&gt;
            0xf2 → /* PIC_OP_SET_PRIORITY */&lt;br /&gt;
                code := get_input();&lt;br /&gt;
                priority := code &amp;amp; 0xf;&lt;br /&gt;
                drawenable |= DRAW_ENABLE_PRIORITY;&lt;br /&gt;
&lt;br /&gt;
            0xf3 → /* PIC_OP_DISABLE_PRIORITY */&lt;br /&gt;
                drawenable &amp;amp;= ~DRAW_ENABLE_PRIORITY;&lt;br /&gt;
&lt;br /&gt;
            0xf4 → /* PIC_OP_RELATIVE_PATTERNS */&lt;br /&gt;
                IF (pattern_code &amp;amp; PATTERN_FLAG_USE_PATTERN) THEN&lt;br /&gt;
                    pattern_nr := (get_input() &amp;gt;&amp;gt; 1) &amp;amp; 0x7f&lt;br /&gt;
                FI&lt;br /&gt;
&lt;br /&gt;
                (x,y) := GetAbsCoordinates();&lt;br /&gt;
&lt;br /&gt;
                DrawPattern(x, y, col1, col2, priority, control, drawenable,&lt;br /&gt;
                         pattern_code &amp;amp; PATTERN_FLAG_USE_PATTERN,&lt;br /&gt;
                         pattern_size, pattern_nr, pattern_code &amp;amp; PATTERN_FLAG_RECTANGLE);&lt;br /&gt;
&lt;br /&gt;
                WHILE (peek_input() &amp;lt; 0xf0) DO BEGIN&lt;br /&gt;
                    IF (pattern_code &amp;amp; PATTERN_FLAG_USE_PATTERN) THEN&lt;br /&gt;
                        pattern_nr := (get_input() &amp;gt;&amp;gt; 1) &amp;amp; 0x7f&lt;br /&gt;
                    FI&lt;br /&gt;
                    (x,y) =  GetRelCoordinates(x,y);&lt;br /&gt;
                    DrawPattern(x, y, col1, col2, priority, control, drawenable,&lt;br /&gt;
                             pattern_code &amp;amp; PATTERN_FLAG_USE_PATTERN,&lt;br /&gt;
                             pattern_size, pattern_nr, pattern_code &amp;amp; PATTERN_FLAG_RECTANGLE);&lt;br /&gt;
                END&lt;br /&gt;
&lt;br /&gt;
            0xf5 → /* PIC_OP_RELATIVE_MEDIUM_LINES */&lt;br /&gt;
                (oldx, oldy) := GetAbsCoordinates();&lt;br /&gt;
                WHILE (peek_input() &amp;lt; 0xf0) DO BEGIN&lt;br /&gt;
                    temp := get_input();&lt;br /&gt;
                    IF (temp &amp;amp; 0x80) THEN&lt;br /&gt;
                        y := oldy - (temp &amp;amp; 0x7f)&lt;br /&gt;
                    ELSE&lt;br /&gt;
                        y := oldy + temp&lt;br /&gt;
                    FI&lt;br /&gt;
                    x = oldx + get_input();&lt;br /&gt;
                     DitherLine(oldx, oldy, x, y, col1, col2, priority, special, drawenable);&lt;br /&gt;
                    (oldx, oldy) := (x, y);&lt;br /&gt;
                END&lt;br /&gt;
&lt;br /&gt;
            0xf6 → /* PIC_OP_RELATIVE_LONG_LINES */&lt;br /&gt;
                (oldx, oldy) :=  GetAbsCoordinates()&lt;br /&gt;
                WHILE (peek_input() &amp;lt; 0xf0) DO BEGIN&lt;br /&gt;
                    (x, y) := GetAbsCoordinates();&lt;br /&gt;
                    DitherLine(oldx, oldy, x, y, col1, col2, priority, special, drawenable);&lt;br /&gt;
                    (oldx, oldy) := (x, y);&lt;br /&gt;
                END&lt;br /&gt;
&lt;br /&gt;
            0xf7 → /* PIC_OP_RELATIVE_SHORT_LINES */&lt;br /&gt;
                (oldx, oldy) =  GetAbsCoordinates()&lt;br /&gt;
                WHILE (peek_input() &amp;lt; 0xf0) DO BEGIN&lt;br /&gt;
                    (x, y) := GetRelCoordinates(oldx, oldy);&lt;br /&gt;
                    DitherLine(oldx, oldy, x, y, col1, col2, priority, special, drawenable);&lt;br /&gt;
                    (oldx, oldy) := (x, y);&lt;br /&gt;
                END&lt;br /&gt;
&lt;br /&gt;
            0xf8 → /* PIC_OP_FILL */&lt;br /&gt;
                IF (fill_in_black) THEN&lt;br /&gt;
                    (oldc1, oldc2) := (c1, c2);&lt;br /&gt;
                FI&lt;br /&gt;
&lt;br /&gt;
                WHILE (peek_unput() &amp;lt; 0xf0) DO BEGIN&lt;br /&gt;
                    (x, y) := GetAbsCoordinates();&lt;br /&gt;
                    DitherFill(x, y, col1, col2, priority, special, drawenable);&lt;br /&gt;
                END&lt;br /&gt;
&lt;br /&gt;
                IF (fill_in_black) THEN&lt;br /&gt;
                    (c1, c2) := (oldc1, oldc2);&lt;br /&gt;
                FI&lt;br /&gt;
&lt;br /&gt;
            0xf9 → /* PIC_OP_SET_PATTERN */&lt;br /&gt;
                pattern_code := get_input() &amp;amp; 0x37;&lt;br /&gt;
                pattern_size := pattern_code &amp;amp; 0x7;&lt;br /&gt;
&lt;br /&gt;
            0xfa → /* PIC_OP_ABSOLUTE_PATTERNS */&lt;br /&gt;
                WHILE (peek_input() &amp;lt; 0xf0) DO&lt;br /&gt;
                    IF (pattern_code &amp;amp; PATTERN_FLAG_USE_PATTERN)&lt;br /&gt;
                        pattern_nr := (get_input() &amp;gt;&amp;gt; 1) &amp;amp; 0x7f&lt;br /&gt;
                    FI&lt;br /&gt;
                    (x, y) := GetAbsCoordinates();&lt;br /&gt;
                    DrawPattern(x, y, col1, col2, priority, control, drawenable,&lt;br /&gt;
                             pattern_code &amp;amp; PATTERN_FLAG_USE_PATTERN,&lt;br /&gt;
                             pattern_size, pattern_nr, pattern_code &amp;amp; PATTERN_FLAG_RECTANGLE);&lt;br /&gt;
                    END&lt;br /&gt;
&lt;br /&gt;
            0xfb → /* PIC_OP_SET_CONTROL */&lt;br /&gt;
                control := get_input() &amp;amp; 0x0f;&lt;br /&gt;
                drawenable |= DRAW_ENABLE_CONTROL;&lt;br /&gt;
&lt;br /&gt;
            0xfc → /* PIC_OP_DISABLE_CONTROL */&lt;br /&gt;
                drawenable &amp;amp;= ~DRAW_ENABLE_CONTROL;&lt;br /&gt;
&lt;br /&gt;
            0xfd → /* PIC_OP_RELATIVE_MEDIUM_PATTERNS */&lt;br /&gt;
                IF (pattern_code &amp;amp; PATTERN_FLAG_USE_PATTERN) THEN&lt;br /&gt;
                    pattern_nr := (get_input() &amp;gt;&amp;gt; 1) &amp;amp; 0x7f;&lt;br /&gt;
                FI&lt;br /&gt;
&lt;br /&gt;
                (oldx, oldy) := GetAbsCoordinates();&lt;br /&gt;
&lt;br /&gt;
                DrawPattern(x, y, col1, col2, priority, control, drawenable,&lt;br /&gt;
                         pattern_code &amp;amp; PATTERN_FLAG_USE_PATTERN,&lt;br /&gt;
                         pattern_size, pattern_nr, pattern_code &amp;amp; PATTERN_FLAG_RECTANGLE);&lt;br /&gt;
&lt;br /&gt;
                WHILE (peek_input() &amp;lt; 0xf0) DO BEGIN&lt;br /&gt;
                    IF (pattern_code &amp;amp; PATTERN_FLAG_USE_PATTERN) THEN&lt;br /&gt;
                        pattern_nr := (get_input() &amp;gt;&amp;gt; 1) &amp;amp; 0x7f;&lt;br /&gt;
                    FI&lt;br /&gt;
            &lt;br /&gt;
                    temp := get_input();&lt;br /&gt;
                    IF (temp &amp;amp; 0x80)&lt;br /&gt;
                        y := oldy - (temp &amp;amp; 0x7f)&lt;br /&gt;
                    ELSE&lt;br /&gt;
                        y := oldy + temp&lt;br /&gt;
                    FI&lt;br /&gt;
                    x := oldx + get_input();&lt;br /&gt;
                    DrawPattern(x, y, col1, col2, priority, control, drawenable,&lt;br /&gt;
                             pattern_code &amp;amp; PATTERN_FLAG_USE_PATTERN,&lt;br /&gt;
                             pattern_size, pattern_nr, pattern_code &amp;amp; PATTERN_FLAG_RECTANGLE);&lt;br /&gt;
                END&lt;br /&gt;
&lt;br /&gt;
            0xfd → /* PIC_OP_OPX */&lt;br /&gt;
                COND get_input():&lt;br /&gt;
                    0x00 → /* PIC_OPX_SET_PALETTE_ENTRY */&lt;br /&gt;
                        WHILE peek_input() &amp;lt; 0xf0 DO BEGIN&lt;br /&gt;
                            index := get_input();&lt;br /&gt;
                            color := get_input();&lt;br /&gt;
                            palette[index / 40][color % 40] := color;&lt;br /&gt;
                        END&lt;br /&gt;
&lt;br /&gt;
                    0x01 → /* PIC_OPX_SET_PALETTE */&lt;br /&gt;
                        palette_number := get_input();&lt;br /&gt;
                        FOR i := 0 TO 39 DO&lt;br /&gt;
                            palette[palette_number][i] := get_input();&lt;br /&gt;
                        OD&lt;br /&gt;
&lt;br /&gt;
                    0x02 → /* PIC_OPX_MONO0 */&lt;br /&gt;
                        skip_input(41);&lt;br /&gt;
&lt;br /&gt;
                    0x03 → /* PIC_OPX_MONO1 */&lt;br /&gt;
                        skip_input(1);&lt;br /&gt;
&lt;br /&gt;
                    0x04 → /* PIC_OPX_MONO2 */&lt;br /&gt;
                    0x05 → /* PIC_OPX_MONO3 */&lt;br /&gt;
                        skip_input(1);&lt;br /&gt;
&lt;br /&gt;
                    0x06 → /* PIC_OPX_MONO4 */&lt;br /&gt;
                    0x07 → /* PIC_OPX_EMBEDDED_VIEW */ /* SCI01 operation */&lt;br /&gt;
                    0x08 → /* PIC_OPX_SET_PRIORITY_TABLE */ /* SCI01 operation */&lt;br /&gt;
&lt;br /&gt;
            0xff → return (visual, control, priority, aux);&lt;br /&gt;
        END OF COND&lt;br /&gt;
      END&lt;br /&gt;
END&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;#039;&amp;#039;&amp;#039;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.&amp;#039;&amp;#039;&amp;#039;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;PROCEDURE DrawPattern(x, y, col1, col2, priority, control, drawenable : Integer;  solid : Boolean ;  pattern_size, pattern_nr : Integer; rectangle : Boolean)&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Alters (x,y) so that 0 &amp;lt;= (x - pattern_size), 319 &amp;gt;= (x + pattern_size), 189 &amp;gt;= (y + pattern_size) and 0 &amp;lt;= (y - pattern_size), then draws a rectangle or a circle filled with col1, col2, priority, control, as determined by drawenable.&lt;br /&gt;
&lt;br /&gt;
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)&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;PROCEDURE DitherLine(x, y, xend, yend, color1, color2, priority, control, drawenable : Integer)&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Draws a dithered line between (x, y+10) and (xend, yend+10). If the appropriate drawenable flags&lt;br /&gt;
are set, it draws &amp;#039;priority&amp;#039; to the priority map, &amp;#039;control&amp;#039; to the control map, and &amp;#039;color1&amp;#039; and &amp;#039;color2&amp;#039;&lt;br /&gt;
(alternating) to the visual map. The auxiliary map is bitwise-or&amp;#039;d with the drawenable flag while this is&lt;br /&gt;
done.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;PROCEDURE DitherFill(x, y, col0, col1, priority, control, drawenable : Integer)&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Fills all layers for which drawenable is set with the appropriate content. Diagonal filling is not allowed. Boundaries are determined as follows:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;x&amp;lt;0, x&amp;gt;319, y&amp;lt;10, y&amp;gt;199 are hard boundaries. We now determine the &amp;#039;boundary map&amp;#039; bound_map and the allowed color legal_color. If bound_map[coordinates] = legal_color, then the pixel may be filled.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;IF (drawenable &amp;amp; DRAW_ENABLE_VISUAL)&lt;br /&gt;
    bound_map = visual;&lt;br /&gt;
    legal_color = 0xf;&lt;br /&gt;
ELSIF (drawenable &amp;amp; DRAW_ENABLE_PRIORITY)&lt;br /&gt;
    bound_map = priority;&lt;br /&gt;
    legal_color = 0;&lt;br /&gt;
ELSIF (drawenable &amp;amp; DRAW_ENABLE_CONTROL)&lt;br /&gt;
    bound_map = control;&lt;br /&gt;
    legal_color = 0;&lt;br /&gt;
ELSE&lt;br /&gt;
    return;&lt;br /&gt;
FI&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==Windows, Dialogs and Controls==&lt;br /&gt;
&lt;br /&gt;
&amp;#039;&amp;#039;&amp;#039;by Lars Skovlund&amp;#039;&amp;#039;&amp;#039;&lt;br /&gt;
&lt;br /&gt;
Version 1.0, 7. July 1999&lt;br /&gt;
&lt;br /&gt;
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.&lt;br /&gt;
&lt;br /&gt;
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:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;typedef struct&lt;br /&gt;
{&lt;br /&gt;
  short top, left, bottom, right;&lt;br /&gt;
}&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
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.&lt;br /&gt;
&lt;br /&gt;
Windows are created using the KNewWindow kernel function. Each window has six attributes which are passed from the script to the kernel function:&lt;br /&gt;
&lt;br /&gt;
Bounding rectangle&amp;lt;br&amp;gt;&lt;br /&gt;
Title&amp;lt;br&amp;gt;&lt;br /&gt;
Type&amp;lt;br&amp;gt;&lt;br /&gt;
Priority&amp;lt;br&amp;gt;&lt;br /&gt;
Foreground color&amp;lt;br&amp;gt;&lt;br /&gt;
Background color&lt;br /&gt;
&lt;br /&gt;
Of these, the type and priority are the most interesting, because they decide the appearance of the window. The type is a bit field:&lt;br /&gt;
&lt;br /&gt;
bit 0 - transparency&amp;lt;br&amp;gt;&lt;br /&gt;
bit 1 - window does _not_ have a frame&amp;lt;br&amp;gt;&lt;br /&gt;
bit 2 - the window has a title&amp;lt;br&amp;gt;&lt;br /&gt;
bit 3-6 - unused&amp;lt;br&amp;gt;&lt;br /&gt;
bit 7 - see below&lt;br /&gt;
&lt;br /&gt;
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&amp;#039;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,&lt;br /&gt;
&lt;br /&gt;
Bit 1 specifies a window without a frame. The frame is the black shading you can see in the corner of a message box.&lt;br /&gt;
&lt;br /&gt;
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.&lt;br /&gt;
&lt;br /&gt;
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&amp;#039;s responsibility to draw a window frame on the WM port. CB1 uses this style for its ornate windows, and draws the frame manually.&lt;br /&gt;
&lt;br /&gt;
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.&lt;br /&gt;
&lt;br /&gt;
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.&lt;br /&gt;
&lt;br /&gt;
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 KNewWindow (the Rect is split in its fields, to nsTop, nsLeft etc.)&lt;br /&gt;
&lt;br /&gt;
To create a window structure, use KNewWindow (see [[SCI_Specifications:_Chapter_5_(cont.)_-_Kernel_functions#Kernel_function_0x13:_NewWindow.28Rect.2C_HeapPtr.2C_word.2C_word.2C_word.2C_word.29|the Section called Kernel function 0x13: NewWindow(Rect, HeapPtr, word, word, word, word) in Chapter 5]]); to remove it again, apply KDisposeWindow (see [[SCI_Specifications:_Chapter_5_(cont.)_-_Kernel_functions#Kernel_function_0x16:_DisposeWindow.28HeapPtr_Window.29|the Section called Kernel function 0x16: DisposeWindow(HeapPtr Window) in Chapter 5]]) on it.&lt;br /&gt;
&lt;br /&gt;
So how do we put stuff inside these windows? That question is a little complicated to answer, because it is really a shared effort between the interpreter 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.&lt;br /&gt;
&lt;br /&gt;
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.&lt;br /&gt;
&lt;br /&gt;
The type numbers are laid out as follows:&lt;br /&gt;
&lt;br /&gt;
# - Button control&lt;br /&gt;
# - Text control&lt;br /&gt;
# - Edit control&lt;br /&gt;
# - Icon control&lt;br /&gt;
# - not used&lt;br /&gt;
# - Selector control (as in the Save and Restore boxes)&lt;br /&gt;
&lt;br /&gt;
The gauge &amp;quot;controls&amp;quot; are not really controls. I don&amp;#039;t know how they work (yet).&lt;br /&gt;
&lt;br /&gt;
Each control also has a state value. These are laid out as follows:&lt;br /&gt;
&lt;br /&gt;
: 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.&amp;lt;br&amp;gt;&lt;br /&gt;
: bit 1 - unknown. Always set, except for the text and icon controls&amp;lt;br&amp;gt;&lt;br /&gt;
: bit 2 - disabled. When this bit is set, a button is grayed out. No other control types are affected.&amp;lt;br&amp;gt;&lt;br /&gt;
: bit 3 - selected. When this bit is set, a frame is drawn around the control.&lt;br /&gt;
&lt;br /&gt;
Note that state 3 is by far the most common. With that explained, I&amp;#039;ll move on to the kernel functions. There are three functions associated with controls - KDrawControl (see [[SCI_Specifications:_Chapter_5_(cont.)_-_Kernel_functions#Kernel_function_0x17:_DrawControl.28HeapPtr.29|the Section called Kernel function 0x17: DrawControl(HeapPtr) in Chapter 5]]), KHiliteControl (see [[SCI_Specifications:_Chapter_5_(cont.)_-_Kernel_functions#Kernel_function_0x18:_HiliteControl.28HeapPtr.29|the Section called Kernel function 0x18: HiliteControl(HeapPtr) in Chapter 5]]) and KEditControl (see [[SCI_Specifications:_Chapter_5_(cont.)_-_Kernel_functions#Kernel_function_0x19:_EditControl.28HeapPtr.29|the Section called Kernel function 0x19: EditControl(HeapPtr) in Chapter 5]]). Note that there is a KOnControl kernel call which is entirely unrelated to window management.&lt;br /&gt;
&lt;br /&gt;
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.&lt;br /&gt;
&lt;br /&gt;
:: &amp;#039;&amp;#039;&amp;#039;&amp;#039;&amp;#039;Note&amp;#039;&amp;#039;&amp;#039; 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 &amp;quot;forgets&amp;quot; to switch back while stepping across instructions. Thus, all graphics commands are redirected to the debug window port. Not a pretty sight.&amp;#039;&amp;#039;&lt;br /&gt;
&lt;br /&gt;
==Pictures and movement control==&lt;br /&gt;
&lt;br /&gt;
&amp;#039;&amp;#039;&amp;#039;By Lars Skovlund&amp;#039;&amp;#039;&amp;#039;&lt;br /&gt;
&lt;br /&gt;
Version 1.0, 24. July 1999&lt;br /&gt;
&lt;br /&gt;
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&amp;#039;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.&lt;br /&gt;
&lt;br /&gt;
Many functions which need to access these maps do so by using a bit-field. The bits are laid out as follows (but don&amp;#039;t set more than one at a time!)&lt;br /&gt;
&lt;br /&gt;
bit 0 - Visual&amp;lt;br&amp;gt;&lt;br /&gt;
bit 1 - Priority&amp;lt;br&amp;gt;&lt;br /&gt;
bit 2 - Control&lt;br /&gt;
&lt;br /&gt;
It is important to understand that, although being represented as colors on the screen, a priority/control &amp;quot;color&amp;quot; should be considered a number. The colors map to values according to the standard EGA color values.&lt;br /&gt;
&lt;br /&gt;
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 &amp;quot;base rectangle&amp;quot; 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.&lt;br /&gt;
&lt;br /&gt;
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&amp;#039;t walk on white control areas.&lt;br /&gt;
&lt;br /&gt;
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.&lt;br /&gt;
&lt;br /&gt;
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.&lt;br /&gt;
&lt;br /&gt;
The OnControl() system call is explained in [[SCI_Specifications:_Chapter_5_(cont.)_-_Kernel_functions#Kernel_function_0x52:_OnControl.28word.2C_Point_.7C_Rect.29|the Section called Kernel function 0x52: OnControl(word, Point | Rect) in Chapter 5]].&lt;br /&gt;
&lt;br /&gt;
;Notes&lt;br /&gt;
&amp;lt;references group=Note/&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;amp;nbsp;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span style=&amp;quot;float: left&amp;quot;&amp;gt;[[SCI Specifications: Chapter_2_-_Resource_files|&amp;amp;lt; Previous: Chapter 2 - Resource files]]&amp;lt;/span&amp;gt;&amp;lt;span style=&amp;quot;float: right&amp;quot;&amp;gt;[[SCI Specifications: Chapter_4_-_The_Sound_subsystem|Next: Chapter 4 - The Sound subsystem &amp;amp;gt;]]&amp;lt;/span&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;amp;nbsp;&lt;br /&gt;
&lt;br /&gt;
[[Category:Control Areas]]&lt;br /&gt;
[[Category:SCI Resources]]&lt;br /&gt;
[[Category:Sierra Creative Interpreter Specifications]]&lt;/div&gt;</summary>
		<author><name>Jeremiah Nellis</name></author>
	</entry>
	<entry>
		<id>http://sciwiki.sierrahelp.com/index.php?title=Brian_Provinciano%27s_SCI_Tools&amp;diff=452</id>
		<title>Brian Provinciano&#039;s SCI Tools</title>
		<link rel="alternate" type="text/html" href="http://sciwiki.sierrahelp.com/index.php?title=Brian_Provinciano%27s_SCI_Tools&amp;diff=452"/>
		<updated>2012-10-20T18:29:24Z</updated>

		<summary type="html">&lt;p&gt;Jeremiah Nellis: /* Gumby&amp;#039;s SCI Tools */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;===Gumby&amp;#039;s SCI Tools===&lt;br /&gt;
&lt;br /&gt;
SCI Development Tools by Gumby (all tools are for SCI0 games unless otherwise specified)&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;#039;&amp;#039;&amp;#039;Said() String Generator&amp;#039;&amp;#039;&amp;#039; - (based on desired user input) for development of SCI0 games&lt;br /&gt;
&amp;lt;blockquote&amp;gt;&lt;br /&gt;
* [[Image:ZIP.GIF|ZIP File]][[SCI:Gumby/SCISaidGen.zip|SCISaidGen]]&amp;lt;span class=&amp;quot;DLInfo&amp;quot;&amp;gt; (ZIP file) [2651 KB]&amp;lt;/span&amp;gt;&lt;br /&gt;
&amp;lt;/blockquote&amp;gt;&lt;br /&gt;
&amp;#039;&amp;#039;&amp;#039;SCI Text Dumper&amp;#039;&amp;#039;&amp;#039; - Dumps all text resources &amp;amp; then runs them through a spelling &amp;amp; grammar checker prior to finally loading the text resources back in.&lt;br /&gt;
&amp;lt;blockquote&amp;gt;&lt;br /&gt;
* [[Image:ZIP.GIF|ZIP File]][[SCI:Gumby/SCITextDumper.zip|SCITextDumper]]&amp;lt;span class=&amp;quot;DLInfo&amp;quot;&amp;gt; (ZIP file) [2735 KB]&amp;lt;/span&amp;gt;&lt;br /&gt;
&amp;lt;/blockquote&amp;gt;&lt;br /&gt;
&amp;#039;&amp;#039;&amp;#039;SCI Vocab Editor&amp;#039;&amp;#039;&amp;#039; - Extracts the vocabulary for a game into Excel format for manipulation &amp;amp; then &amp;#039;re-loads&amp;#039; the updated vocab back into the game.&lt;br /&gt;
&amp;lt;blockquote&amp;gt;&lt;br /&gt;
* [[Image:ZIP.GIF|ZIP File]][[SCI:Gumby/SCIVocabEditor.zip|SCIVocabEditor]]&amp;lt;span class=&amp;quot;DLInfo&amp;quot;&amp;gt; (ZIP file) [2993 KB]&amp;lt;/span&amp;gt; &lt;br /&gt;
&amp;lt;/blockquote&amp;gt;&lt;br /&gt;
&amp;#039;&amp;#039;&amp;#039;Dummy Script Compiler&amp;#039;&amp;#039;&amp;#039; - Utility to workaround initial compilation of scripts that contain circular dependencies (via &amp;#039;use&amp;#039; inclusion). &lt;br /&gt;
&amp;lt;blockquote&amp;gt;&lt;br /&gt;
* [[Image:ZIP.GIF|ZIP File]][[SCI:Gumby/dummyScriptCompiler.zip|DummyScriptCompiler]]&amp;lt;span class=&amp;quot;DLInfo&amp;quot;&amp;gt; (ZIP file) [2993 KB]&amp;lt;/span&amp;gt; &lt;br /&gt;
&amp;lt;/blockquote&amp;gt;&lt;br /&gt;
&amp;#039;&amp;#039;&amp;#039;Recreate MAP File&amp;#039;&amp;#039;&amp;#039; - Utility to recreate a .MAP file based on a set of RESOURCE.XXX (001, 002, etc) files. &lt;br /&gt;
&amp;lt;blockquote&amp;gt;&lt;br /&gt;
* [[Image:ZIP.GIF|ZIP File]][[SCI:Gumby/recreateMapFile.zip|RecreateMapFile]]&amp;lt;span class=&amp;quot;DLInfo&amp;quot;&amp;gt; (ZIP file) [2993 KB]&amp;lt;/span&amp;gt; &lt;br /&gt;
&amp;lt;/blockquote&amp;gt;&lt;br /&gt;
&amp;#039;&amp;#039;&amp;#039;ResDumpPack&amp;#039;&amp;#039;&amp;#039; - Utility to dump &amp;amp; pack resources to/from RESOURCE.XXX files.&lt;br /&gt;
&amp;lt;blockquote&amp;gt;&lt;br /&gt;
* [[Image:ZIP.GIF|ZIP File]][[SCI:Gumby/resDumpPack.zip|ResDumpPack]]&amp;lt;span class=&amp;quot;DLInfo&amp;quot;&amp;gt; (ZIP file) [2993 KB]&amp;lt;/span&amp;gt; &lt;br /&gt;
&amp;lt;/blockquote&amp;gt;&lt;br /&gt;
&amp;#039;&amp;#039;&amp;#039;SCI Digital Sound Pack 1 - Doors&amp;#039;&amp;#039;&amp;#039; - Digital sounds to be used with SNDBLAST.DRV sound driver&lt;br /&gt;
&amp;lt;blockquote&amp;gt;&lt;br /&gt;
* [[Image:ZIP.GIF|ZIP File]][[SCI:Gumby/SCIDigitalSoundPack1-Doors.zip|SCI Digital Sound Pack 1 - Doors]]&amp;lt;span class=&amp;quot;DLInfo&amp;quot;&amp;gt; (ZIP file) [701 KB]&amp;lt;/span&amp;gt; &lt;br /&gt;
&amp;lt;/blockquote&amp;gt;&lt;br /&gt;
&amp;#039;&amp;#039;&amp;#039;SCI Digital Sound Pack 2 - Animals&amp;#039;&amp;#039;&amp;#039; - Digital sounds to be used with SNDBLAST.DRV sound driver&lt;br /&gt;
&amp;lt;blockquote&amp;gt;&lt;br /&gt;
* [[Image:ZIP.GIF|ZIP File]][[SCI:Gumby/SCIDigitalSoundPack2-Animals.zip|SCI Digital Sound Pack 2 - Animals]]&amp;lt;span class=&amp;quot;DLInfo&amp;quot;&amp;gt; (ZIP file) [2152 KB]&amp;lt;/span&amp;gt; &lt;br /&gt;
&amp;lt;/blockquote&amp;gt;&lt;br /&gt;
&amp;#039;&amp;#039;&amp;#039;SCI Midi Pack 1 - Music&amp;#039;&amp;#039;&amp;#039; - Midi music sounds to be used with SNDBLAST.DRV or MPUMIDI.DRV sound driver (possibly others)&lt;br /&gt;
&amp;lt;blockquote&amp;gt;&lt;br /&gt;
* [[Image:ZIP.GIF|ZIP File]][[SCI:Gumby/SCIMidiPack1-Music.zip|SCI Midi Pack 1 - Music]]&amp;lt;span class=&amp;quot;DLInfo&amp;quot;&amp;gt; (ZIP file) [378 KB]&amp;lt;/span&amp;gt; &lt;br /&gt;
&amp;lt;/blockquote&amp;gt;&lt;br /&gt;
&amp;#039;&amp;#039;&amp;#039;SCI0 32bit Sound Utilities (Snd2Mid, Mid2Snd, SndPrf, ExtractWav)&amp;#039;&amp;#039;&amp;#039; - Port of Ravi&amp;#039;s 16 bit utilities (Snd2Mid, Mid2Snd, SndPrf) to C# and a new utility ExtractWav&lt;br /&gt;
&amp;lt;blockquote&amp;gt;&lt;br /&gt;
* [[Image:ZIP.GIF|ZIP File]][[SCI:Gumby/SCI032bitSoundUtils(Snd2Mid,Mid2Snd,SndPrf,ExtractWav).zip|SCI0 32bit Sound Utilities]]&amp;lt;span class=&amp;quot;DLInfo&amp;quot;&amp;gt; (ZIP file) [37 KB]&amp;lt;/span&amp;gt; &lt;br /&gt;
&amp;lt;/blockquote&amp;gt;&lt;br /&gt;
&amp;#039;&amp;#039;&amp;#039;SCI Narrate&amp;#039;&amp;#039;&amp;#039; - Add a narrator to your SCI fan games.  Leverages the Google Translate API.&lt;br /&gt;
&amp;lt;blockquote&amp;gt;&lt;br /&gt;
* [[Image:ZIP.GIF|ZIP File]][[SCI:Gumby/SCI_Narrate.zip|SCI Narrate]]&amp;lt;span class=&amp;quot;DLInfo&amp;quot;&amp;gt; (ZIP file) [44 KB]&amp;lt;/span&amp;gt; &lt;br /&gt;
&amp;lt;/blockquote&amp;gt;&lt;br /&gt;
&amp;#039;&amp;#039;&amp;#039;Create Text Resources Tool&amp;#039;&amp;#039;&amp;#039; - Parses all source script files &amp;amp; extracts all the Print() strings and puts them into text resources&lt;br /&gt;
&amp;lt;blockquote&amp;gt;&lt;br /&gt;
* [[Image:ZIP.GIF|ZIP File]][[SCI:Gumby/CreateTextRes.zip|CreateTextRes]]&amp;lt;span class=&amp;quot;DLInfo&amp;quot;&amp;gt; (ZIP file) [94 KB]&amp;lt;/span&amp;gt; &lt;br /&gt;
&amp;lt;/blockquote&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;#039;&amp;#039;&amp;#039;sciAudio&amp;#039;&amp;#039;&amp;#039; - Play MP3/WAV sound files external to the SCI0 virtual machine.&lt;br /&gt;
&amp;lt;blockquote&amp;gt;&lt;br /&gt;
* [[Image:ZIP.GIF|ZIP File]][[SCI:Gumby/sciAudio_1.0_with_source.zip|sciAudio]]&amp;lt;span class=&amp;quot;DLInfo&amp;quot;&amp;gt; (ZIP file) [199 KB]&amp;lt;/span&amp;gt; &lt;br /&gt;
&amp;lt;/blockquote&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;#039;&amp;#039;&amp;#039;LockerGnome Quest Redux&amp;#039;&amp;#039;&amp;#039; - Temporary home for this demo game until it can be moved to sciprogramming&lt;br /&gt;
&amp;lt;blockquote&amp;gt;&lt;br /&gt;
* [[Image:ZIP.GIF|ZIP File]][[SCI:Gumby/GnomeQuestRedux.zip|GnomeQuestRedux]]&amp;lt;span class=&amp;quot;DLInfo&amp;quot;&amp;gt; (ZIP file) [plenty of KB]&amp;lt;/span&amp;gt; &lt;br /&gt;
&amp;lt;/blockquote&amp;gt;&lt;br /&gt;
&amp;amp;nbsp; &lt;br /&gt;
&lt;br /&gt;
[[category:SCI Tools]]&lt;/div&gt;</summary>
		<author><name>Jeremiah Nellis</name></author>
	</entry>
	<entry>
		<id>http://sciwiki.sierrahelp.com/index.php?title=Looking_with_the_right_mouse_button&amp;diff=512</id>
		<title>Looking with the right mouse button</title>
		<link rel="alternate" type="text/html" href="http://sciwiki.sierrahelp.com/index.php?title=Looking_with_the_right_mouse_button&amp;diff=512"/>
		<updated>2012-09-29T15:42:16Z</updated>

		<summary type="html">&lt;p&gt;Jeremiah Nellis: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;To accomplish this we will use the priority colors - you can use the control colors as well.&lt;br /&gt;
&lt;br /&gt;
&amp;#039;&amp;#039;&amp;#039;Step 1:&amp;#039;&amp;#039;&amp;#039;  Trace &amp;amp; fill all the objects in your room with a priority color.  For immediately adjacent objects, use a different color.&lt;br /&gt;
&lt;br /&gt;
&amp;#039;&amp;#039;&amp;#039;Step 2:&amp;#039;&amp;#039;&amp;#039;  Determine the bounding rectangle around each object.  This will allow you to re-use a priority color more than once per room.  Note that you can have overlapping bounding rectangles for objects - just make sure that the objects have different priority colors.  To aid with determining the coordinates of the rectangles, temporarily include the following code in your handleEvent method to give you the cursor hotspot location on a right-click:&lt;br /&gt;
&amp;lt;div class=&amp;quot;CodeBlockHeader&amp;quot;&amp;gt;Code:&amp;lt;/div&amp;gt;&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;sci&amp;quot; class=&amp;quot;cs&amp;quot;&amp;gt;&lt;br /&gt;
        (if(== (send pEvent:type) evMOUSEBUTTON and == (send pEvent:modifiers) 515)&lt;br /&gt;
            FormatPrint(&amp;quot;x:%d, y:%d&amp;quot; (send pEvent:x) (send pEvent:y) )	 &lt;br /&gt;
	)&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;#039;&amp;#039;&amp;#039;Step 3:&amp;#039;&amp;#039;&amp;#039;  Modify your &amp;#039;look&amp;#039; logic&lt;br /&gt;
&amp;lt;div class=&amp;quot;CodeBlockHeader&amp;quot;&amp;gt;Code:&amp;lt;/div&amp;gt;&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;sci&amp;quot; class=&amp;quot;cs&amp;quot;&amp;gt;&lt;br /&gt;
        (if(Said(&amp;#039;look/box&amp;#039;)&lt;br /&gt;
        	or&lt;br /&gt;
                   (    == (send pEvent:type) evMOUSEBUTTON  // mouse click&lt;br /&gt;
        	    and == (send pEvent:modifiers) 515   // specifically a right mouse click&lt;br /&gt;
        	    and == $0002 OnControl(ocPRIORITY (send pEvent:x) (send pEvent:y))  // on NAVY priority color&lt;br /&gt;
&lt;br /&gt;
                    // check that the mouse is in the bounding rectangle for this object&lt;br /&gt;
        	    and &amp;gt; (send pEvent:x) 93&lt;br /&gt;
        	    and &amp;lt; (send pEvent:x) 132&lt;br /&gt;
        	    and &amp;gt; (send pEvent:y) 78&lt;br /&gt;
        	    and &amp;lt; (send pEvent:y) 110&lt;br /&gt;
                   )&lt;br /&gt;
           )&lt;br /&gt;
           Print(&amp;quot;The box is closed&amp;quot;)&lt;br /&gt;
	)&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Or for much cleaner implementation, create a class and then create instances of the class for each right-clickable area:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div class=&amp;quot;CodeBlockHeader&amp;quot;&amp;gt;Code:&amp;lt;/div&amp;gt;&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;sci&amp;quot; class=&amp;quot;cs&amp;quot;&amp;gt;&lt;br /&gt;
(class MouseLookObj&lt;br /&gt;
   (properties&lt;br /&gt;
      priorityColor $0000&lt;br /&gt;
      xMin 0&lt;br /&gt;
      xMax 0&lt;br /&gt;
      yMin 0&lt;br /&gt;
      yMax 0&lt;br /&gt;
   )&lt;br /&gt;
   (method (rightClicked pEvent)&lt;br /&gt;
   	  MouseLook(pEvent)&lt;br /&gt;
   )   &lt;br /&gt;
)&lt;br /&gt;
&lt;br /&gt;
(procedure (MouseLook pEvent) of MouseLookObj&lt;br /&gt;
       (if (== (send pEvent:type) evMOUSEBUTTON&lt;br /&gt;
    	    and == (send pEvent:modifiers) 515&lt;br /&gt;
    	    and == priorityColor OnControl(ocPRIORITY (send pEvent:x) (send pEvent:y))&lt;br /&gt;
    		and &amp;gt; (send pEvent:x) xMin&lt;br /&gt;
    		and &amp;lt; (send pEvent:x) xMax&lt;br /&gt;
    		and &amp;gt; (send pEvent:y) yMin&lt;br /&gt;
    		and &amp;lt; (send pEvent:y) yMax)&lt;br /&gt;
	      return(TRUE)&lt;br /&gt;
	)&lt;br /&gt;
        return(FALSE)&lt;br /&gt;
)&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
In your room script:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div class=&amp;quot;CodeBlockHeader&amp;quot;&amp;gt;Code:&amp;lt;/div&amp;gt;&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;sci&amp;quot; class=&amp;quot;cs&amp;quot;&amp;gt;&lt;br /&gt;
(instance public BoxLook of MouseLookObj&lt;br /&gt;
    (properties &lt;br /&gt;
        priorityColor $0002 &lt;br /&gt;
        xMin  93 &lt;br /&gt;
        xMax 132 &lt;br /&gt;
        yMin  78&lt;br /&gt;
        yMax 110&lt;br /&gt;
    )&lt;br /&gt;
)&lt;br /&gt;
&lt;br /&gt;
....&lt;br /&gt;
&lt;br /&gt;
(if(Said(&amp;#039;look/box&amp;#039;) or BoxLook:rightClicked(pEvent))&lt;br /&gt;
    Print(&amp;quot;The box is closed&amp;quot;)&lt;br /&gt;
)&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;/div&gt;</summary>
		<author><name>Jeremiah Nellis</name></author>
	</entry>
	<entry>
		<id>http://sciwiki.sierrahelp.com/index.php?title=Give_the_ego_footstep_sounds&amp;diff=365</id>
		<title>Give the ego footstep sounds</title>
		<link rel="alternate" type="text/html" href="http://sciwiki.sierrahelp.com/index.php?title=Give_the_ego_footstep_sounds&amp;diff=365"/>
		<updated>2012-09-17T03:59:47Z</updated>

		<summary type="html">&lt;p&gt;Jeremiah Nellis: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;Here&amp;#039;s how to do it, using the SNDBLAST or MTBLAST drivers.  I created 4 separate WAV footstep sounds &amp;amp; appended them to 4 empty sound resources.  Then in the room script, I added a doit() method which basically checks the current loop of the ego.  On two of the cells, we trigger a random sound playback of one of the footsteps.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div class=&amp;quot;CodeBlockHeader&amp;quot;&amp;gt;Code:&amp;lt;/div&amp;gt;&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;sci&amp;quot; class=&amp;quot;cs&amp;quot;&amp;gt;&lt;br /&gt;
(local&lt;br /&gt;
    currentCel&lt;br /&gt;
    previousCel&lt;br /&gt;
    loop&lt;br /&gt;
)&lt;br /&gt;
&lt;br /&gt;
...&lt;br /&gt;
&lt;br /&gt;
(method (doit)&lt;br /&gt;
	(var randomSound)&lt;br /&gt;
        = currentCel (send gEgo:cel)&lt;br /&gt;
&lt;br /&gt;
        (if (&amp;lt;&amp;gt; currentCel previousCel)&lt;br /&gt;
            = loop (send gEgo:loop)&lt;br /&gt;
            = randomSound Random(0 3) &lt;br /&gt;
 &lt;br /&gt;
            // ego is walking horizontally&lt;br /&gt;
	    (if(== loop 0 or == loop 1)&lt;br /&gt;
	       (if(== currentCel 0 or == currentCel 4)	    &lt;br /&gt;
		    (send gTheSoundFX:&lt;br /&gt;
		            prevSignal(0)&lt;br /&gt;
			    stop()&lt;br /&gt;
			    number(randomSound)&lt;br /&gt;
			    play()&lt;br /&gt;
		    )&lt;br /&gt;
		)&lt;br /&gt;
	     )&lt;br /&gt;
			 &lt;br /&gt;
	    // ego is walking vertically&lt;br /&gt;
	    (if(== loop 2 or == loop 3)&lt;br /&gt;
	       (if(== currentCel 3 or == currentCel 0)	    &lt;br /&gt;
		    (send gTheSoundFX:&lt;br /&gt;
			   prevSignal(0)&lt;br /&gt;
			   stop()&lt;br /&gt;
		           number(randomSound)&lt;br /&gt;
			   play()&lt;br /&gt;
		     )&lt;br /&gt;
	        )&lt;br /&gt;
	    )&lt;br /&gt;
	)&lt;br /&gt;
	= previousCel currentCel&lt;br /&gt;
)&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
I did have to make a modification to the ego view in the template game.  The &amp;#039;vertical&amp;#039; animations (the ones where the ego is walking toward/away from you) only had 5 cells, which made the ego sound like he was hobbling.  I added an additional cell to each loop which worked, but the result is that the ego appears to be dancing.  Quite humorous.&lt;br /&gt;
&lt;br /&gt;
I&amp;#039;ve uploaded the demo (with source code) to the fan games section.&lt;br /&gt;
&lt;br /&gt;
[[Category:Examples]]&lt;/div&gt;</summary>
		<author><name>Jeremiah Nellis</name></author>
	</entry>
	<entry>
		<id>http://sciwiki.sierrahelp.com/index.php?title=Robust_Parse_Part_3:Prepositions&amp;diff=363</id>
		<title>Robust Parse Part 3:Prepositions</title>
		<link rel="alternate" type="text/html" href="http://sciwiki.sierrahelp.com/index.php?title=Robust_Parse_Part_3:Prepositions&amp;diff=363"/>
		<updated>2012-08-04T20:43:26Z</updated>

		<summary type="html">&lt;p&gt;Jeremiah Nellis: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&amp;#039;&amp;#039;&amp;#039;Robust Parse Part 3: Prepositions&amp;#039;&amp;#039;&amp;#039;&lt;br /&gt;
&lt;br /&gt;
Up to this point, we&amp;#039;ve sort of glossed over prepostions.  I briefly touched on them in the first part of this series, when we took the verb &amp;#039;climb&amp;#039; and created two different verb definitions so we could get differentiation between &amp;#039;climb up&amp;#039; and &amp;#039;climb down&amp;#039;.  We also faked a bit of preposition handling by burying them inside our &amp;#039;verb name&amp;#039; text resource. &lt;br /&gt;
&lt;br /&gt;
So, what happens if we run the last Robust Parse demo game and try the following inputs:&lt;br /&gt;
&lt;br /&gt;
look in&amp;lt;br/&amp;gt;&lt;br /&gt;
run with&amp;lt;br/&amp;gt;&lt;br /&gt;
listen to&amp;lt;br/&amp;gt;&lt;br /&gt;
&lt;br /&gt;
You&amp;#039;ll see that we get the same output as you would get if we simply typed &amp;#039;look&amp;#039;, &amp;#039;run&amp;#039; or &amp;#039;listen&amp;#039;.  Well, this doesn&amp;#039;t make much sense, does it?  In order to address this shortcoming, we&amp;#039;ll put in some additional parsing of the user input the same way we extract the adjectives and nouns.  Again, I&amp;#039;m not going to post the code here, but download the newest Robust Parse demo &amp;amp; you can review the code there.  The script which has been modified is the GetObjDescrip.&lt;br /&gt;
&lt;br /&gt;
Next, we&amp;#039;ll have to set up some additional parsing of said strings in the ParseVerb script.  Here are the relevant sections for LOOK, RUN and LISTEN.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div class=&amp;quot;CodeBlockHeader&amp;quot;&amp;gt;Code:&amp;lt;/div&amp;gt;&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;sci&amp;quot; class=&amp;quot;cs&amp;quot;&amp;gt;&lt;br /&gt;
	/********** LISTEN **********/&lt;br /&gt;
	(if(Said(&amp;#039;listen/*/*&amp;gt;&amp;#039;))&lt;br /&gt;
	   = Verb VERB_LISTEN&lt;br /&gt;
	   = unneededSecond TRUE	&lt;br /&gt;
	)&lt;br /&gt;
 &lt;br /&gt;
        (if(Said(&amp;#039;listen&amp;lt;*/[/*]&amp;gt;&amp;#039;))  // Here is our new Said() to handle prepositions&lt;br /&gt;
           = Verb VERB_LISTEN&lt;br /&gt;
           = needNoun TRUE&lt;br /&gt;
        )&lt;br /&gt;
	&lt;br /&gt;
	(if(Said(&amp;#039;listen/*[/!*]&amp;gt;&amp;#039;)) &lt;br /&gt;
	   = Verb VERB_LISTEN	&lt;br /&gt;
	)&lt;br /&gt;
	&lt;br /&gt;
	(if(Said(&amp;#039;listen[/!*]&amp;gt;&amp;#039;))&lt;br /&gt;
	   = Verb VERB_LISTEN	&lt;br /&gt;
	)&lt;br /&gt;
	&lt;br /&gt;
	/********** EXAMINE **********/&lt;br /&gt;
	(if(Said(&amp;#039;(examine,look)/*/*&amp;gt;&amp;#039;))&lt;br /&gt;
	   = Verb VERB_LOOK&lt;br /&gt;
	   = unneededSecond TRUE&lt;br /&gt;
	)   	&lt;br /&gt;
 &lt;br /&gt;
        (if(Said(&amp;#039;(examine,look)&amp;lt;*/[/*]&amp;gt;&amp;#039;))  // Here is our new Said() to handle prepositions&lt;br /&gt;
           = Verb VERB_LOOK&lt;br /&gt;
           = needNoun TRUE&lt;br /&gt;
        )&lt;br /&gt;
	&lt;br /&gt;
	(if(Said(&amp;#039;(examine,look)/*[/*]&amp;gt;&amp;#039;))&lt;br /&gt;
	   = Verb VERB_LOOK&lt;br /&gt;
	)   &lt;br /&gt;
	&lt;br /&gt;
	(if(Said(&amp;#039;(examine,look)[/*]&amp;gt;&amp;#039;))&lt;br /&gt;
	   = Verb VERB_LOOK&lt;br /&gt;
	)   &lt;br /&gt;
	 &lt;br /&gt;
	/********** RUN **********/&lt;br /&gt;
	(if(Said(&amp;#039;run/*/*&amp;gt;&amp;#039;))&lt;br /&gt;
	   = Verb VERB_RUN&lt;br /&gt;
	   = unneededNoun TRUE&lt;br /&gt;
	   = unneededSecond TRUE&lt;br /&gt;
	)&lt;br /&gt;
 &lt;br /&gt;
        (if(Said(&amp;#039;run&amp;lt;*/[/*]&amp;gt;&amp;#039;)) // Here is our new Said() to handle prepositions&lt;br /&gt;
           = Verb VERB_RUN&lt;br /&gt;
           = needNoun TRUE&lt;br /&gt;
        )&lt;br /&gt;
	&lt;br /&gt;
        (if(Said(&amp;#039;run/*[/!*]&amp;gt;&amp;#039;)) &lt;br /&gt;
           = Verb VERB_RUN	&lt;br /&gt;
           = unneededNoun TRUE&lt;br /&gt;
	)&lt;br /&gt;
	&lt;br /&gt;
	(if(Said(&amp;#039;run[/!*]&amp;gt;&amp;#039;))&lt;br /&gt;
	   = Verb VERB_RUN&lt;br /&gt;
	)&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
	&lt;br /&gt;
Next, we need to modify the RobustPragmaFail script.  I&amp;#039;ve left the old code commented out to see the comparisons:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div class=&amp;quot;CodeBlockHeader&amp;quot;&amp;gt;Code:&amp;lt;/div&amp;gt;&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;sci&amp;quot; class=&amp;quot;cs&amp;quot;&amp;gt;&lt;br /&gt;
/******************************************************************************&lt;br /&gt;
 RobustPragmaFail.sc&lt;br /&gt;
 ******************************************************************************/&lt;br /&gt;
(include &amp;quot;sci.sh&amp;quot;)&lt;br /&gt;
(include &amp;quot;game.sh&amp;quot;)&lt;br /&gt;
/******************************************************************************/&lt;br /&gt;
(script ROBUSTPRAGMAFAIL_SCRIPT)&lt;br /&gt;
&lt;br /&gt;
(use &amp;quot;main&amp;quot;)&lt;br /&gt;
(use &amp;quot;controls&amp;quot;)&lt;br /&gt;
/******************************************************************************/&lt;br /&gt;
(procedure public (RobustPragmaFail) &lt;br /&gt;
  (if(== needNoun TRUE and == nounSaidCnt UNSET)&lt;br /&gt;
       //FormatPrint(&amp;quot;What do you want to %s?&amp;quot; VERB_NAMES Verb)&lt;br /&gt;
  	 FormatPrint(&amp;quot;What do you want to %s?&amp;quot; @verbDescrip)&lt;br /&gt;
  	 return(TRUE)&lt;br /&gt;
  )&lt;br /&gt;
 &lt;br /&gt;
  (if(== needSecond TRUE and == secondSaidCnt UNSET)&lt;br /&gt;
       //FormatPrint(&amp;quot;What do you want to %s the %s with?&amp;quot; VERB_NAMES Verb @nounDescrip)&lt;br /&gt;
  	 FormatPrint(&amp;quot;What do you want to %s the %s with?&amp;quot; @verbDescrip @nounDescrip)&lt;br /&gt;
  	 return(TRUE)&lt;br /&gt;
  )&lt;br /&gt;
  &lt;br /&gt;
  (if(== unneededNoun TRUE and &amp;lt;&amp;gt; nounSaidCnt UNSET)&lt;br /&gt;
       //FormatPrint(&amp;quot;I understood only as far as you wanting to %s.&amp;quot; VERB_NAMES Verb)&lt;br /&gt;
  	 FormatPrint(&amp;quot;I understood only as far as you wanting to %s.&amp;quot; @verbDescrip)&lt;br /&gt;
  	 return(TRUE)&lt;br /&gt;
  )&lt;br /&gt;
  &lt;br /&gt;
  (if(== unneededSecond TRUE and &amp;lt;&amp;gt; secondSaidCnt UNSET)&lt;br /&gt;
       //FormatPrint(&amp;quot;I understood only as far as you wanting to %s the %s.&amp;quot; VERB_NAMES Verb @secondDescrip)&lt;br /&gt;
  	 FormatPrint(&amp;quot;I understood only as far as you wanting to %s the %s.&amp;quot; @verbDescrip @secondDescrip)&lt;br /&gt;
  	 return(TRUE)&lt;br /&gt;
  )&lt;br /&gt;
  &lt;br /&gt;
  return(FALSE)&lt;br /&gt;
)&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
As you can see, we&amp;#039;ve removed all the references to the VERB_NAMES text resource &amp;amp; replaced them with a string similar to our @nounDescrip and @secondDescrip.  Finally, we need to change our VERB_NAMES text resources to only hold the verb names themselves.  Before this, we occassionally putting verbs and prepositions in this text resource.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div class=&amp;quot;CodeBlockHeader&amp;quot;&amp;gt;Code:&amp;lt;/div&amp;gt;&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;sci&amp;quot; class=&amp;quot;cs&amp;quot;&amp;gt;&lt;br /&gt;
/***************** Text.000 (verb names) *****************/&lt;br /&gt;
Num	Text&lt;br /&gt;
------	----- &lt;br /&gt;
0	cut&lt;br /&gt;
1	run&lt;br /&gt;
2	dig&lt;br /&gt;
3	listen&lt;br /&gt;
4	look&lt;br /&gt;
5	run&lt;br /&gt;
6	climb&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
In addition to cleaning up the VERB_NAMES text resource, we also need to create a new text resource for all the prepositions in our game.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div class=&amp;quot;CodeBlockHeader&amp;quot;&amp;gt;Code:&amp;lt;/div&amp;gt;&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;sci&amp;quot; class=&amp;quot;cs&amp;quot;&amp;gt;&lt;br /&gt;
/***************** Text.004 (preposition names) *****************/&lt;br /&gt;
Num	Text&lt;br /&gt;
------	----- &lt;br /&gt;
0	down&lt;br /&gt;
1	with&lt;br /&gt;
2	up&lt;br /&gt;
3	in&lt;br /&gt;
4	to&lt;br /&gt;
5	at&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Let&amp;#039;s put it to the test.  Fire up the Robust Parse demo game and try these inputs:&lt;br /&gt;
&lt;br /&gt;
&amp;#039;look in&amp;#039; results in &amp;#039;What do you want to look in?&amp;#039;&amp;lt;br/&amp;gt;&lt;br /&gt;
&amp;#039;run up&amp;#039; results in &amp;#039;What do you want to run up?&amp;#039;&amp;lt;br/&amp;gt;&lt;br /&gt;
&amp;#039;listen to&amp;#039; results in &amp;#039;What do you want to listen to?&amp;#039;&amp;lt;br/&amp;gt;&lt;br /&gt;
&lt;br /&gt;
That&amp;#039;s it!  Now our game handles prepositions properly.&lt;br /&gt;
&lt;br /&gt;
[[Category:The SCI Parser]]&lt;br /&gt;
[[Category:Examples]]&lt;br /&gt;
[[Category:Tutorials]]&lt;/div&gt;</summary>
		<author><name>Jeremiah Nellis</name></author>
	</entry>
	<entry>
		<id>http://sciwiki.sierrahelp.com/index.php?title=Robust_Parse_Part_2:Object_Disambiguation&amp;diff=361</id>
		<title>Robust Parse Part 2:Object Disambiguation</title>
		<link rel="alternate" type="text/html" href="http://sciwiki.sierrahelp.com/index.php?title=Robust_Parse_Part_2:Object_Disambiguation&amp;diff=361"/>
		<updated>2012-08-04T20:42:51Z</updated>

		<summary type="html">&lt;p&gt;Jeremiah Nellis: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&amp;#039;&amp;#039;&amp;#039;Robust Parse (Adjectives &amp;amp; Object Disambiguation)&amp;#039;&amp;#039;&amp;#039;&lt;br /&gt;
&lt;br /&gt;
&amp;#039;&amp;#039;&amp;#039;Parsing nouns:&amp;#039;&amp;#039;&amp;#039;&amp;lt;br/&amp;gt;&lt;br /&gt;
In our previous code for parsing nouns, we were setting the noun upon a successful match of a Said() string.  Now, we will introduce the possibility of multiple nouns differentiated by the use adjectives.  This means that potentially multiple nouns will be matched via multiple Said()s.&lt;br /&gt;
&lt;br /&gt;
For review, we were previously parsing nouns (ParseNoun.sc) similar to this: &lt;br /&gt;
&amp;lt;div class=&amp;quot;CodeBlockHeader&amp;quot;&amp;gt;Code:&amp;lt;/div&amp;gt;&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;sci&amp;quot; class=&amp;quot;cs&amp;quot;&amp;gt;&lt;br /&gt;
	(if(Said(&amp;#039;*/rock&amp;gt;&amp;#039;))&lt;br /&gt;
	   = noun ROCK_OBJ	&lt;br /&gt;
	)&lt;br /&gt;
	&lt;br /&gt;
	(if(Said(&amp;#039;*/window&amp;gt;&amp;#039;))&lt;br /&gt;
	   = noun WINDOW_OBJ	&lt;br /&gt;
	)   &lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;	&lt;br /&gt;
We&amp;#039;ll need to change our technique to this:&lt;br /&gt;
&amp;lt;div class=&amp;quot;CodeBlockHeader&amp;quot;&amp;gt;Code:&amp;lt;/div&amp;gt;&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;sci&amp;quot; class=&amp;quot;cs&amp;quot;&amp;gt;&lt;br /&gt;
	(if(Said(&amp;#039;*/rock[&amp;lt;small]&amp;gt;&amp;#039;))&lt;br /&gt;
	   = nounSaid[++nounSaidCnt] SMALL_ROCK_OBJ&lt;br /&gt;
	)&lt;br /&gt;
&lt;br /&gt;
	(if(Said(&amp;#039;*/window[&amp;lt;center]&amp;gt;&amp;#039;))	&lt;br /&gt;
	   = nounSaid[++nounSaidCnt] CENTER_WINDOW_OBJ&lt;br /&gt;
	)&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
First off, note that we have a new array &amp;#039;nounSaid&amp;#039; (which is defined in the Main.sc) along with a counter of how many nouns we&amp;#039;ve matched (nounSaidCnt). I&amp;#039;d recommend making the array size roughly 10, which is an artificial maximum for the number of times a single noun can be duplicated in a game.  By duplicated, I mean the same noun but differentiated with adjectives (e.g. gold key, silver key, copper key).  You probably aren&amp;#039;t going to have more than 10 different keys in a game, but I suppose you might.  If you do, make it large enough to fit your needs. &lt;br /&gt;
&lt;br /&gt;
Also see that we have now introduced adjectives &amp;amp; that they are optional.  All of your nouns in your Said()s *must* include optional adjectives. If you do not specify an adjective, that means that any adjective input by the user will match, which is inappropriate.  For example, without the &amp;#039;[&amp;lt;small]&amp;#039; portion of the said in the first example, you could type &amp;#039;small rock&amp;#039;, &amp;#039;bright rock&amp;#039;, &amp;#039;dirty rock&amp;#039;, &amp;#039;ugly rock&amp;#039;, etc. and the Said() would evaluate to true.  This doesn&amp;#039;t mean that the adjectives must be optional.  You are free to make them mandatory by removing the brackets &amp;#039;[]&amp;#039; around them which would force the user to enter &amp;#039;small&amp;#039; every time they wanted to refer to the &amp;#039;rock&amp;#039;.&lt;br /&gt;
&lt;br /&gt;
We&amp;#039;ve also changed our object constants slightly (SMALL_ROCK_OBJ, CENTER_WINDOW_OBJ).  This is because we will have multiple &amp;#039;rock&amp;#039; and &amp;#039;window&amp;#039; objects.  &lt;br /&gt;
&lt;br /&gt;
Now that we&amp;#039;ve layed the groundwork, let&amp;#039;s make things a bit more complicated:&lt;br /&gt;
&amp;lt;div class=&amp;quot;CodeBlockHeader&amp;quot;&amp;gt;Code:&amp;lt;/div&amp;gt;&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;sci&amp;quot; class=&amp;quot;cs&amp;quot;&amp;gt;&lt;br /&gt;
	(if(Said(&amp;#039;*/rock[&amp;lt;small]&amp;gt;&amp;#039;))&lt;br /&gt;
	   = nounSaid[++nounSaidCnt] SMALL_ROCK_OBJ&lt;br /&gt;
	)&lt;br /&gt;
&lt;br /&gt;
	(if(Said(&amp;#039;*/rock[&amp;lt;large]&amp;gt;&amp;#039;))&lt;br /&gt;
	   = nounSaid[++nounSaidCnt] LARGE_ROCK_OBJ&lt;br /&gt;
	)&lt;br /&gt;
&lt;br /&gt;
	(if(Said(&amp;#039;*/rock[&amp;lt;giant]&amp;gt;&amp;#039;))&lt;br /&gt;
	   = nounSaid[++nounSaidCnt] GIANT_ROCK_OBJ&lt;br /&gt;
	)&lt;br /&gt;
	&lt;br /&gt;
	(if(Said(&amp;#039;*/window[&amp;lt;right]&amp;gt;&amp;#039;))	&lt;br /&gt;
	   = nounSaid[++nounSaidCnt] RIGHT_WINDOW_OBJ&lt;br /&gt;
	)&lt;br /&gt;
	&lt;br /&gt;
	(if(Said(&amp;#039;*/window[&amp;lt;center]&amp;gt;&amp;#039;))	&lt;br /&gt;
	   = nounSaid[++nounSaidCnt] CENTER_WINDOW_OBJ&lt;br /&gt;
	)&lt;br /&gt;
	&lt;br /&gt;
	(if(Said(&amp;#039;*/window[&amp;lt;left]&amp;gt;&amp;#039;))	&lt;br /&gt;
	   = nounSaid[++nounSaidCnt] LEFT_WINDOW_OBJ&lt;br /&gt;
	)&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;	&lt;br /&gt;
So, now we have three rocks &amp;amp; three windows in our game.  We will use the same pattern in the ParseSecond.sc script as well with references to an array &amp;amp; counter of &amp;#039;secondSaid&amp;#039; and &amp;#039;secondSaidCnt&amp;#039;:&lt;br /&gt;
&amp;lt;div class=&amp;quot;CodeBlockHeader&amp;quot;&amp;gt;Code:&amp;lt;/div&amp;gt;&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;sci&amp;quot; class=&amp;quot;cs&amp;quot;&amp;gt;&lt;br /&gt;
	(if(Said(&amp;#039;*/*/rock[&amp;lt;small]&amp;gt;&amp;#039;))&lt;br /&gt;
	   = secondSaid[++secondSaidCnt] SMALL_ROCK_OBJ&lt;br /&gt;
	)&lt;br /&gt;
&lt;br /&gt;
	(if(Said(&amp;#039;*/*/rock[&amp;lt;large]&amp;gt;&amp;#039;))&lt;br /&gt;
	   = secondSaid[++secondSaidCnt] LARGE_ROCK_OBJ&lt;br /&gt;
	)&lt;br /&gt;
&lt;br /&gt;
	.&lt;br /&gt;
	.&lt;br /&gt;
	.&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
We&amp;#039;ll need to update our game.sh to reflect the new objects:&lt;br /&gt;
&amp;lt;div class=&amp;quot;CodeBlockHeader&amp;quot;&amp;gt;Code:&amp;lt;/div&amp;gt;&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;sci&amp;quot; class=&amp;quot;cs&amp;quot;&amp;gt;&lt;br /&gt;
// Nouns&lt;br /&gt;
(define TREE_OBJ        0)&lt;br /&gt;
(define SAW_OBJ         1)&lt;br /&gt;
(define GROUND_OBJ      2)&lt;br /&gt;
(define SHOVEL_OBJ      3)&lt;br /&gt;
(define BIRD_OBJ        4)&lt;br /&gt;
(define HOUSE_OBJ       5)&lt;br /&gt;
(define DOOR_OBJ        6)&lt;br /&gt;
(define KEY_OBJ         7)&lt;br /&gt;
(define LEFT_WINDOW_OBJ    8)&lt;br /&gt;
(define CENTER_WINDOW_OBJ  9)&lt;br /&gt;
(define RIGHT_WINDOW_OBJ  10)&lt;br /&gt;
(define SMALL_ROCK_OBJ    11)&lt;br /&gt;
(define LARGE_ROCK_OBJ    12)&lt;br /&gt;
(define GIANT_ROCK_OBJ    13)&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
We&amp;#039;ll also need to update our &amp;#039;Noun names&amp;#039; text resource:&lt;br /&gt;
&amp;lt;div class=&amp;quot;CodeBlockHeader&amp;quot;&amp;gt;Code:&amp;lt;/div&amp;gt;&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;sci&amp;quot; class=&amp;quot;cs&amp;quot;&amp;gt;&lt;br /&gt;
/***************** Text.001 (noun names) *****************/&lt;br /&gt;
Num	Text&lt;br /&gt;
------	-----&lt;br /&gt;
0	tree&lt;br /&gt;
1	saw&lt;br /&gt;
2	ground&lt;br /&gt;
3	shovel&lt;br /&gt;
4	bird&lt;br /&gt;
5	house&lt;br /&gt;
6	door&lt;br /&gt;
7	key&lt;br /&gt;
8	rock&lt;br /&gt;
9	window&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
Don&amp;#039;t forget to update your vocabulary with the new adjectives and nouns as well.&lt;br /&gt;
&lt;br /&gt;
We will need to make some modifications to our RobustPragmaFail.sc script.  Basically, we need to change the logic to be testing for the number of nouns that were matched (nounSaidCnt) since we are no longer setting the &amp;#039;noun&amp;#039; variable (yet!).  We&amp;#039;ve also changed the print statements to use a new global strings &amp;#039;nounDescrip&amp;#039; and &amp;#039;secondDescrip&amp;#039;, which we will address next. &lt;br /&gt;
&amp;lt;div class=&amp;quot;CodeBlockHeader&amp;quot;&amp;gt;Code:&amp;lt;/div&amp;gt;&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;sci&amp;quot; class=&amp;quot;cs&amp;quot;&amp;gt;&lt;br /&gt;
(procedure public (RobustPragmaFail) &lt;br /&gt;
  (if(== needNoun TRUE and == nounSaidCnt UNSET)&lt;br /&gt;
  	 FormatPrint(&amp;quot;What do you want to %s?&amp;quot; VERB_NAMES Verb)&lt;br /&gt;
  	 return(TRUE)&lt;br /&gt;
  )&lt;br /&gt;
 &lt;br /&gt;
  (if(== needSecond TRUE and == secondSaidCnt UNSET)&lt;br /&gt;
  	 FormatPrint(&amp;quot;What do you want to %s the %s with?&amp;quot; VERB_NAMES Verb @nounDescrip)&lt;br /&gt;
  	 return(TRUE)&lt;br /&gt;
  )&lt;br /&gt;
  &lt;br /&gt;
  (if(== unneededNoun TRUE and &amp;lt;&amp;gt; nounSaidCnt UNSET)&lt;br /&gt;
  	 FormatPrint(&amp;quot;I understood only as far as you wanting to %s.&amp;quot; VERB_NAMES Verb)&lt;br /&gt;
  	 return(TRUE)&lt;br /&gt;
  )&lt;br /&gt;
  &lt;br /&gt;
  (if(== unneededSecond TRUE and &amp;lt;&amp;gt; secondSaidCnt UNSET)&lt;br /&gt;
  	 FormatPrint(&amp;quot;I understood only as far as you wanting to %s the %s.&amp;quot; VERB_NAMES Verb @secondDescrip)&lt;br /&gt;
  	 return(TRUE)&lt;br /&gt;
  )&lt;br /&gt;
  &lt;br /&gt;
  return(FALSE)&lt;br /&gt;
)&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
Before calling the RobustPragmaFail, we&amp;#039;ll need to call a new procedure called GetObjectDescrip.sc.  The purpose of this script is to extract *exactly* what the user inputted for the noun &amp;amp; second.  We need to do this to support the following example:  Let&amp;#039;s say you have a &amp;#039;rock&amp;#039; in your game.  What happens when you enter an invalid adjective for your noun (perhaps &amp;#039;cold rock&amp;#039;), but a valid adjective for some other noun in your game.  Wouldn&amp;#039;t it be nice to be able to provide a detailed error message back to them, something like: &amp;#039;I don&amp;#039;t see any ugly rock here.&amp;#039;&lt;br /&gt;
&lt;br /&gt;
I&amp;#039;m not going to post the code here (you can get it from the new version of RobustParseDemo game) as it&amp;#039;s fairly lengthly and unexciting. However, rest assured that it&amp;#039;s only purpose is to take apart the user input and capture the noun &amp;amp; second as it was input into the nounDescrip and secondDescrip variables.  In order to support this script, we need to create a new text resource that will be used to match adjectives.  It should hold every adjective defined for your game (just like the noun names text resource).&lt;br /&gt;
&amp;lt;div class=&amp;quot;CodeBlockHeader&amp;quot;&amp;gt;Code:&amp;lt;/div&amp;gt;&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;sci&amp;quot; class=&amp;quot;cs&amp;quot;&amp;gt;&lt;br /&gt;
/***************** Text.002 (adjective names) *****************/&lt;br /&gt;
Num	Text&lt;br /&gt;
------	-----&lt;br /&gt;
0	tall &lt;br /&gt;
1	rusty&lt;br /&gt;
2	hard&lt;br /&gt;
3	garden&lt;br /&gt;
4	song&lt;br /&gt;
5	brown&lt;br /&gt;
6	front&lt;br /&gt;
7	silver&lt;br /&gt;
8	left&lt;br /&gt;
9	center&lt;br /&gt;
10	right&lt;br /&gt;
11	small&lt;br /&gt;
12      large&lt;br /&gt;
13      giant&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
The remainder of our changes we are making is in the ValidateNouns.sc script.&lt;br /&gt;
&lt;br /&gt;
First, we will determine which nouns that were referenced are actually here:&lt;br /&gt;
&amp;lt;div class=&amp;quot;CodeBlockHeader&amp;quot;&amp;gt;Code:&amp;lt;/div&amp;gt;&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;sci&amp;quot; class=&amp;quot;cs&amp;quot;&amp;gt;&lt;br /&gt;
	(for (=i 0) (&amp;lt;= i nounSaidCnt) (++i)&lt;br /&gt;
	  	  // if the object is here, add it to our diambiguate string&lt;br /&gt;
		  (if (    == objectLocations[nounSaid[i]] gRoomNumber&lt;br /&gt;
		        or == objectLocations[nounSaid[i]] INVENTORY&lt;br /&gt;
		        or == objectLocations[nounSaid[i]] EVERYWHERE)	&lt;br /&gt;
		      = nounsHere[nounsHereCnt] nounSaid[i]	      		&lt;br /&gt;
		      ++nounsHereCnt&lt;br /&gt;
		  )&lt;br /&gt;
	)&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
Then, we will determine if we need to ask the user if they need to be more specific:&lt;br /&gt;
&amp;lt;div class=&amp;quot;CodeBlockHeader&amp;quot;&amp;gt;Code:&amp;lt;/div&amp;gt;&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;sci&amp;quot; class=&amp;quot;cs&amp;quot;&amp;gt;	&lt;br /&gt;
	(if(== nounsHereCnt 0)&lt;br /&gt;
	      = noun UNSET	  	&lt;br /&gt;
	)(else&lt;br /&gt;
		  (if(&amp;gt; nounsHereCnt 1)&lt;br /&gt;
&lt;br /&gt;
		  	(for (=i 0) (&amp;lt; i nounsHereCnt) (++i)&lt;br /&gt;
	&lt;br /&gt;
		  	   (if(== i 0)&lt;br /&gt;
		  	   	  StrCpy(@disambigStr &amp;quot;the &amp;quot;)  &lt;br /&gt;
			   )&lt;br /&gt;
			   &lt;br /&gt;
			   (if(&amp;lt;&amp;gt; i 0 and &amp;lt;&amp;gt; i (- nounsHereCnt 1))&lt;br /&gt;
			   	  StrCat(@disambigStr &amp;quot;, the &amp;quot;)&lt;br /&gt;
			   )&lt;br /&gt;
			   &lt;br /&gt;
			   (if(== i (- nounsHereCnt 1))&lt;br /&gt;
			   	  StrCat(@disambigStr &amp;quot; or the &amp;quot;)&lt;br /&gt;
			   )&lt;br /&gt;
	&lt;br /&gt;
                           Format(@fullNounDesc &amp;quot;%s&amp;quot; NOUN_FULLNAMES nounsHere[i])&lt;br /&gt;
                           StrCat(@disambigStr @fullNounDesc)&lt;br /&gt;
			)&lt;br /&gt;
&lt;br /&gt;
		    FormatPrint(&amp;quot;Which %s do you mean, %s?&amp;quot; @nounDescrip @disambigStr)&lt;br /&gt;
		    return(FALSE)		&lt;br /&gt;
		  )(else&lt;br /&gt;
		    = noun nounsHere[0]  // the only noun here	&lt;br /&gt;
	 	  )&lt;br /&gt;
	)&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
At this point we&amp;#039;ve successfully determined which noun is being referenced, but we are still not sure if it&amp;#039;s here in the room.  Finally, we make sure that the noun is actually here:&lt;br /&gt;
&amp;lt;div class=&amp;quot;CodeBlockHeader&amp;quot;&amp;gt;Code:&amp;lt;/div&amp;gt;&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;sci&amp;quot; class=&amp;quot;cs&amp;quot;&amp;gt;	&lt;br /&gt;
    (if (== noun UNSET and &amp;gt; StrLen(@nounDescrip) 0)&lt;br /&gt;
	    (if (     &amp;lt;&amp;gt; objectLocations[noun] gRoomNumber&lt;br /&gt;
	          and &amp;lt;&amp;gt; objectLocations[noun] INVENTORY&lt;br /&gt;
	          and &amp;lt;&amp;gt; objectLocations[noun] EVERYWHERE)&lt;br /&gt;
	             FormatPrint(&amp;quot;I don&amp;#039;t see any %s here.&amp;quot; @nounDescrip)&lt;br /&gt;
	             return(FALSE)&lt;br /&gt;
		)         	&lt;br /&gt;
	)&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
When building our error output for disambiguating nouns, we need the full noun description (adjective + noun).  For this, we will utilize a new text resource.  This text resource needs to be correlated to the values that we assigned our object constants in game.sh. &lt;br /&gt;
&amp;lt;div class=&amp;quot;CodeBlockHeader&amp;quot;&amp;gt;Code:&amp;lt;/div&amp;gt;&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;sci&amp;quot; class=&amp;quot;cs&amp;quot;&amp;gt;&lt;br /&gt;
/***************** Text.003 (full noun names) *****************/&lt;br /&gt;
Num	Text&lt;br /&gt;
------	-----&lt;br /&gt;
0	tall tree &lt;br /&gt;
1	rusty saw&lt;br /&gt;
2	hard ground&lt;br /&gt;
3	garden shovel&lt;br /&gt;
4	song bird&lt;br /&gt;
5	brown house&lt;br /&gt;
6	front door&lt;br /&gt;
7	silver key&lt;br /&gt;
8	left window&lt;br /&gt;
9	center window&lt;br /&gt;
10	right window&lt;br /&gt;
11	small rock&lt;br /&gt;
12      large rock&lt;br /&gt;
13      giant rock&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&amp;#039;&amp;#039;&amp;#039;Testing:&amp;#039;&amp;#039;&amp;#039;&lt;br /&gt;
Let&amp;#039;s try it out.  Start up the new RobustParseDemo game &amp;amp; try some things out:&lt;br /&gt;
&lt;br /&gt;
&amp;#039;&amp;#039;&amp;#039;While in the house room (there are three windows and one (small) rock there):&amp;#039;&amp;#039;&amp;#039;&amp;lt;br/&amp;gt;&lt;br /&gt;
&amp;#039;look window&amp;#039; results in &amp;#039;Which window do you mean, the left window, the center window or the right window?&amp;#039;&amp;lt;br/&amp;gt;&lt;br /&gt;
&amp;#039;look small rock&amp;#039; results in &amp;#039;It&amp;#039;s small.  More like a pebble, actually&amp;#039;&amp;lt;br/&amp;gt;&lt;br /&gt;
&amp;#039;look rock&amp;#039; - same result as before.  We don&amp;#039;t need to specify &amp;#039;small&amp;#039; in this case because it&amp;#039;s the only one here.&amp;lt;br/&amp;gt;&lt;br /&gt;
&amp;#039;look brown rock&amp;#039; results in &amp;#039;I don&amp;#039;t see any brown rock here.&amp;#039; (bad adjective pairing)&amp;lt;br/&amp;gt;&lt;br /&gt;
&amp;#039;look large rock&amp;#039; results in &amp;#039;I don&amp;#039;t see any large rock here.&amp;#039; (good adjective pairing, but that object isn&amp;#039;t in this room)&amp;lt;br/&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;#039;&amp;#039;&amp;#039;While in the tree room (there are two rocks there):&amp;#039;&amp;#039;&amp;#039;&amp;lt;br/&amp;gt;&lt;br /&gt;
&amp;#039;look window&amp;#039; results in &amp;#039;I don&amp;#039;t see any window here&amp;#039;&amp;lt;br/&amp;gt;&lt;br /&gt;
&amp;#039;look rock&amp;#039; results in &amp;#039;Which rock do you mean, the large rock or the giant rock?&amp;#039;&amp;lt;br/&amp;gt;&lt;br /&gt;
&amp;#039;look large rock&amp;#039; results in &amp;#039;It&amp;#039;s a large rock&amp;#039;&amp;lt;br/&amp;gt;&lt;br /&gt;
&amp;#039;look giant rock&amp;#039; results in &amp;#039;It&amp;#039;s a giant rock&amp;#039;&amp;lt;br/&amp;gt;&lt;br /&gt;
&amp;#039;cut down tree with rock&amp;#039; results in &amp;#039;Which rock do you mean, the large rock or the giant rock?&amp;#039;&amp;lt;br/&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Multiple adjective handling:&lt;br /&gt;
Everything we&amp;#039;ve done above will support this, just use the supported Said() syntax for multiple adjectives:&lt;br /&gt;
&amp;lt;div class=&amp;quot;CodeBlockHeader&amp;quot;&amp;gt;Code:&amp;lt;/div&amp;gt;&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;sci&amp;quot; class=&amp;quot;cs&amp;quot;&amp;gt;&lt;br /&gt;
	(if(Said(&amp;#039;*/rock[&amp;lt;(small,tiny,miniature)]&amp;gt;&amp;#039;))&lt;br /&gt;
	   = nounSaid[++nounSaidCnt] SMALL_ROCK_OBJ&lt;br /&gt;
	)&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
Notes:&lt;br /&gt;
- If you have ambiguous objects as in these examples, it&amp;#039;s courteous to the user to specify the valid adjectives when looking at the object.  Examine the &amp;#039;small rock&amp;#039; example above - when we typed &amp;#039;look rock&amp;#039;, it is indicated that it&amp;#039;s small.&lt;br /&gt;
&lt;br /&gt;
- Again, don&amp;#039;t use synonyms for your adjectives.  Instead use the method above of including multiple adjectives in our Said() strings.&lt;br /&gt;
&lt;br /&gt;
[[Category:The SCI Parser]]&lt;br /&gt;
[[Category:Examples]]&lt;br /&gt;
[[Category:Tutorials]]&lt;/div&gt;</summary>
		<author><name>Jeremiah Nellis</name></author>
	</entry>
	<entry>
		<id>http://sciwiki.sierrahelp.com/index.php?title=Robust_Parse_Part_1:_A_Different_Way_To_Handle_User_Input&amp;diff=357</id>
		<title>Robust Parse Part 1: A Different Way To Handle User Input</title>
		<link rel="alternate" type="text/html" href="http://sciwiki.sierrahelp.com/index.php?title=Robust_Parse_Part_1:_A_Different_Way_To_Handle_User_Input&amp;diff=357"/>
		<updated>2012-07-28T14:17:10Z</updated>

		<summary type="html">&lt;p&gt;Jeremiah Nellis: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&amp;#039;&amp;#039;&amp;#039;Robust Parse:  A different way to handle user input&amp;#039;&amp;#039;&amp;#039;&amp;lt;br/&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Do you want your text-based user interaction to be better?  Want to have parsing that beats the pants off of every single SCI Sierra game (yes, really!)?  Well, here&amp;#039;s how to do it.&lt;br /&gt;
&lt;br /&gt;
I&amp;#039;m writing this to address some of the shortcomings with parsing the user input. &lt;br /&gt;
This solution was inspired by how the parsing takes place in Inform.  I didn&amp;#039;t dream this up completely on my own; I&amp;#039;m just applying similar techniques in SCI.&lt;br /&gt;
&lt;br /&gt;
&amp;#039;&amp;#039;&amp;#039;Existing SCI error handling constructs:&amp;#039;&amp;#039;&amp;#039;&amp;lt;br/&amp;gt;&lt;br /&gt;
wordFail:  &amp;#039;I don&amp;#039;t understand the word %s&amp;#039;:  Very good.  Very specific and provides good feedback that the user has a typo, or worst case the game just doesn&amp;#039;t understand their word choice.  If this message comes up excessively, the game designer needs to consider putting in some synonymns into the vocab.  However, this is a direct reflection of the designers&amp;#039; shortcomings, not the implementation of the parsing, etc.&lt;br /&gt;
&lt;br /&gt;
syntaxFail: &amp;#039;That doesn&amp;#039;t appear to be a proper sentence&amp;#039;:  For example: &amp;#039;up jump&amp;#039; (presumably instead of &amp;#039;jump up&amp;#039;).  This happens occasionally &amp;amp; I&amp;#039;m not sure if anything can be done here, except changing the message returned to the user to use a well-known standard sentence structure in the form of &amp;#039;verb &amp;lt;noun&amp;gt; &amp;lt;prep&amp;gt; &amp;lt;noun&amp;gt;&amp;#039;.&lt;br /&gt;
&lt;br /&gt;
semanticFail: &amp;#039;That sentence doesn&amp;#039;t make sense&amp;#039;: I unfortunately do not have an example.  Again, not much we can do here, short of asking the user to restate their request in a standard way, similar to syntaxFail.&lt;br /&gt;
&lt;br /&gt;
pragmaFail: &amp;#039;You&amp;#039;ve left me responseless&amp;#039;:  &amp;#039;&amp;#039;&amp;#039;This is the worst possible thing a user can see.&amp;#039;&amp;#039;&amp;#039;  We&amp;#039;ve done everything we can to parse their input, but we&amp;#039;ve come up with nothing &amp;amp; this is the best we can do - provide a &amp;#039;canned&amp;#039; response to the user.  &amp;#039;&amp;#039;&amp;#039;It&amp;#039;s horrific.&amp;#039;&amp;#039;&amp;#039;&lt;br /&gt;
&lt;br /&gt;
&amp;#039;&amp;#039;&amp;#039;Overview of Solution&amp;#039;&amp;#039;&amp;#039;&amp;lt;br/&amp;gt;&lt;br /&gt;
 1) Parse the verb&lt;br /&gt;
 2) Parse the noun &amp;amp; &amp;#039;second&amp;#039; noun&lt;br /&gt;
 3) Check to make sure the verbs are utilized properly, otherwise throw error (this is the replacement for the stock &amp;#039;pragmaFail&amp;#039; method)&lt;br /&gt;
 4) Check to make sure that the nouns specified are &amp;#039;here&amp;#039;, otherwise throw error&lt;br /&gt;
 5) Call an &amp;#039;action&amp;#039; script to handle the specified verb&lt;br /&gt;
&lt;br /&gt;
&amp;#039;&amp;#039;&amp;#039;Part 1: Parse the Verb&amp;#039;&amp;#039;&amp;#039;&amp;lt;br/&amp;gt;&lt;br /&gt;
In this step we performing the parsing of the verb.  We will also be the flagging of missing or superfluous nouns, which will be used to build the output error message we will display to the user in Step 3.&lt;br /&gt;
&lt;br /&gt;
Each verb will typically be represented with three different Said() string if statements.  This is so we can determine whether a verb, verb/noun or verb/noun/noun combination was entered.  Note the &amp;#039;no-claim&amp;#039; operator (&amp;#039;&amp;gt;&amp;#039;) at the end of each Said() string - this allows us to continue evaluating Said() statements for the nouns and &amp;#039;second&amp;#039; nouns in the following steps.&lt;br /&gt;
&amp;lt;div class=&amp;quot;CodeBlockHeader&amp;quot;&amp;gt;Code:&amp;lt;/div&amp;gt;&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;sci&amp;quot; class=&amp;quot;cs&amp;quot;&amp;gt;&lt;br /&gt;
        = Verb UNSET                // initialize it to &amp;#039;nothing&amp;#039; before each parse&lt;br /&gt;
&lt;br /&gt;
	(if(Said(&amp;#039;dig/*/*&amp;gt;&amp;#039;))      // ex: dig in ground with shovel&lt;br /&gt;
	   = Verb VERB_DIG	&lt;br /&gt;
	)&lt;br /&gt;
&lt;br /&gt;
	(if(Said(&amp;#039;dig/*[/!*]&amp;gt;&amp;#039;))  // ex: dig in ground&lt;br /&gt;
	   = Verb VERB_DIG&lt;br /&gt;
	   = needSecond TRUE	// what do you want to dig in the ground with?&lt;br /&gt;
	)&lt;br /&gt;
	&lt;br /&gt;
	(if(Said(&amp;#039;dig[/!*]&amp;gt;&amp;#039;))    // ex: dig&lt;br /&gt;
	   = Verb VERB_DIG&lt;br /&gt;
	   = needNoun TRUE    // what do you want to dig in?&lt;br /&gt;
	)&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
In the code above, we have three different Said() statements, each one will apply true based on what is inputted.  This represents all the possibilities for the verb &amp;#039;dig&amp;#039; (remember, each sentence that a user inputs is always split into a maximum of 3 parts, so we&amp;#039;ve got it covered).  They match a 3-part, 2-part and 1-part user input, respectively starting with the verb &amp;#039;dig&amp;#039;.   &lt;br /&gt;
&lt;br /&gt;
Within each &amp;#039;if&amp;#039; statement, the first thing we do is set our global &amp;#039;Verb&amp;#039; variable to the verb &amp;#039;dig&amp;#039;, which we&amp;#039;ve defined in our game.sh as a constant - in this case an integer.  There must be verb constants set up for every verb in our game and are ideally numbered from zero to n.&lt;br /&gt;
&lt;br /&gt;
You also see references to other global variables &amp;#039;needNoun&amp;#039; and &amp;#039;needSecond&amp;#039;.   Not shown are two other globals &amp;#039;unneededNoun&amp;#039; and &amp;#039;unneededSecond&amp;#039;.  These 4 variables are initalized to FALSE before each parse, and are set to TRUE when the inputted sentence does not make sense.&lt;br /&gt;
&lt;br /&gt;
Let&amp;#039;s look at the first &amp;#039;if&amp;#039; statement.  It will capture a user input of something like &amp;#039;dig in ground with shovel&amp;#039;.  We set the verb global variable to VERB_DIG, we&amp;#039;ll get into why we do this later.  This if statement happens to be evaluating a &amp;#039;good parse&amp;#039; in the game.&lt;br /&gt;
&lt;br /&gt;
Next, the second &amp;#039;if&amp;#039; statement in the example.  It applies when the user enters &amp;#039;dig in ground&amp;#039;.  Again, we set our verb global.  Then, since the sentence isn&amp;#039;t specific enough for us, we set our &amp;#039;needSecond&amp;#039; variable to true.  This indicates that we are expecting a second noun to be entered and it wasn&amp;#039;t supplied.  We&amp;#039;ll use this flag later to tell the user that they goofed &amp;amp; need to be more specific.&lt;br /&gt;
&lt;br /&gt;
The third &amp;#039;if&amp;#039; is just like the second, except the user has entered something even less specific, the sentence of simply &amp;#039;dig&amp;#039;.  This time we set our &amp;#039;needNoun&amp;#039; variable to TRUE, indicating they didn&amp;#039;t enter the first noun.  We could additionally set the &amp;#039;needSecond&amp;#039; variable to TRUE, but we don&amp;#039;t do anything with it, as we stop reporting an error at the initial noun.&lt;br /&gt;
&lt;br /&gt;
&amp;#039;&amp;#039;&amp;#039;Part 2: Parsing the noun &amp;amp; &amp;#039;second&amp;#039; noun&amp;#039;&amp;#039;&amp;#039;&amp;lt;br/&amp;gt;&lt;br /&gt;
Next, we parse the remaining two portions of the user input (noun &amp;amp; second).  This is simpler than parsing the verbs as we are just looking for a match on the nouns in the relative positions in the Said() string.  Note that we also are setting the &amp;#039;noun&amp;#039; and &amp;#039;second&amp;#039; global variables with constants defined in a similar fashion as our verb constants.&lt;br /&gt;
&amp;lt;div class=&amp;quot;CodeBlockHeader&amp;quot;&amp;gt;Code:&amp;lt;/div&amp;gt;&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;sci&amp;quot; class=&amp;quot;cs&amp;quot;&amp;gt;&lt;br /&gt;
	= noun UNSET		// initialize it to &amp;#039;nothing&amp;#039; before each parse&lt;br /&gt;
	(if(Said(&amp;#039;*/ground&amp;gt;&amp;#039;))&lt;br /&gt;
	   = noun GROUND_OBJ	&lt;br /&gt;
	)&lt;br /&gt;
	&lt;br /&gt;
	(if(Said(&amp;#039;*/shovel&amp;gt;&amp;#039;))&lt;br /&gt;
	   = noun SHOVEL_OBJ	&lt;br /&gt;
	)  &lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
and:&lt;br /&gt;
&amp;lt;div class=&amp;quot;CodeBlockHeader&amp;quot;&amp;gt;Code:&amp;lt;/div&amp;gt;&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;sci&amp;quot; class=&amp;quot;cs&amp;quot;&amp;gt;&lt;br /&gt;
	= second UNSET	 // initialize it to &amp;#039;nothing&amp;#039; before each parse&lt;br /&gt;
	(if(Said(&amp;#039;*/*/ground&amp;gt;&amp;#039;))&lt;br /&gt;
	   = second GROUND_OBJ	&lt;br /&gt;
	)&lt;br /&gt;
	&lt;br /&gt;
	(if(Said(&amp;#039;*/*/shovel&amp;gt;&amp;#039;))&lt;br /&gt;
	   = second SHOVEL_OBJ	&lt;br /&gt;
	)&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&amp;#039;&amp;#039;&amp;#039;Part 3: A robust &amp;#039;pragmaFail&amp;#039; method&amp;#039;&amp;#039;&amp;#039;&amp;lt;br/&amp;gt;&lt;br /&gt;
In order to prepare for this part, let&amp;#039;s check a few things.  You&amp;#039;ve got all your verbs &amp;amp; nouns defined as constants, right?  Great.  Now we need to go one step further &amp;amp; create two text resources.  One will be for verb &amp;#039;names&amp;#039; and one for &amp;#039;noun&amp;#039; names.  This is where we store the text of the verbs and nouns so we can regurgitate them back to the user in our pragamaFail method.  The index of the text resource is correlated to the value of the constant, seen below:&lt;br /&gt;
&amp;lt;div class=&amp;quot;CodeBlockHeader&amp;quot;&amp;gt;Code:&amp;lt;/div&amp;gt;&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;sci&amp;quot; class=&amp;quot;cs&amp;quot;&amp;gt;&lt;br /&gt;
/***************** game.sh *****************/&lt;br /&gt;
(define UNSET		-1)&lt;br /&gt;
&lt;br /&gt;
// Verbs&lt;br /&gt;
(define VERB_CUT        0)&lt;br /&gt;
(define VERB_CLIMBUP    1)&lt;br /&gt;
(define VERB_CLIMBDOWN  2)&lt;br /&gt;
(define VERB_DIG        3)&lt;br /&gt;
(define VERB_LISTEN     4)&lt;br /&gt;
(define VERB_LOOK       5)&lt;br /&gt;
(define VERB_RUN        6)&lt;br /&gt;
&lt;br /&gt;
// Nouns&lt;br /&gt;
(define TREE_OBJ        0)&lt;br /&gt;
(define SAW_OBJ         1)&lt;br /&gt;
(define GROUND_OBJ      2)&lt;br /&gt;
(define SHOVEL_OBJ      3)&lt;br /&gt;
(define BIRD_OBJ        4)&lt;br /&gt;
(define HOUSE_OBJ       5)&lt;br /&gt;
(define DOOR_OBJ        6)&lt;br /&gt;
(define KEY_OBJ         7)&lt;br /&gt;
&lt;br /&gt;
// Text resource numbers&lt;br /&gt;
(define VERB_NAMES      0)&lt;br /&gt;
(define NOUN_NAMES      1)&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div class=&amp;quot;CodeBlockHeader&amp;quot;&amp;gt;Code:&amp;lt;/div&amp;gt;&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;sci&amp;quot; class=&amp;quot;cs&amp;quot;&amp;gt;&lt;br /&gt;
/***************** Text.000 (verb names) *****************/&lt;br /&gt;
Num	Text&lt;br /&gt;
------	----- &lt;br /&gt;
0	cut&lt;br /&gt;
1	climb up&lt;br /&gt;
2	climb down&lt;br /&gt;
3	dig&lt;br /&gt;
4	listen to&lt;br /&gt;
5	look at&lt;br /&gt;
6	run&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div class=&amp;quot;CodeBlockHeader&amp;quot;&amp;gt;Code:&amp;lt;/div&amp;gt;&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;sci&amp;quot; class=&amp;quot;cs&amp;quot;&amp;gt;&lt;br /&gt;
/***************** Text.001 (noun names) *****************/&lt;br /&gt;
Num	Text&lt;br /&gt;
------	-----&lt;br /&gt;
0	tree&lt;br /&gt;
1	saw&lt;br /&gt;
2	ground&lt;br /&gt;
3	shovel&lt;br /&gt;
4	bird&lt;br /&gt;
5	house&lt;br /&gt;
6	door&lt;br /&gt;
7	key&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
Now that we&amp;#039;ve laid the groundwork, let&amp;#039;s proceed on to the code for Step 3:&lt;br /&gt;
&amp;lt;div class=&amp;quot;CodeBlockHeader&amp;quot;&amp;gt;Code:&amp;lt;/div&amp;gt;&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;sci&amp;quot; class=&amp;quot;cs&amp;quot;&amp;gt;&lt;br /&gt;
(procedure public (RobustPragmaFail) &lt;br /&gt;
  (if(== needNoun TRUE and == noun UNSET)&lt;br /&gt;
  	 FormatPrint(&amp;quot;What do you want to %s?&amp;quot; VERB_NAMES Verb)&lt;br /&gt;
  	 return(TRUE)&lt;br /&gt;
  )&lt;br /&gt;
 &lt;br /&gt;
  (if(== needSecond TRUE and == second UNSET)&lt;br /&gt;
  	 FormatPrint(&amp;quot;What do you want to %s the %s with?&amp;quot; VERB_NAMES Verb NOUN_NAMES noun)&lt;br /&gt;
  	 return(TRUE)&lt;br /&gt;
  )&lt;br /&gt;
  &lt;br /&gt;
  (if(== unneededNoun TRUE and &amp;lt;&amp;gt; noun UNSET)&lt;br /&gt;
  	 FormatPrint(&amp;quot;I understood only as far as you wanting to %s.&amp;quot; VERB_NAMES Verb)&lt;br /&gt;
  	 return(TRUE)&lt;br /&gt;
  )&lt;br /&gt;
  &lt;br /&gt;
  (if(== unneededSecond TRUE and &amp;lt;&amp;gt; second UNSET)&lt;br /&gt;
  	 FormatPrint(&amp;quot;I understood only as far as you wanting to %s the %s.&amp;quot; VERB_NAMES Verb NOUN_NAMES noun)&lt;br /&gt;
  	 return(TRUE)&lt;br /&gt;
  )&lt;br /&gt;
  &lt;br /&gt;
  return(FALSE)&lt;br /&gt;
)&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
Now you can see all of the pieces from our previous two steps come together.  Each if statement handles a different combination of needed (or unneeded) nouns.  In our previous &amp;#039;dig&amp;#039; example, here&amp;#039;s the output from two different bad user inputs:&lt;br /&gt;
&lt;br /&gt;
	&amp;#039;&amp;#039;&amp;#039;&amp;quot;dig&amp;quot;&amp;#039;&amp;#039;&amp;#039; results in &amp;#039;&amp;#039;&amp;#039;&amp;quot;What do you want to dig?&amp;quot;&amp;#039;&amp;#039;&amp;#039;&amp;lt;br/&amp;gt;&lt;br /&gt;
	&amp;#039;&amp;#039;&amp;#039;&amp;quot;dig in ground&amp;quot;&amp;#039;&amp;#039;&amp;#039;  results in &amp;#039;&amp;#039;&amp;#039;&amp;quot;What do you want to dig in the ground with?&amp;quot;&amp;#039;&amp;#039;&amp;#039;&lt;br /&gt;
&lt;br /&gt;
The last two if statements work similar to to first two if statements, but for the reverse scenario, where the user has provided too many nouns (instead of too few).  The FormatPrint statements rely on looking up the verb name from the VERB_NAMES text resource (in this case text.000) and the NOUN_NAMES text resource (text.001) to give the user a warm-fuzzy about their bad input.&lt;br /&gt;
&lt;br /&gt;
&amp;#039;&amp;#039;&amp;#039;Part 4: Are the nouns here?&amp;#039;&amp;#039;&amp;#039;&amp;lt;br/&amp;gt;&lt;br /&gt;
Good, so we&amp;#039;ve now implemented a much better solution for reporting bad user input back to the user.  We are ready to continue our error checking.  Let&amp;#039;s suppose our user input is &amp;#039;dig in ground with shovel&amp;#039;.  Completely valid, but what if we are inside a building?  Or if there is no shovel here?  This just doesn&amp;#039;t make sense in this context.  We need to make sure that the nouns being referenced are actually in the current room or in the inventory.&lt;br /&gt;
&lt;br /&gt;
In this example, I&amp;#039;ve implemented a global array of noun locations, and like the text resources, their indexes correspond to the noun constants.   Before we launch into more code, I know that this is a non-standard way of tracking where objects are, but for this example I believe it helps with clarity.  It should be easy to modify the code to use the &amp;#039;ownedBy&amp;#039; and &amp;#039;put&amp;#039; methods.&lt;br /&gt;
&amp;lt;div class=&amp;quot;CodeBlockHeader&amp;quot;&amp;gt;Code:&amp;lt;/div&amp;gt;&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;sci&amp;quot; class=&amp;quot;cs&amp;quot;&amp;gt;&lt;br /&gt;
/*************** Main.sc *************/&lt;br /&gt;
/* global variables */&lt;br /&gt;
	Verb&lt;br /&gt;
	noun&lt;br /&gt;
	second	&lt;br /&gt;
	needNoun&lt;br /&gt;
	needSecond&lt;br /&gt;
	unneededNoun&lt;br /&gt;
	unneededSecond&lt;br /&gt;
&lt;br /&gt;
/* The array that will track where our objects are */	&lt;br /&gt;
	objectLocations[10]  // one for each object in our game&lt;br /&gt;
&lt;br /&gt;
/* in the init() method of Main.sc */&lt;br /&gt;
	= objectLocations[TREE_OBJ] TREE_ROOM&lt;br /&gt;
	= objectLocations[SAW_OBJ] NOWHERE&lt;br /&gt;
	= objectLocations[GROUND_OBJ] EVERYWHERE&lt;br /&gt;
	= objectLocations[SHOVEL_OBJ] HOUSE_ROOM&lt;br /&gt;
	= objectLocations[BIRD_OBJ] TREE_ROOM&lt;br /&gt;
	= objectLocations[HOUSE_OBJ] HOUSE_ROOM&lt;br /&gt;
	= objectLocations[DOOR_OBJ] HOUSE_ROOM&lt;br /&gt;
	= objectLocations[KEY_OBJ] INVENTORY&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
You&amp;#039;ll notice that we&amp;#039;ve introduced more constants here: room constants.  These are defined in our game.sh.  Note that the the positive numbers should correspond to your room script numbers.  INVENTORY, EVERYWHERE and NOWHERE are special values&lt;br /&gt;
&amp;lt;div class=&amp;quot;CodeBlockHeader&amp;quot;&amp;gt;Code:&amp;lt;/div&amp;gt;&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;sci&amp;quot; class=&amp;quot;cs&amp;quot;&amp;gt;&lt;br /&gt;
// Rooms&lt;br /&gt;
(define INVENTORY      -2)&lt;br /&gt;
(define EVERYWHERE     -1)&lt;br /&gt;
(define NOWHERE         0)&lt;br /&gt;
// From here, the number should match the room script numbers&lt;br /&gt;
(define HOUSE_ROOM      1)&lt;br /&gt;
(define TREE_ROOM       2)&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
Here&amp;#039;s the procedure that does the checking for whether the nouns are &amp;#039;in-scope&amp;#039;:&lt;br /&gt;
&amp;lt;div class=&amp;quot;CodeBlockHeader&amp;quot;&amp;gt;Code:&amp;lt;/div&amp;gt;&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;sci&amp;quot; class=&amp;quot;cs&amp;quot;&amp;gt;&lt;br /&gt;
(procedure public (ValidateNouns) &lt;br /&gt;
	(if(&amp;lt;&amp;gt; noun UNSET)&lt;br /&gt;
	    (if (     &amp;lt;&amp;gt; objectLocations[noun] gRoomNumber&lt;br /&gt;
	          and &amp;lt;&amp;gt; objectLocations[noun] INVENTORY&lt;br /&gt;
	          and &amp;lt;&amp;gt; objectLocations[noun] EVERYWHERE)&lt;br /&gt;
	             FormatPrint(&amp;quot;I don&amp;#039;t see any %s here.&amp;quot; NOUN_NAMES noun)&lt;br /&gt;
	             return(FALSE)&lt;br /&gt;
		)         	&lt;br /&gt;
	)&lt;br /&gt;
&lt;br /&gt;
	(if(&amp;lt;&amp;gt; second UNSET)&lt;br /&gt;
	    (if (     &amp;lt;&amp;gt; objectLocations[second] gRoomNumber&lt;br /&gt;
	          and &amp;lt;&amp;gt; objectLocations[second] INVENTORY&lt;br /&gt;
	          and &amp;lt;&amp;gt; objectLocations[second] EVERYWHERE)&lt;br /&gt;
	             FormatPrint(&amp;quot;I don&amp;#039;t see any %s here.&amp;quot; NOUN_NAMES second)&lt;br /&gt;
	             return(FALSE)&lt;br /&gt;
		)         	&lt;br /&gt;
	)&lt;br /&gt;
	&lt;br /&gt;
	// All the nouns are here&lt;br /&gt;
	return(TRUE)&lt;br /&gt;
)&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
Let&amp;#039;s go through it.  For the first noun, we check to make sure that it&amp;#039;s actually been specified, the check to see if the noun is either in the current room, inventory or everywhere (everywhere being specified for something like &amp;#039;ground&amp;#039; or &amp;#039;sky&amp;#039; if your game takes place completely outside).  We do the same check for the second noun.  If either of these if statements evaluate true, we return FALSE (indicating failure), otherwise we return TRUE (all good to continue parsing).&lt;br /&gt;
&lt;br /&gt;
&amp;#039;&amp;#039;&amp;#039;Part 5:  Call the action script&amp;#039;&amp;#039;&amp;#039;&amp;lt;br/&amp;gt;&lt;br /&gt;
At this point, we&amp;#039;ve narrowed our input down to being as legitimate as possible without knowing if the combination of verbs and nouns make sense.  At this point we will create a procedure for each verb that we&amp;#039;ve specified &amp;amp; either perform the action that user asked for, or tell them that their verb and nouns don&amp;#039;t make sense together.&lt;br /&gt;
&lt;br /&gt;
Below is the &amp;#039;CallAction&amp;#039; script, which is purposed to simply call another procedure based on the verb input:&lt;br /&gt;
&amp;lt;div class=&amp;quot;CodeBlockHeader&amp;quot;&amp;gt;Code:&amp;lt;/div&amp;gt;&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;sci&amp;quot; class=&amp;quot;cs&amp;quot;&amp;gt;&lt;br /&gt;
(procedure public (CallAction) &lt;br /&gt;
    (if(== Verb VERB_CUT)       CutAction() return)&lt;br /&gt;
    (if(== Verb VERB_CLIMBUP)   ClimbUpAction() return)&lt;br /&gt;
    (if(== Verb VERB_CLIMBDOWN) ClimbDownAction() return)&lt;br /&gt;
    (if(== Verb VERB_DIG)       DigAction() return)&lt;br /&gt;
    (if(== Verb VERB_LISTEN)    ListenAction() return)&lt;br /&gt;
    (if(== Verb VERB_LOOK)      LookAction() return)&lt;br /&gt;
    (if(== Verb VERB_RUN)       RunAction() return)    &lt;br /&gt;
)&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
Let&amp;#039;s take a peek at the DigAction procedure:&lt;br /&gt;
&amp;lt;div class=&amp;quot;CodeBlockHeader&amp;quot;&amp;gt;Code:&amp;lt;/div&amp;gt;&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;sci&amp;quot; class=&amp;quot;cs&amp;quot;&amp;gt;&lt;br /&gt;
(procedure public (DigAction) 	&lt;br /&gt;
	// Could be &amp;quot;dig ground with shovel&amp;quot;  or &amp;quot;dig with shovel in ground&amp;quot;&lt;br /&gt;
	(if (&amp;lt;&amp;gt; second SHOVEL_OBJ and &amp;lt;&amp;gt; noun SHOVEL_OBJ)&lt;br /&gt;
            Print(&amp;quot;That doesn&amp;#039;t have a blade adequate for digging.&amp;quot;)&lt;br /&gt;
	    return	&lt;br /&gt;
	)&lt;br /&gt;
	&lt;br /&gt;
	(if (&amp;lt;&amp;gt; second GROUND_OBJ and &amp;lt;&amp;gt; noun GROUND_OBJ)&lt;br /&gt;
	    Print(&amp;quot;It would be best if you dug in something sensible!&amp;quot;)	&lt;br /&gt;
	    return&lt;br /&gt;
	)&lt;br /&gt;
		&lt;br /&gt;
        Print(&amp;quot;Nice hole. What next?&amp;quot;)&lt;br /&gt;
)&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
In the case of digging, we&amp;#039;ve programmed it as a bit of a &amp;quot;red herring&amp;quot;.  You really don&amp;#039;t accomplish anything, but it illustrates the point.  In the first if, we are making sure that the user is trying to dig with the shovel.  Next we make sure that what the user is trying to dig in is the ground.  Finally, the &amp;#039;good parse&amp;#039; results represents success; we&amp;#039;ve dug a hole.&lt;br /&gt;
&lt;br /&gt;
&amp;#039;&amp;#039;&amp;#039;Testing&amp;#039;&amp;#039;&amp;#039;&amp;lt;br/&amp;gt;&lt;br /&gt;
Here are some sample inputs to test &amp;#039;digging&amp;#039; (note that these will all work in the Robust Parse Demo game that I&amp;#039;ve created):&lt;br /&gt;
&lt;br /&gt;
dig&amp;lt;br/&amp;gt;&lt;br /&gt;
dig in ground&amp;lt;br/&amp;gt;&lt;br /&gt;
dig in ground with shovel&amp;lt;br/&amp;gt;&lt;br /&gt;
dig in house&amp;lt;br/&amp;gt;&lt;br /&gt;
dig in house with bird&amp;lt;br/&amp;gt;&lt;br /&gt;
dig in house with key&amp;lt;br/&amp;gt;&lt;br /&gt;
etc... (try every noun if you wish!)&amp;lt;br/&amp;gt;&lt;br /&gt;
&lt;br /&gt;
And of course try these commands in both rooms (there are only 2 in the demo) to see the varying results.&lt;br /&gt;
&lt;br /&gt;
&amp;#039;&amp;#039;&amp;#039;Conclusion:&amp;#039;&amp;#039;&amp;#039;&amp;lt;br/&amp;gt;&lt;br /&gt;
You can see that getting a very robust parse takes a lot of parts &amp;amp; a lot of error checking along the way.  However, we&amp;#039;ve gained the flexibility to apply any verb to any noun in any room and get a sensible response from the game, which results in a very satisfying and rich experience for the user.&lt;br /&gt;
&lt;br /&gt;
&amp;#039;&amp;#039;&amp;#039;Miscellaneous Notes:&amp;#039;&amp;#039;&amp;#039;&amp;lt;br/&amp;gt;&lt;br /&gt;
- Memory utilization:  Following this template will potentially generate some very large heap utilization.  Though not necessary in the demo game, I still put in DisposeScript() calls everywhere possible to mitigate this.  If memory usage becomes excessive, it will most likely be a problem in ParseVerb, ParseNoun and ParseSecond scripts.  To address this, simply split the scripts in two or more pieces (e.g. ParseVerbAthruM, ParseVerbNthruZ) and change the calls to the scripts accordingly in the RobustParse routine. &lt;br /&gt;
&lt;br /&gt;
- Do not have words in your vocabulary that you have not provided a successful parse for.  Doing so only enables the user to use these words and make us look stupid because it will fall through to the pragmaFail method.  This means dump the template game&amp;#039;s vocabulary.  Yes, dump it.  Use the (nearly) empty vocab provided in the Robust Parse Demo game.&lt;br /&gt;
&lt;br /&gt;
- The use of synonyms is discouraged.  Instead of synonymns, use the words in the parse itself with the grouping operator (parens) .  It will make troubleshooting easier.  Once you have bound two words together via a synonym, it is impossible to separate them and can cause unintentional results at parse time.&lt;br /&gt;
&lt;br /&gt;
- Noun disambiguation.  This is where adjectives come into play - this is a whole other topic.&lt;br /&gt;
&lt;br /&gt;
[[Category:The SCI Parser]]&lt;br /&gt;
[[Category:Examples]]&lt;br /&gt;
[[Category:Tutorials]]&lt;/div&gt;</summary>
		<author><name>Jeremiah Nellis</name></author>
	</entry>
	<entry>
		<id>http://sciwiki.sierrahelp.com/index.php?title=Minimum_Vocabulary_To_Compile_Template_Game&amp;diff=359</id>
		<title>Minimum Vocabulary To Compile Template Game</title>
		<link rel="alternate" type="text/html" href="http://sciwiki.sierrahelp.com/index.php?title=Minimum_Vocabulary_To_Compile_Template_Game&amp;diff=359"/>
		<updated>2012-06-30T16:15:49Z</updated>

		<summary type="html">&lt;p&gt;Jeremiah Nellis: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;Here are words necessary for compiling the template game:&lt;br /&gt;
&lt;br /&gt;
&amp;#039;&amp;#039;&amp;#039;Main.sc:&amp;#039;&amp;#039;&amp;#039; (if you remove the sample code, you don&amp;#039;t need these words)&lt;br /&gt;
 object&lt;br /&gt;
 hi&lt;br /&gt;
&lt;br /&gt;
&amp;#039;&amp;#039;&amp;#039;Menubar.sc:&amp;#039;&amp;#039;&amp;#039;&lt;br /&gt;
 color&lt;br /&gt;
 all&lt;br /&gt;
 delay&lt;br /&gt;
 game&lt;br /&gt;
 done&lt;br /&gt;
 restart&lt;br /&gt;
 restore&lt;br /&gt;
 save&lt;br /&gt;
&lt;br /&gt;
&amp;#039;&amp;#039;&amp;#039;Don&amp;#039;t remove these (you&amp;#039;ll regret it):&amp;#039;&amp;#039;&amp;#039;&lt;br /&gt;
 * (anyword)&lt;br /&gt;
 !* (noword)&lt;br /&gt;
&lt;br /&gt;
[[Category:Examples]]&lt;/div&gt;</summary>
		<author><name>Jeremiah Nellis</name></author>
	</entry>
	<entry>
		<id>http://sciwiki.sierrahelp.com/index.php?title=Inline_If_Statements&amp;diff=276</id>
		<title>Inline If Statements</title>
		<link rel="alternate" type="text/html" href="http://sciwiki.sierrahelp.com/index.php?title=Inline_If_Statements&amp;diff=276"/>
		<updated>2012-02-17T15:08:10Z</updated>

		<summary type="html">&lt;p&gt;Jeremiah Nellis: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&amp;#039;&amp;#039;Note:  This article only applies to SCI Companion&amp;#039;&amp;#039;&lt;br /&gt;
&lt;br /&gt;
The &amp;quot;if&amp;quot; statement does not return a value, making a the nesting of if&amp;#039;s (inline) like this not possible:&lt;br /&gt;
&amp;lt;div class=&amp;quot;CodeBlockHeader&amp;quot;&amp;gt;Code:&amp;lt;/div&amp;gt;&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;sci&amp;quot; class=&amp;quot;cs&amp;quot;&amp;gt;&lt;br /&gt;
(if (&amp;gt; a ((if(&amp;gt; b c) 5)(else 9)) d)     // This syntax works in SCI Studio, but will not compile in SCI Companion&lt;br /&gt;
  ...&lt;br /&gt;
)&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
As indicated above, this code &amp;#039;&amp;#039;&amp;#039;will&amp;#039;&amp;#039;&amp;#039; work in Studio, but will not work in Companion.  The way to handle this in Companion is to implement a procedure, which will return a value:&lt;br /&gt;
&amp;lt;div class=&amp;quot;CodeBlockHeader&amp;quot;&amp;gt;Code:&amp;lt;/div&amp;gt;&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;sci&amp;quot; class=&amp;quot;cs&amp;quot;&amp;gt;&lt;br /&gt;
(procedure public (iif pCondition pTrue pFalse)&lt;br /&gt;
   (if (pCondition)&lt;br /&gt;
     return pTrue&lt;br /&gt;
   )(else &lt;br /&gt;
     return pFalse &lt;br /&gt;
   )&lt;br /&gt;
)&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The original statement can now be re-written as:&lt;br /&gt;
&amp;lt;div class=&amp;quot;CodeBlockHeader&amp;quot;&amp;gt;Code:&amp;lt;/div&amp;gt;&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;sci&amp;quot; class=&amp;quot;cs&amp;quot;&amp;gt;&lt;br /&gt;
(if (&amp;gt; a iif(&amp;gt; b c 5 9) d) &lt;br /&gt;
  ...&lt;br /&gt;
)&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
[[Category:Conditional Statements]]&lt;br /&gt;
[[Category:Examples]]&lt;br /&gt;
[[Category:Scripting]]&lt;br /&gt;
[[Category:Syntax]]&lt;/div&gt;</summary>
		<author><name>Jeremiah Nellis</name></author>
	</entry>
	<entry>
		<id>http://sciwiki.sierrahelp.com/index.php?title=Goto_Statements&amp;diff=349</id>
		<title>Goto Statements</title>
		<link rel="alternate" type="text/html" href="http://sciwiki.sierrahelp.com/index.php?title=Goto_Statements&amp;diff=349"/>
		<updated>2011-02-18T15:28:16Z</updated>

		<summary type="html">&lt;p&gt;Jeremiah Nellis: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;This can be accomplished with inline assembly code.  Verbatim from the &amp;#039;Inline Assembly&amp;#039; page in the SCI Studio Help File:&lt;br /&gt;
&amp;lt;div class=&amp;quot;CodeBlockHeader&amp;quot;&amp;gt;Code:&amp;lt;/div&amp;gt;&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;sci&amp;quot; class=&amp;quot;cs&amp;quot;&amp;gt;&lt;br /&gt;
// the inline assembly is quite versatile. Here&amp;#039;s a crafty example:&lt;br /&gt;
(if(something)&lt;br /&gt;
  (asm jmp _a_goto_label)&lt;br /&gt;
)&lt;br /&gt;
(asm _a_goto_label: )&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Note that the inline assembly code functionality is implemented in SCI Studio, but not in SCI Companion.&lt;br /&gt;
&lt;br /&gt;
[[Category:Examples]]&lt;br /&gt;
[[Category:Scripting]]&lt;br /&gt;
[[Category:Syntax]]&lt;/div&gt;</summary>
		<author><name>Jeremiah Nellis</name></author>
	</entry>
	<entry>
		<id>http://sciwiki.sierrahelp.com/index.php?title=Arrays_as_Object_Properties&amp;diff=351</id>
		<title>Arrays as Object Properties</title>
		<link rel="alternate" type="text/html" href="http://sciwiki.sierrahelp.com/index.php?title=Arrays_as_Object_Properties&amp;diff=351"/>
		<updated>2011-02-06T21:59:59Z</updated>

		<summary type="html">&lt;p&gt;Jeremiah Nellis: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;According to &amp;#039;&amp;#039;&amp;#039;Lars Skovlund&amp;#039;&amp;#039;&amp;#039;:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;blockquote&amp;gt;&lt;br /&gt;
There is no way to do what you ask. That&amp;#039;s part of the reason why they had to introduce the Memory call in SCI01 (but that&amp;#039;s an ugly solution to the problem.&lt;br /&gt;
There is a hack that you can use, however. Declare a single local variable followed by the arrays you need. Then you can (at least from the point of view of the PMachine, not sure about Brian&amp;#039;s compiler) index into the large arrays by addressing the lone local variable and using a bit of arithmetic.&lt;br /&gt;
&lt;br /&gt;
So I&amp;#039;m saying something like:&lt;br /&gt;
&amp;lt;div class=&amp;quot;CodeBlockHeader&amp;quot;&amp;gt;Code:&amp;lt;/div&amp;gt;&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;sci&amp;quot; class=&amp;quot;cs&amp;quot;&amp;gt;&lt;br /&gt;
(local&lt;br /&gt;
  baseVar&lt;br /&gt;
  array1[10]&lt;br /&gt;
  array2[10]&lt;br /&gt;
)&lt;br /&gt;
&lt;br /&gt;
(instance Blah of Obj&lt;br /&gt;
  (properties&lt;br /&gt;
    arrayPos 1&lt;br /&gt;
 )&lt;br /&gt;
)&lt;br /&gt;
&lt;br /&gt;
(instance Blarg of Obj&lt;br /&gt;
  (properties&lt;br /&gt;
    arrayPos 11&lt;br /&gt;
  )&lt;br /&gt;
)&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&amp;lt;/blockquote&amp;gt;&lt;br /&gt;
&lt;br /&gt;
To access the array, you use a reference like:&lt;br /&gt;
&amp;lt;div class=&amp;quot;CodeBlockHeader&amp;quot;&amp;gt;Code:&amp;lt;/div&amp;gt;&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;sci&amp;quot; class=&amp;quot;cs&amp;quot;&amp;gt;&lt;br /&gt;
  baseVar[(Blah:arrayPos)]     // Gets the 1st value from array1&lt;br /&gt;
  baseVar[(Blarg:arrayPos)]    // Get the 1st value from array2&lt;br /&gt;
&lt;br /&gt;
  baseVar[+ (Blah:arrayPos) 1]     // Gets the 2nd value from array1&lt;br /&gt;
  baseVar[+ (Blarg:arrayPos) 1]    // Get the 2nd value from array2&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
[[Category:Examples]]&lt;br /&gt;
[[Category:Syntax]]&lt;/div&gt;</summary>
		<author><name>Jeremiah Nellis</name></author>
	</entry>
	<entry>
		<id>http://sciwiki.sierrahelp.com/index.php?title=Point_and_Click_Tutorial:_Chapter_9_-_Prepare_the_Text_for_our_Point_and_Click_Rooms&amp;diff=480</id>
		<title>Point and Click Tutorial: Chapter 9 - Prepare the Text for our Point and Click Rooms</title>
		<link rel="alternate" type="text/html" href="http://sciwiki.sierrahelp.com/index.php?title=Point_and_Click_Tutorial:_Chapter_9_-_Prepare_the_Text_for_our_Point_and_Click_Rooms&amp;diff=480"/>
		<updated>2011-01-06T02:55:14Z</updated>

		<summary type="html">&lt;p&gt;Jeremiah Nellis: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;And to think that prior to Chapter 3 of this tutorial, you may have never before made use of any text resources, but now and when we actually get to coding the rooms, they are going to become your very best friends.&lt;br /&gt;
&lt;br /&gt;
==Text Resources for the Inventory==&lt;br /&gt;
&lt;br /&gt;
Now, I realize that without actually seeing the code that is going to be accessing this resource, you might not believe that we are actually going to use them, trust me on this one, I am pretty sure that you will. If not, you can always come in later and change these to something else if you don&amp;#039;t like what I have everything set up to do. This text resource is going to handle most of the default clicks, or clicks on things that aren&amp;#039;t handled by the room&amp;#039;s scripts, mainly clicks on ego help, and whatnot.&lt;br /&gt;
&lt;br /&gt;
Open up a new text resource and let&amp;#039;s begin with the help statements.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;ol&amp;gt;&lt;br /&gt;
&amp;lt;li value=&amp;quot;0&amp;quot;&amp;gt;Welcome to %s . A point and click adventure.&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li value=&amp;quot;1&amp;quot;&amp;gt;To control your characters interactions, select the desired action from the action menu. Walk, talk, look, get are all represented by icons and clicking on one will change your cursor accordingly.&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li value=&amp;quot;2&amp;quot;&amp;gt;To use an inventory item, you must first open the inventory screen and select it from the items you are carrying. Clicking on the backpack icon will open the inventory screen.&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li value=&amp;quot;3&amp;quot;&amp;gt;The system menu allows you to save, load, restart, quit, or change your speed and volume settings. You can reach the system screen by clicking on the center blue sphere of the menu graphic.&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li value=&amp;quot;4&amp;quot;&amp;gt;To return the menu to actions simply click the smaller blue sphere to the left of the system menu option.&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li value=&amp;quot;5&amp;quot;&amp;gt;Hope this has been helpful, enjoy playing %s!&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;/ol&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Just to make sure, you have plenty of room to add in more help messages if you feel you need them, we are going to go ahead and add in a few empty lines just so you won&amp;#039;t have to rearrange things in the future. The next line that we are actually going to start using is going to be line 10, so if you want, go ahead and just enter a space or whatever in lines 6 through 9 just in case.&lt;br /&gt;
&lt;br /&gt;
Now, let&amp;#039;s go ahead and add in a few lines for random &amp;quot;action&amp;quot; clicks on the ego.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;ol&amp;gt;&lt;br /&gt;
&amp;lt;li value=&amp;quot;0&amp;quot;&amp;gt;What a handsome fellow!&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li value=&amp;quot;1&amp;quot;&amp;gt;Vanity is never an attractive trait.&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li value=&amp;quot;2&amp;quot;&amp;gt;That&amp;#039;s strange, I don&amp;#039;t remember ever putting these clothes on.&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li value=&amp;quot;3&amp;quot;&amp;gt;Talking to yourself has rarely ever been considered a good sign.&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li value=&amp;quot;4&amp;quot;&amp;gt;Do you really think that you would find yourself that interesting?&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li value=&amp;quot;5&amp;quot;&amp;gt;&amp;quot;Hi there me, How am I doing?&amp;quot;&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li value=&amp;quot;6&amp;quot;&amp;gt;You sir, are no Michael Jackson, keep your hands off yourself.&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li value=&amp;quot;7&amp;quot;&amp;gt;When I think about you I touch myself.&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li value=&amp;quot;8&amp;quot;&amp;gt;You quickly adjust your clothes. After all who knows, there may be some fly young hotties in the next room.&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li value=&amp;quot;9&amp;quot;&amp;gt;Whatever you are trying to do to yourself, knock it off&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li value=&amp;quot;10&amp;quot;&amp;gt;I&amp;#039;m not really sure if I would want to use that on myself.&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li value=&amp;quot;11&amp;quot;&amp;gt;Oh yeah, stick it my ear. That&amp;#039;s a good idea.&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li value=&amp;quot;12&amp;quot;&amp;gt;Your brilliant use for that in this way clearly illustrates that you are in a league of your own. So much so, that I am not even going to allow it, try something else.&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li value=&amp;quot;13&amp;quot;&amp;gt;I am not even sure how I could use that there.&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li value=&amp;quot;14&amp;quot;&amp;gt;Hmm, interesting idea... but I think we would need a permit.&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;/ol&amp;gt;&lt;br /&gt;
&lt;br /&gt;
That takes care of all of the clicks on the ego and random item clicks in room, I have the point and click script set up to randomly pick from three possible responses for each action, look, talk, hand, items. Now, we need to handle the texts for the &amp;quot;system&amp;quot; options, basically the &lt;br /&gt;
statements that are printed along with the quit and restart dialogs.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;ol&amp;gt;&lt;br /&gt;
&amp;lt;li value=&amp;quot;0&amp;quot;&amp;gt;Are you serious? You really want to start all the way back at the beginning again?&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li value=&amp;quot;1&amp;quot;&amp;gt;Do you really want to quit?&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;/ol&amp;gt;&lt;br /&gt;
&lt;br /&gt;
That is all we need out of this text resource for the tutorial, save this as number 950.&lt;br /&gt;
&lt;br /&gt;
Now, While we are creating texts, let&amp;#039;s go ahead and start off with Room 1&amp;#039;s text resource. As the point and click script is currently written, you &amp;#039;&amp;#039;&amp;#039;will&amp;#039;&amp;#039;&amp;#039; need a separate text resource for each room. The room number should correspond to the text resource number, so room 1 will require text resource 1.&lt;br /&gt;
&lt;br /&gt;
The default clicks handled by the point and click script require that line 0, 1, and 2, be set up as the rooms default clicks (or clicks on stuff that is not handled in the rooms script specifically) as the following actions look, talk, and get.&lt;br /&gt;
&lt;br /&gt;
So for instance, clicking on nothing with the look cursor will print text resource line 0, the general description of the room.&lt;br /&gt;
&lt;br /&gt;
Open up another new text resource and enter this stuff.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;ol&amp;gt;&lt;br /&gt;
&amp;lt;li value=&amp;quot;0&amp;quot;&amp;gt;You find yourself standing in the great white void of room 1&amp;#039;s nothingness.&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li value=&amp;quot;1&amp;quot;&amp;gt;Yelling into the void, you are greeted with an eerie silence, if only there was someone here to talk to.&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li value=&amp;quot;2&amp;quot;&amp;gt;Reaching out, you find, as many philosopher&amp;#039;s have over the centuries, just how hard it is to grasp true nothingness.&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;/ol&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Since this resource is going to be used for room 1, save it as resource number 1.&lt;br /&gt;
&lt;br /&gt;
All right, that is that, we now have two text resources for the point and click room. Remember 950 holds all of the texts which are needed for the point and click menu itself, while text resource 1 holds all of the texts for room 1 specifically. As you add in more rooms, room 2 will try to access text resource 2 and so on.&lt;br /&gt;
&lt;br /&gt;
That sums up the creation of the Point and Click Text resources!&lt;br /&gt;
&lt;br /&gt;
&amp;amp;nbsp;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span style=&amp;quot;float: left&amp;quot;&amp;gt;[[Point and Click Tutorial: Chapter 8 - Ordering the Additional Cursors|&amp;amp;lt; Previous: Chapter 8 - Ordering the Additional Cursors]]&amp;lt;/span&amp;gt;&lt;br /&gt;
&amp;lt;span style=&amp;quot;float: right&amp;quot;&amp;gt;[[Point and Click Tutorial: Chapter 10 - Point and Click Menu Views|Next: Chapter 10 - Point and Click Menu Views &amp;amp;gt;]]&amp;lt;/span&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;amp;nbsp;&lt;br /&gt;
&lt;br /&gt;
[[Category:Text Resources]]&lt;br /&gt;
[[Category:Tutorials]]&lt;/div&gt;</summary>
		<author><name>Jeremiah Nellis</name></author>
	</entry>
</feed>