+-------------------------------+

  A TADS Tip Sheet, version 0.3b

 +-------------------------------+


TADS, Michael J. Roberts' Text Adventure Development System, is a very
powerful and flexible programming system for developing text adventures.
(interactive fiction) However with that power comes a good deal of
complexity. Here are some tips that I've come up with over the past four
years of TADS authoring. And I thought that there may well be beginning
TADS authors out there who could use some of these tips. Feel free to
mail me with any suggestions for new tips or, indeed, corrections. I can
be reached at tela@tela.bc.ca.

Note that this tip sheet was originally written prior to the publication of
the TADS 2.2 Release Notes. Some of the material in this tipsheet is
actually explained, in far more detail, in those notes, especially the
rewritten Book of the Parser.

 - N. K. Guy, tela design. (http://www.tela.bc.ca/tela/)


RESTRICTIONS:

You may distribute, modify and copy this file as much as you like,
but it cannot be bought or sold. Please include this notice and a
list of any changes you made if you choose to redistribute it.


STANDARD PARANOID ANTI-LITIGATION STUFF:

I believe that the information contained in this document is reasonably
accurate. However, I make *no* guarantees of *any kind* that the
document is error free or will meet your needs or anything like that.
You assume full risk for using or not using any information in this
file. If you find something wrong, please mail me a correction and I'll
fix it. I hope that's all that needs to be said on this point.

 Also, any mention made within this document of commercial or shareware
products is purely for informational purposes, and does not imply an
endorsement of any kind by anybody.


VERSION HISTORY:

Version 0.1. Written 4/26/93 N. K. Guy (tela@tela.bc.ca)
updated to 0.1a. (banana tree example code fixed) 3/18/94
updated to 0.2 to reflect TADS 2.2.1.0 Freeware 10/19/96
updated to 0.3. Added the #pragma C+ and setit() issues, TADS Page URL. 10/28/96
updated to 0.3a. Added the numberedObject stuff. 1/15/97
updated to 0.3b. Added Ditch Day, hiddenItem/obstacle and moveInto bits. 12/23/97


WHAT IS TADS?

TADS, the Text Adventure Development System, is a particularly groovy
system for programming text adventure games (sometimes called
"interactive fiction") on a variety of computer platforms. TADS and Graham
Nelson's Inform are the two most powerful and most popular development
systems for writing text adventures currently available at time of writing.

 TADS was originally a shareware package written and published by High
Energy Software. However, in mid 1996 TADS author Michael J. Roberts
publicly announced that TADS was to become a freeware product and that
High Energy Software would be shutting down the bulletin board system
that it used to support the program. He has made good on his promise,
and has even freely released the source code that makes up the program.
You no longer have to pay anyone to use TADS - it's totally free!
However, Mike Roberts retains copyright to the TADS system, so you can't
go and change it or try (operative word here is try) and make lots of
money off it without his permission.

 For more information on TADS have a look at the unofficial TADS page:

 http://www.tela.bc.ca/tela/tads/


WHERE CAN I GET IT?

You can find the latest and greatest version of TADS in a variety of
places, including, if you have access to Internet FTP:

 ftp://ftp.gmd.de/if-archive/programming/tads/

 This site, the Interactive Fiction Archive (if-archive) is at GMD, the
German National Research Centre for Information Technology. It's run by
volunteer maintainers Volker Blasius and David Kinder, to whom we all
owe a debt of gratitude. Note that if you don't live in Germany and find
the connection to be rather slow, or if you want to be a good
net.citizen and minimize your use of overtaxed international links, you
can access the if-archive at a number of mirror sites. For example, US
users may want to try Washington University's mirror at wu-archive:

 ftp://ftp.wustl.edu/doc/misc/if-archive/programming/tads/

 European users outside Germany could try the Finnish University and
Research Network's mirror:

 ftp://ftp.funet.fi/pub/misc/if-archive/programming/tads/

 Additionally, if you have access to Usenet news and you're interested in
discussions on the topic of writing interactive fiction, check out the
newsgroup:

 news:rec.arts.int-fiction.

 For discussions on the topic of playing interactive fiction games, check
out the newsgroup:

 news:rec.games.int-fiction.



 +---------+

  Some Tips

 +---------+


READ THE MANUAL.

TADS has a great manual. A wondrous manual. Michael J. Roberts clearly
poured half his soul and an awful lot of time into writing it. Read it.
Worship it. This may be something of an obvious tip, but spending time
with it will minimize time wasted later on figuring out why something
won't work.

 The manual is available in two forms at time of writing. The first is
typeset using TeX, the powerful and deeply arcane typesetting language
popular within the academic community. If you have a program that can
display TeX files (or, more accurately, that can convert the TeX files
into DVI files for display purposes) then you might want to get that. The
TeX files can be found at:

 ftp://ftp.gmd.de/if-archive/programming/tads/manuals/

 The second is an HTML (HyperText Markup Language) translation of the TeX
files for Web browsers, converted by yours truly. This version is on the
Web at:

  http://www.tela.bc.ca/tela/tads-manual/

 I'll probably upload it to the GMD if-archive as well. And I'm sure the
TeX files will be converted into all kinds of other formats over the
next while.


READ THE TADVER.* FILES.

Your copy of TADS should have come with a file called TADSVER.xxx,
where xxx is the operating system you use. This file is extremely
handy - it lists all the new features and fixed problems with the
latest versions of TADS. There are many useful new features that have
been added to TADS since the version 2 manual was released, and this
file documents them. No TADS user should be without it!

 Note that there are two versions of the TADSVER file - one that
lists all of the new features up to version 2.1 or so, (TADSV200.xxx)
and another file that lists the changes from 2.1 onwards. I've put the
most recent version of the Macintosh TADSVER file online at:

  http://www.tela.bc.ca/tela/tads-manual/tadsver-mac.html


READ SOME SOURCE CODE.

One of the best ways to learn how to program is, in my opinion, to find
some well-written source code and play with it for hours on end. You can
learn a lot through doing this. Tearing someone else's source apart and
modifying it for your own ends is a very educational activity.

 TADS used to ship with the full source for a small game, Ditch Day Drifter,
which illustrates many important basic features of TADS. Unfortunately
somewhere along the way the Ditch Day code got left out of the standard
TADS distribution. If you never got a copy, there's one at this URL:

 ftp://ftp.gmd.de/if-archive/games/tads/ditchday.zip

 And if you are on the Internet and have access to the treasure trove of stuff
in the if-archive at ftp.gmd.de, check out the sample source code
available there. For instance, there is an Examples directory in the TADS
programming area that contains a number of small source code examples
written by many TADS authors. A lot of these examples are written
specifically to teach people about various principles of game design.
Others are written to implement commonly-used features. For example, I
wrote a little set of modules that I find very useful for testing games
in progress. That file, wizard.t, is available in the examples directory.
Another useful file is bugs.t by Stephen Granade, which provides patches
for some minor bugs in the adv.t TADS libraries.

 ftp://ftp.gmd.de/if-archive/programming/tads/examples/

 In addition to the mini code examples there is original TADS source to a
number of complete full-length games on ftp.gmd.de as well. For example,
Dave Baggett, in a deeply admirable selfless gesture, has ported the
classic Colossal Cave (ie: "Adventure") game to TADS and published the
source code in order to help train future generations of TADS authors.
He's also made the source to his epic game "Legend" available. 1995
Interactive Fiction Contest winner Magnus Olsson has put the source to
his winning entry "Uncle Zebulon's Will" in the same directory, and TADS
author Michael J. Roberts has put his games "Deep Space Drifter" and
"Perdition's Flames" online as well.

 ftp://ftp.gmd.de/if-archive/games/source/tads/

 There are also a lot of other files in the if-archive that, although not
directly related to TADS, nevertheless contain extremely useful
information. For example, Graham Nelson's Inform compiler, which
generates games compatible with the classic Z-machine system designed by
Infocom, has a well-written manual that contains a lot of useful tips
that can be used by any text adventure author. Check out his fascinating
"Craft of Adventure" document.

 ftp://ftp.wustl.edu/doc/misc/if-archive/info/


 Now let's get into some of the technical tips.


*NEVER* MODIFY GAME STATE IN VERIFY METHODS.

This is a very very common problem. The way TADS uses the "verify"
method in a verb can be quite confusing, and it can lead to a lot of
problems. Verify methods are object methods that start with "ver".

 Basically, remember that TADS doesn't use the verify method solely
to see if an item can be verbed appropriately. It also uses the *same
method* as part of its disambiguation routine. When it does so it
silently calls the method. That means it calls it, but suppresses any
text that the message may try to produce. If any text is produced and
hidden then the game knows that the item in question can't be verbed by
the verb.

 The upshot of all this is that if you change the state of the game
somehow and don't simply display text you can really get strange
things happening when that verify method is triggered inadventently
by a disambiguation routine.

 Here's a concrete example. This is bad:

 badMagicTurkey: item
   sdesc = "magic turkey"
   [ etc. etc. ]
   verDoTouch( actor ) =
   {
     "Good heavens! The magical turkey vanishes
     in a cloud of tangerine-coloured vapour! ";
     self.moveInto( nil );
   }
 ;

 The code is bad because the disambiguation function might call that
verify method sometime, and if it does so it'll suppress the text but
modify the game state by moving the turkey into nil. Thus our turkey may
suddenly vanish for no readily apparent reason, and the player won't be
notified when it does. The fix? Simply do this:

 goodMagicTurkey: item
   [ etc. etc. ]
   verDoTouch( actor ) = {}
   doTouch( actor ) =
   {
      "Good heavens! The magical turkey vanishes
      in a cloud of tangerine-coloured vapour! ";
      self.moveInto( nil );
   }
 ;

 Since our verify method has simply an empty method the runtime just
moves on to the actual verb method and executes it. No problems.
Check out pages 36-39 of the TADS manual (a crucial section, by the
way) and particularly page 39 for more details. This is the section
titled "Disambiguation" in Chapter 4.


*NEVER* SET OBJECT LOCATIONS MANUALLY AT RUNTIME.

This is actually explained in chapter 4 of the manual, but I feel it's
worth repeating here.

 It's OK to specify an item's location manually in the initial game
definition. For example, this is cool, insofar as euphoniums can possibly
be considered to be cool:

 Euphonium: item
  location = bandRoom
 ;

 What you *don't* want to do is set an item's location manually like that
within code that is executed during game play. Doing so totally messes
things up, because then the contents property of the container within which
the item is located is not updated correctly. So the following code is bad:

 Euphonium.location := Wastebasket;

 Instead, you want to use the moveInto() method, like this:

 Euphonium.moveInto( Wastebasket );

 That keeps everything neatly synched up.


COMMON COMPILER ERRORS.

Some of the most common compile-time errors result from forgetting
to add a semicolon or not closing parentheses properly. As
explained on page 201 of the manual, the compiler will try to skip
ahead to the next code object if it encounters a problem. Thus if
you end up with an endless string of compile-time errors appearing
on your screen when you try and compile you can usually safely
ignore most of the errors - it was likely the first one that caused
all the problems.

 Another common problem is accidentally adding a semicolon after an
if statement, thus:

   if ( elvis.isDead );
   {
     say( 'No kidding. ' );
   }

 This will cause a compile-time error as the semicolon after the
if(); statement will tell the compiler that the if statement is
complete.

Yet another easily made error is to name a local variable the same name
as a function. You can't do that.


COMMON RUNTIME ERRORS.

If you forget to return a value from a method or function you'll get
the dreaded 1010 error. This could also mean that you've asked the
game to evaluate a property that doesn't exist. For instance, if
you have something like this:

   if ( Me.location.isUpstairs )

 and Me.location = nil, you'll have problems because TADS will try to
figure out the isUpstairs property of a non-existent object. You'd be
better off doing this:

   if ( Me.location and Me.location.isUpstairs )

 Another common problem involves the number of arguments you send to a
function. Let's say you've invented a nice function like this:

   superDuperFunction: function( parm1, parm2, parm3 )
   {
      // ingenious code in here.
   }

 Now if you call your function using this code:

   superDuperFunction( nil, true, nil, nil );

 you'll get the annoying TADS-1026 error. The same error will occur if
you call a method with the wrong number of arguments.
 

TO MODIFY ADV.T OR NOT TO MODIFY ADV.T?

That is the question. This is one of those perennial Difficult
Decisions that TADS authors have to face. There are essentially three
basic approaches as I see it.

1) Don't touch adv.t at all. The only changes made are done through
   TADS 2.1's "modify" and "replace" features.

   Pros: game doesn't break when a new version of adv.t is released.

   Cons: as your game gets complex it gets confusing tracking all the
   patches you've made to adv.t.

