
                   Object Oriented Programming in Script

                          Author: Jeff Stephenson
                            Date: 4 April 1988



                            SIERRA CONFIDENTIAL

                             Table of Contents



Object Oriented Programming  . . . . . . . . . . . . . . . . . . . . . .   3

Object Oriented Terminology  . . . . . . . . . . . . . . . . . . . . . .   6

Classes  . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .   8
     Defining Classes  . . . . . . . . . . . . . . . . . . . . . . . . .   8
     Compiling Classes . . . . . . . . . . . . . . . . . . . . . . . . .   9

Objects  . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .  11

Sending Messages . . . . . . . . . . . . . . . . . . . . . . . . . . . .  12

An Extended Example  . . . . . . . . . . . . . . . . . . . . . . . . . .  13


                        Object Oriented Programming


Object oriented programming (OOP) is a relatively new paradigm in
programming.  The Smalltalk language, developed at Xerox PARC, was the
first language to fully use the concept of OOP.  Since then, many languages
(such as C++, Scheme, Objective C, and Actor) have incorporated the concepts
to different degrees.  Because of the power of OOP for things such as
simulations (and after all, what are adventure games?), Script was designed
with the intention that much of the programming would use this concept. 
Those of us using the language over the last several months have found
ourselves moving more and more away from its procedural aspects and toward
the OOP aspects -- rooms, dialogs, menus, everything is now an object of one
sort or another.

OOP languages basically turn the data/procedure relationship in
conventional programming inside out: instead of sending data to a procedure
for the procedure to act upon, we send a message to data (an object) telling
it what to do.  This allows the sender of the message to obtain a service
from the receiver object with no knowledge of how this service is performed,
something which is not possible in procedural languages.

As an example, consider displaying the 'value' of data elements in a
program in a procedural language and then an OOP language.  In this example,
we'll assume that the procedural language is untyped (as opposed to the
current direction of strong typing in C, Ada, Pascal, etc.).  Strong typing
would make the follow exercise even harder.  To make the example more
concrete, we'll imagine that we want to be able to display one of two data
element types: a list of strings or an array of integers.

Procedurally, we'll use a C-like language (with lots of extensions which
don't exist in C) and write

     Show(data)
     /* Here's one place C would have a problem -- data could either be
      * a list of strings or an array of integers.  What type does one
      * declare?
      */
     {
          switch (typeof(data)) {       /* how is typeof() implemented? */
               case stringList:
                    for (str = ListStart(data) ;
                         str != NULL ;
                         str = ListNext(data)
                        )
                              printf(str);
                    break;
               case integerArray:
                    for (i = 0 ; i < sizeof(data) ; ++i)
                         printf("%d", data[i]);
                    break;
               }
     }

Note that one could not easily write this in C because of strong data typing
and the difficulty of implementing both typeof() and this particular use of
sizeof().  What usually ends up happening in a procedural language is that
instead of one general-purpose Show() procedure, one writes a lot of
special purpose ShowStringList() and ShowIntegerArray() procedures and
whoever wants to display something has to be aware of the type of data being
displayed and call the appropriate procedure.

Contrast this with object-oriented programming.  Either type of data can be
displayed by simply sending the data object the show message:

     (data show:)

