From: librik@cory.Berkeley.EDU (David Librik)
Subject: Re: TADS fragment & moaning
Organization: University of California, at Berkeley
Date: Fri, 13 Nov 1992 04:12:35 GMT

amead@s.psych.uiuc.edu (Alan Mead) writes:

>I disagree with David Librik about the usefullness of reading ADV.T .
>Or maybe we just disagree on the meaning of "getting started".

I never suggested that you read it.  But you should have it printed out
and accessible, because to do many things you need to use standard properties
of basic ADV.T classes -- and these properties are poorly documented (if at
all) in the TADS manual.  (For instance, the manual's description of a Room
does not mention enterRoom or the whole leaveList structure.  These are
well-documented in the source code, though).  It's clear that Mike Roberts
intended TADS programmers to use the source.

>I *do* think you should read DITCH.T as it has a lot of neat tricks (I
>often think some features are there just to demonstrate them).  In
>fact, if you are at the stage where you are implementing "special
>effects" then I don't think you are "getting started" anymore.

Not only are there "tricks" in DITCH, it's the only place you can see how
to use basic TADS functions like daemons, fuses, and notifies.  The lack of
good examples and explanations of them is one of the few failings of the
manual.

>Also, just because the ADV.T source is there, I woudn't advise anyone
>to alter it except as a last resort.  You will have to edit the game to
>make it compatible with future versions of ADV.T (even running the
>slight risk that your changes will be incompatible with some future
>expansion of ADV.T). ...

>Further, I think you can do most things by defining new classes in your own
>source file.
[ code deleted ]

You can't avoid modifying ADV.T, I'm afraid.  You can supplant the whole ADV
structure if you want (using "erooms" rather than Rooms, as your example
showed), but then you have to redo darkrooms, nestedrooms, etc. etc.  The
secret is to figure out exactly what needs to be done, and comment the heck
out of it when you do it.  This discussion will probably soon be moot, as
I've was told (rumor rumor) that TADS 2.0 will have an explicit way of
overriding bits of the definitions in ADV.T without having to modify that
file.

>I'd like to see other people's tricks too.  I haven't implemented any verbs
>more complicated than the above.

(it's all code from here on out, skip the rest of this note if you don't care)

Here is code to handle a "score room" like the Well House in ADVENTURE.
Treasures are marked by having their istreasure property set; their point
value is stored in their value property.

(put this within a Room definition)
/*
 * This is the "score room" -- treasures left in here cause points to be
 * gained.  If they're not here, you don't get the points for them.  Handle
 * that.  Grab( obj ) is called when "obj" is being removed from the room,
 * or from anything inside the room (including you!), though it doesn't
 * actually move "obj."  roomDrop( obj ) is called when "obj" is being
 * dropped in the room, and actually moves "obj" too.  Add on to them.
 * Note that if an object is being directly moveInto()ed into this room,
 * that doesn't count as "dropping," so you'll need to increase the score
 * yourself.
 */
Grab( obj ) = {
	      local loc;

	      local := obj.location;
	      inherited.Grab( obj );
	      if (loc = self)			// was it in the room?
			if (obj.istreasure)	// was it a treasure?
				incscore(-obj.value);
	      }

roomDrop( obj ) = {
		  inherited.roomDrop( obj );
		  if (obj.istreasure)
			incscore(obj.value);
		  }

---------

Here is some more complicated code, that handles the whole business of
"magic words" -- things that you SAY that have an effect.  In fact, this is
a general solution to the problem of handling things you say.  Any object
can be declared to be "listening" by having its islistening property set
to true.  If an object is listening, that object's listen() method will be
called when you say things.  It's up to the object to decide what to do
about it.  The example here involves a security system.

preinit: function
{
  // Set up the listenlist.  When an actor does a "say strObj" (for some
  // string), the "listen" method of each object on this list will be called.
  local o;

  strObj.listenlist := [];
  o := firstobj();
  while( o <> nil )
  {
	if ( o.islistening ) strObj.listenlist := strObj.listenlist + o;
	o := nextobj( o );
  }
... whatever else goes in preinit ...
}

Now in strObj, modify the doSay method:

doSay( actor ) =
{
	local rem, cur, tot, i;

	"Okay, \""; say( self.value ); "\".";

	// descend the listenlist, calling every member's "listen" method
	rem := self.listenlist;
	tot := length( rem );
	i := 1;
	while ( i <= tot )
	{
	    cur := rem[i];
	    cur.listen( actor, self.value );
	    i := i + 1;
	}
}

Now an example of this in use.  Here is the object that controls the
security system, which interrogates the adventurer entering the Vault.

securitySystem: thing
{
   islistening = true;
...
   listen( actor, string ) =
	{
	// only listening if system just asked "Who goes there?", and only
	// for secret password "PLUMBER".
	if ((Me.location = vault) and (self.loudspeakerActive)
	    and (lower(string) = 'plumber'))
		{
		self.loudspeakerPassed := true;
		}
	}

There is a method of the security system called Run, which is run as a daemon
(by notify) when you enter the vault.  It does things like ask "who goes
there?" and checks variables like loudspeakerPassed to see if you gave the
right answer.  This can also be used to handle "walkie talkies" which are
listening to you if you are holding them.

This is turning into comp.lang.tads, here.

- David Librik
librik@cory.Berkeley.edu