2) Modify adv.t as needed, brazenly ignoring "modify" and "replace."

   Pros: the game can include a myriad features that go beyond the
   fairly basic adv.t defaults.

   Cons: it's a lot more work to maintain as every single time a new
   version of adv.t is released you've got to go through manually and
   check every bit of code to make sure it still works.

3) Skip adv.t altogether and use WorldClass instead.

   Pros & Cons: See next section.

 Either way it's good practice to document thoroughly any changes you
make to either adv.t or std.t or both.


TAKE A LOOK AT WORLDCLASS.

David Baggett, half of the Adventions team famous for the Unnkulian
Unventures, has designed a complete replacement class library system for
TADS. WorldClass replaces the standard adv.t and std.t TADS libraries
altogether.

 WorldClass is an extremely powerful and flexible class library system
that lets you do some pretty impressive stuff. It's much more consistent
in structure and naming, and supports a lot of very useful concepts. For
instance, it lets you treat all five senses equally in a game, and can
handle abstractions like knowledge of items.

 There are two disadvantages to WorldClass as I see it, however. The
first is that it's considerably slower than adv.t on old machines. If
you have a reasonably modern computer, this won't be an issue, but if
you have a really ancient clunker (eg: Mac Plus, IBM PC AT) then you'll
find WorldClass games take a long time thinking between moves. This is
because all items in the game are considered, rather than just those in
your immediate surroundings. This means that cool stuff like knowledge
classes are supported, but does slow things down.

 Second, WorldClass is quite a bit more complicated than adv.t. It lets
