Difference between revisions of "AGI/Specifications/Logic"

Jump to navigation Jump to search
m
Text replacement - "</source>" to "</syntaxhighlight>"
m (→‎Other commands: adding agi256 note)
m (Text replacement - "</source>" to "</syntaxhighlight>")
 
(11 intermediate revisions by 3 users not shown)
Line 1: Line 1:
=The LOGIC language=
=The script language=


<span id="Logic"></span>
<span id="Logic"></span>
==LOGIC syntax==
==Source code conventions==


This is the ''official'' LOGIC syntax that has been decided on. It is not the same syntax as Sierra used. All LOGIC decoders and compilers should comply with this syntax, so that programmers can be sure that code they produce can be used properly with any program.
This section lists conventions that will be adopted in the AGI script
language description in this document. They may differ from Sierra's
original syntax, but the resulting bytecode is strictly the same.


===Action Commands===
===Commands and operators===


Normal action commands are specified by the command name followed by brackets which contain the arguments, separated by commas. A semicolon is placed after the brackets. The brackets are required even if there are no arguments. The arguments given must have the correct prefix for that type of argument as explained later in this document (this is to make sure the programmer does not use a var, for example, when they think they are using a flag).
Normal commands are specified by the command name followed by
brackets which contain the arguments, separated by commas. A semicolon
is placed after the brackets. The brackets are required even if there
are no arguments. The arguments given must have the correct prefix for
that type of argument as explained later in this document (this is to
make sure the programmer does not use a var, for example, when they
think they are using a flag).


<syntaxhighlight lang="cpp">
     assign.v(v50,0);
     assign.v(v50,0);
     program.control();
     program.control();
</syntaxhighlight>


Multiple commands may be placed on the one line:
Multiple commands may be placed on the one line:


    reset(f6); reset(f7);
<syntaxhighlight lang="cpp">
  reset(f6); reset(f7);
</syntaxhighlight>


Substitutions for the following action commands are available:
Substitutions for the following action commands are available:


<syntaxhighlight lang="cpp">
     increment(v30);      v30++;
     increment(v30);      v30++;
     decrement(v30);      v30--;
     decrement(v30);      v30--;
Line 34: Line 47:
     lindirectv(v30,v32);  *v30 = v32;
     lindirectv(v30,v32);  *v30 = v32;
     rindirect(v30,v32);  v30 = *v32;
     rindirect(v30,v32);  v30 = *v32;
</syntaxhighlight>


===if structures and test commands===
===Conditionals and tests===


An if structure looks like this:
An '''if''' structure looks like this:


<syntaxhighlight lang="cpp">
     if (<test commands>) {
     if (<test commands>) {
         <action commands>
         <action commands>
     }
     }
</syntaxhighlight>


or like this :
or like this :


<syntaxhighlight lang="cpp">
     if (<test commands>) {
     if (<test commands>) {
         <action commands>
         <action commands>
Line 51: Line 68:
       <more action commands>
       <more action commands>
     }
     }
</syntaxhighlight>


Carriage returns are not necessary:
Multiple commands can be placed in a single line:


<syntaxhighlight lang="cpp">
     if (<test commands>) { <action Commands> } else { <more action commands> }
     if (<test commands>) { <action Commands> } else { <more action commands> }
</syntaxhighlight>


Test commands are coded like action commands except there is no semicolon. They are separated by && or || for AND or OR.
Test commands are coded like action commands except there is no semicolon. They are separated by && or || for AND or OR.