Since both Arrays and Lists are sub-types of the Collection type they
implement this in the same way (they actually share the code):

     (method (show)
          (self eachElementDo: #show:)
     )

Both the list and the array simple send each of their elements the message
requesting the element to display itself.  The elements, strings and
integers, implement the show method in different manners.  The show method
for a string might be

     (method (show)
          (Print str)
     )

whereas that for the integer might be

     (method (show)
          (Print "%d" number)
     )

Note how much simpler the OOP code is than the procedural code.  This is
because the responsibility for displaying something is delegated to the
object being displayed, freeing the calling code from knowing anything
about it.  In fact, because of this passing on of responsibility, the above
code will also handle lists which contain elements of several data types --
(data show:) would also work if data were a list which contained a string,
an integer, a list of integers, an array of strings, and a list of arrays of
lists of strings.  No change in code is necessary.

Another benefit of the OOP code is that adding a new data type is as easy as
writing the show method for the data type.  In the procedural code, the
Show() procedure would need re-writing, as would the typeof() and sizeof()
procedures -- the addition of the new type propagates throughout the code
rather than remaining isolated in the new type.


Rather than continuing to give examples in an unspecified language, we will
first define the terms to be used in discussions of OOP languages and then
give the syntax and commands which Script uses.  Following that will be more
examples of the use of OOP in adventure game coding.Object Oriented Terminology

Property:
     Properties are data associated with an object.  A door object might
     have such properties as the room number into which it opens, its state
     (open or closed), and its position on the screen.

Method:
     A method is a procedure which is internal to an object or class.  A
     door object might have a method open which causes the door to change
     state from closed to open.

Message:
     Methods of an object are invoked by sending the object messages.  In
     Script a message is sent to an object by enclosing the object name,
     then the message, in parenthesis (much like a procedure call):

          (doorToCloset open:)

     sends the open: message to the object doorToCloset.

Selector:
     Selectors are used in messages to indicate the method which is to be
     invoked.  The symbol open: in the above example of messaging is the
     selector for the open method.

Object:
     An object is a collection of properties and methods bundled together,
     and should be considered to be a distinct entity (hence the use of the
     word 'object').

Class:
     A class is a 'generic' object of a certain type.  It has no real
     existence of its own, but provides the default methods and property
     values to those objects which are instances (see below) of it.  Classes
     may have sub-classes, which are more specific types of a class (for
     example, the class SlidingDoor is a sub-class of the class Door) and
     super-classes, which are generalizations of the class (the class
     Opening might be a super-class of the class Door).

Instance:
     An instance of a class is a 'concrete' object which has the properties
     and methods of the class, but whose properties are distinctly its own. 
     For example the object doorToCloset is an instance of the class Door
     which is different from the object doorToPatio, another instance of
     class Door.  Changing the property values of an instance (object) of a
     class will not affect the property values of other instances of the
     class.

Inheritance:
     Inheritance is one of the most important concepts in OOP, and is
     responsible for much of its power.  A sub-class inherits all the
     methods and properties of its super-class, then goes on to add its own
     distinct properties and methods, or to modify an inherited method from
     its super-class.  We might define the class ElevatorDoor as a sub-
     class of the class Door.  It would thus inherit the properties of Door
     but would add a property to tell whether the light associated with the
     door is on or off.  It would also inherit Door's methods, but would
     modify the open method to not only change the state of the ElevatorDoor
     to open, but also to change the state of the light property to on. 
     All other methods work just the same as for the Door class.

Self:
     Often, an object needs to invoke one of its own methods, without really
     knowing who it is (it may be executing code inherited from its super-
     class).  This is done by sending a message to the object self, which is
     always the object which invoked the current method.

Super:
     An important factor in using inheritance to define new methods is being
     able to get access to the super-class's code for a method within the
     newly defined method.  The class super is provided for this purpose --
     sending a message to class super invokes the method within the super-
     class of self, rather than the method within self.  Thus, the open
     method for the class ElevatorDoor might contain the code

          (super open:)
          (= lightState on)

     which calls upon the open method of the class Door to do its stuff,
     then sets the light state to on.


                             A Note on Naming

There are a number of conventions which are normally (but not universally)
followed in naming things in object oriented programming.  Properties, being
data, usually have names which are nouns; methods, being actions on data,
usually have names which are verbs; classes and instances, which may
represent either concrete objects or actions, may have either nouns or verbs
as names.

The first letter of property, method, and instance names is lowercase,
whereas the first letter of class name is uppercase.  In both types of
names, succeeding words in the names are set off in the name by capitalizing
the first letter of the word, e.g. AutomaticDoor or elevatorDoor.

                                  Classes


                             Defining Classes

The first step in any object-oriented programming project is to define the
classes which will be used in the project.  Generally there is already a
large library of classes to draw on (in this case the classes documented in
Script Classes for Adventure Games), and often these classes are all one
will need in the project.  However, in order to define new classes and to
understand the old ones, it is necessary to understand the class statement
for defining a class.

The form of the class statement is:

     (class aClass kindof superClass
          (properties
               aProperty value
               ...
          )

          (methods
               aMethod
               ...
          )

          (method (aMethod [p1 p2 ...] [&tmp t1 t2 ...])
               code
          )
          ...

          [(procedure ...)]
     )

This statement defines aClass as a sub-class (kindof) superClass.  This
means that it inherits all of superClass' properties and methods, and will
either modify or add to them.  In order for the sc compiler to compile this
class definition, superClass must either have been defined earlier in the
current source file or in another file which will be compiled before this
file will be compiled, adding the super-class definition to the file
classdef (more on this at the end of this section).

The properties section of the class statement is where new properties are
introduced and old default property values redefined.  All entries in this
section are of the form aProperty value where aProperty is a symbol and
value is a constant expression.  If aProperty is not a property of
superClass, it is added as a new property in the class being defined and its
default value is value.  If the property exists in superClass, its default
value for the class being defined is just changed to value.

The methods section of the class statement lists any symbols which will be
the names of methods added to superClass to create the class being defined. 
Listing a method which is already defined in superClass does nothing, and a
method name need not be listed in the methods section if it is only being
redefined.

The method statement in the class statement is almost identical to the
procedure statement described in The Script Programming Language.  It
differs in that the properties of the class in which the method is defined
can be accessed as if they were variables, i.e. by simply using their names. 
Also, code in a method definition is the only place in which sends to the
objects self and super are valid.  Only methods inherited from the super-
class or listed in the methods section may be defined.  As in procedures,
the compiler-defined variable argc gives the number of parameters passed to
the method.

Note that procedures may also be included in a class statement.  These
procedures can be used by the methods defined within the class, but cannot
be accessed from outside the class definition.


                             Compiling Classes

Source files containing class definitions are compiled with the sc compiler
just like any other source file.  There are some subtleties involved where
class definitions are concerned, however, arising from the fact that all
sub-classes of a class must be defined after the class' definition.  Thus
the order of source file compilation is very important -- the files
containing the lowest level classes (such as Object) must be compiled first,
followed by successive sub-classes.  An understanding of how the compiler
maintains information on all the classes will clarify how the class
compilation process works.

Two files, classdef and selector constitute the database in which the
compiler tracks the classes being defined.  The first thing that the
compiler does when compiling a file is to read in the file selector, which
defines the symbols which are known to be selectors and the selector numbers
corresponding to them.  From this it also obtains the largest selector
number currently defined, which will mark the point from which it will
assign new selector numbers when they are needed.  If you are compiling on a
network, this file will be locked when you start compiling.  This prevents
anyone else from starting a compile (and possibly changing the information
in the database) while you are using it.

The compiler next reads the file classdef (if it exists), from which it
obtains information about the classes which have already been compiled.  The
information in classdef includes the class number (assigned by the
compiler), the number of the script in which it is defined, the class number
of the class' super-class, the names of the class' methods, and the names of
the class' properties with their default values.

The compiler now gets around to reading your source code.  As the compiler
encounters each class definition, it records in its class symbol table the
characteristics of the class.  If the class already has an entry in the
symbol table because it has been previously defined, that entry is cleared
and the class is redefined using the current source code.  This guarantees
that the compiler is always using the most current class definition.

The class definition is built from the information contained in the methods
and properties sections -- the selectors encountered here are added to those
inherited from the class' super-class to arrive at the structure of the
class being defined.  Any symbol encountered in a properties or methods
section of a class definition is looked up in a special symbol table for
selectors.  If it is not present there, it is entered in the selector table
and assigned the next available selector number.  Symbols are also entered
in the selector symbol table if they are undefined symbols encountered in
the position which a selector would occupy in a message to an object.

Assuming that the source file compiles with no errors, the compiler rewrites
classdef and selector from its class and selector symbol tables.  On multi-
files compilations this is done after each successful compilation.  The
external database is thus kept as up-to-date as possible.  Along with these
files, the compiler rewrites classtbl and vocab.001 after each successful
compilation.  Classtbl is a table which gives the script number in which
each class is defined, and is used by the kernel to load the appropriate
script when a class is referenced.  Vocab.001 is a file which contains the
names of all the selectors in a format which can be used by the kernel to
display selector names in error and debugging messages.

At the start of a project, you start with no classdef file and a selector
file which is a copy of the file selector.new.  The latter file contains the
definitions of those selectors which the kernel needs to know about and
which thus must have particular numbers.  As you compile files, beginning
with system.sc, the files classdef and selector grow with the addition of
new classes and selectors.  This growth is a one-way street, though --
nothing you do to your source code will cause a class or selector to be
removed from these files.  Thus, by the end of the project you are likely to
have a number of obsolete classes and selectors hanging around in the
database.  To winnow the chaff from these files you should, near the end of
the project, delete classdef, copy selector.new over your existing selector,
and recompile all your files (in the proper order, of course!).  This leaves
you with a class/selector database with only those classes and selectors
which you are using.             Objects


Objects are specific instances of a class, and are defined using the
instance statement:

     (instance anObject of aClass
          (properties
               aProperty: value
               ...
          )

          (method (aMethod [p1 p2 ...] [&tmp t1 t2 ...])
               code
          )
          ...

          [(procedure ...)]
     )

This defines anObject as an instance of class aClass.  The properties and
method statements are optional and are used to over-ride the default values
and methods inherited from aClass.

The ID of an object or a class is what tells the sci kernel where to send
messages.  The object ID is obtained by simply writing the object's name
wherever an expression is valid -- it can be assigned to a variable or
passed as a parameter to a procedure.  Thus, if we define egoObj as an
instance of class Ego,

     (instance egoObj of Ego)

we can assign the ID of egoObj to the global variable ego:

     (global   ego       0)
     (= ego egoObj)

Once this has been done, the following two expressions are equivalent:

     (ego x?)
     (egoObj x?)

To find the distance from the object ego to the object wolf, we can pass
the wolf's ID as an argument to ego's distanceTo: method:

     (ego distanceTo: wolf)

Any unknown symbol encountered in a compilation is assumed to be the ID of
some object which is to be defined later in the source file.  If no object
with the symbol as its name is encountered by the end of the file, an error
will be raised.             Sending Messages


The syntax for sending a message to an object is identical to that for a
procedure call.  The object name (or an expression which evaluates to an
object ID) is followed by the message selector and any parameters, all
enclosed in parentheses.  There are three different kinds of messages which
can be sent to objects:

Setting a property:
     A property of an object can be set by sending a message whose message
     selector is the name of the property followed by a colon (':') followed
     by the new value of the property:

          (ego x:23) or (ego x: 23)

     sets the x property of ego to 23.

Requesting the value of a property:
     The value of a property can be obtained by sending a message with no
     parameters whose message selector is the name of the property followed
     by a question mark ('?'):

          (ego x?)

     will return the value of the x property of ego.

Invoking a method:
     A method of an object can be invoked by sending a message with any
     number of parameters whose message selector is the name of the method
     followed by a colon (':'):

          (ego moveTo: x y) or (ego moveTo:x y)

     tells ego to move to coordinates x and y by invoking the moveTo method
     of ego.


Any number of messages can be sent in one fell swoop:

     (ego
          x:50
          y:50
          setMotion: MoveTo 100 100
          setCycle: Reverse self
     )

will position ego at coordinates (50, 50), start him moving to coordinates
(100, 100), and set him to cycle in reverse cel order.  When multiple
messages are sent to an object, the messager in the kernel sends them one at
a time in left to right order.  In multiple message sends, all parameters
are evaluated before the messages are sent.An Extended Example


The only way to really understand OOP is not to read about it, but to dive
into an example and get a feel for how it is used (or better yet to actually
write code!).  The following extended example goes through the development
of a new class, the AutomaticDoor, for adventure games.  Before continuing,
it is advisable to read through Script Classes for Adventure Games in order
to become familiar with the classes upon which the AutomaticDoor is built.

The AutomaticDoor concept was inspired by Space Quest, in which there are
lots of doors which open whenever ego gets near them and close when he
moves away.  We would like the doors to do this by themselves, like good
automatic doors, rather than having to explicitly write code in each room
which checks ego's position, remembers whether the door is open or closed,
opens or closes the door, etc.

The first step in defining a class is conceptual -- determining what the
class represents and thus what properties and methods it should have in
order to carry out its role in the scheme of things.

We'll say that a door is a subclass of the Actor class, since it will be an
object visible on the screen.  A door goes somewhere, so it should have an
entranceTo property which tells us which room is on the other side of the
door.  The door may or may not be locked, so we'll need a locked property to
keep track of this, along with a key property which is the ID of a key
object which locks or unlocks the door.  Doors generally make some sort of
noise when opening and closing, so we'll add openSnd and closeSnd as
properties to tell us what sound the door makes.  Then there is the question
of keeping track of whether the door is opening, open, closing, or closed. 
This state will be kept in the property doorState.  Finally, since this is
an automatic door, it will need some way of telling when an Actor is near
enough to cause it to open.  This will be dealt with by an object of class
Code, whose ID will be kept in the actorNearBy property.

This gives us the beginnings of the class statement:

     (class AutomaticDoor kindof Actor
          (properties
               entranceTo 0
               locked FALSE
               key 0
               openSnd 0
               closeSnd 0
               doorState 0
               actorNearBy 0
          )
     )


We'll need symbolic definitions for the state of the door:

     (enum
          doorOpen
          doorOpening
          doorClosed
          doorClosing
     )



To this we now need to add the methods section.  The methods are the things
we wish to have the door do.  Thus, we will want methods open and close, as
well as lock and unlock:

     (methods
          open                ;open the door
          close               ;close the door
          lock                ;lock the door
          unlock              ;unlock the door
     )


We'll start with the init: method (inherited from Prop), which adds the door
to a room when we first enter the room.  This should handle having the door
be open if it is the door to the room which we have come from and closed
otherwise.

     (method (init &tmp doorState)
          (= doorState
               (if (== prevRoomNum entranceTo)
                    ;We just came from the room to which this door
                    ;is an entrance -- the door should be open.
                    doorOpen
               else
                    ;We didn't come through this door -- have
                    ;it closed.
                    doorClosed
          )

          ;Set the cel based on whether the door is open or closed.  This
          ;assumes that cel 0 is the cel with the door entirely closed.
          (= cel
               (if (== doorState closed)
                    0
               else
                    (- (NumCels view loop) 1)
               )
          )

          ;Pass the initialization along to the super-class to add the
          ;door to the cast, etc.
          (super init:)

          ;Stop updating the door, to reduce the burden on the animation
          ;system.
          (self stopUpd:)
     )

Note that we have not added the actorNearBy code at this point -- that will
be specific to each door.

We now want methods to open and close doors.  They should know enough not to
try opening a locked door or one which is either already opened or opening. 
Also, if a door-opening sound has been defined for the door (by putting a
the object ID of a Sound in openSnd), that sound should be played as the
door opens.  The same goes for the door closing.

     (method (open)
          (if  (and (! locked)
                    (!= doorState doorOpening)
                    (!= doorState doorOpen)
               )

               ;If the door is not opened or opening, start it doing so by
               ;having it cycle to the end of its loop.  When it is done,
               ;the cycle instance will cue us.
               (= doorState opening)
               (self setCycle: EndLoop self:)
               (if openSnd
                    (openSnd doit:)
               )
          )
     )

     (method (close)
          ;We don't have to worry about the door being locked,
          ;since in that case it wouldn't be open.
          (if  (and
                    (!= doorState closing)
                    (!= doorState closed)
               )
               (= doorState closing)
               (self setCycle: BegLoop self)
               (if closeSnd
                    (closeSnd doit:)
               )
          )
     )

When either the EndLoop or BegLoop cycle type initiated by open or close is
done, the cycle class will cue the door.  The cue method must thus handle
the change from doorOpening to doorOpen and from doorClosing to doorClosed:

     (method (cue)
          (= doorState
               (if (== doorState doorOpening) doorOpen else doorClosed)
          )
          (self stopUpd:)
     )

Note that we stop updating the door when it is no longer cycling in order to
reduce the load on the animation system.

Locking and unlocking the door may be done by anyone who has the key to it. 
Though not in the class system yet, each Actor will have a has: method which
will test to see if the Actor has a certain inventory object.  We use this
to define the lock and unlock methods, which take the Actor who is trying
to do the action as a parameter.  Note the use of a common procedure to
exploit the similarities in code:

     (method (lock who)
          (DoLock who TRUE)
     )

     (method (unlock who)
          (DoLock who FALSE)
     )

     (procedure (DoLock who newLockState)
          (if (who has: key)
               (= locked newLockState)
          else
               (Print "You don't have the proper key!")
          )
     )

Remember that the property key has the ID of the object which is the key to
this door.  

Since the init: method of the door has added the door to the cast, the door
will be sent the doit: message during each animation cycle.  This is the
ideal place to hook in the check to see if the door should be opened or
closed.  The door will check to see if any Actor is near enough (as defined
by a TRUE return from the code whose ID is in actorNearBy), and if so will
invoke the open: method.  Otherwise, it will invoke the close: method.  Note
that since these methods already check to see if the given operation is in
progress or is completed, we can invoke them blindly without creating any
problems.

     (method (doit)
          ;If there is no test for a nearby actor, don't try to test.
          (if (== actorNearBy 0) (return))

          ;See if anyone is near.
          (if (cast firstTrue: #perform: actorNearBy)
               (self open:)
          else
               (self close:)
          )
     )

The test in this method works in the following way:  we tell each member of
the cast to perform: the code whose ID is in actorNearBy.  If any member of
the cast returns TRUE from this code, the firstTrue: method will end and
return the ID of that member.  If no member returns TRUE, firstTrue: will
return NULL.  Thus the conditional statement will be TRUE if any element of
the cast returns TRUE to the code in actorNearBy.  The general structure for
this code (each door will have its own specific test for nearness) is:

     (instance nearByTest of Code
          (method (doit theObj)
               (return
                    code to test the nearness of the Actor
               )
          )
     )


Now that the methods have been defined for the AutomaticDoor class, we can
use it to define doors in any room in the game.  Say we're in a room which
has two doors (like the starting room of Space Quest).  The first is a face-
on door to a closet, which we'll call closetDoor.  Since it's face-on and
there are no obstructions, we'll use a simple position check to see whether
ego is near it:

     (instance closetDoor of AutomaticDoor
          ;Set the initial position of the object and
          ;say that it opens into the closet.
          (properties
               x:100
               y:60
               view:vClosetDoor
               entranceTo:closet
               actorNearBy:nearCloset
          )
     )

     (instance nearCloset of Code
          (method (doit theObj)
               (return
                    (and
                         (< x (theObj x?))
                         (> (+ x (CelWide view loop cel)) (theObj x?))
                         (< (abs (- y (theObj y?))) 10)
                    )
               )
          )
     )

The code in nearCloset checks to see if the object's x position is within
the bounds of the door and whether it is within 10 pixels of the door
vertically.  If all the above are true, it returns TRUE.

The second door will be an entrance to a secret room.  Let's say that the
room is so messy near the door that the only easy way to tell if ego is near
it is to draw some control into the picture and see if ego is on the
control.  Also, since the room to which this door leads is secret, we'll
need the cardKey object to unlock the door.

     (instance secretDoor of AutomaticDoor
          (properties
               x:10
               y:80
               entranceTo:secretRoom
               locked:TRUE
               key:cardKey
               actorNearBy:nearSecretDoor
          )
     )

     (instance nearSecretDoor of Code
          (method (doit theObj)
               (return
                    (OnControl theObj secretControl)
               )
          )


In the room code, we add the doors during the initialization phase:

     (method (init)
          ...
          (closetDoor init:)
          (secretDoor init:)
          ...
     )


     (if (Said 'lock / door')
          (cond
               ((closetDoor actorNearBy: ego)
                    (closetDoor lock:)
               )
               ((secretDoor actorNearBy: ego)
                    (secretDoor lock:)
               )
               (else
                    (Print "You're not near a door!")
               )
          )
     )


     (if (Said 'unlock / door')
          (cond
               ((closetDoor actorNearBy:)
                    (closetDoor unlock:)
               )
               ((secretDoor actorNearBy:)
                    (secretDoor unlock:)
               )
               (else
                    (Print "You're not near a door!")
               )
          )
     )

We use the door's own actorNearBy check to see if ego is close enough to
open the door.


Thus concludes our excursion into Object Oriented Programming.  The idea
behind this style of programming is to create abstractions of the things you
are modeling, decide how all these classes are related, and set up a
hierarchy of super- and sub-classes which encapsulates these relationships. 
In the classes are hidden the methods which do things to objects which are
instances of the classes, and the properties, which are the defining
characteristics of the class.  Objects are then instances of a given class
which have particular values for the properties and may even have different
methods for implementing a certain concept.

What all this setup gives you is the ability in your code to say

     (secretDoor unlock:)

to unlock a door, rather than having to write the code in-line or writing an
unlock routine which needs to handle all the possible cases of doors which
occur in the game.

Enjoy.

                                   Index

class  . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 6
class statement  . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 8
classdef . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 9
inheritance  . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 7
instance . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 6, 11
kindof . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 8
message  . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 6, 12
messager . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .  12
method . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 6, 8, 9, 11
     invoking  . . . . . . . . . . . . . . . . . . . . . . . . . . . . .  12
methods  . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .  8, 9
naming . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 7
object . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 6
procedure  . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 8, 11
properties . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 8, 11
property . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 6
     requesting  . . . . . . . . . . . . . . . . . . . . . . . . . . . .  12
     setting . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .  12
selector . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .  6, 9
self . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 7
sub-class  . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 6
super  . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 7
super-class  . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 6