you do a lot more than adv.t, but does have a steeper learning curve as
a result. If you want to knock off a quick mini game, you might want to
stick with adv.t. But if your ambitions are a bit higher, consider
spending the time to learn what WorldClass can do for you!

 WorldClass, including Paul Gilbert's excellent manual, is in the
if-archive at:

 ftp://ftp.gmd.de/if-archive/programming/tads/worldclass/

 Or you can check the WorldClass Programming Page:

 http://www.df.lth.se/~mol/progtadsworldclass.html


CASE IS NORMALLY SIGNIFICANT.

When you *play* a TADS game you can enter commands in upper, lower or
mixed case and everything works fine. However, TADS *code* is
normally case sensitive. If you're having problems with a variable
or object name not being recognized double-check to make sure that
the capitalization is consistent. Common problems involve
properties like "islit" or "isseen" and methods like "verDoTake" and the
like. WorldClass is considerably more consistent than adv.t on this
score.

 Newer versions of the compiler do permit case insensitivity, but
you'll likely find your game won't compile with this option turned
on unless you check your entire source code for case issues.


CHECK OUT THE TADS DEBUGGER.

One of the coolest things about TADS is that it has a fabulous source
code debugger. This was one of the major perks for buying the shareware
version of TADS back when it was shareware. And now that TADS has gone
freeware the debugger is freely available at your disposal. At least, if
you use Macintosh or MS-DOS computers it is. At time of writing the
debugger wasn't available for any other platforms, but since the source
code is available I'm sure busy hands are at work as we speak, porting
the program to every platform under the sun.

 So be sure to check the thing out if you can get your hands on it. It
