Expanding the Standard Library

When adding grammar statements to the library there are a few points to be aware of. This chapter attempts to identify these points and assist you making your additions as seemless and robust as possible.

When adding a new verb to the library, it is important to be sure that you are doing a good thing. Adding a new verb simple to facilitate a guess-the-word type puzzle is definitely a bad thing. On the other hand, having an obvious verb missing is almost as annoying as being made to guess an obscure one. Also consider that adding a new very doesn't always mean adding a new function. You may find that a required verb is simply a synonym for an existing verb. In this case, simply add a new grammar statement with the synonym and point it to the same function. In the library file you will find many functions that are mapped to from more than one grammar statement. For example, here is the start of the global function +insert and its matching grammar statements:

   grammar insert *held on *present      >insert_on
   grammar put *held on *present         >insert_on

   {+insert_on 
   break +reach noun2
   ...

Another possiblity it to define "put" as an acutal synonym of "insert". There are potential dangers with this method that are described in the section on synonyms.

Now for a few general rules. Each verb that involves touching an object should usually to check that the object does not have the attribute OUT_OF_REACH before allowing the player to manipulate it. This, of course, does not apply to verbs that can only be performed on objects that are being held. The following line of code is an example from the top of the +take function:

     {+take
     break +reach noun1

This above line tells the JACL interpreter to break true if the function +reach breaks true. In practice, this means that if the the object is unreachable by the player, nothing beyond this line will be executed. Below is the content of the +reach function from the library:

     {+reach
     if noun4 has OUT_OF_REACH
       write <p> noun4{The} " " noun4{is} " out of reach.^"
       set TIME = false
       break false
     endif
     }

This function simply tests if the specified object has the attribute OUT_OF_REACH. If so, an appropriate message is displayed and the variable TIME is set to false. Finally, the break false command says that the execution should not continue after calling break command. If the object does not have the attribute OUT_OF_REACH, the function will terminate normally (an implicit break true), and executing will then continue from the line after the calling break command.

Most verbs will also make a similar call to the function +darkness. This function tests whether the player is currently in darkness or not. Actions that require the player to see should have the line:

     break +darkness

If your verb causes the object to be moved, such as the take verb, you must also ensure that the object is given the attribute TOUCHED if the move was successful. This will ensure that any tests as to whether the object has been moved from its initial position or not will be accurate. This time an example from the end of the +take function:

   ...
   override
   write "<p>You take " noun1{the} .^
   move noun1 to player
   ensure noun1 has TOUCHED
   }

If the verb performs any tests to check whether the move should be successfully completed under the current circumstances or not, an override command should be added directly before any effects are coded, such as in the example above. This allows override functions to be associated with objects in order to change the default outcome while still taking advantage of the tests you have coded. Below is an example of the type of tests that should be performed. The exacts tests you will require are, of course, specific to the nature of the verb you are coding.


   grammar ask *present for *carried             >ask_for

   {+ask_for
   if here has UNDER_WATER
      write "<p>Talking under water isn't very easy.^"
      set TIME = false
      break     
   endif 
   if noun1 hasnt ANIMATE
      write <p> noun1{The} " seem" noun1{s} " to be ignoring "
      write "your request.^"
      break     
   endif 
   if noun1 has DEAD
      write <p> noun1{The} " " noun1{is} " a bit too dead to "
      write "respond.^"
      set TIME = false
      break     
   endif 
   if noun1 = player
      write "<p>I think it might be time to take a break and "
      write "get a cup of tea.^"
      set TIME = false
      break     
   endif

As you will have seen above, it is also important that the variable TIME is set to false if the move typed by the player could not be performed. The state of this variable determines whether the eachturn functions are executed, as if a move is not possible, time shouldn't pass.

One last thing to keep in mind when adding grammar statements is whether its scope indicators are going to clash with any other existing grammar statements. For example, consider the following two lines:

     grammar give *present grief >hassle

     grammar give *held to *present >give_to

Each games vocabulary is stored as a tree. The following tree is a representation of the two grammar statements above.

Given the two grammar statements above, the command

     give sword to troll

would produce the message

     You can't use the word "to" in that context.

This is because sword is a match for *present, therefore causing the parser to branch down a path that only allows to word grief to be used next. This is obviously not the desired effect. Using $text in a grammar statement is equally dangerous. As an exteme example, using $text as the first word of the first grammar statement will prevent any others from ever matching. It is therefore important to bare in mind that grammar statements are tested in the order they appear in the game file, starting from the top.