Adding your own commands can be very useful if you want the player to do something specific to the game which Quest doesn't have built-in support for - for example you might want the player to be able to type "READ BOOK", or have them able to eat something or write on something.
There are two ways of adding commands to Quest - you can either set up a verb, which lets you do things to objects, or you can add a custom command.
You can add a verb using the verb tag in the define game block.
When you've added a verb such as "eat", when the player types something like "eat potato", Quest will see if that object exists. If not, an error message is printed. If the object does exist, Quest checks for an "eat" property or action. If a property is defined, it is printed. If an action is set up, that script is run. If there is no property or action set up for that object, it can't be eaten, and so Quest will run the verb's script. Usually the verb script is something like msg <You can't eat that.>.
Verbs make it very easy to add the majority of custom commands that you might want to add to a game. However, you may want to add more complex commands, or commands that aren't directly to do with objects - for example, SIT DOWN, or CRUSH ... USING .... Also, you might want to have one block of script handle all the "eating" in your game, rather than having to retype a similar script for each object's "eat" action. For these, you should use custom commands instead.
To add a custom command, use a command tag, either in the define game block (if you want the command to apply throughout the whole game), or in a specific define room block (if you want the command to apply only when the player is in that room).
Typically in a command, there are some keywords that must be present, for example "read" or "eat", and some variable or variables which represent either an object specified by the player (such as "book", "apple"), or some other text specified by the player (such as the player's name, or a message they want to write on something).
The command statement takes the general syntax:
command <... #variable1#... #variable2#...> script
where "..." represents a word or number of words that the user must type in for this command. "#variable...#" represents a string variable, and the text that the user types in that place will go into the string variable specified. You can specify multiple commands on the same line by separating them with semicolons.
A simple example is:
command <say #text#> msg <I say, that's nice!>
Now, whenever a player types anything starting with the word "SAY", whatever they type after it will be put into the "text" string variable, and the script "msg <I say, that's nice!>" will be executed. So, if they player types "SAY HELLO", the script will execute with "HELLO" put into the string variable "text". Our script might then access that variable to say something to the player - see the extended example below.
For text, things are that simple, but if we want the player to specify an object name, it's a bit more complicated, as this object may have an alias - that is, in your game's ASL code it may have a different name to the name that is presented to the player. An object called "thing002" might be called "book" to the player, so we need a way for the player to be able to type "book" and have this automatically translated to "thing002" for the purposes of our script. This is accomplished by prefixing the variable name with the "@" symbol - think of it as standing for "alias" or "object".
Including the "@" symbol means that:
Although for simple games that don't use any aliases, omitting the "@" will cause no problems (as what the player thinks an object is called, and what Quest thinks an object is called, are exactly the same thing), it's not a habit we recommend you get into. Plus you'll miss out on the user-friendliness of Quest telling the player that there's no such thing as a "BOK".
When you later refer to this variable in your code, whether or not you included the "@" in the command statement, the variable is usually accessed in the same way - that is, the "normal" #...# form without using the "@" symbol. (See the extended example below for an examples of when we use the #...# form and when we use the #@...# form).
We can mix the two forms of variable in one command if we wish, although normally we only use one variable in a command anyway.
Here's an example which should hopefully make it all clear:
define room <canteen> define object <fooditem001> alias <beans> properties <edible> look <Glorious baked beans.> end define define object <chips> properties <edible> look <Delicious, chunky potato chips, fried to perfection.> end define define object <Andrea> speak say <Yes! What do you want?> end define command <ask andrea for #@food#; request #@food#; give me #@food#> { ' see below for an explanation of why we use #food# some times, and ' #@food# at other times. if property <#food#; edible> then { give <#food#> msg <You put the #@food# on to your tray.> } else say <I don't think you'll be able to manage that, dear.> } command <say #text# to andrea; say #text#> { ' here, we always use #text#, as there is no object name to disambiguate - ' all we are interested in is the raw text. msg <You say "#text#", but Andrea isn't listening.> } end define
This example sets up a canteen with two choices of food in it. The player can type "ASK ANDREA FOR ..." followed by the name of any food item, or also "REQUEST ..." or "GIVE ME ...". The script after the command statement checks whether the item requested is edible, and then acts accordingly. If you specify an item of food that doesn't exist, the default Quest "badthing" error is printed, and the script doesn't run.
In the example above, note that we have an object called fooditem001. This has an alias "beans". Now, in our code, we must always refer to this object as fooditem001, because that is its name in our code. However, the player doesn't know what fooditem001 is - as far as the player is concerned, this object is called "beans". (Of course, usually if we were to have a small game like this, we would just call the object "beans" in our code anyway, but when you have a bigger game, or objects are created on the fly, you may find that what the player calls your objects is not what your code calls the same objects - you might have several objects you want the player to call "beans", but you have to call them separate names in code).
So that we don't end up asking Quest to do something to the non-existent object beans, and so that we don't end up with our character "Andrea" talking to the player in jargon about "fooditem001", we have to use two different ways of referring to the one string variable named food, which tells us what the player typed in. Because we want "beans" to be automatically converted to fooditem001 for our code should the player type in "beans" in the "ASK ANDREA FOR..." command and its relatives, we refer to the food string variable using the #@...# form (i.e., "#@food#") when setting up the command - see the command lines in the example.
A few lines down we then check whether the item that the player typed in is edible, by seeing whether it has an edible property set. In this case we need to check for the property using the code object name, which would be fooditem001 for our aliased "beans". This means we use the #...# form for the "if property ..." line in the example.
We then use the #...# form for the give command which moves the item to the player's inventory. However, we then want to print a message telling the player that they have put the item onto their tray - and, since this is text that is presented to the player (and not used in code for actually doing anything to this object), we use the #@...# form - so if we just moved fooditem001 to the player's inventory, we want to tell the player that they put the beans onto their tray - not that they put the "fooditem001" on their tray!
Our other object, chips, has no alias - it is called chips in code, and the player will refer to it as "chips". In this case, when the player types ASK ANDREA FOR CHIPS, both #food# and #@food# will return the same thing ("chips"), as you would expect.
As for our "SAY ..." command, whatever the player types here will have nothing to do with objects - so we use the #...# form, as we don't want any conversion of any kind to take place. Also, if we used the #@...# form for our command statement, the command would only work if the player wanted to SAY BEANS or SAY CHIPS, and we wouldn't want to limit our players' vocabularies quite so drastically.
If, in our example, Andrea got annoyed at rude customers and we required the player to type something like ASK ANDREA FOR BEANS POLITELY instead, we could use a statement of the form:
command <ask andrea for #@food# politely> (script)
You can have even more flexible command statements, writing to more than one string variable:
command <make #thing# with #@object#> ... command <put #@thing# and #@otherthing# in #@container#> ... command <write "#text#" on #@surface# using #@object#> ...
You can override any command that exists throughout the game in a particular room by defining a command of the same form in that room's definition block. The priority of finding commands that fit what the player types in goes from the top of the current room definition block to the bottom, then to the top of the game definition block to the bottom. In our example with Andrea in the canteen above, if we wanted to implement the "ask ... politely" form of the command we would have to do this above the non-polite command definition - otherwise we could find the player asking Andrea whether they could have some "beans politely" for lunch, and that could be embarrassing.