lets you run a game and step and trace through the source, making it
really easy to find bugs. You can even go in and change variables and
stuff, making it quite simple to test your code. The Mac version is
particularly nice, as it uses multiple windows to display the game, the
command line for the debugger and the source code. In fact, at time of
writing the Macintosh is the best platform for writing TADS games with
(in my opinion) for this very reason.


DON'T USE "THING".

Never create an object of type "thing". You'll get a runtime error
if the player tries to pick it up. Always create an object of type
"item" if you want something small and takeable. An item with "thing" as
its class is, of course, just fine.


LOCAL STATEMENTS.

Local statements must be the first statements to appear in a block
of code. Otherwise you get a "general syntax error." As mentioned
in the manual on page 71, the only kind of code that can precede a
local statement is another local statement. Thus, this next code
segment won't compile because its local statement is preceded by
something else:

 superFunction: function
 {
   "Hello there! ";
   local burp := true;
 }

 This (admittedly rather pointless) function will work flawlessly
if you put the local statement at the top, before any other statements
within the brackets.


WHY THE HECK WON'T FLOATING ITEMS, HIDDEN ITEMS OR OBSTACLES WORK?

In all likelihood you've defined something in the game as being a floating
item, hidden item or obstacle without also defining it as being a member of
whatever class it needs to be. In other words, this won't work:

   tree: floatingItem

 but this will:

   tree: fixeditem, floatingItem

 (of course, it may sound like a bit of a contradiction in terms to have a
tree that's both fixed and floating, but there you go.)

If you look in adv.t you'll notice that floatingItems and hiddenItems and
obstacles are all defined as objects rather than items. That means they
contain no code of any kind. The class is being used as a marker class
rather than one from which code is inherited.

 Note that if you've coded your stuff correctly and it still doesn't work
then it's possible that you neglected to include the preinit() code that
sets up the list of all floating and hidden items in the game.


WHENCE DOUBLE-QUOTED STRINGS?

By "double-quoted" I mean strings of text that are delineated by
quotation marks rather than apostrophes. There's a crucial difference.
TADS displays the former whenever it sees them but won't display the
latter unless you explicitly use the say() function. In other words,
this won't work:

   if ( self.colour = "red" )
     self.colour;

 The runtime will automatically display the word "red" whenever it
evaluates this piece of code. You probably don't want that. Instead
you should do this:

   if ( self.colour = 'red' )
     say( self.colour );

 Why does TADS have this unusual double-quoted string concept? Well,
because it's very useful. Adventure games are constantly displaying
text. It'd be extremely tedious to have to say something like
"printf( 'blah blah' );" or whatever all the time just to get words
on the screen. Double-quoted TADS strings are a useful shortcut.
This is explained on page 21 of the printed manual. 


"OF" IS A SPECIAL WORD IN OLDER TADS VERSIONS.

As described on page 32 of the manual, the word "of" is a special word
that gets removed by the parser in older versions of TADS. If you want
to use it in some other context (say, "accuse Ronald of murder") then be
sure to upgrade to version 2.2, which lets you use "of" as a preposition
and removes the previously hardcoded restriction.


PLURAL AND SINGULAR PROBLEMS.

Let's say you have an object somewhere with a noun of "blinds".
Let's say you also have another object elsewhere with a plural of
"blinds". Now you won't be able to refer to the item with only a
noun set to "blinds" - you'll get the "I don't see that here"
message. Both have to be either noun only or plural only.


CONDITIONAL VOCABULARY.

TADS doesn't permit conditional vocabulary in noun and adjective
definitions. It sets up a table of vocabulary words at compile time. So
something like this is not legal:

   noun =
   {
     if ( self.isBig )
       return( 'big' );
     else
       return( 'small' );
   }

 However, starting with version 2.2 you can add and delete words at will
using the addword() and delword() built-in functions. These don't let you
set up conditional code like the example above, but do let you add and
delete vocabulary words at runtime. Very handy feature!

(note however that there is a bug in the Macintosh version of the TADS
runtime at time of writing. If you add a word using addword() and then
undo that move then the word is not removed as it should be.)


SPACES AFTER STRINGS.

It's usually good form to add an extra space after a string of text,
thus:

   ldesc = "It's an ordinary turnip. "

 instead of:

   ldesc = "It's an ordinary turnip."

 Why? Well you never know what text might be displayed next. If, say,
a daemon displays some text without first printing a "\b"; sequence
to add a blank line you'll get your sentences running together.
Adding a blank space prevents this from happening.


TADS IS OBJECT-ORIENTED.

It really is! Don't code up objects with endless case statements and
if-else statements when you can inherit properties and methods from
classes. You'll find the code is much more elegant and easy to
understand and often takes up less room as well. Thus, this following
piece of code is a Really Clunky Way to do things:

 bananaTree: fixeditem, floatingItem
   sdesc =
   {
     switch( Me.location )
     {
        case Forest:
          "big";
          break;
        case Greenhouse:
          "small";
          break;
        case Jungle:
          "enormous";
          break;
      }
      " banana tree";
   }
   [ etc etc ]
   locationOK = true
   location =
   {
      if ( Me.location = Forest or Me.location = Greenhouse
      or Me.location = Jungle )
        return( Me.location );
   }
 ;

 This is a somewhat better way to do the same sort of thing:

  bananaTree: fixeditem, floatingItem
    sdesc =
    {
      Me.location.bananaTreeString;
      " banana tree";
    }
    [ etc etc ]
    locationOK = true
    location =
    {
       if ( Me.location.hasBananaTree )
         return( Me.location );
    }
  ;

 Then you could set the hasBananaTree property to nil in the "room"
class, so that all other rooms would inherit this nil value.
Special locations could have the property set to true. Likewise,
those special locations could have their bananaTreeString
properties set to display the appropriate message.

 What's the advantage of doing it this way? Well, putting special
case code into special rooms means you don't have to hardcode a
whole pile of unwieldy conditional coding into the floating item.
Also, special case stuff (ie: the forest having a tree or whatever)
is associated with special case locations.

 (note: this isn't the world's greatest piece of sample code as it
has one major inconsistency in it. That is, unless you've also
modified the chair item class in adv.t to pass the hasBananaTree
value through, the tree will mysteriously vanish if you sit down on
anything. Just something to keep in mind!)


BREAKING OUT OF THE RUNTIME.

Sometimes TADS gets stuck and only displays an error message instead
of accepting input. Other times you type something but absolutely
nothing is displayed - the game just returns you to the > prompt.
These usually indicate a bug in your TADS code. In either case
typing the special command $$ABEND in the runtime window should
force the runtime to quit.


BEWARE CONTROL CHARACTERS.

It seems that accidentally embedding a control character in your TADS
source will often cause the compiler to bomb. If you're getting
mysterious compiler errors from a piece of code that looks perfectly
legitimate, you might have accidentally typed an invisible control
character into your code - maybe your finger slipped off the shift key
or something.

In cases like this it's a good idea to run your source through a filter
program to eliminate any possible control characters before trying to
figure out why an otherwise reasonable-looking piece of code isn't
working. For example, Macintosh users of BBEdit can use that text
editor's "Zap Gremlins" feature to toast all control characters.


BEWARE OF #pragma C+

Remember that TADS supports two different styles of operators - its own
style, and the style used in C. There are some similarities and some
differences between these two styles.

 TADS lets you choose which style of operator you want. If you include
the header "#pragma C+" at the start of each source code file then the
compiler will use C style operators. If you don't include this header
or include the header "#pragma C-" then TADS will use its default style.

 The thing to beware of is that some examples of TADS coding out there
use the traditional style and some the C style. The vast majority of the
code I've seen uses the traditional style, but I've noticed a handful of
code examples (usually written by Mike Roberts in his documentation)
that use the C style. This can lead to problems if you copy a chunk of
code that uses one style operator and paste it into another file that
uses the other style.

 So, let's say you see some code that includes this line:
 
 if ( v == inspectVerb )

 That was written in the C style. The traditional TADS operator style
would have read like this:

  if ( v = inspectVerb )

 Likewise, you might see some code that looks like this:

  if ( self.value != nil )
 
 The traditional TADS way to code that is:
 
  if ( self.value <> nil )

 The other common problem operator is the assignment operator. In the C
style it's this:

  trombone.noiseValue = true;

 but in the traditional TADS style it's this:

  trombone.noiseValue := true;

 So be sure to check which operator method the code you're using is
written in. If the code contains the line #pragma C+ at the start then
you know for sure it's written in the C style. However if it doesn't
have anything then you're best off checking the code carefully to make
sure that it is, in fact, written in the traditional TADS style. Some of
the operators are compatible between styles - but others are not and
will cause the compiler to choke.

 The C style operators are described in detail in the TADS 2.2 Release
Notes.


ADD IN THE DEBUG FUNCTIONS

The standard debugTrace() function simply lets you enter the debugger's
command line mode when you're running it. It's useful, but recent
versions of TADS support a much niftier extension to the function. This
extension turns on a diagnostic mode when you're playing a game. Even
more usefully, this diagnostic mode works with the standard runtime as
well as with the debugger program.

 The diagnostic mode works like this. Let's say it's turned on and you
type the command:

  >examine the iron bench

 The runtime then displays the following extra information:

  .  Checking words:
  ...  examine (verb)
  ...  the (article)
  ...  iron (adj)
  ...  bench (noun)
  .  Checking for actor
  .  Reading noun phrase
  ...  iron (treating as adjective)
  ...  bench (treating as noun)
  ...  found objects matching vocabulary:
  .....  white wooden bench
  .....  cast iron bench
  .  executing verb:  examine
  ..  setting it:  cast iron bench

 The runtime then displays the normal response to the command; in this
case:

  You're looking at the cold cast iron frame of an old-fashioned park
  bench.  It seems to have been painted recently with glossy black enamel.

 Note all the useful information. The game breaks down the command,
telling you which words it's treating as nouns or adjectives, then lists
all the objects in the game that match the supplied input. In this case
my game contains two items that have 'bench' as a noun, but the game
disambiguates further and only selects the cast iron one. It also
performs a setit() on the bench item.

 To add this handy feature to your game just add the following verbs:

  debugonVerb: sysverb
    verb = 'debugon'
    action( actor ) =
    {
      if ( debugTrace( 1, true ) )
        "Debug diagnostic mode engaged. ";
      abort;
    }
  ;
  
  debugoffVerb: sysverb
    verb = 'debugoff'
    action( actor ) =
    {
      if ( debugTrace( 1, nil ) )
        "Debug diagnostic mode disengaged. ";
      abort;
    }
  ;

 This problem with setit() is due to be fixed in the next version of the
TADS runtime.


"it" IS A PROBLEM WITH numObj AND strObj OBJECTS

Here's an obscure one. Let's say you have a method in a numObj
or strObj object. Here's a silly example of this:

  narfVerb: deepverb
    verb = 'narf'
    sdesc = "narf"
    doAction = 'Narf'
  ;

  numObj: basicNumObj;
    verDoNarf( actor ) = {}
    doNarf( actor ) =
    {
      local i, len;

      len := self.value;
      if ( len = 0 )
      	"No narf. ";
      else
      {
        "\b\t";
        for ( i := 1 ; i <= len ; ++i )
          "Narf! ";
      }
    }

 This pointless piece of code works like this:

 >narf 4

  Narf! Narf! Narf! Narf!

 The problem is that TADS will then set the value of "it" to numObj.
Which means that if the player types, say, "examine it" after issuing
the "narf" command, nothing will happen:

 >narf 3

  Narf! Narf! Narf!

 >examine it

 >

 This occurs because the numObj object hasn't got any verb methods
defined for any common verbs. Exactly the same thing will happen with
strObj objects, thus:

 >say "hello"
 You say "hello."

 >eat it

 >

 The easiest way to deal with this problem is to put the line setit( nil );
into your doNarf method. This resets the value of "it" to nil, safely
avoiding the whole mess.

 A more complex solution is to create a universally accessible floating
item that has no vocabulary words associated with it, then setting 'it'
to be that object. This allows for fancy tricks like this:

  >say "hello"
  Okay.  You say "hello."

  >x them
  I'm not sure what you're referring to by "them," because the last thing
  you referred to was the text "hello."


WHERE IS THE NUMBEREDOBJECT CODE? 

 The code for handling numbered objects seems to be missing from
the 2.2.1 adv.t distribution. Here it is. 

  /*
   *  numbered_cleanup: function
   *  This function is used as a fuse to delete objects created by the
   *  "numberedObject" class in reponse to calls to its newNumbered
   *  method. Whenever that method creates a new object, it sets up a fuse
   *  call to this function to delete the object at the end of the turn in
   *  which it created the object.
  */
  numbered_cleanup: function( obj )
  {
    delete obj;
  }

  /*
   *  numberedObject: object
   *  This class can be added to a class list for an object to allow it to
   *  be used as a generic numbered object.  You can create a single object
   *  with this class, and then the player can refer to that object with
   *  any number.  For example, you can create a single "button" object
   *  that the player can refer to with "button 100'' or "button 1000''
   *  or any other number.  If you want to limit the range of acceptable
   *  numbers, override the "num_is_valid" method so that it displays
   *  an appropriate error message and returns "nil" for invalid numbers.
   *  If you want to use a separate object to handle references to the object
   *  with a plural ("look at buttons"), override "newNumberedPlural" to
   *  return the object to handle these references; by default, the original
   *  object is used to handle plurals.
  */

  class numberedObject: object
    adjective = '#'
    anyvalue( n ) = { return n; }
    clean_up = { delete self; }
    newNumberedPlural( a, v ) = { return self; }
    newNumbered( a, v, n ) =
    {
      local obj;

      if ( n = nil ) return self.newNumberedPlural( a, v );
      if ( not self.num_is_valid( n ) ) return nil;
      obj := new self;
      obj.value := n;
      setfuse( numbered_cleanup, 0, obj );
      return obj;
    }
    num_is_valid( n ) =
    {
      if ( n = 0 )
      {
        "There aren't zero "; self.pluraldesc; " here! ";
        return nil;
      }
      else if ( n > self.maxNum )
      {
        "There aren't that many "; self.pluraldesc; "! ";
        return nil;
      }
      else
     return true;
    }
    dobjGen( a, v, i, p ) =
    {
      if ( self.value = nil )
      {
        "You'll have to be more specific about which one you mean. ";
        exit;
      }
    }
    iobjGen( a, v, d, p ) = { self.dobjGen( a, v, d, p ); }
    maxNum = 10
  ;


 +--------------+

  Macintosh Tips

 +--------------+


 Here are some tips for the users of the Macintosh version of TADS.
I don't normally do compilation on the DOS or UNIX or other flavours
of TADS so I'm not going to include any tips for those platforms
unless someone sends me some.


COMPILER BOMBS.

If you have a very large game and you're having problems with the
compiler crashing when you try to compile, it's possible you don't
have enough memory allocated. Try increasing the amount of memory
set aside for the compiler by changing the setting in the "Get
Info" box. 1500 K is usually enough for even a big game.


MULTIFINDER OR SYSTEM 7.x.

Don't forget that TADS can run in the background under MultiFinder
or under System 7.x. However once TADS has finished loading in the
files and starts the actual compilation it'll lock up your Mac for
the duration of the compile.


TEXT EDITOR.

If you're struggling with editing code on a word processor or
something, take a look at some of the freeware and shareware text
editors out there. There are quite a few, including Edit II and
Alpha. Probably one of the best (IMHO) is BBEdit, however.
 BBEdit itself is now payware, but there's still a freeware "Lite"
(sic) version available. Any version is ideal for editing TADS
code. They do bracket and brace balancing, semi-automatic
formatting, GREP search and replace, no wordwrap and a thousand and
one other features. Try to find version 2.2.2 which, unlike the
newer BBEdit Lite, can do file comparisons. This function,
analogous to a "diff" utility, is an extremely nice way to compare
older versions of source with the new. Of course obsessive hackers
can check out the port of emacs...


COMMAND-PERIOD.

Don't forget that TADS can now break out of endless loops by hitting
command-period, like all good Mac programs do.


 Note that the HTML version of this file normally lives at:

 http://www.tela.bc.ca/tela/tads/authoring/tads-tip-sheet.html