When the player enters a command you will want the game to check that the command is reasonable. The Alan system checks some obvious things automatically - for example if the player tries to pick up an object that isn't at the current location, Arun replies that the object can't be seen. The author may want to do other, more complicated checks - to see if objects are edible, readable or too heavy to lift for example. This can be done by defining object 'attributes'.
Lets place a couple more objects in the street:
OBJECT Tin AT Street CONTAINER IS NOT Takeable. END OBJECT. OBJECT Bomb AT Street IS NOT Takeable. DESCRIPTION "There is bomb securely bolted to a lamp post." END OBJECT.
You will notice that these object definitions both include a phrase IS NOT Takeable
and the rubbish tin definition includes the phrase CONTAINER.
These are example of object 'attributes.' The container attribute is a special built-in Alan attribute that we will discuss at the end of this lesson. 'Takeable' on the other hand is an object attribute that I have simply made up. Default object attributes are created by entering a section like this anywhere in the Alan source code:
OBJECT ATTRIBUTES Takeable.
After takeable
you could list any other attributes you might want to use in the game such as edible, eatable, sticky or whatever.
All objects in the game will have the attributes listed under OBJECT ATTRIBUTES
by default. So all objects - such as the 'note' - in our game will be 'takeable' by default. If an object should have other than the default state of an attribute the author can over-ride the default in the object definition. In our example game the player is not allowed to pick up the bomb or rubbish tin so they have IS NOT Takeable
in their definitions.
You can also use attributes that aren't relevant to all objects
by specifying them just in the objects that need them. For example
you might want one object, perhaps a glob of glue, to be 'sticky' until
it dries out. You can define a 'sticky' attribute for the glue object
just by adding the phrase IS Sticky.
to the definition
of your 'glob of glue' object:
OBJECT glob NAME glob 'of' glue AT Street IS NOT Takeable. IS Sticky. END OBJECT.
Because it isn't defined in the OBJECT ATTRIBUTES
section, the 'sticky' attribute is undefined for other objects. Therefore
you can't check the stickiness of objects in global verbs. Only verbs within
the definition 'glob of glue' object will be able to use the 'sticky'
attribute.
Attributes don't have to be either on or off - 'IS'
or 'IS NOT'
. You can also define attributes that
hold a value - either a number or a text string. For example:
OBJECT ATTRIBUTES Weight 1. Colour "blue". OBJECT glob NAME glob 'of' glue AT Street HAS Weight 0. HAS Colour "white". END OBJECT.
You can read more about attributes in section 3.3 of the Alan manual.
Object attributes become useful when we incorporate attribute 'checks' in our verb definitions. For example, to make use of a 'takeable' attribute we would check that an object was 'takeable' in the definition of the 'take' verb.
VERB take CHECK Object IS Takeable ELSE "You can't take that." DOES LOCATE OBJECT IN Inventory. "Taken." END VERB.
So when a player tries to take an object by typing 'take note' for example, the 'take' verb now checks to see if the object has the Takeable
attribute. If so, the DOES
part of the verb definition is executed. If not the ELSE
part of the CHECK
is executed and the rest of the verb definition is ignored.
You can string a variety of checks together in one verb with AND
between the checks. All the checks must be passed if the DOES
part of the verb is to be executed.
VERB take CHECK Object IS Takeable ELSE "You can't take that." AND OBJECT NOT IN Inventory ELSE "You already have it." DOES LOCATE OBJECT IN Inventory. "Taken." END VERB.
We haven't defined a syntax for 'take' in earlier lessons because the 'take' verb follows the default Alan syntax of 'verbname followed by an objectname'. For some purposes an author may want to define the syntax for a 'verb object' verb.
The standard syntax for a take verb, if it was required, would be something like this
SYNTAX take = take (obj).
We haven't seen a syntax with a word in brackets before. This means that the syntax for the 'take' verb is the word 'take' followed by any other word that the player types in and lets call that second word obj. The object names the player types when entering a command are called verb 'parameters.' We can use the 'obj' parameter in verb CHECK
s and so on where we previously had the keyword OBJECT
. Like OBJECT
, the 'obj' parameter refers to whatever game object the player named after the word 'take' in their command input.
VERB take CHECK Obj IS Takeable ELSE "You can't take that." AND Obj NOT IN Inventory ELSE "You already have it." DOES LOCATE Obj IN Inventory. "Taken." END VERB.
We can interchange the use of OBJECT
(which, by default, is the Alan parameter that refers to the first object mentioned in the player's input) and Obj
(or whatever else you define in your 'take' SYNTAX
statement). You may prefer to still use the keyword OBJECT
for simple verbs like 'take' so that the take verb looks similar to other verbs like 'read' or 'eat' which don't have a syntax defined and therefore use the default OBJECT
keyword. It would probably make your source code more readable though to use the parameter name you've defined if a verb does have a SYNTAX
statement.
You might be wondering why you might want to define the syntax for a verb that uses the default 'verb object' syntax. One reason is to allow the use of multiple objects with the verb.
For some verbs, such as take, the player may want to perform the verb on more than one object at a time. For example, the player may want to type "take the salt and the pepper" or "take all". If the player tried this in a game where the 'take' verb used the default syntax the game would reply "You can't refer to multiple objects with 'take'."
The author can allow the player to refer to multiple objects with a verb by adding an asterisk after the object parameter name in the SYNTAX
statement. For example, in the case of the 'take' verb, we would simply add an asterix to the end of the SYNTAX
definition.
SYNTAX take = take (obj)*.
As with locations, we can give objects more descriptive names by adding a NAME
clause after the OBJECT
statement.
OBJECT Tin NAME Big Rubbish Tin AT Street
The default description of this object will now be 'There is a big rubbish tin here' and the player can refer to the object with its full name - for example 'take big rubbish tin'. Arun assumes that the last word in the NAME
phrase is a noun and any words before it are adjectives. It allows the player to refer to the object by just the last word, the 'noun' - eg 'take tin' - or with any or all of the adjectives as well - eg: 'take big tin' or 'take rubbish tin' - and it even accepts the adjectives out of order - eg 'take rubbish big tin'
Remember that if a word in the NAME
clause is enclosed in single quote-marks (perhaps because the name contains an Alan keyword) the word has to be in lower case so the player can use it. For example
OBJECT Counter1 NAME 'check' 'in' counter AT Airport
You can add even more ways the player can refer to an object by defining synonyms for the object's name or for the words in the NAME
clause if the object has one. You define synonyms for object names or adjectives the same way we've defined them for verbs in earlier lessons. For example
SYNONYMS can = tin. garbage = rubbish.
The player can now refer to the tin as a 'can' or a 'garbage can' or a 'garbage tin' or a 'big garbage can', etc.
IF
and CHECK
Statements in Verbs As well as using CHECK
statements to check if using the verb makes sense in the current circumstances (and displaying some text if it doesn't), the game author can use another type of Alan statement, the IF
statement, within a verb's DOES
section to enable the verb to do different things depending on the circumstances.
Let's use the 'read' verb for the 'note' object to illustrate the difference between CHECK
and IF
statements.
The 'read' verb could contain a CHECK
statement to see if the player has the object.
VERB Read CHECK OBJECT IN Inventory ELSE "You don't have that." DOES "Its just someone's old shopping list scrawled on the notepaper." END VERB Read.
If the player doesn't have the object then the CHECK
would not be 'passed' and the "You don't have that." message would be displayed. The remainder of the verb definition, including the DOES
section, would not be executed.
You could be kinder to the player by defining an IF
statement within the DOES
section of the verb to automatically pick up the note if the player tries to read the note when they don't already have it.
VERB Read DOES IF Note NOT IN Inventory THEN LOCATE Note IN Inventory. "(You pick up the piece of notepaper.)$p" END IF. "Its just someone's old shopping list scrawled on the notepaper." END VERB Read.
With this verb definition, if the player tries to read the note when he's not already holding it, the following will be displayed
> read note (You pick up the notepaper.) Its just someone's old shopping list scrawled on the notepaper. >
IF
and CHECK
The difference between CHECK
and IF
statements is that CHECK
statements are used before the main DOES
section of a verb to verify that the circumstances are suitable for executing the rest of the verb while IF
statements are used within the DOES
section to allow the verb to do various things depending on various circumstances.
CHECK
statements don't offer as much programming flexibility as IF
statements because if a CHECK
is not passed then the remainder of the verb definition is not executed. On the other hand, if the result of an IF
statement is just going to be a 'you can't do that' type of message it would be better to use a CHECK
statement.
CHECK
s and 'take all' For example using CHECK
s rather than IF
statements in the 'take' verb makes the command 'take all' work better. Arun will perform the verb on all objects that are available at the current location, except the ones that don't pass the CHECK
s for the verb. So by using CHECK
s instead of IF
statements, the ALL mechanisms will be much more natural:
We defined the take verb like this using CHECK
s
VERB take CHECK OBJECT IS Takeable ELSE "You can't take that." AND OBJECT NOT IN Inventory ELSE "You already have it." DOES LOCATE OBJECT IN Inventory. "Taken." END VERB.
Instead we could've defined it like this using IF
s
VERB take DOES IF OBJECT IS NOT takeable then "You can't take that!" ELSIF OBJECT IN Inventory THEN "You already have it." ELSE LOCATE OBJECT IN inventory. "Taken." END IF. END VERB.
But if many 'not takeable' objects were at the current location that second definition of the verb could result in an untidy response like this to 'take all'
> take all (air) You can't take that! (sky) You can't take that! (ground) You can't take that! (shirt) You can't take that! (pants) You can't take that! (wicker basket) You can't take that! (old radio) You can't take that! (office chair) You can't take that! (snub nose gun) Taken.
Because when processing multiple objects, CHECK
messages aren't displayed, using our CHECK
s version you would get the following
> take all (snub nose gun) Taken.
So far we've defined verbs that involve no objects (eg: 'quit') or one object (eg: 'read') now we'll define a verb with two objects. Using a SYNTAX
statement we can define complicated phrases like 'put the fruit in the bowl' (A player always has the option of typing 'the' in front of an object name. Arun ignores such words so they don't have to be separately specified in the SYNTAX
statement.)
SYNTAX put = put (obj1) in (obj2)
A simple 'put' verb could then be defined like this
VERB put DOES LOCATE obj1 IN obj2. END VERB.
Note how we are now using the bracketed words in the SYNTAX
statement in the verb definition. The bracketed words or 'parameters' are the way to identify the objects the player mentioned in their command.
Of-course we should add some CHECK
statements to the verb to make sure the player is attempting something that is currently possible
VERB put CHECK Obj1 IN Inventory ELSE "You don't have the $1." AND Obj2 HERE ELSE "The $2 is not here." DOES LOCATE obj1 IN obj2. END VERB.
The second CHECK
in the example above - "AND Obj2 HERE"
- is not necessary as, by default, Alan only allows the player to refer to objects at the current location anyway.
I added that redundant check to help illustrate another Alan feature. You will notice the use of $1
and $2
in the quoted text in that example. These two phrases refer to the first and second parameters in the SYNTAX
statement - obj1
and obj2
respectively. For example, if the player typed 'put the note in the tin' and the player didn't currently have the note, the "Obj1 IN Inventory" CHECK
would not be passed and the text "You don't have the note" would be displayed by Arun.
The recommended alternative to using $1
and $2
in text is to use a SAY
statement. The statement SAY obj1
. would display the name of the first object referred to by the player. So an alternative way of defining the above 'put' verb would be
VERB put CHECK Obj1 IN Inventory ELSE "You don't have the" SAY obj1. "$$." --($$ means don't insert a space here) AND Obj2 HERE ELSE "The" SAY Obj2. "is not here." DOES LOCATE obj1 IN obj2. END VERB.
I find that a bit long-winded so, being a bit lazy, I stick to using $1
and $2
etc. One difference between using $1
etc and SAY
is that $1
echoes the text the player used to refer to an object but 'SAY Obj1'
etc uses the object's defined name. The author can choose which effect is more desirable in different circumstances and choose one or the other method.
For example, the player could type 'put message in the tin' as "message" is a synonym for "note". If the 'note' object wasn't at the player's location and the author had used SAY Obj1
the response would be "You don't have the note", if the author had used $1
the response would be "You don't have the message".
We can also add some checking to the SYNTAX
definition. 'Syntax checking' is done using a WHERE
statement. At the SYNTAX
definition level you can check that the player is using the right types of objects in the right order in the command. For example, the statement 'WHERE obj1 ISA Object'
checks that the player hasn't entered, for example, the name of a location when only the name of an object makes sense
SYNTAX put = put (obj1) in (obj2) WHERE obj1 ISA Object ELSE "You can't do that." AND obj2 ISA Container ELSE "You can't put things in there."
You could check some of those sorts of things using CHECK
s in the start of the verb definition or even IF
statements in the DOES
part of the verb but it is more logical to check that the right type of words are being used at the very beginning of the process of deciphering what the player is trying to say.
Furthermore, syntax checks are an important aid to avoiding 'run-time errors.' Run-time errors are problems, such as dividing a number by zero, that can occur when a program is executed even though the program's source code was valid and compilable.
Attempting to put one object into another object that isn't a container is an example of a run-time error that could occur in an Interactive FIction program. The Alan compiler tries to detect any source code which might result in run-time errors and refuses to compile it. The author's syntax checks assist the Alan compiler to perform this source code verification. For example, because we defined obj2
as a container in the syntax for the 'put' verb, the Alan compiler will allow Alan statements like LIST
and EMPTY
to be used in association with obj2
in the 'put' verb otherwise the compiler would not.
When we defined the 'list_inventory' verb we used the LIST
statement to display the contents of the 'inventory' object. LIST
can be used to display the contents of any container. We can add the statement LIST Tin
to the DESCRIPTION
section of the 'tin' object so the contents of the rubbish tin are included in the 'street' location description.
OBJECT Tin NAME Rubbish Tin AT Street CONTAINER IS NOT Takeable. DESCRIPTION LIST Tin. END OBJECT.
If there is nothing in the rubbish tin, the default text "The rubbish tin is empty'"appears in the location description. When playing the example game for lesson six, try putting the note into the rubbish tin and then using the 'look' command to see the effect of the LIST
statement.