A TADS Tutorial: Lesson Seven
Creating Your Own Verbs
Review
In the last lesson, you learned how to write verification methods for verbs that act on either one or two objects (direct and indirect). If a verification method prints out a message (usually a descriptive error message), the action is never completed.
Verbs That Take No Objects
Sometimes, you want to have a verb that the player can just type on a line by itself, with no objects. The TADS library of default classes (adv.t) already contains many one-word commands (e.g., LOOK, NORTH, JUMP, etc.). How do you create your own? Well, as an example, let's say we want to allow the player to type "SCREAM." Here's how you'd do it:So we created a new object called screamVerb, inheriting from the class deepverb. It uses the property verb. Like noun and adjective, it defines new vocabulary words that the parser must learn to recognize and associate with this programming object.screamVerb : deepverb verb = 'scream' sdesc = "scream" action( actor ) = { "Aaaaaiiiiieeeee!!!\n"; "(You feel much better now.) "; } ;The action(actor) method contains the program that is executed when the player types the one-word command.
Creating a New Verb That Takes a Direct Object
Okay, let's say we also want to allow the player to scream at something. In other words, we want to allow the following command:SCREAM AT DIRECT-OBJECT
So the verb in this example is actually a two-word verb (scream at), that expects a single direct object. Here is how we would define this new verb:
The last line names the verification and action methods that will be associated with this verb. In other words, the last line teaches TADS that when the player types SCREAM AT FROG, it should first call the verification method frog.verDoScreamat(actor), and then frog.doScreamat(actor).screamatVerb : deepverb verb = 'scream at' sdesc = "scream at" doAction = 'Screamat' ;Notice that we used the TADS convention of making the "at" in "Screamat" lower case, because it's a two-word verb that takes only a direct object.
Creating a New Verb That Takes a Direct and Indirect Object
Okay, let's say that we want to define a verb "WAVE" that can be used in one of three ways:WAVEWell, we've already discussed how to program the first two verb templates. In fact, all of these ways of using the verb "wave" can be expressed in one verb object, let's call it waveVerb:
WAVE DIRECT-OBJECT
WAVE DIRECT-OBJECT AT INDIRECT-OBJECTThe action(actor) method defines what happens when the player types the command WAVE all by itself. The doAction line establishes verDoWave and doWave as the methods for handling the command WAVE DIRECT-OBJECT.waveVerb : deepverb verb = 'wave' sdesc = "wave" action( actor ) = { "You wave your hand at no one in particular. "; } doAction = 'Wave' ioAction( atPrep ) = 'WaveAt' ;The last line is one you haven't seen yet. It says that when the verb "wave" is used in conjunction with the preposition "at," then we are using the two-object form of the verb wave "WAVE DIRECT-OBJECT AT INDIRECT-OBJECT" and that both of the objects should be verified and acted upon using the methods:
verIoWaveAt(actor)Again, we stick with the TADS convention of capitalizing the preposition in a verb that takes two objects.
verDoWaveAt(actor, iobj)
ioWaveAt(actor, dobj)You may wonder what "atPrep" is. It is one of several preposition programming objects defined in adv.t. The useful thing about preposition objects is that they can represent several variants of the same preposition. For example, onPrep is a preposition object that represents "on," "onto," "on to," "down on," and "upon."
Some of the other preposition objects defined in adv.t that you can feel free to use are:
aboutPrep: about
aroundPrep: around
atPrep: at
behindPrep: behind
betweenPrep: between/in between
inPrep: in/into/in to/down in
fromPrep: from
offPrep: off/off of
onPrep: on/onto/on to/down on/upon
outPrep: out/out of
overPrep: over
thruPrep: through/thru
toPrep: to
withPrep: with
Using the New Verbs
Once you've defined the deepverb objects that teach TADS to recognize the verb and call the right methods, you can program objects to respond to your new verbs using the techniques discussed in Lesson Six.As an example, let's create a frog that we can scream at, or wave a wand at. If you scream at the frog, it is startled, but nothing significant happens. If you wave a wand at the frog, it turns into a beautiful princess (done by moving the frog object to nil and moving the princess object into the player's current location).
The frog's verification methods are empty, because there's really no unusual error case in which we wouldn't want to permit the player to scream at the frog, or wave something at it.
Now we can program the wand. It needs some verification methods to permit the user to type WAVE WAND and WAVE WAND AT FROG, and to disallow unusual cases (such as the player trying to wave the wand when he isn't holding the wand). The verDoWave method handles the verification for the WAVE WAND possibility and the verDoWaveAt method handles the verification for the more complex WAVE WAND AT INDIRECT-OBJECT possibility.frog : item location = startroom noun = 'frog' adjective = 'ugly' sdesc = "ugly frog" adesc = "an ugly frog" ldesc = "You've never seen such an ugly frog in your entire life. " verDoScreamat(actor) = {} doScreamat(actor) = { if (actor.isCarrying(frog)) { "Startled, the frog tries to squirm out of your grip, but it can't seem to break free. "; } else { "Startled, the frog jumps several feet into the air. When it lands, it glares at you, blinking its protruding eyes."; } } verIoWaveAt(actor) = {} ioWaveAt(actor, dobj) = { if (dobj == wand) { "You wave the wand at the frog, and much to your surprise, it turns into a beautiful princess! "; frog.moveInto(nil); princess.moveInto(actor.location); } else { "Nothing happens. "; } } ;wand : item location = startroom noun = 'wand' adjective = 'magic' sdesc = "magic wand" ldesc = "The black wand has a silver tip which sparkles. " verDoWave(actor) = { if (not actor.isCarrying(self)) { "You're not holding the wand! "; } else { "You wave the wand around in the air. The air seems to shimmer a bit, but nothing happens. "; } } verDoWaveAt(actor, iobj) = { if (not actor.isCarrying(self)) { "You're not holding the wand! "; } else if (iobj != frog) { "The air around <<iobj.thedesc>> seems to shimmer a bit, but nothing happens. "; } } ;
Sample Transcript
Here's what the game looks like once you've programmed these new verbs and items:Cave You are standing in a cave. You see an ugly frog and a magic wand here. >SCREAM Aaaaaiiiiieeeee!!! (You feel much better now.) >WAVE You wave your hand at no one in particular. >EXAMINE WAND The black wand has a silver tip which sparkles. >EXAMINE FROG You've never seen such an ugly frog in your entire life. >GET WAND Taken. >SCREAM AT FROG Startled, the frog jumps several feet into the air. When it lands, it glares at you, blinking its protruding eyes. >GET FROG Taken. >SCREAM AT FROG Startled, the frog tries to squirm out of your grip, but it can't seem to break free. >DROP FROG Dropped. >WAVE WAND You wave the wand around in the air. The air seems to shimmer a bit, but nothing happens. >WAVE WAND AT FROG You wave the wand at the frog, and much to your surprise, it turns into a beautiful princess!