How To Quickly Write An Adventure Game by Derek T. Jones This document describes how to write your own adventure game quickly and easily, and also how to take advantage of more advanced features when your game becomes more complex. You should already be familiar with what playing an adventure game is like. If you aren't, try the adventures that came with this package to understand the "feel" of moving through an artificial universe by text and imagination alone. Archetype is more than just a language for writing adventures. It is a more general-purpose language that was designed with the writing of adventure games in mind. For this reason, there is a good deal of existing Archetype code that must be combined with your own adventure's objects and rooms in order for them to behave like a text adventure. Here's an example of the simplest adventure possible: include "standard" room first_room methods 'INITIAL' : 'START HERE' -> player end Try it. Type that into a text file; name it TEST1.ACH . You can create a text file by using a text editor such as vi, SLED, QEDIT, or the DOS 6.2 EDIT command, among others. You can also create a text file on a word processor, as long as you make sure that you don't save the file in the word processor's native format. For example, using WordPerfect to create your adventure, you would have to use Text Out to save the file. Using Microsoft Works, you would use the Save As option and check the "Text" box. Most word processors have an option for storing your file without any special formatting codes. Now create the adventure. Before the adventure can actually be played, it has to be translated into a binary format so that it can be loaded and executed quickly. During this translation the program you wrote is also checked for any syntax errors, meaning errors in Archetype grammar (not English grammar!). Throughout this document, anything in an example typed in boldface indicates something you have to type; plain text indicates program output or prompts. So now create your adventure: C:\>create test1 This may take about a minute, if you're using a 10MHz 8088 with floppy drives, like I have. Probably it runs much faster on your more advanced machine. If you get the error "Cannot open STANDARD.ACH", simply make sure that all the .ACH files that came with the package are in the same directory as the CREATE.EXE program. To play the adventure, type: C:\>perform test1 Not much to do, is there? Find out just what you can do: What should I do now? help You will see a list of some of the verbs that the program will understand. Synonyms for verbs will not appear in this list. In other words, if "shoot" and "kill" are defined simply as synonyms for "attack", only the verb "attack" will show up in this list. Notice that the system verbs - help, save, load, quit - and the direction verbs - north, south, east, west, northeast, northwest, southeast, southwest, up, and down - are all in this list. These verbs were defined in the STANDARD.ACH Archetype file that you included when you typed include "standard" at the top of your program. Other things were defined as well, for example, the "room" type. When you typed room first_room, it created a room object named "first_room". The properties of this room were defined in STANDARD.ACH: the ability to have exits in the cardinal directions (north, south, northwest, etc.); the ability to contain any objects dropped in it, descriptions that vary based on whether or not this is the player's first visit to it, and so forth. The 'INITIAL' message and its significance were also defined in STANDARD.ACH . Before anything else starts in the game, this message is broadcast to every object defined - objects you created as well as those created in STANDARD.ACH . By putting this message in the methods section and following it with a colon and a statement, you indicated that "first_room" had some specific action to take when it received the 'INITIAL' message. In this case, the action is to send the message 'START HERE' to the player object. The player object is also defined in STANDARD.ACH; it contains attributes having to do with the player's location, how much they can carry, etc. The player object defines the 'START HERE' message, and has a method for it which causes it to move into the room which sent the message. The "->" symbol, meaning "send this message to that object", is not defined in STANDARD.ACH . Neither is the word "include", the word "methods" or "end", or even the general structure of your room definition. Those are defined by Archetype itself1. However, it is important to remember that much of what you will come to think of as "Archetype" is actually STANDARD.ACH, and especially INTRPTR.ACH, which are themselves written in Archetype! Once you know more about writing adventure games, you might want to go in yourself and make your own modifications. HOWEVER IT IS AN EXTREMELY BAD PLAN TO MAKE CHANGES TO INTRPTR.ACH UNLESS YOU ARE VERY CERTAIN YOU KNOW WHAT YOU ARE DOING. In fact you should never actually change INTRPTR.ACH. You should make a copy with a different name which you use yourself. If you screw up INTRPTR.ACH, adventure games you make with it will work erratically or not at all. Beware! But enough with the alarmist injunctions. On to more and greater things. First of all, how about giving your room an interesting description. Right now it's just "a nondescript room." The room's description is one of its attributes, named "desc". Attributes are listed before the word methods when an object is described. You might change your object definition as followed: room first_room desc : "room with the word START painted on the ceiling" methods 'INITIAL' : 'START HERE' -> player end The "desc" attribute is actually defined to "nondescript room" in the "room" type defined in INTRPTR.ACH; if you don't redefine it yourself, your room object will inherit the "desc" attribute's value just by virtue of being based on the "room" type. The interesting attributes and methods of the room type are shown below: type room IsAroom : TRUE desc : "nondescript room" intro : "I can see" empty_intro : "There is nothing of interest here." methods 'FIRSTDESC' : UNDEFINED 'BRIEF' : write "In the ", desc, "." 'LONGDESC' : write "I'm in the ", desc, "." end Attributes: IsAroom Always TRUE. It should not be changed. If every type defines an attribute called "IsA", it makes it easy to test for the type of an unknown object with a test such as "if obj.IsAroom then..." desc A short description of the room. It should not contain any detailed description; just the name of the room. It should also not contain any article at the front such as "a", "an", or "the". intro As can be seen from its default value, this is what is written at the beginning of the room's inventory list when the player types "look" at the prompt. If the room is dark, you might want to define it as "I can barely make out" or something. But you will usually want to leave it alone. empty_intro What is written when the room is empty. Again, you will usually want to leave this one alone. Methods: 'FIRSTDESC' This method is invoked whenever the player first enters the room, and never again. A good place to put description that causes your story to unfold; or to put first-time traps or surprises. It is important to remember that more than just written output statements can appear in a method. 'LONGDESC' Invoked whenever the room is first entered or when the player types "look" at the prompt. 'BRIEF' Invoked whenever the player re-enters a previously entered room. Usually this is just a brief reminder of what the room is. The fact that this method is invoked on subsequent visits helps your adventure feel like a book that is "unfolding"; 'FIRSTDESC' is reactions the character has initially and never again; 'LONGDESC' is the result of a long slow look, and 'BRIEF' is when the character is just passing through. The methods section also contains the exits out of the room. The name of the message should be the name of the exit. It should return a single value - the room into which it exits. For example, a room with the following methods: 'east' : kitchen 'west' : if door.open then bedroom will have an exit to the east leading into the kitchen, and, if the open attribute of the door object is TRUE, an exit to the west. Methods always return a value to the sender: the last expression executed within them. The 'east' method will always return the "kitchen" object; the 'west' method returns the value of an if statement, which in turn returns its last executed expression. Suppose we fill out our example room a little more: room first_room desc : "room with the word START painted on the ceiling" methods 'INITIAL' : 'START HERE' -> player 'LONGDESC' : write "I'm standing in a small bare room with ", "the word \"START\" "painted on the ceiling in neon ", "green paint. The plaster is chipped a little and ", "the dirty white linoleum floor is something I ", "wouldn't want to have to touch with anything ", "but my shoes." 'FIRSTDESC' : write "Welcome to my first adventure! Hope you enjoy it. ", "I was walking innocently along the sidewalk on my ", "way to the store one day when a flash of light just ", "to my left blinded me. When my vision cleared I ", "found myself... somewhere else... without ", "explanation..." # Exits 'north' : hallway # no other obvious way end There are a few new things here: The pound sign (#), the comment, causes itself and everything to the end of the line to be ignored by the CREATE.EXE program. You can use this operator to make notes to yourself or to someone else who might need to read it later. Note the usage of the write statement. No string (characters surrounded by double quotes) can be longer than 256 characters, and usually they're easier to see and use if they're not longer than one line. But the write statement takes any number of comma-separated strings and writes them out to the screen in such a way that they "wrap" at the end of a line, like a word processor. This way you don't have to worry about fitting them carefully to screen margins yourself. Furthermore, if you have a very long description that goes beyond the screen, Archetype will pause and give the player a "Hit any key to continue" message, so that none of the text is lost off the top. Also notice the \" used in the 'FIRSTDESC' method. We want double quotes within double quotes, but of course the presence of (") means the end of a string. Putting a backslash (\) in front of a double quote means that the double quote is part of the ongoing string. More About Exits An exit usually goes both ways. Take a look at the north exit in your first room. It points to the hallway, which we have not yet defined. Define it as follows: room hallway desc : "long north-south hallway" methods 'LONGDESC' : >>I'm standing in a narrow hallway north of the START room. 'south' : first_room end Before any other exits you might define for the hallway, you should first make an exit going south back to the original room. Otherwise, the north exit from the start_room will be a one-way exit. This is something to watch out for, since no room has any exits other than the ones you define for it. Of course, sometimes you might do this on purpose: a trapdoor or hole, for example. Objects How about putting some objects in your adventure? Objects that you can pick up and carry around? Try the following: object necklace desc : "diamond necklace" location : start_room end Be sure that all your room and object definitions are in the same TEST1.ACH file. CREATE it again and PERFORM it. Notice that without any other information about the diamond necklace, you can pick it up, look at it, drop it, and so forth, referring to it as "the diamond necklace", "a diamond necklace", "the necklace", "a necklace", or just "necklace". Of course, the necklace itself isn't very interesting yet since you didn't define anything special for it. It merely inherited the attributes of an object type (defined in STANDARD.ACH), enough structure to allow it to behave like an object. These inherited attributes are shown below: type object IsAobject : TRUE desc : "nondescript object" visible : TRUE location : UNDEFINED pronoun : "it" full : UNDEFINED syn : UNDEFINED size : 1 capacity : UNDEFINED methods 'look' : write "Nothing strikes me as unusual about ", 'DEF' -> self, "." 'get' : if location = player then write "I've already got ", 'DEF' -> self, "." else if size > player.capacity then >>I can't carry that much. else { location := player; 'MOVE' write "I picked up ", 'DEF' -> self, "." } 'pick up' : 'get' 'pick_up' : 'get' 'take' : 'get' 'drop' : if location ~= player then write "I don't have ", 'DEF' -> self, "." else { location := player.location; 'MOVE' write "I put down ", 'DEF' -> self, "." } 'put down' : 'drop' 'put_down' : 'drop' end Attributes: IsAobject Serves the same function as IsAroom in the room type above. However it is even more important since the interpreter depends on it. desc A very important attribute; it must almost always be defined. It is the full name of your object the way it appears on screen, and, if full is not defined, indicates how the player can talk about it as well. The interpreter assumes that you have defined desc in the form "adjective adjective ... adjective noun", so that if desc was "great big red ball", the player could refer to it as "ball", "red ball", "big red ball", or "great big red ball", but not "great ball", "red big ball", or any other combination. full The full name of your object; the way the player would talk about it at the prompt. For example, with the diamond necklace this would be "diamond necklace". You need to use this attribute if you don't want to allow some of the names that the interpreter might generate, given your particular desc attribute, since its presence prevents the interpreter from using the desc attribute to generate vocabulary names. One example might be "ball of wax", where the interpreter will accept "of wax" as a valid name for the object. You might then set full to "ball of wax" and set syn to "ball|wax" (see below). syn Synonyms for your object. If there is more than one synonym you can put them all in the same string, separated by vertical bars. You can use this attribute whether or not you define the full attribute. For example, if you have an object whose desc attribute is "scientific calculator", and you want the player to be able to refer to it as "calc" as well as "scientific calculator" and "calculator" (which the interpreter will generate if full is not defined), just set syn to "calc". visible Whether or not the object will show up in an inventory of the room. Usually TRUE; you might make it FALSE if the object is not really what the player might think of as an object, like a magic word or something. If your adventure required that the player type "say sesame" at some point, there would actually have to be an object named "sesame" to handle the action. This object would have visible set to FALSE and probably 'ACCESS' set to return TRUE. (See Methods below.) location Another very important attribute. It is set to the location of the object and indicates the object's physical position. NOTE: just setting this attribute equal to some other object is not enough to actually change its position. It must be set and then the 'MOVE' method must be invoked. (See Methods below.) pronoun Indicates what pronoun should be used for the object. Although usually "it", it can be any pronoun, such as "them", "him", "her", etc. If the player has just mentioned this object, they can continue to refer to it by this pronoun, until they refer to another object with the same pronoun. size The size of the object. Size in what? Cubic inches? Square feet? Well, you decide. It is used to determine how much more the player can carry. If it is zero, or UNDEFINED, it means that it has no significant weight; the player can carry as many of these kinds of objects as he wants. If it is larger than one, the player will be able to carry fewer. When the total of all the sizes of the objects the player is carrying exceeds player.capacity, the player gets the message "I can't carry any more." Thus, if the weight of objects is important in your game, you might need to set player.capacity yourself in the 'INITIAL' method of your starting room. capacity How many objects can be put inside this object (if all sizes are equal to 1). When the total of all the sizes of the objects whose location attribute points to this object exceeds capacity, no more objects can be put "inside". NOTICE that the most important attributes, the attributes without which you would not be able to see or mention the object, are the desc and location attributes. Without desc, the interpreter cannot put its name on screen or know what names can be used by the player to describe it. Without location, the object is not actually anywhere within your game. All the others default to "reasonable" values. Methods There are no methods which are mandatory in order to make your object accessible. Note that the necklace defined above only required two attributes in order to be part of the game. But the methods section of an object contains three kinds of messages: 1. System messages, like 'DEF', 'INDEF', 'BEFORE', 'AFTER', etc. These messages are in all uppercase letters. It is a bad idea to define your own messages which are in all capital letters; it only increases the possibility of colliding with the system messages. 2. Verb messages, like 'get', 'north', 'kill...with', etc. These are in all lowercase letters. How to define your own verbs will be covered below, in "Parsing and Verb Messages". 3. General purpose messages. Any other message you put in the methods section of an object, just to group certain commonly invoked actions together. In order to conflict neither with system messages or verbs, these are usually lowercase with the first letters capitalized, like 'Wake Up' or 'Begin'. Parsing and Verb Messages When the player enters a command, the interpreter puts the subject of the sentence in main.subj and the direct object into main.dobj. It then creates a single verb message that incorporates both the main verb and prepositional phrases, and sends the message to main.subj. (For completeness, the verb is put into main.verb and the prepositional phrase into verb.prep.) The message is constructed as follows: * If there is just one main verb phrase and a subject, then the message is simply the verb phrase, words separated by one space. Examples: "get object" sends the 'get' message to . "put down the object" sends the 'put down' message to . * If there is a verb phrase, a subject, and a prepositional phrase, then the message is the verb phrase followed by an underscore (_) and then the prepositional phrase. Examples: "pick the object up" sends 'pick_up' to ; "take the coat off" sends 'take_off' to . * If there is a verb phrase, a subject, a prepositional phrase, and a direct object, then the message is the verb phrase followed by an ellipsis (...) and the prepositional phrase. Examples: "take the uniform off of the dead guard" sends 'take...off of' to ; "pick up the key with the wad of chewing gum" sends 'pick up...with' to . Methods tied to messages with ellipses can count on main.dobj being defined. * If there is a verb phrase but no subject or direct object, then it is sent to the object that the player is "in". This is how hollow objects handle verbs like "leave" or "get out". Moving Things Around One of the very first things that you will probably want to do is to move some object from one place to another. This involves doing two things: changing the object's location, and then sending it the 'MOVE' message. If you forget the 'MOVE' message, the adventure will behave strangely. Somtimes the object will act like it's there, and sometimes it won't. Even if an object changes its own location, it still must send the 'MOVE' message to itself. (Where the definition of the 'MOVE' method comes from is covered in "Inheritance" below.) The first example here is from an object which is a rock. When this rock is thrown at a glass vase, we want the glass vase to shatter and disappear. The player would type "Throw the rock at the vase" causing the message 'throw...at' to be sent to "rock", with main.dobj set to glass_vase. The object definitions are shown below: object glass_vase location : start_room desc : "glass vase" end object rock location : start_room desc : "big ugly rock" methods 'throw...at' : { if main.dobj = glass_vase then { write "It shatters into miniscule pieces! It's gone!" glass_vase.location = UNDEFINED # Nowheresville 'MOVE' -> glass_vase } else write "It bounces off of ", 'DEF' -> main.dobj, "." } # throw...at end Note the 'DEF' message sent to main.dobj. It means the "definite" name of the object. 'INDEF' means the "indefinite" name. For the glass vase, the 'DEF' method returns "the glass vase" and 'INDEF' returns "a glass vase". There is also the message 'NEG INDEF', for "Negative Indefinite". It is used for the message "I don't see ... here". For most objects it is usually the same as 'INDEF', but for an object where 'INDEF' is "some apples", 'NEG INDEF' would be "any apples". Inheritance How can the glass_vase object above respond to messages like 'DEF', 'INDEF', and 'MOVE' since they aren't defined in the methods section of glass_vase? Because they were inherited from the "object" type. All of the attributes and methods of the "object" type are part of glass_vase unless glass_vase redefines them. Doing Things Up Front There are some actions that have to be taken before the game even gets underway, before the player has a chance to type the first command. Many of these can be done just by initializing an attribute to the right value, like setting the initial locations of all the objects. But sometimes the action taken needs to be several statements. In this case, simply define an 'INITIAL' method for your object. Every object in the game receives the 'INITIAL' method before the player ever begins the game. Doing Things Periodically Sometimes there are actions that an object should take once per turn, or things that should happen every so often. There is a 'BEFORE' message sent out before the player is asked for input and an 'AFTER' message which is sent out after the player's actions have taken effect. To receive these messages, however, an object has to ask up front to be on the list of objects which will be sent such a message, by sending the message 'REGISTER' to the correct event handler: the object "before" for the 'BEFORE' message, and the object "after" for the 'AFTER' message. Registering is usually done in the 'INITIAL' method. The object in the example below puts out a random scary message about once out of every ten turns that the player takes: object scary_sounds methods 'INITIAL' : 'REGISTER' -> before 'BEFORE' : { if ?10 = 1 then case ?5 of { 1 : write "I hear a far-off groan..." 2 : write "A bat flaps by close overhead!" 3 : write "I seem to hear a shuffling step behind me...!" 4 : write "A sense of dread weighs on me..." 5 : write "There is a clammy draft of air on the back ", "of my neck..." } # case } # if end In the example above, the scary_sounds object has no desc or location attribute since it isn't a tangible object. It only writes things to the screen. However, for tangible objects with a 'BEFORE' or 'AFTER' method, it's important to know whether the object is accessible to the player before doing anything. Otherwise the object acts "out of nowhere". The 'ACCESS' method, inherited from the "object" type, returns TRUE if the object is accessible to the player and FALSE if it is not. An object is "accessible" if: the player has the object, the player and the object are in the same location, or the player is "in" the object. The example below is a monster that will roar in protest, and snatch away the Wand of Power if the player is carrying it: object monster location : dungeon desc : "monster" methods 'INITIAL' : 'REGISTER' -> after 'AFTER' : if 'ACCESS' -> self and wand.location = player then { write "The monster lets out a roar of protest and ", "snatches ", 'DEF' -> wand, " from me." wand.location := self 'MOVE' -> wand } end If the 'AFTER' method didn't check for 'ACCESS' -> self to be true, the monster would roar and take the wand the moment the player acquired it, even if the player was nowhere near the monster. Did I Happen to Mention...? (The 'MENTION' Message) The pronouns in Archetype usually refer to the last time an object with that pronoun was referred to in a player command. Sometimes it may appropriate, however, to cause a different object to become the object of interest. Take, for example, the following exchange: What should I do now? pick up the wallet I picked up the wallet. What should I do now? open it I opened the wallet. A driver's license fell out! What should I do now? get it I already have the wallet. At that point, the player probably expected "it" to refer to the most interesting object just mentioned. This can be done by having the driver's license object send the 'MENTION' message to the "main" object ('MENTION' -> main). Additionally, an object can be directed to mention itself by sending it the 'MENTION SELF' message. The code below implements the situation above, with the difference that when the user finally types "get it", they will pick up the license, not the wallet. object wallet location: dresser desc: "wallet" methods 'open' : { writes "I opened the wallet. " if license.location <> self then write "Nothing happened." else { write "A driver's license fell out!" license.location = player.location 'MOVE' -> license 'MENTION SELF' -> license } end Customizing the Game Environment The interpreter is comprised of several objects, such as "main", "player", and the various basic verbs ("get", "drop"). You can change certain default attributes of these objects to different values to give your adventure a different "look and feel". main.prompt, for example, is the string that is printed just before asking the player for input. It defaults to the string "\nWhat should I do now? ". The \n means a new line, so that the prompt will print a blank line and then the words. main.wait_message is the string that is printed when the player simply types a RETURN in response to main.prompt. It defaults to "I wait patiently." compass.intro is the string printed out before giving the list of visible exits. Defaults to "I can exit". compass.empty_intro is the string printed if there are no visible exits. Defaults to "There are no visible exits." player.intro is printed before listing the player's inventory. Defaults to "I am carrying". player.empty_intro is printed when the player is carrying nothing. Defaults to "I am empty-handed." player.capacity is generally the number of objects that the player can carry before getting the message "I can't carry that much." It is actually, however, the upper limit of the sum of the size attributes of the player's objects. In other words, if any object has a size attribute that is greater than one, player.capacity will be reached more quickly. Defaults to 8. Some other parts of the environment, like the strings that are printed out when a room is entered, cannot be changed by direct assignment, since they are part of a type definition. But you can define your own type based on the interpreter's type and modify anything you want about it. As an example, below, suppose that when the player enters a room you want the game to say, "You can see" before giving a list of visible objects or "Nothing here." if there aren't any: type my_room based on room intro : "You can see" empty_intro : "Nothing here." end After this, of course, make sure that all your rooms are of type "my_room" and not of type "room". Remember that the entire main interpreter, INTRPTR.ACH, is written in Archetype. Once you read the Archetype manual you may be able to understand the code in there better and modify it to suit your taste. Disabling Verbs As in the previous examples, the handling of a verb is usually left up to the main subject of the sentence. If there is some universal sense to a verb (like 'get'), then it is usually defined in a type on which objects are based, so that all objects inherited from that type appear to handle that verb the same way. Once in awhile, however, it may make more sense to disable the verb "at the source", before the subject of the sentence gets a chance at it. You can do this by setting the disabled attribute of the verb you wish to disable to a string which should be printed instead of passing the message to the main subject. One verb in particular, "lookV" (the verb 'look'), will affect the interpreter when disabled. No room descriptions will be printed upon entering a room and 'i' (inventory) will not respond either. Instead, lookV.disabled will be written. This is a convenient way to make the player blind if the "lights" should go out in the adventure. Defining Your Own Verbs Normally, the only verbs and prepositions that Archetype will parse and process are those defined in LEXICON.ACH . If you want the parser to recognize a verb or preposition of your own, you must define a "Verb" or "lex" object. The interesting attributes of a "lex" object are as below, using the preposition "in" as an example: type lex based on null full : 'in' # the full or "true" name syn : 'inside|into' # bar-separated synonyms, all translated # to .full if encountered on_menu : TRUE # whether this shows up when the player # types "help" end The full attribute is what anything in syn becomes, before it is combined with other verbs. If an example object "box" defines a method for the verb message 'look in', it will receive that message if the player types "look in the box", "look inside the box", or "look into the box". NOTE that if the "box" object defines a method for the verb message 'look inside', it will never be invoked. "inside" will translate to "in" before it is combined with "look". These kinds of objects are usually never referred to by name within the adventure (none of your programming code needs to reference them), so they are usually left "nameless" by giving them a name of "null": lex null full : 'under' end The "Verb" type is based on "lex", meaning that it has all of the above attributes, plus: type Verb based on lex disabled : UNDEFINED # see "Disabling Verbs" above interpret : UNDEFINED # who should receive the verb # message (if not main.subj) normal : FALSE # whether this verb has a normal, # "default" action end All three of these attributes have three associated methods: 'DISABLED', 'INTERPRET', and 'NORMAL'. If an attribute is neither FALSE nor UNDEFINED, the method associated with that attribute is invoked. As described above in "Disabling Verbs", the typical way to disable a verb is simply to assign a value to its disabled attribute. However, if you are defining your own verb, you can supply a 'DISABLED' method which does something other than just write the string in disabled to the screen. Remember that the verb's .disabled attribute must still be set to TRUE for its 'DISABLED' method to be invoked. The 'INTERPRET' method, invoked if interpret is defined, normally just makes sure that ('ACCESS' -> interpret) is true, then sends its full attribute to whatever object interpret is pointing to. Be sure that you assign an object to this attribute, not a string as with the disabled attribute. The 'NORMAL' method is invoked if normal is defined, and if the recipient of the verb message doesn't have a method defined for the verb. The 'NORMAL' method just writes the string in the attribute normal by default. Here's an example of the verb 'kill' (just as it is defined for The Gorreven Papers): Verb null full : 'kill' syn : 'attack|fight' normal : "That's not the kind of thing I can kill." end Whenever the player tries to 'kill' something, or 'attack' it, or 'fight' it, and the object named has no method defined for the 'kill' verb, the game will print, "That's not the kind of thing I can kill." If there is a more complicated "default" action, normal can simply be set to TRUE and the 'NORMAL' method can be defined as complicated as necessary. Here is another example from The Gorreven Papers, this time for the verb 'search': Verb null full : 'search' syn : 'examine' normal : TRUE methods 'NORMAL' : if main.subj.IsAhollow_object then { >>I get closer for a more thorough look. player.location := main.subj; 'MOVE' -> player } else if main.subj.IsAguard_type and main.subj.alive then write "He's not going to permit that kind of scrutiny; ", "not while he's alive." else if ('look' -> main.subj) = ABSENT then write "I find nothing unusual even upon a close search." end The 'NORMAL' method will be invoked if the player tries to 'search' an object that has no 'search' method defined. Note at the bottom that it finally sends 'look' to the main.subj, so that a 'search' is at least as good as a 'look'. However, if this sending returns ABSENT, showing that there is no 'look' method defined for the object, then it writes out a message of its own. This is more important than it probably seems. If sending that verb to main.subj is ABSENT, it means that nothing was done at all, and the player will be greeted with a blank line. Of course, if a 'look' method was defined anywhere in main.subj's ancestry, so that main.subj could inherit the method, then that is the method that will have been invoked. Another way of defining a default action for a verb is to create a type based on the object type and then define everything in your game as being of that type, so that they will all inherit the default handlings of those verbs. The methods just described, however, allow you to customize your own verbs without having the cooperation of a carefully planned inheritance tree. The order of handling of the methods described are: 1. The interpreter determines both the verb and the verb message. (If the player typed "open the box with the key", then 'open' is the verb and 'open...with' is the verb message.) 2. If the verb has its interpret attribute defined, then 'INTERPRET' is sent to it. Nothing more is done; the verb is expected to handle the rest. Remember that the inherited 'INTERPRET' method simply sends the verb message to the object pointed to by interpret. Thus, if you have a verb that is better handled by the direct object than the subject, the interpret attribute can be defined as main.dobj. 3. If the verb has its disabled attribute defined, then 'DISABLED' is sent to it. Nothing more is done. 4. Steps 2 and 3 are done for the verb message. In other words, it is possible to define a Verb object whose full attribute is something like 'shoot...with'. 5. The verb message is sent to the subject of the sentence. If that object has a method defined for that message, nothing more is done. 6. If the verb message is the full name of a Verb object, and it has its normal attribute defined, then 'NORMAL' is sent to that Verb object. 7. If the verb alone has a normal attribute defined, then 'NORMAL' is sent to that Verb object. Learning More The sample game BARE.ACH is a bare-bones adventure that manages to show off many of the features described here, plus a few more. It is heavily commented to help walk you through the flow of the code. If the comments get in the way, look at BARER.ACH, which is the same adventure, without comments. Once you become familiar with the Archetype Reference Manual, which describes all of the aspects of the Archetype language proper, you will be able to read the .ACH files that make up the interpreter and perhaps write your own interpreter with a different flavor. The program ANIMAL.ACH demonstrates how an entirely different kind of game can be written with Archetype, in this case, the old Animal game, where the computer tries to guess what animal you are thinking of, and has you teach it when it gets one wrong. Try it, and look at the code. Enjoy! 1A computer language such as Archetype is actually only a standard. What enforces this standard is the CREATE.EXE program, which will refuse to create a binary, executable file from your source code (your .ACH file) if any of the rules of this standard are broken.