<syntaxhighlight lang="cpp">
     if (isset(f5) &&
     if (isset(f5) &&
         greatern(v5,6)) { ......
         greatern(v5,6)) { ......
</syntaxhighlight>


Again, carriage returns are not necessary within the if statement:
Multiple tests can be placed in a single line within the if statement:


<syntaxhighlight lang="cpp">
     if (lessn(v5,6) && (greatern(v5,2)) { .......
     if (lessn(v5,6) && (greatern(v5,2)) { .......


     if (isset(f90) && equalv(v32,v34)
     if (isset(f90) && equalv(v32,v34)
         && greatern(v34,20)) { .......
         && greatern(v34,20)) { .......
</syntaxhighlight>


A ! placed in front of a command signifies a NOT.
A '''!''' placed in front of a command negates its result:


<syntaxhighlight lang="cpp">
     if (!isset(f7)) {
     if (!isset(f7)) {
       ......
       ......
</syntaxhighlight>


Boolean expressions are not necessarily simplified so they must follow the rules set down by the file format. If test commands are to be ORred together, they must be placed in brackets.
Boolean expressions are not necessarily simplified so they must follow the rules set down by the file format. If test commands are to be ORred together, they must be placed in brackets.


<syntaxhighlight lang="cpp">
     if ((isset(f1) || isset(f2)) {
     if ((isset(f1) || isset(f2)) {
       ......
       ......
Line 81: Line 108:
       ......
       ......


     if (isset(1) || (isset(2) && isset(3))) {    is NOT legal
     if (isset(1) || (isset(2) && isset(3))) {    // is NOT legal
</syntaxhighlight>


Depending on the compiler, simplification of boolean expressions may be supported, so the above may not apply in all cases (although if these are rules are followed then the logic will work with all compilers).
Depending on the compiler, simplification of boolean expressions may be supported, so the above may not apply in all cases (although if these are rules are followed then the logic will work with all compilers).


Substitutions for the following test commands are available:
The following test commands and operations are equivalent:


<syntaxhighlight lang="cpp">
     equaln(v30,4)        v30 == 4
     equaln(v30,4)        v30 == 4
     equalv(v30,v32)      v30 == v32
     equalv(v30,v32)      v30 == v32
Line 99: Line 128:
     !lessn(v30,4)        v30 >= 4
     !lessn(v30,4)        v30 >= 4
     !lessv(v30,v32)      v30 >= v32
     !lessv(v30,v32)      v30 >= v32
</syntaxhighlight>


Also, flags can be tested for by just using the name of the flag:
Also, flags can be tested for by just using the name of the flag:


<syntaxhighlight lang="cpp">
     if (f6) { .....
     if (f6) { .....


     if (v7 > 0 && !f6) { .....
     if (v7 > 0 && !f6) { .....
</syntaxhighlight>


===Argument types===
===Argument types===
Line 110: Line 142:
There are 9 different types of arguments that commands use:
There are 9 different types of arguments that commands use:


    * Number (no prefix)
* Number (no prefix)
    * Var (prefix ``v'')
* Var (prefix "v")
    * Flag (prefix ``f'')
* Flag (prefix "f")
    * Message (prefix ``m'')
* Message (prefix "m")
    * Object (prefix ``o'')
* Object (prefix "o")
    * Inventory Item (prefix ``i'')
* Inventory Item (prefix "i")
    * String (prefix ``s'')
* String (prefix "s")
    * Word (prefix ``w'')
* Word (prefix "w")
    * Controller (prefix ``c'')
* Controller (prefix "c")


The said test command uses its own special arguments which will be described later.
The said test command uses its own special arguments which will be described later.


Each of these types of arguments is given by the prefix and then a number from 0--255, e.g. v5, f6, m27, o2.
Each of these types of arguments is given by the prefix and then a number from 0--255, e.g. '''v5''', '''f6''', '''m27''', '''o2'''.


The word type is words that the player has typed in, not words that are stored in the words.tok file. Strings are the temporary string variables stored in memory, not to be confused with messages (that are stored in the LOGIC resources). Controllers are menu items and keys.
The "word" type is words that the player has typed in, not words that are stored in the '''words.tok''' file. Strings are the temporary string variables stored in memory, not to be confused with messages (that are stored in the LOGIC resources). Controllers are menu items and keys.


Compilers can enforce type checking, so that the programmer must use the correct prefix for an argument so that they know they are using the right type. Decoders should display arguments with the right type.
Compilers can enforce type checking, so that the programmer must use the correct prefix for an argument so that they know they are using the right type. Decoders should display arguments with the right type.


<syntaxhighlight lang="cpp">
     move.obj(so4,80,120,2,f66);
     move.obj(so4,80,120,2,f66);
     if (obj.in.box(so2,30,60,120,40)) { .....
     if (obj.in.box(so2,30,60,120,40)) { .....
</syntaxhighlight>


A complete list of the commands and their argument types is available as part of AGI Specs.
A complete list of the commands and their argument types is available in [[AGI/Specifications/Resources#Command_list_and_argument_typesas | Command list and argument types table]].


Messages and inventory items may be given in either numerical text format:
Messages and inventory items may be given in either numerical text format:


<syntaxhighlight lang="cpp">
     print("He's not here.");
     print("He's not here.");
     print(m12);
     print(m12);
     if (has("Jetpack")) { .....
     if (has("Jetpack")) { .....
     if (has(io9)) { .....
     if (has(io9)) { .....
</syntaxhighlight>


Messages can also be split over multiple lines:
Messages can also be split over multiple lines:


<syntaxhighlight lang="cpp">
     print("This message is split "
     print("This message is split "
           "over multiple lines.");
           "over multiple lines.");
</syntaxhighlight>


Quote marks must be used around messages and object names. This is important because some messages or object names may contain brackets or commas, which could confuse the compiler. This is also the case for the said command which will be described shortly.
Quote marks must be used around messages and object names. This is important because some messages or object names may contain brackets or commas, which could confuse the compiler. This is also the case for the '''said''' command which will be described shortly.


<syntaxhighlight lang="cpp">
     if (has("Buckazoid(s)")) { .....        // no ambiguity here about where
     if (has("Buckazoid(s)")) { .....        // no ambiguity here about where
                                             // the argument ends
                                             // the argument ends
</syntaxhighlight>


The said test command uses different parameters to all the other commands. Where as the others use 8 bit arguments (0--255), said takes 16 bit arguments (0--65535). Also, the number of arguments in a said command can vary. The numbers given in the arguments are the word group numbers from the words.tok file.
The '''said''' test command uses different parameters to all the other commands. Where as the others use 8 bit arguments (0--255), '''said''' takes 16 bit arguments (0--65535). Also, the number of arguments in a '''said''' command can vary. The numbers given in the arguments are the word group numbers from the '''words.tok''' file.


<syntaxhighlight lang="cpp">
     if (said(4,80)) { .....
     if (said(4,80)) { .....
</syntaxhighlight>


Words can also be given in place of the numbers:
Words can also be given in place of the numbers:


<syntaxhighlight lang="cpp">
     if (said("look")) { .....
     if (said("look")) { .....
     if (said("open","door")) { .....
     if (said("open","door")) { .....
</syntaxhighlight>


Quote marks must also be used around the words.
Quote marks must also be used around the words.


===Labels and the goto command===
===Labels and the '''goto''' command===


Labels are given like this:
Labels are given like this:


<syntaxhighlight lang="cpp">
     Label1:
     Label1:
</syntaxhighlight>


The label name can contain letters, numbers, and the characters "_" and ".". No spaces are allowed.
The label name can contain letters, numbers, and the characters "_" and ".". No spaces are allowed. The '''goto''' command takes one parameter, the name of a label.
 
The goto command takes one parameter, the name of a label.


<syntaxhighlight lang="cpp">
     goto(Label1);
     goto(Label1);
</syntaxhighlight>


===Comments===
===Comments===
Line 177: Line 223:
There are three ways that comments can be used.
There are three ways that comments can be used.


<syntaxhighlight lang="cpp">
     // Rest of line is ignored
     // Rest of line is ignored
     [  Rest of line is ignored
     [  Rest of line is ignored
     /* Text between these are ignored */
     /* Text between these are ignored */
</syntaxhighlight>


The /*...*/ can be nested:
The /*...*/ can be nested:


<syntaxhighlight lang="cpp">
     /* comment start
     /* comment start
       print("Hello");    // won't be run
       print("Hello");    // won't be run
Line 190: Line 239:
       print("Hey!");    // won't be run, still inside comments
       print("Hey!");    // won't be run, still inside comments
     */                  // uncomments
     */                  // uncomments
</syntaxhighlight>


===Defines===
===Defines===
Line 195: Line 245:
To give vars, flags etc. proper names the #define command is used. The name of the define is given followed by the define value:
To give vars, flags etc. proper names the #define command is used. The name of the define is given followed by the define value:


<syntaxhighlight lang="cpp">
     #define ego o0
     #define ego o0
     #define room_descr "This is a large hall with tall pillars down each side."
     #define room_descr "This is a large hall with tall pillars down each side."
</syntaxhighlight>


Then the define name can be used in place of the define value:
Then the define name can be used in place of the define value:


<syntaxhighlight lang="cpp">
     draw(ego);
     draw(ego);
     print(room_descr);
     print(room_descr);
</syntaxhighlight>


Define names can only be used in arguments of commands (including gotos and the v0 == 3 type syntax), although some compilers may allow you to use them anywhere.
Define names can only be used in arguments of commands (including gotos and the v0 == 3 type syntax), although some compilers may allow you to use them anywhere.
Line 213: Line 267:
You can include another file in your logic source code by using the #include command:
You can include another file in your logic source code by using the #include command:


<syntaxhighlight lang="cpp">
     #include "file.txt"
     #include "file.txt"
</syntaxhighlight>


When the compiler encounters the above line, it will replace it with the contents of file.txt.
When the compiler encounters the above line, it will replace it with the contents of file.txt.
Line 222: Line 278:
In some cases you may want to assign a specific number to a message so you can refer to it in other places. This is done by using the #message command, followed by the number of the message then the message itself:
In some cases you may want to assign a specific number to a message so you can refer to it in other places. This is done by using the #message command, followed by the number of the message then the message itself:


<syntaxhighlight lang="cpp">
     #message 4 "You can't do that now."
     #message 4 "You can't do that now."
</syntaxhighlight>


Then you can give the message number as the parameter in commands:
Then you can give the message number as the parameter in commands:


<syntaxhighlight lang="cpp">
     print(m4);
     print(m4);
</syntaxhighlight>


Or embed the message in commands as normal and the number you assigned to it before will be used:
Or embed the message in commands as normal and the number you assigned to it before will be used:


<syntaxhighlight lang="cpp">
     print("You can't do that now.");
     print("You can't do that now.");
</syntaxhighlight>


#message can be used anywhere in the file, so you do not have to set the message before you use it.
#message can be used anywhere in the file, so you do not have to set the message before you use it.
Line 236: Line 298:
===The return command===
===The return command===


The return command is just a normal action command (number 0), with no arguments. This must be the last command in every logic.
The return command is just a normal action command (number 0), with no arguments. This must be the last command in every script.


<span id="CommandRef"></span>
<span id="CommandRef"></span>
Line 249: Line 311:
increment(n)
increment(n)


    The value of the variable n is incremented by one, i.e. vn = vn+1. If the value is already 255, it is left unchanged.
:The value of the variable n is incremented by one, i.e. vn = vn+1. If the value is already 255, it is left unchanged.


decrement(n)
decrement(n)


    The value of the variable vn is decremented by one, i.e. vn = vn-1. If the value is 0, it is left unchanged.
:The value of the variable vn is decremented by one, i.e. vn = vn-1. If the value is 0, it is left unchanged.


assign(n,m)
assign(n,m)


    Variable vn is assigned the value m, i.e. vn = m
:Variable vn is assigned the value m, i.e. vn = m


assignv(n,m)
assignv(n,m)


    Variable vn is assigned the value of vm, i.e. vn = vm.
:Variable vn is assigned the value of vm, i.e. vn = vm.


addn(n,m),addv(n,m)
addn(n,m),addv(n,m)


    The value of variable vn is incremented by m (vm), i.e. vn = vn + m (vm).
:The value of variable vn is incremented by m (vm), i.e. vn = vn + m (vm).


    If the value is greater than 255 the result wraps over 0 (so 250 + 10 == 4). (Information by XoXus)
:If the value is greater than 255 the result wraps over 0 (so 250 + 10 == 4). ''(Information by XoXus)''


subn(n,m), subv(n,m)
subn(n,m), subv(n,m)


    The value of vn is decremented by m (vm), i.e. vn = vn - m (vm).
:The value of vn is decremented by m (vm), i.e. vn = vn - m (vm).


    If the value is lesser than 0 the result wraps (so 1 - 2 == 255). (Information by XoXus)
:If the value is lesser than 0 the result wraps (so 1 - 2 == 255). ''(Information by XoXus)''


lindirectn(n,m)
lindirectn(n,m)


    Variable vi where i is the value of vn is assigned a value m, i.e. Var(vn) = m.
:Variable vi where ''i'' is the value of vn is assigned a value m, i.e. Var(vn) = m.


lindirectv(n,m)
lindirectv(n,m)


    Variable vi where i is the value of vn is assigned the value of vm, i.e. Var(vn) = vm.
:Variable vi where ''i'' is the value of vn is assigned the value of vm, i.e. Var(vn) = vm.


rindirect(n,m)
rindirect(n,m)


    Variable vn is assigned the value of vi where i is the value of vm, i.e. vn = Var(vm).
:Variable vn is assigned the value of vi where ''i'' is the value of vm, i.e. vn = Var(vm).
 
muln(n,m)
muln(n,m)


    Variable vn is multiplied by m, i.e. vn = vn * m.
:Variable vn is multiplied by m, i.e. vn = vn * m.
 
mulv(n,m)
mulv(n,m)


    Variable vn is multiplied by the value of vm, i.e. vn = vn * vm.
:Variable vn is multiplied by the value of vm, i.e. vn = vn * vm.
 
::''(What happens on overflow? --VB)''


    (What happens on overflow? --VB)
divn(n,m)
divn(n,m)


    Variable vn is divided by m, i.e. vn = vn / m.
:Variable vn is divided by m, i.e. vn = vn / m.
 
divv(n,m)
divv(n,m)


    Variable vn is divided by the value of vm, i.e. vn = vn / vm.
:Variable vn is divided by the value of vm, i.e. vn = vn / vm.


    (What happens on division by 0? --VB)
::''(What happens on division by 0? --VB)''


random(n,m,k)
random(n,m,k)


    Variable vk is assigned a random value in the range between n and m. Now let us consider the commands changing flag values. Remember that a flag can only have a value 0 or 1.
:Variable vk is assigned a random value in the range between n and m. Now let us consider the commands changing flag values. Remember that a flag can only have a value 0 or 1.
 
===Flag commands===


set(n)
set(n)


    fn is set to 1.
:fn is set to 1.


set.v(n)
set.v(n)


    fi, where i is the value of vn, is set to 1. i.e. flag(vn) = 1.
:fi, where i is the value of vn, is set to 1. i.e. flag(vn) = 1.


reset(n)
reset(n)


    fn is set to 0.
:fn is set to 0.


reset.v(n)
reset.v(n)


    fi, where i is the value of vn, is set to 0, i.e. flag(vn) = 0.
:fi, where i is the value of vn, is set to 0, i.e. flag(vn) = 0.


toggle(n)
toggle(n)


    fn toggles its value.
:fn toggles its value.


toggle.v(n)
toggle.v(n)


    fi, where i is the value of vn, i.e. flag(vn), toggles is value.
:fi, where i is the value of vn, i.e. flag(vn), toggles is value.


===Commands to load and unload resources===
===Commands to load and unload resources===
Line 337: Line 405:
When the internal memory is full, the program has to be broken into parts which are loaded and unloaded as the story unfolds in the given room, or PICTURE, VIEW, and SOUND resources have to be manipulated using the commands below.
When the internal memory is full, the program has to be broken into parts which are loaded and unloaded as the story unfolds in the given room, or PICTURE, VIEW, and SOUND resources have to be manipulated using the commands below.


Remember that when a resource is unloaded, all resources loaded after it are also automatically unloaded!
Remember that when a resource is unloaded, all resources loaded after it are also automatically unloaded (in the Sierra interpreter).


load.logic(n)
load.logic(n)


    Load into memory the LOGIC resource number n, i.e. Logic(n)
:Load into memory the LOGIC resource number n, i.e. Logic(n)
 
load.logic.v(n)
load.logic.v(n)


    Load into memory the LOGIC resource number i, where i is the value of vn, i.e. Logic(vn)
:Load into memory the LOGIC resource number i, where i is the value of vn, i.e. Logic(vn)


load.pic(n)
load.pic(n)


    Loads into memory the PICTURE resource number i, where i is the value of vn, i.e. Picture(vn)
:Loads into memory the PICTURE resource number i, where i is the value of vn, i.e. Picture(vn)


    (This may be a mistake in the original: I would expect this command to be load.pic.v, while load.pic(n) would load resource number n. --VB)
::''(This may be a mistake in the original: I would expect this command to be load.pic.v, while load.pic(n) would load resource number n. --VB)''


    (load.pic.v may be a more appropriate name for it, but the name above is what they gave it. There is no equivalent command that takes a number rather than a variable. --LE)
::''(load.pic.v may be a more appropriate name for it, but the name above is what they gave it. There is no equivalent command that takes a number rather than a variable. --LE)''


load.view(n)
load.view(n)


    Loads into memory the VIEW resource number n, i.e. View(n).
:Loads into memory the VIEW resource number n, i.e. View(n).


load.view.v(n)
load.view.v(n)


    Loads into memory the VIEW resource number i, where i is the value of vn, i.e. View(vn)
:Loads into memory the VIEW resource number i, where i is the value of vn, i.e. View(vn)


load.sound(n)
load.sound(n)


    Loads into memory the SOUND resource number n, i.e. Sound(n).
:Loads into memory the SOUND resource number n, i.e. Sound(n).


    (Note that there is no load.sound.v listed. I wonder if this is a mistake or there really is no way to load a sound with indirection (unlikely, I think) --VB)
::''(Note that there is no load.sound.v listed. I wonder if this is a mistake or there really is no way to load a sound with indirection (unlikely, I think) --VB)''


    (There really is no way of loading a sound with indirection. The command doesn't exist. --LE)
::''(There really is no way of loading a sound with indirection. The command doesn't exist. --LE)''


discard.pic(n)
discard.pic(n)


    Unloads PICTURE resource number i, where i is the value of vn.
:Unloads PICTURE resource number i, where i is the value of vn.


discard.view(n)
discard.view(n)


    Unload VIEW resource number n, i.e. View(n).
:Unload VIEW resource number n, i.e. View(n).


discard.view.v(n)
discard.view.v(n)


    Unloads VIEW resource number i where i is the value of vn, i.e. View(vn).
:Unloads VIEW resource number i where i is the value of vn, i.e. View(vn).


    (And what about discard.logic, discard.logic.v, discard.sound, and discard.sound.v? --VB)
::''(And what about discard.logic, discard.logic.v, discard.sound, and discard.sound.v? --VB)''


    (There must be some other way that those commands are removed from memory, because the commands you mention above don't exist. --LE)
::''(There must be some other way that those commands are removed from memory, because the commands you mention above don't exist. --LE)''


===Program control commands===
===Program control commands===
Line 390: Line 459:
new.room command is one of the most powerful commands of the interpreter.
new.room command is one of the most powerful commands of the interpreter.


It is used to change algorithms of the object behaviour, props, etc. Automatic change of Ego coordinates imitates moving into a room adjacent to the edge of the initial one. (Sounds awkward but that's what it says. --VB)
It is used to change algorithms of the object behavior, props, etc. Automatic change of Ego coordinates imitates moving into a room adjacent to the edge of the initial one. ''(Sounds awkward but that's what it says. --VB)''


The format of the command:
The format of the command:
Line 396: Line 465:
new.room(n), new.room.v(n)
new.room(n), new.room.v(n)


    These commands do the following:
:These commands do the following:


      1. Commands stop.update and unanimate are issued to all objects;
:# Commands stop.update and unanimate are issued to all objects;
      2. All resources except Logic(0) are discarded;
:# All resources except Logic(0) are discarded;
      3. Command player.control is issued;
:# Command player.control is issued;
      4. unblock command is issued;
:# unblock command is issued;
      5. set.horizon(36) command is issued;
:# set.horizon(36) command is issued;
      6. v1 is assigned the value of v0; v0 is assigned n (or the value of vn when the command is new.room.v); v4 is assigned 0; v5 is assigned 0; v16 is assigned the ID number of the VIEW resource that was associated with Ego (the player character).
:# v1 is assigned the value of v0; v0 is assigned n (or the value of vn when the command is new.room.v); v4 is assigned 0; v5 is assigned 0; v16 is assigned the ID number of the VIEW resource that was associated with Ego (the player character).
      7. Logic(i) resource is loaded where i is the value of v0 !
:# Logic(i) resource is loaded where i is the value of v0 !
      8. Set Ego coordinates according to v2:
:# Set Ego coordinates according to v2:
              * if Ego touched the bottom edge, put it on the horizon;
::* if Ego touched the bottom edge, put it on the horizon;
              * if Ego touched the top edge, put it on the bottom edge of the screen;
::* if Ego touched the top edge, put it on the bottom edge of the screen;
              * if Ego touched the right edge, put it at the left and vice versa.
::* if Ego touched the right edge, put it at the left and vice versa.
      9. v2 is assigned 0 (meaning Ego has not touched any edges).
:# v2 is assigned 0 (meaning Ego has not touched any edges).
      10. f5 is set to 1 (meaning in the first interpreter cycle after the new_room command all initialization parts of all logics loaded and called from the initialization part of the new room's logic will be called. In the subsequent cycle f5 is reset to 0 (see section Interpreter work cycle and the source of the ``Thunderstorm'' program. This is very important!).
:# f5 is set to 1 (meaning in the first interpreter cycle after the new_room command all initialization parts of all logics loaded and called from the initialization part of the new room's logic will be called. In the subsequent cycle f5 is reset to 0 (see section Interpreter work cycle and the source of the "Thunderstorm" program. This is very important!).
      11. Clear keyboard input buffer and return to the main AGI loop.
:# Clear keyboard input buffer and return to the main AGI loop.


===Subroutine call commands===
===Subroutine call commands===
Line 417: Line 486:
call(n), call.v(n)
call(n), call.v(n)


    LOGIC resource number n (or number i where i the value of vn) is executed as a subroutine. If the logic with the given ID is not loaded in memory, it is temporarily loaded and discarded after returning from the call (this takes extra time). call does not change any variables or flags.
:LOGIC resource number n (or number i where i the value of vn) is executed as a subroutine. If the logic with the given ID is not loaded in memory, it is temporarily loaded and discarded after returning from the call (this takes extra time). call does not change any variables or flags.


return
return


    This command returns control to the interpreter if it is executed in Logic(0), or to the command following the call command which called the current logic.
:This command returns control to the interpreter if it is executed in Logic(0), or to the command following the '''call''' command which called the current logic.
jump <label>


    This command unconditionally transfers control to a command starting after label label within the same logic.
jump &lt;label&gt;
 
:This command unconditionally transfers control to a command starting after label '''label''' within the same logic.


set.scan.start(), reset.scan.start()
set.scan.start(), reset.scan.start()


    Normally, when a logic is called using call command, execution begins at the first instruction. set.scan.start command sets the entry point at the command following it, while reset.scan.start returns the entry point to the beginning.
:Normally, when a logic is called using call command, execution begins at the first instruction. '''set.scan.start''' command sets the entry point at the command following it, while '''reset.scan.start''' returns the entry point to the beginning.


===Object control commands===
===Object control commands===
Line 434: Line 504:
The interpreter controls the movement of objects in the screen automatically checking the following conditions:
The interpreter controls the movement of objects in the screen automatically checking the following conditions:


    * If an object priority is 0 it cannot cross an unconditional barrier (pixels with priority 0).
* If an object priority is 0 it cannot cross an unconditional barrier (pixels with priority 0).
    * If an object priority is 15 and a command ignore.block has not been given to it, it cannot cross a conditional barrier (pixels with priority 1) and leave the block set using the block command.
* If an object priority is 15 and a command '''ignore.block''' has not been given to it, it cannot cross a conditional barrier (pixels with priority 1) and leave the block set using the block command.
    * If an object has not been given ignore.horizon command, it cannot move above the horizon set using the set.horizon command.
* If an object has not been given '''ignore.horizon''' command, it cannot move above the horizon set using the '''set.horizon''' command.
    * An object should follow the conditions set using object.on.water and object.on.land commands (see below).
* An object should follow the conditions set using '''object.on.water''' and '''object.on.land''' commands (see below).


Object number 0 is called Ego. It is different from others in that the player may move it around using the keyboard.
Object number 0 is called Ego. It is different from others in that the player may move it around using the keyboard.
Object description commands


animate.obj(n)
animate.obj(n)


    Object number n is included in the list of object controlled by the interpreter. Objects not included in that list are considered inexistent!
:Object number n is included in the list of object controlled by the interpreter. Objects not included in that list are considered inexistent!


unanimate.all()
unanimate.all()


    All objects are removed from the control list and are considered inexistent.
:All objects are removed from the control list and are considered inexistent.


set.view(n,m), set.view.v(n,m)
set.view(n,m), set.view.v(n,m)


    Object n is associated with a VIEW resource number m (or pointed to by vm), which may be an image of the object.
:Object n is associated with a VIEW resource number m (or pointed to by vm), which may be an image of the object.


set.loop(n,m), set.loop.v(n,m)
set.loop(n,m), set.loop.v(n,m)


    Chooses a loop m (or vm) in the VIEW resource associated with the object n.
:Chooses a loop m (or vm) in the VIEW resource associated with the object n.


fix.loop(n)
fix.loop(n)


    Turns off automatic choice of loop number for the object number n.
:Turns off automatic choice of loop number for the object number n.


release.loop(n)
release.loop(n)


    <pre>Turns on automatic choice of loop number depending on the direction of motion of the object n.
:Turns on automatic choice of loop number depending on the direction of motion of the object n.
 


                           1
                           1
Line 476: Line 544:
                     6    |    4
                     6    |    4
                           5
                           5
     
   
 
:Automatic choice of the loop is done according to the table:
    Automatic choice of the loop is done according to the table:
 
        * for objects with fewer than 4 but more than 1 loops:


:* for objects with fewer than 4 but more than 1 loops:


               Direction  0  1  2  3  4  5  6  7  8
               Direction  0  1  2  3  4  5  6  7  8
                 Loop    x  x  0  0  0  x  1  1  1
                 Loop    x  x  0  0  0  x  1  1  1


        * for objects with more than 4 loops:
:* for objects with more than 4 loops:
 


               Direction  0  1  2  3  4  5  6  7  8
               Direction  0  1  2  3  4  5  6  7  8
                 Loop    x  3  0  0  0  2  1  1  1
                 Loop    x  3  0  0  0  2  1  1  1


    x means that the current loop number is retained.</pre>
:x means that the current loop number is retained.


set.cel(n,m), set.cel.v(n,m)
set.cel(n,m), set.cel.v(n,m)


    Selects a cel m in the current loop of the object n.
:Selects a cel m in the current loop of the object n.


last.cel(n,m)
last.cel(n,m)


    The number of the last cel of the current loop of the object n is stored in vm.
:The number of the last cel of the current loop of the object n is stored in vm.


current.cel(n,m)
current.cel(n,m)


    The number of the current cel of the object n is stored in vm.
:The number of the current cel of the object n is stored in vm.


current.loop(n,m)
current.loop(n,m)


    The number of the current loop of the object n is stored in vm.
:The number of the current loop of the object n is stored in vm.


current.view(n,m)
current.view(n,m)


    The number of the current VIEW resource associated with the object n is stored in vm.
:The number of the current VIEW resource associated with the object n is stored in vm.


set.priority(n,m), set.priority.v(n,m)
set.priority(n,m), set.priority.v(n,m)


    Set priority of the view of the object n to m (or vm).
:Set priority of the view of the object n to m (or vm).


release.priority(n)
release.priority(n)


    Turns on the automatic priority choice for the object n. The priority is set depending on the vertical coordinate of the object. This way, as an object moves down it approaches the viewer. See section Priority bands and control lines for a table of y coordinates and the associated priorities.
:Turns on the automatic priority choice for the object n. The priority is set depending on the vertical coordinate of the object. This way, as an object moves down it approaches the viewer. See [[AGI/Specifications/Overview#Priority section | Priority bands and control lines]] for a table of y coordinates and the associated priorities.


get.priority(n,m)
get.priority(n,m)


    The value of the current priority of the object n is stored in vm.
:The value of the current priority of the object n is stored in vm.


position(n,x,y), position.v(n,x,y)
position(n,x,y), position.v(n,x,y)


    Coordinates of the object n, not yet displayed on the screen, are set to x and y (or vx and vy).
:Coordinates of the object n, not yet displayed on the screen, are set to x and y (or vx and vy).


draw(n)
draw(n)


    Object n is shown on the screen. The image uses the values of the loop and the cel in the VIEW resource associated with the object n (see set.view), as well as the priority and coordinates of the object. If a command start.cycling is also issued, a looped animation for object n is shown until stopped (for example, with stop.cycling).
:Object n is shown on the screen. The image uses the values of the loop and the cel in the VIEW resource associated with the object n (see '''set.view'''), as well as the priority and coordinates of the object. If a command '''start.cycling''' is also issued, a looped animation for object n is shown until stopped (for example, with '''stop.cycling''').


erase(n)
erase(n)


    Object n is erased from the screen.
:Object n is erased from the screen.


get.posn(n,x,y)
get.posn(n,x,y)


    Coordinates of the object n are stored in vx and vy. Coordinates of the object are coordinates of the base point (bottom left corner) of cels of the VIEW resource associated with the object.
:Coordinates of the object n are stored in vx and vy. Coordinates of the object are coordinates of the base point (bottom left corner) of cels of the VIEW resource associated with the object.


    The interpreter automatically plays the animation (a loop in the VIEW resource) associated with the object, starting at the specified cel. The following commands control this process.
:The interpreter automatically plays the animation (a loop in the VIEW resource) associated with the object, starting at the specified cel. The following commands control this process.


start.cycling(n)
start.cycling(n)


    Enables automatic change of cels in a chosen (using set.loop) loop of a VIEW resource associated with the object n (using set.view).
:Enables automatic change of cels in a chosen (using set.loop) loop of a VIEW resource associated with the object n (using set.view).


stop.cycling(n)
stop.cycling(n)


    Disables automatic change of cels in a chosen (using set.loop) loop of a VIEW resource associated with the object n (using set.view).
:Disables automatic change of cels in a chosen (using set.loop) loop of a VIEW resource associated with the object n (using set.view).


normal.cycle(n)
normal.cycle(n)


    Cels of the loop associated with the object n follow in a normal order: 0, 1, 2, ..., k-1, 0, 1, 2, ...
:Cels of the loop associated with the object n follow in a normal order: 0, 1, 2, ..., k-1, 0, 1, 2, ...


reverse.cycle(n)
reverse.cycle(n)


    Cels of the loop associated with the object n follow a reverse order: k-1, k-2, ..., 1, 0, k-1, k-2, ..., 1, 0, ...
:Cels of the loop associated with the object n follow a reverse order: k-1, k-2, ..., 1, 0, k-1, k-2, ..., 1, 0, ...


end.of.loop(n,m)
end.of.loop(n,m)


    Plays the loop associated with the object n once, from the current cel to the last. When finished, fm is set to 1.
:Plays the loop associated with the object n once, from the current cel to the last. When finished, fm is set to 1.


reverse.loop(n,m)
reverse.loop(n,m)


    Plays the loop associated with the object n once in a reverse order, from the current cel to the first. When finished, fm is set to 1.
:Plays the loop associated with the object n once in a reverse order, from the current cel to the first. When finished, fm is set to 1.


cycle.time(n,m)
cycle.time(n,m)


    vm sets the time in interpreter cycles between cel changes for the object n. When vm = 1 cels are changed every cycle.
:vm sets the time in interpreter cycles between cel changes for the object n. When vm = 1 cels are changed every cycle.


===Object motion control commands===
===Object motion control commands===


The following commands can be given to the object included in the interpreter control list with animate.obj:
The following commands can be given to the object included in the interpreter control list with '''animate.obj''':


set.horizon(n)
set.horizon(n)


    Set the horizon to y = n.
:Set the horizon y coordinate to n.


ignore.horizon(n)
ignore.horizon(n)


    Object n moves regardless of the horizon position.
:Object n moves regardless of the horizon position.


observe.horizon(n)
observe.horizon(n)


    Object n cannot move above the horizon.
:Object n cannot move above the horizon.


block(x1,y1,x2,y2)
block(x1,y1,x2,y2)


    Sets a rectangular area (block).
:Sets a rectangular area (block).
 


         (x1, y1)
         (x1, y1)
Line 603: Line 667:
unblock()
unblock()


    Cancels previously set block.
:Cancels previously set block.


ignore.blocks(n)
ignore.blocks(n)


    Object n moves ignoring conditional barriers (pixels with priority 1) and a block set with the block command.
:Object n moves ignoring conditional barriers (pixels with priority 1) and a block set with the block command.


observe.blocks(n)
observe.blocks(n)


    Object n may not cross conditional barriers or leave the block.
:Object n may not cross conditional barriers or leave the block.


ignore.objs(n)
ignore.objs(n)


    Object n moves regardless of positions of other objects.
:Object n moves regardless of positions of other objects.


observe.objs(n)
observe.objs(n)


    Object n treats other objects as obstacles.
:Object n treats other objects as obstacles.


player.control()
player.control()


    The player is allowed to control Ego (object number 0) using the keyboard or the joystick.
:The player is allowed to control Ego (object number 0) using the keyboard or the joystick.


program.control()
program.control()


    The player is not allowed to control object 0 (Ego).
:The player is not allowed to control object 0 (Ego).


stop.motion(n)
stop.motion(n)


    Motion of object n is stopped. If n == 0, program.control is automatically executed.
:Motion of object n is stopped. If n == 0, '''program.control''' is automatically executed.


start.motion(n)
start.motion(n)


    Motion of object n is started. If n == 0 (Ego), player.control automatically executed.
:Motion of object n is started. If n == 0 (Ego), player.control automatically executed.


step.size(n,m)
step.size(n,m)


    vn determines the number of pixels the object n moves each step. (The actual value in pixels is the step size / 4! --CM)
:vn determines the number of pixels the object n moves each step. ''(The actual value in pixels is the step size / 4! --CM)''


step.time(n,m)
step.time(n,m)


    vn determines the speed of object n motion: delay in the interpreter cycles between consecutive steps. If vm = 1, step occurs on every cycle.
:vn determines the speed of object n motion: delay in the interpreter cycles between consecutive steps. If vm = 1, step occurs on every cycle.


move.obj(n,x,y,s,m), move.obj.v(n,x,y,s,m)
move.obj(n,x,y,s,m), move.obj.v(n,x,y,s,m)


    Object n is told to move to the point (x,y) (or vx, vy) by s pixels every step. When the destination is reached, fm is set to 1. If n == 0 (Ego), program.control is executed automatically.
:Object n is told to move to the point (x,y) (or vx, vy) by s pixels every step. When the destination is reached, fm is set to 1. If n == 0 (Ego), '''program.control''' is executed automatically.


follow.ego(n,s,m)
follow.ego(n,s,m)


    Object n is told to chase object 0 (Ego) by s pixels every step. When Ego and object coordinates become equal, fm is set to 1.
:Object n is told to chase object 0 (Ego) by s pixels every step. When Ego and object coordinates become equal, fm is set to 1.


wander(n)
wander(n)


    Object n randomly changes the direction of its motion (wanders). If n == 0 (Ego), program.control is issued automatically.
:Object n randomly changes the direction of its motion (wanders). If n == 0 (Ego), program.control is issued automatically.


normal.motion(n)
normal.motion(n)


    Special object motion mode is canceled. The object continues to move in the direction it was moving in at the time the command was issued.
:Special object motion mode is canceled. The object continues to move in the direction it was moving in at the time the command was issued.


set.dir(n,m)
set.dir(n,m)


    Object n is told to move in the direction vm.
:Object n is told to move in the direction vm.
 


                           1
                           1
Line 675: Line 738:
                     6    |    4
                     6    |    4
                           5
                           5
     


get.dir(n,m)
get.dir(n,m)


    Direction of object n motion is stored in vm.
:Direction of object n motion is stored in vm.


object.on.water(n)
object.on.water(n)


    Object n is allowed to be only in the area where its base line is completely on pixels with priority 3 (water surface).
:Object n is allowed to be only in the area where its base line is completely on pixels with priority 3 (water surface).


object.on.land(n)
object.on.land(n)


    Object n is not allowed to touch pixels of water surface (priority 3).
:Object n is not allowed to touch pixels of water surface (priority 3).


object.on.anything(n)
object.on.anything(n)


    Motion restrictions previously set on the object n with commands object.on.water or object.on.land are cancelled.
:Motion restrictions previously set on the object n with commands '''object.on.water''' or '''object.on.land''' are cancelled.


reposition(n,dx,dy)
reposition(n,dx,dy)


    Object n jumps from its current location into the location with coordinates (x + vdx, y + vdy).
:Object n jumps from its current location into the location with coordinates (x + vdx, y + vdy).


    (Shouldn't there be reposition and reposition.v? --VB)
::''(Shouldn't there be reposition and reposition.v? --VB)''


    (There should be, but they don't exist. --LE)
::''(There should be, but they don't exist. --LE)''


reposition.to(n,x,y), reposition.to.v(n,x,y)
reposition.to(n,x,y), reposition.to.v(n,x,y)


    Similar to the preceding command, but the object is moved to the point x, y (vx,vy).
:Similar to the preceding command, but the object is moved to the point x, y (vx,vy).


stop.update(n)
stop.update(n)


    Object n is removed from the list of objects updated by the interpreter on each step. The object stays on the screen unchanged.
:Object n is removed from the list of objects updated by the interpreter on each step. The object stays on the screen unchanged.


start.update(n)
start.update(n)


    Object n is redrawn on each interpreter step.
:Object n is redrawn on each interpreter step.


force.update(n)
force.update(n)


    Object n is redrawn immediately, without waiting for the end of the interpreter cycle.
:Object n is redrawn immediately, without waiting for the end of the interpreter cycle.


distance(n,m,d)
distance(n,m,d)


    If both objects n and m are on the screen, then
:If both objects n and m are on the screen, then  


    vd = abs(x(n) - x(m)) + abs(y(n) - y(m)),
<syntaxhighlight lang="cpp">vd = abs(x(n) - x(m)) + abs(y(n) - y(m))</syntaxhighlight>


    otherwise vd = 255.
, otherwise vd = 255.


===Inventory item management commands===
===Inventory item management commands===


OBJECT resources, stored in a separate file object, are most often used to represent inventory items. An item is a structure which consists of a one-byte field called room and a string of text, the item name.
OBJECT resources, stored in a separate file object, are most often used to represent inventory items. An item is a structure which consists of a one-byte field called room and a string of text (the member name).


If the room field of an item is 255, the item belongs to the player. Otherwise the item is considered to be in the room with the corresponding ID number.
If the room field of an item is 255, the item belongs to the player. Otherwise the item is considered to be in the room with the corresponding ID number.
Line 733: Line 795:
get(n), get.v(n)
get(n), get.v(n)


    Stores 255 in room field of an object n, which means that the player owns it.
:Stores 255 in room field of an object n, which means that the player owns it.


drop(n)
drop(n)


    Stores 0 in the room field of object n.
:Stores 0 in the room field of object n.


put(n,m), put.v(n,m)
put(n,m), put.v(n,m)


    Stores the value m (or vm) in the room field of the object n.
:Stores the value m (or vm) in the room field of the object n.


get.room.v(n,m)
get.room.v(n,m)


    Stores the value of the room field of object vn in vm.
:Stores the value of the room field of object vn in vm.


status()
status()


    The screen is switched to text mode; the top line displays ``You are carrying:'', then the names of the object with room field equal to 255 are listed. If there are no such objects, the word ``nothing'' is displayed.
:The screen is switched to text mode; the top line displays "You are carrying:", then the names of the object with room field equal to 255 are listed. If there are no such objects, the word "nothing" is displayed.


    If f13 is set (allow item selection), a highlight appears which allows the player to select an item name. When ENTER is pressed, the selected object number is stored in v25. When ESC is pressed, 255 is stored in v25.
:If f13 is set (allow item selection), a highlight appears which allows the player to select an item name. When ENTER is pressed, the selected object number is stored in v25. When ESC is pressed, 255 is stored in v25.


===Picture resource management commands===
===Picture resource management commands===


The following commands operate on PICTURE resources, loaded in the interpreter memory using load.pic:
The following commands operate on PICTURE resources, prepared using PM editor and loaded in the interpreter memory using '''load.pic''':


draw.pic(n)
draw.pic(n)


    A PICTURE resource number i, where i is the value of vn is executed. As the result, the background picture is created in the internal buffer of the interpreter. Before execution, the buffer is cleared, i.e. all pixels are set to colour 15 and priority 4.
:A PICTURE resource number i, where i is the value of vn is executed. As the result, the background picture is created in the internal buffer of the interpreter. Before execution, the buffer is cleared, i.e. all pixels are set to color 15 and priority 4.


overlay.pic(n)
overlay.pic(n)


    Just like the above, only the internal buffer is not cleared before drawing. Picture(vn) is drawn over the existing picture.
:Just like the above, only the internal buffer is not cleared before drawing. Picture(vn) is drawn over the existing picture.


add.to.pic(a,b,c,d,e,f,g), add.to.pic.v(a,b,c,d,e,f,g)
add.to.pic(a,b,c,d,e,f,g), add.to.pic.v(a,b,c,d,e,f,g)


    A picture of a VIEW resource is added to the background as its component. Typically, this is used to add small complicated details which would require too many PICTURE resource commands to draw.
:A picture of a VIEW resource is added to the background as its component. Typically, this is used to add small complicated details which would require too many PICTURE resource commands to draw.


    Parameters are:
:Parameters are:


        * a (va): number of the VIEW resource;
:* a (va): number of the VIEW resource;
        * b (vb): loop number;
:* b (vb): loop number;
        * c (vc): cel number;
:* c (vc): cel number;
        * d (vd): x coordinate;
:* d (vd): x coordinate;
        * e (ve): y coordinate;
:* e (ve): y coordinate;
        * f (vf): priority;
:* f (vf): priority;
        * g (vg): margin.
:* g (vg): margin.


    If margin is 0, 1, 2, or 3, the base of the cel is surrounded with a rectangle of the corresponding priority. If margin > 4, this extra margin is not shown.
:If margin is 0, 1, 2, or 3, the base of the cel is surrounded with a rectangle of the corresponding priority. If margin > 4, this extra margin is not shown.


show.pic()
show.pic()


    Shows internal buffer on the screen.
:Shows internal buffer on the screen.
 
    ATTENTION! Please use the following sequence of commands when loading PICTURE resources in the interpreter memory:


:ATTENTION! Please use the following sequence of commands when loading PICTURE resources in the interpreter memory:


<syntaxhighlight lang="cpp">
     load.pic(n);
     load.pic(n);
     draw.pic(n);
     draw.pic(n);
Line 793: Line 855:
     ...
     ...
     show.pic();
     show.pic();
</syntaxhighlight>


    Any other order may crash the interpreter without any diagnostic messages.
:Any other order may crash the interpreter without any diagnostic messages.


Sound resource management commands
===Sound resource management commands===


sound(n,m)
sound(n,m)


    Starts playback of the SOUND resource number n. When finished, fm is set to 1.
:Starts playback of the SOUND resource number n. When finished, fm is set to 1.


stop.sound()
stop.sound()


    Stops the playback.
:Stops the playback.


===Text management commands===
===Text management commands===
Line 810: Line 873:
prevent.input()
prevent.input()


    Prevents the user from entering anything using the keyboard.
:Prevents the user from entering anything using the keyboard.


accept.input()
accept.input()


    Allows the user to enter text using the keyboard.
:Allows the user to enter text using the keyboard.


print(n), print.v(n)
print(n), print.v(n)


    Opens a text window in the centre of the screen, where a message number n (or vn) from the messages field of the current LOGIC resource is displayed. Output mode is determined by f15 (see flag description). The message is a NULL-terminated string of text. In addition to letters, digits, and other symbols, the string may contain:
:Opens a text window in the centre of the screen, where a message number n (or vn) from the messages field of the current LOGIC resource is displayed. Output mode is determined by f15 (see [[AGI/Specifications/Internals#Flag | Flag description]]). The message is a NULL-terminated string of text. In addition to letters, digits, and other symbols, the string may contain:


        * Newline character (0x0A);
:* Newline character (0x0A);
        * Format element:
:* Format element:
              o %v<decimal number>: at this place the output will include a decimal value of variable with the given number.
:** %v<decimal number>: at this place the output will include a decimal value of variable with the given number.
              o %m <number>: the text of the message with the given number is inserted at this place.
:** %m <number>: the text of the message with the given number is inserted at this place.
              o %0 <number>: the name of the item with the given number is inserted at this place.
:** %0 <number>: the name of the item with the given number is inserted at this place.
              o %w <number>: a vocabulary word with the given number is inserted at this place.
:** %w <number>: a vocabulary word with the given number is inserted at this place.
              o %s <number>: a string variable with the given number is inserted at this place.
:** %s <number>: a string variable with the given number is inserted at this place.
              o %g <number>: a message with this number from message field of Logic(0) is inserted at this place.
:** %g <number>: a message with this number from message field of Logic(0) is inserted at this place.


    For %v, you can add a vertical line and a number of characters the output should take. In this case leading zeros are not suppressed in the output.
:For %v, you can add a vertical line and a number of characters the output should take. In this case leading zeros are not suppressed in the output.


     Example: %v34|2
     Example: %v34|2


    When you write your messages, remember that the interpreter wraps the text between the lines as needed when the message is displayed.
:When you write your messages, remember that the interpreter wraps the text between the lines as needed when the message is displayed.


display(r,c,n), display.v(r,c,n)
display(r,c,n), display.v(r,c,n)


    Prints a message number n (vn) in the row r (vr), starting with the column c (vc). No window is created, so it is up to the programmer to erase the output when it is no longer needed.
:Prints a message number n (vn) in the row r (vr), starting with the column c (vc). No window is created, so it is up to the programmer to erase the output when it is no longer needed.


print.at(n,x,y,l), print.at.v(n,x,y,l)
print.at(n,x,y,l), print.at.v(n,x,y,l)


    Analogous to print but the programmer can specify the window location. x, y, and l are constants specifying coordinates of the top left corner of the window and its width in character cells of a 40x25 screen.
:Analogous to print but the programmer can specify the window location. x, y, and l are constants specifying coordinates of the top left corner of the window and its width in character cells of a 40x25 screen.


version()
version()


    Prints interpreter version in the centre of the screen.
:Prints interpreter version in the centre of the screen.


text.screen()
text.screen()


    The screen switches to the text mode 40x25.
:The screen switches to the text mode 40x25.


graphics()
graphics()


    The screen returns to the graphics mode. The picture on the screen is restored.
:The screen returns to the graphics mode. The picture on the screen is restored.


set.cursor.char(n)
set.cursor.char(n)


    First byte of the message n is used as a text mode cursor.
:First byte of the message n is used as a text mode cursor.


set.text.attribute(fg,bg)
set.text.attribute(fg,bg)


    Sets foreground and background colours for display, get.num and get.string commands.
:Sets foreground and background colors for display, '''get.num''' and '''get.string''' commands.


clear.lines(n,m,c)
clear.lines(n,m,c)


    Clears text lines from n to m using colour c.
:Clears text lines from n to m using color c.


clear.text.rect(x1,y1,x2,y2,c)
clear.text.rect(x1,y1,x2,y2,c)


    Clears a rectangular area with top left corner coordinates (x1,y1) and bottom right coordinates (x2,y2) using colour c.
:Clears a rectangular area with top left corner coordinates (x1,y1) and bottom right coordinates (x2,y2) using color c.


status.line.on()
status.line.on()


    Shows the status line containing the current score and sound status (on/off).
:Shows the status line containing the current score and sound status (on/off).


status.line.off()
status.line.off()


    Removes the status line.
:Removes the status line.


===String management commands===
===String management commands===
Line 883: Line 946:
set.string(n,m)
set.string(n,m)


    Stores message number m in the string variable n.
:Stores message number m in the string variable n.


word.to.string(n,m)
word.to.string(n,m)


    Word number m of the user input is stored in sn.
:Word number m of the user input is stored in sn.


get.string(n,m,x,y,l)
get.string(n,m,x,y,l)


    User input is stored in sn. m is the number of the message used as the prompt. x, y and l are input position and maximum string length.
:User input is stored in sn. m is the number of the message used as the prompt. x, y and l are input position and maximum string length.


parse(n)
parse(n)


    Parses sn as if it was entered by the player.
:Parses sn as if it was entered by the player.


get.num(n,m)
get.num(n,m)


    Enters a number from the keyboard into vm. Message n is used as the prompt.
:Enters a number from the keyboard into vm. Message n is used as the prompt.


===Initialization commands===
===Initialization commands===
Line 905: Line 968:
set.key(s,c)
set.key(s,c)


    Set interpreter's special key. c is the key code (decimal number from 0 to 255) and s (if the key is a regular, or CTRL+key pair). the ASCII code (for example, TAB is 0x0009). If the key is a function key or ALT+key pair, the corresponding IBM-PC keyboard scan code is in the high byte of s. For example, the scan code of F1 is 0x3B00, ALT+Z is 0x2C00.
:Set interpreter's special key. c is the key code (decimal number from 0 to 255) and s (if the key is a regular, or CTRL+key pair). the ASCII code (for example, TAB is 0x0009). If the key is a function key or ALT+key pair, the corresponding IBM-PC keyboard scan code is in the high byte of s. For example, the scan code of F1 is 0x3B00, ALT+Z is 0x2C00.


    Does ``key code'' mean the key scan code, or the ASCII code of the character? Is the IBM-PC scan code valid in other platforms as well? -- CM
::''Does "key code" mean the key scan code, or the ASCII code of the character? Is the IBM-PC scan code valid in other platforms as well? -- CM''


set.game.id(n)
set.game.id(n)


    Message n is scanned by the interpreter and compared with its internal identifier. On mismatch, the program exits. For the AGDS interpreter the identifier is ``TQ''. See also section Game IDs.
:Message n is scanned by the interpreter and compared with its internal identifier. On mismatch, the program exits. For the AGDS interpreter the identifier is "TQ". See also [[AGI/Specifications/Internals#Game_IDs_and_loaders | section Game IDs and loaders]].


script.size(n)
script.size(n)


    Sets the size of script table in bytes. Script table stores codes of some interpreter commands. It is needed by the interpreter to correctly reload resources when restore_game is executed.
:Sets the size of script table in bytes. Script table stores codes of some interpreter commands. It is needed by the interpreter to correctly reload resources when restore_game is executed.


trace.info(n,m,l)
trace.info(n,m,l)


    Sets the built-in debugger parameters. n is the number of LOGIC resource with command names, and m and l are the first line and height of the debugger window.
:Sets the built-in debugger parameters. n is the number of LOGIC resource with command names, and m and l are the first line and height of the debugger window.


trace.on()
trace.on()


    Turns on the debugger. In general, the debugger is turned on with SCROLL LOCK key when the command name table is loaded even if this command does not occur in the program.
:Turns on the debugger. In general, the debugger is turned on with SCROLL LOCK key when the command name table is loaded even if this command does not occur in the program.


log(n)
log(n)


    This is a debugging command. It writes a log message in the format
:This is a debugging command. It writes a log message in the format
 


         Room <current room> Input line <current input line> ... message ...
         Room <current room> Input line <current input line> ... message ...


    where the message is given by number n. Output is sent to a file.
:where the message is given by number n. Output is sent to a file.


    (Are these debugging commands valid only for AGDS, or they work in AGI as well? --CM)
::''(Are these debugging commands valid only for AGDS, or they work in AGI as well? --CM)''


===Menu management commands===
===Menu management commands===
Line 942: Line 1,004:
set.menu(n)
set.menu(n)


    Message n is used as the header of the menu elements which follow.
:Message n is used as the header of the menu elements which follow.


set.menu.item(n,c)
set.menu.item(n,c)


    Message n is used as a menu element, where c is this element's code (a number between 0 and 255).
:Message n is used as a menu element, where c is this element's code (a number between 0 and 255).


submit.menu()
submit.menu()


    Ends menu creation.
:Ends menu creation.


enable.item(c), disable.item(c)
enable.item(c), disable.item(c)


    Enables or disables a menu item with the code c.
:Enables or disables a menu item with the code c.




Line 974: Line 1,036:
menu.input()
menu.input()


    If f14 is set, a menu system is shown on the screen, allowing the user to choose an item. Whether an item with the code c has been chosen can be tested using a command controller(c), where c is the code assigned to the menu item.
:If f14 is set, a menu system is shown on the screen, allowing the user to choose an item. Whether an item with the code c has been chosen can be tested using a command controller(c), where c is the code assigned to the menu item.


===Logical commands===
===Logical test commands===
====Test commands====


The result of test command can be either TRUE or FALSE.
The result of test command can be either TRUE or FALSE.
Line 983: Line 1,044:
equaln(n,m)
equaln(n,m)


    TRUE if vn = m.
:TRUE if vn = m.


equalv(n,m)
equalv(n,m)


    true if vn = vm.
:true if vn = vm.


lessn(n,m)
lessn(n,m)


    TRUE if vn < m.
:TRUE if vn < m.


lessv(n,m)
lessv(n,m)


    TRUE if vn < vm.
:TRUE if vn < vm.


greatern(n,m)
greatern(n,m)


    TRUE if vn > m.
:TRUE if vn > m.


greaterv(n,m)
greaterv(n,m)


    TRUE if vn > vm.
:TRUE if vn > vm.


isset(n)
isset(n)


    TRUE if fn is set.
:TRUE if fn is set.
 
isset.v(n)
isset.v(n)


    TRUE if Flag(vn) is set.
:TRUE if Flag(vn) is set.


has(n)
has(n)


    TRUE if the room field of item n is 255, i.e. the item belongs to the player.
:TRUE if the room field of item n is 255, i.e. the item belongs to the player.


obj.in.room(n,m)
obj.in.room(n,m)


    TRUE if room field of the object n is vm.
:TRUE if room field of the object n is vm.


posn(n,x1,y1,x2,y2)
posn(n,x1,y1,x2,y2)


    TRUE if the coordinates of the base point of the cel which is the current image of object n satisfies the equations x1 <= x <= x2 and y1 <= y <= y2.
:TRUE if the coordinates of the base point of the cel which is the current image of object n satisfies the equations x1 <= x <= x2 and y1 <= y <= y2.


obj.in.box(n,x1,y1,x2,y2)
obj.in.box(n,x1,y1,x2,y2)


    TRUE if the base of the object n is completely within the rectangle specified using its top left (x1,y1) and bottom right (x2,y2) corners.
:TRUE if the base of the object n is completely within the rectangle specified using its top left (x1,y1) and bottom right (x2,y2) corners.




Line 1,039: Line 1,101:
center.position(n,x1,y1,x2,y2)
center.position(n,x1,y1,x2,y2)


    TRUE of the center of the base line of the object n is inside the rectangle specified as its top left and bottom right corners.
:TRUE of the center of the base line of the object n is inside the rectangle specified as its top left and bottom right corners.
right.position(n,x1,y1,x2,y2)
right.position(n,x1,y1,x2,y2)


    TRUE of the right side of the base line of the object n is inside the rectangle specified as its top left and bottom right corners.
:TRUE of the right side of the base line of the object n is inside the rectangle specified as its top left and bottom right corners.


have.key()
have.key()


    TRUE if the user has pressed any key on the keyboard. Used to create cycles to wait until any key is pressed.
:TRUE if the user has pressed any key on the keyboard. Used to create cycles to wait until any key is pressed.


compare.strings(s1,s2)
compare.strings(s1,s2)


    TRUE if s1 == s2.
:TRUE if s1 == s2.


said(n,W(i))
said(n,W(i))


    where i = 1, ..., n.
:where i = 1, ..., n.


    See section Player input parsing.
:See section Player input parsing.


controller(n)
controller(n)


    TRUE if the event with code n has occurred:
:TRUE if the event with code n has occurred:


        * a key with the code n was pressed (set using set_key);
:* a key with the code n was pressed (set using set_key);
        * menu item with code n was selected in command menu_input.
:* menu item with code n was selected in command menu_input.


====Other commands====
====Other commands====
Line 1,069: Line 1,131:
configure.screen(a,b,c)
configure.screen(a,b,c)


    Sets position of lines on the screen, where a = 1 (the minimum line number for print), b is the user input line and c is the status line.
:Sets position of lines on the screen, where a = 1 (the minimum line number for print), b is the user input line and c is the status line.


    (Sounds confuse --CM)
::''(Sounds confusing --CM)''


obj.status.v(n)
obj.status.v(n)


    Prints a message for the object vn in the format
:Prints a message for the object vn in the format


 
         Obj &lt;n&gt; x: &lt;pos&gt; y: <pos> pri: <priority> stepsize: &lt;step size&gt;.
         Obj <n> x: <pos> y: <pos> pri: <priority> stepsize: <step size>.


show.mem()
show.mem()


    Displays a report of the interpreter memory status.
:Displays a report of the interpreter memory status.


show.pri.screen()
show.pri.screen()


    Shows priorities of the screen pixels. Priority n is shown as color number n (see color setting commands in I.1.2.1.1).
:Shows priorities of the screen pixels. Priority n is shown as color number n (see color setting commands in I.1.2.1.1).


show.obj(n)
show.obj(n)


    Show cel 0 of loop 0 of the VIEW resource n in the bottom center of the screen. In the center of the screen, a message associated with the VIEW resource is printed.
:Show cel 0 of loop 0 of the VIEW resource n in the bottom center of the screen. In the center of the screen, a message associated with the VIEW resource is printed.


    (That's what they say but I suspect they mean OBJECT n, not VIEW resource. --VB)
::''(That's what they say but I suspect they mean OBJECT n, not VIEW resource. --VB)''


    (Actually, in this case the argument does refer to the VIEW resource. This is because the VIEW in question isn't meant to be a controlled object but instead is simply the picture and textual description of the an inventory item. --LE)
::''(Actually, in this case the argument does refer to the VIEW resource. This is because the VIEW in question isn't meant to be a controlled object but instead is simply the picture and textual description of the an inventory item. --LE)''


shake.screen(n)
shake.screen(n)


    The screen shakes n times.
:The screen shakes n times.


echo.line()
echo.line()


    The last line entered by the user is displayed in the input line.
:The last line entered by the user is displayed in the input line.


cancel.line()
cancel.line()


    Input line is cleared.
:Input line is cleared.


close.window()
close.window()


    If there is a text window on the screen, it is removed.
:If there is a text window on the screen, it is removed.


open.dialogue, close.dialogue()
open.dialogue, close.dialogue()


    Enables and disables get.string and get.num commands if prevent.input has been issued.
:Enables and disables get.string and get.num commands if prevent.input has been issued.


restart.game()
restart.game()


    Restarts the game from the very beginning.
:Restarts the game from the very beginning.


save.game, restore.game()
save.game, restore.game()


    These command save and restore the current state of the game into disk files.
:These command save and restore the current state of the game into disk files.


pause()
pause()


    Stops the interpreter until any key is pressed.
:Stops the interpreter until any key is pressed.


quit(n)
quit(n)


    Exits the interpreter. If n = 1, quits immediately. If n = 0, asks ``Press ENTER to quit. Press ESC to continue.''
:Exits the interpreter. If n = 1, quits immediately. If n = 0, asks "Press ENTER to quit. Press ESC to continue."


init.joy()
init.joy()


    Initialize joystick.
:Initialize joystick.


toggle.monitor()
toggle.monitor()


    Switch RGB monitor into the graphics mode.
:Switch RGB monitor into the graphics mode.
 
upper.left()
upper.left()


    Usually the crossing by an object of various areas and lines is tracked by the base point (bottom right corner) of its cel. After this command, top left corner is used as such a point.
:Usually the crossing by an object of various areas and lines is tracked by the base point (bottom right corner) of its cel. After this command, top left corner is used as such a point.


===Other commands===
===Other commands===
Line 1,149: Line 1,211:
unknown170(n)
unknown170(n)


    This command modifies the behavior of the commands restore.game() and save.game().
:This command modifies the behavior of the commands restore.game() and save.game().


    After calling unknown170(n), where n is a string number (ie: if n == 2 then s2) restore.game() will automatically (without any prompt) restore a savegame with the name stored in string number n and save.game() will automatically save a savegame with the name of string number n.
:After calling unknown170(n), where n is a string number (ie: if n == 2 then s2) restore.game() will automatically (without any prompt) restore a savegame with the name stored in string number n and save.game() will automatically save a savegame with the name of string number n.


    Note: make sure that at least one savegame is present when you call restore.game() or save.game() (that is, when saving a game too).
:Note: make sure that at least one savegame is present when you call restore.game() or save.game() (that is, when saving a game too).
 
    <pre>Example:


:Example:


<syntaxhighlight lang="cpp">
     set.string(s1,"test");
     set.string(s1,"test");
     unknown170(1);
     unknown170(1);
</syntaxhighlight>


    will automatically load the savegame named ``test''.</pre>
:will automatically load the savegame named "test".


    Note: AGI256 uses this command
:Note: AGI256 uses this command


unknown173(n)
unknown173(n)


    This command changes the way that ego is controlled. After calling unknown173(), Ego will only move when a direction key is maintained pressed. If the key is released, ego will stop walking. See also command unknown181().
:This command changes the way that ego is controlled. After calling unknown173(), Ego will only move when a direction key is maintained pressed. If the key is released, ego will stop walking. See also command unknown181().


unknown177(n)
unknown177(n)


    This command control the access to the menu. unknown177(0) will disable access to the menu, even if flag 14 (menu_enabled) is set. Calling unknown177() with a value greater than 0 seem to do nothing else than enabling access to the menu.
:This command control the access to the menu. unknown177(0) will disable access to the menu, even if flag 14 (menu_enabled) is set. Calling unknown177() with a value greater than 0 seem to do nothing else than enabling access to the menu.


unknown181(n)
unknown181(n)


    This command restablishes the default control of Ego. It is normally used after a call to unknown173().
:This command reestablishes the default control of Ego. It is normally used after a call to unknown173().


Note: Be aware that commands 175, 176, 178, 179 and 180 of the last version of AGI (ver 3.002.149) do absolutely nothing.
:Note: Be aware that commands 175, 176, 178, 179 and 180 of the last version of AGI (ver 3.002.149) do absolutely nothing.


<span id="Sample"></span>
<span id="Sample"></span>
Line 1,185: Line 1,248:
(Last updated: 31 August 1997).
(Last updated: 31 August 1997).


Some of you may know that ''The Official Book of King's Quest'' included three small fragments of AGI code for room 7 in the AGI version of KQ4. These fragments are given below along with the same fragments taken from the game itself. There are a few differences which is to be expected but generally the code is very similar. These examples show how the coder wrote the code and what it now looks like in the final product. I've included a few comments where some interesting observations can be seen.
Some of you may know that "The Official Book of King's Quest" included three small fragments of AGI code for room 7 in the AGI version of KQ4. These fragments are given below along with the same fragments taken from the game itself. There are a few differences which is to be expected but generally the code is very similar. These examples show how the coder wrote the code and what it now looks like in the final product. I've included a few comments where some interesting observations can be seen.
Animating the smoke
Animating the smoke


From the book:
From the book:


<pre>animate.obj( smoke);
<syntaxhighlight lang="cpp">
ignore.horizon( smoke);
animate.obj(smoke);
set.view( smoke, v.fish.cabin);
ignore.horizon(smoke);
set.loop( smoke, 1);
set.view(smoke, v.fish.cabin);
ignore.blocks( smoke);
set.loop(smoke, 1);
position( smoke, 95, 16);
ignore.blocks(smoke);
position(smoke, 95, 16);
work = 3;
work = 3;
step.time( smoke, work);
step.time(smoke, work);
cycle.time( smoke, work);
cycle.time(smoke, work);
draw( smoke);</pre>
draw(smoke);
</syntaxhighlight>


From the game:
From the game:


<pre>animate.obj(7);
<syntaxhighlight lang="cpp">
animate.obj(7);
ignore.horizon(7);
ignore.horizon(7);
set.view(7, 114);
set.view(7, 114);
set.loop(7, 1);
set.loop(7, 1);
ignore.objs(7);                [ These two lines have been added.
ignore.objs(7);                // These two lines have been added.
set.priority(7, 5);            [
set.priority(7, 5);            //
ignore.blocks(7);
ignore.blocks(7);
position(7, 95, 16);
position(7, 95, 16);
assignn(152, 3);              [ Equivalent to 'work = 3;'
assignn(152, 3);              // Equivalent to 'work = 3;'
step.time(7, 152);
step.time(7, 152);
cycle.time(7, 152);
cycle.time(7, 152);
draw(7);</pre>
draw(7);
</syntaxhighlight>


Opening the door
Opening the door
Line 1,220: Line 1,287:
From the book:
From the book:


<pre>if (said( open, door)) {    [ must be close enough
<syntaxhighlight lang="cpp">
if (said( open, door)) {    // must be close enough
   if (posn( ego, 86, 120, 106, 133)) {
   if (posn( ego, 86, 120, 106, 133)) {
     if (!night) {
     if (!night) {
       if ( door.open) {
       if ( door.open) {
         print("The door is already open. . .
         print("The door is already open. . .");
       }
       }
       else {
       else {
Line 1,234: Line 1,302:
     }
     }
     else {
     else {
       print("You can't -- it's locked...
       print("You can't -- it's locked...");
     }
     }
   }
   }
Line 1,240: Line 1,308:
     set( notCloseEnough);
     set( notCloseEnough);
   }
   }
}</pre>
}
</syntaxhighlight>


From the game:
From the game:


<pre>if (said(OPEN, DOOR||DOORS||DOORWAY||DOORWAYS)) {
<syntaxhighlight lang="cpp">
if (said(OPEN, DOOR||DOORS||DOORWAY||DOORWAYS)) {
   if (posn(0, 86, 120, 106, 133)) {
   if (posn(0, 86, 120, 106, 133)) {
     if (!isset(38)) {
     if (!isset(38)) {
Line 1,268: Line 1,338:
     set(113);
     set(113);
   }
   }
}</pre>
}
</syntaxhighlight>


===Unlocking the door===
===Unlocking the door===
Line 1,274: Line 1,345:
From the book:
From the book:


<pre>if (said( unlock, door)) {    [must be close enough
<syntaxhighlight lang="cpp">
if (said( unlock, door)) {    // must be close enough
   if (posn( ego, 86, 120, 106, 133)) {
   if (posn( ego, 86, 120, 106, 133)) {
     if (!night) {
     if (!night) {
       print("The door is already unlocked. . .
       print("The door is already unlocked. . .");
     }
     }
     else {
     else {
       printf("You can't, it's locked. . .
       printf("You can't, it's locked. . .");
     }
     }
   }
   }
Line 1,286: Line 1,358:
     set( notCloseEnough);
     set( notCloseEnough);
   }
   }
}</pre>
}
</syntaxhighlight>


From the game:
From the game:


<pre>if (said(UNLATCH||UNLOCK, DOOR||DOORS||DOORWAY||DOORWAYS)) {
<syntaxhighlight lang="cpp">
if (said(UNLATCH||UNLOCK, DOOR||DOORS||DOORWAY||DOORWAYS)) {
   if (posn(0, 86, 120, 106, 133)) {
   if (posn(0, 86, 120, 106, 133)) {
     if (!isset(38)) {
     if (!isset(38)) {
Line 1,303: Line 1,377:
     set(113);
     set(113);
   }
   }
}</pre>
}
</syntaxhighlight>


===Knocking on the door===
===Knocking on the door===
Line 1,309: Line 1,384:
From the book:
From the book:


<pre>if ((said( knock, at, door) || said( knock) ||
<syntaxhighlight lang="cpp">
if ((said( knock, at, door) || said( knock) ||
     said( knock, on, door) || said( knock, door)) {
     said( knock, on, door) || said( knock, door)) {
   if (posn( ego, 86, 120, 106, 133)) {
   if (posn( ego, 86, 120, 106, 133)) {
     if (!night) {
     if (!night) {
       print("You knock on the door. . .
       print("You knock on the door. . .
             a woman says. . .
             a woman says. . .");
     }
     }
     else {
     else {
       printf("You knock on the. . .
       printf("You knock on the. . .
               a man calls out. . .
               a man calls out. . .");
     }
     }
   }
   }
Line 1,324: Line 1,400:
     set( notCloseEnough);
     set( notCloseEnough);
   }
   }
}</pre>
}
</syntaxhighlight>


From the game:
From the game:


<pre>if (said(BANG||KNOCK||RAP||TAP) ||
<syntaxhighlight lang="cpp">
if (said(BANG||KNOCK||RAP||TAP) ||
     said(BANG||KNOCK||RAP||TAP, DOOR||DOORS||DOORWAY||DOORWAYS)) {
     said(BANG||KNOCK||RAP||TAP, DOOR||DOORS||DOORWAY||DOORWAYS)) {
   if (posn(0, 86, 120, 106, 133)) {
   if (posn(0, 86, 120, 106, 133)) {
Line 1,344: Line 1,422:
     set(113);
     set(113);
   }
   }
}</pre>
}
</syntaxhighlight>
 
===Fall rocks===


Fall rocks
{| border=0 align=center
|[[Image:Agispec-kq4_fall_rocks.png|320px|left|frame|King's Quest IV fall rocks]]
|}


From the book:
From the book:


<pre>if (hit.special) {
<syntaxhighlight lang="cpp">
if (hit.special) {
   if ((rf2 || rf3 || rf4)) {
   if ((rf2 || rf3 || rf4)) {
     reset(hit.special);
     reset(hit.special);
Line 1,395: Line 1,479:
     }
     }
   }
   }
}</pre>
}
</syntaxhighlight>


From the game:
From the game:


<pre>if (isset(3)) {    [ hit.special
<syntaxhighlight lang="cpp">
   if (isset(222) || isset(223) || isset(224)) {    [ rf2, rf3, rf4
if (isset(3)) {    [ hit.special
   if (isset(222) || isset(223) || isset(224)) {    // rf2, rf3, rf4
     reset(3);
     reset(3);
     sound(51, 154);
     sound(51, 154);
Line 1,447: Line 1,533:
     }
     }
   }
   }
}</pre>
}
</syntaxhighlight>
TrustedUser
2,147

edits

Navigation menu