RAP 1.0
Reactive Agent Planner for TADS
-------------------------------
by Nate Cull (culln@xtra.co.nz, www.geocities.com/Athens/Forum/6748)


Provisional One Point Nought Docuumentation

Under Construction
Handle with Care
Danger Infohazard
Etc, ...



Archive Contents
----------------

This document should have reached you inside a ZIP archive.  
That archive should have contained:

 RAP10DOC.TXT - RAP 1.0 Documentation (this file)
 RAP10K.T     - RAP 1.0 Kernel (TADS source)
 RAP10P.T     - RAP 1.0 Planbase (TADS source)
 RAPTEST.T    - RAP 1.0 Test Game File (TADS source)
 	

 


FAQ
---

1) What is RAP?
---------------

RAP 1.0 is a goal-planning library for TADS, the Text Adventure 
Development System.  

It's intended for competent TADS authors, so I assume that you're
familiar with the TADS language concepts and syntax, and the general
art of designing text adventures.  If I'm confusing you already,
check out my URL above or rec.arts.int-fiction on Usenet for 
information on the text adventure underground.


2) So what does RAP let me do?
------------------------------

It will let you build smarter NPCs.

Okay, so in IF circles that's a little like claiming to own the 
Brooklyn Bridge.  And you're right to be cynical.  RAP isn't that
smart.  But it is a simple backward-chaining goal search algorithm 
that is adaptable to any situation.  That means, right out of the box 
it:

  * gives NPCs (or the player) the ability to traverse a map without
    specifying individual movements (now you can implement a GO TO 
    command like in _Suspended_ and _Suspect_).  A built-in map
    scanning function generates NPC planbases from existing code 
    with no extra effort.
    
  * can be scaled up to arbitary situations, not just map-crawling.
    Your NPC faces a locked door?  No problem, he can hunt down 
    the key.  She's hungry?  Let her find food.  Implement social
    interactions!  Solve massive computational AI dilemmas on your 
    PC!  (And when you've done it, let me know how, so I can take
    the credit. Heh heh.)

  * is fully object-based and overridable, so you can combine the
    best of procedural TADS methods with list-based goal directed
    behaviour.  A particular RAP plan is too dumb for your NPC?
    Then create a new one on the fly, or implement a complete 
    algorithm in an action step.  Be as simple or creative as you want.

  * uses a shared planbase, so multiple actors in a game can use the
    same knowledge pool, unless you want them to act differently,
    in which case (with a bit more effort) you can.


3)  So what _doesn't_ RAP do?  
-----------------------------

Nothing important. :)

Okay, there are a couple of _tiny_ things.

Firstly, it has no built-in learning ability.  An actor's knowledge 
must be precoded in the form of plans.  That's not a major problem,
since most IF doesn't even need goal-seeking, but it's certainly room
for expansion.  But I have no intention of even trying to think about 
how that could be done at the moment.

Secondly, and a bit more annoying at present, there's no "fog-of-war"
implemented in version 1.0.  RAP assumes total omniscience of the state
of all objects.  That's believable with regards to map-crawling, for an 
actor who knows the area well, but an actor who instantly knows the
location of all objects and people probably needs to be dumbed down a bit.
Building a generic FOW function is next on my implementation list.
In the meantime, you'll just have to hardcode knowledge checks into
each condition's rTrue method.

Thirdly, RAP has no time sense, memory or look-ahead ability.  It will 
follow plans in a rigid, one-step-at-a-time mentality, without considering
consequences or making future predictions.  I have no idea how you would
do that, or even if it's feasible on a PC.  I suspect it's overkill myself,
but it's entirely possible that RAP could find itself walking in circles
in some situations.  If it does, let me know.


3)  How fast is it?

I don't know.  

That's something I want to find out by posting this 1.0 release.
RAPTEST.T computes fast enough, though not instantly, and that's
just dealing with ten rooms and one door.  Exactly how fast it
is in a full-size game could be interesting to learn.

I probably wouldn't want to have a dozen RAP NPCs in a WorldClass
library, though.


4)  What libraries does it work with?

Hopefully anyone's.

Definitely adv.t.

Probably WorldClass.

Are there any others?

I've tested it with adv.t.  I haven't tested it with WorldClass,
but the basic kernel at least should work unchanged.  The 1.0 planbase
may need changing if isCarrying, isIn, isReachable and the methods of
lockable and doorway classes are different.  I haven't used WorldClass
at all so I don't know.  This is one reason why I've separated the
kernel and planbase files, though.

Anyone want to test it with WorldClass?


5)  Enough with the advertising.  How do I use RAP in my game?
--------------------------------------------------------------

Fairly simply.

You include the two RAP 1.0 source files, RAP10K (the 1.0 kernel) and
RAP10P (the planbase), at the start of your game file.

Then, to make your NPC RAP-enabled, define it as a "rapper" class
as well as whatever actor class you're using.

If you want to use the automatic map-crawling functions, make a call
to rBuildMap() in your preinit function.  It's best run at compile time.

Define whatever special conditions or actions you need to make up your
game's planbase.

Then, whenever you want your NPC to make a decision, call its rapAct 
method with a top-level goal (condition and parameter).  

(Or if you want to be really clever, muck around with the lower-level
rFind method yourself.  But I'm not going to bother documenting that
here.)



6)  Huh?  Can you explain that again?
-------------------------------------

No.



7)  So how do I make sense of this thing?
-----------------------------------------

Five ways.

Compile RAPTEST.T and run it.  Play around with it, and don't forget to
YOMIN RAP.  Then read the code.  That will show you how to implement
a trivial map-crawler in RAP.

Read the source code for RAP10K.T and RAP10P.T.  I make no guarantees
about the readability or style of the code - it's 1.0 - but I have 
commented the major API functions.

Read _Alice's New Planner_ in this document, which is a brief overview of 
the RAP way of thinking about the universe.  There may be major errors in
my logic, but that's expected.  Let me know if it's completely 
incomprehensible, though.  The Dormouse tends to drink a lot of mushroom 
tea, and so is not a very reliable editor.  I'm shooting for partially
incomprehensible here.

Post on rec.arts.int-fiction.  I _might_ read it. TADS gurus much 
smarter than I certainly will.

Email me at the address at the top of this document with any questions,
comments, suggestions or allegations of errors.  I'll do my best to
respond intelligently.




Alice's New Planner 
===================
A Confused Sort of Introduction to RAP Planbase Programming
for Looking-Glass Girls and other Ordinary People
-----------------------------------------------------------

RAP thinks backwards.

Which is by and large a good thing, because we all generally think
backwards, even when we think we're thinking forwards.

Confused?  Alice was.

"Let me explain," said Rap, a rather large brown dog who happened 
to be sitting between the Dormouse and the Mock Turtle.

"When I say I think backwards, what I really mean is, when I get
up in the morning I don't start out by thinking of the first thing
I am going to do.  When you get up in the morning, do you first
think about putting on your dress and tying your shoelaces, or
do you think about the bright sunny day and how much fun it will
be to play in the garden?"

Alice wrinkled her eyebrows.  "I don't know.  I generally do both."

"Ah," said the Dormouse sleepily, "but that's because you're a 
Looking-Glass girl, and so you can do things the wrong way round and 
all at once.  Here in TADS-land, we generally only do one thing at 
a time and so we have to make it count."  

"Exactly," said Rap.  "So whenever I think, I do it simply and logically
and start from the top.  I start with a GOAL, which is what I want to
accomplish, and then work out how to make that happen.  Sometimes I
can see immediately what to do -"

"That would be an ACTION," sighed the Dormouse.

" - but otherwise, I have to look for other things to do " -

"SUBGOALS"

" - and which themselves have things to do to make them happen "

"CONDITIONS, PARAMETERS"

"- and so on, reasoning backwards, all the way - "

"BACKWARDS CHAINING" snores the Dormouse, who seems entirely asleep
by now.

" - until eventually I come up with one simple ACTION, which I do.
Like this!"

With which Rap threw a lump of sugar at the sleeping Dormouse, who
lazily opened his eyes and continued speaking as if he had never fallen
asleep.

"- and there you have it," said the Dormouse.  "Perfectly logical.
Backwards is forwards.  The proper way to do things."

"But," said Alice, "I don't understand.  How does this help me write
adventure games?"

The Mock Turtle sighed sadly and unfolded a blackboard from his shell.

"Because it gives," he muttered as he scribbled.  "Your NPCs.  A mind of 
their own.  This," he murmured, almost out of breath, "Is your brain.  
This.  Is your brain.  On RAP.  Or rather, Rap's brain.  On himself.  
Any questions?"


And this is what the Mock Turtle wrote:


rHappy: rCond
  sdesc = "rHappy"
  rTrue(a,p) =
  {
    return (a.isCarrying(ball) and a.isIn(startroom));
  }

  rPlans(a,p) =
    [ [rBe rCarrying ball
       rBe rIn startroom]
    ] 

;

Alice shook her head.  "That doesn't look like TADS code to me!  All those
square brackets!  I must be dreaming about LISP or something equally 
horrid, and I won't have it!  I shall pinch myself and wake up right now!"

"No," growled Rap, "You're still in TADS-land.  We're just using the list
structure.  You have read your TADS manual, haven't you?"

Alice blushed at this, because she _had_ read her TADS manual, but had
forgotten all the bits that came after "#include <adv.t>."  So she nodded
primly and said nothing.

"I will be using TADS list structures a great deal," said Rap firmly,
"in fact almost everything that is in my head is expressed as a list, 
so please pay attention."

The Mock Turtle scowled and rapped on his blackboard-shell.

"Shall we begin?" he said.  "This, harumph, young lady, is the top level 
of your friend Rap's brain, vacant as it is right now.  Translated into 
Looking-Glass English it says this:

     'You are happy if you are in the room "startroom" 
      and carrying the ball.  Otherwise, you are unhappy.

      (And you don't want to be unhappy, though that is 
       something you will be told elsewhere.)

     'You want to be happy?  Here's how.  First be carrying the ball.  
      Second, be in the room "startroom'.  And don't bother doing 
      anything else, because that's all you need to be happy.'  

"As you can see from his rather simple value system, Rap is a refugee 
from the '60s.  Pity you missed that decade, eh what?"

Hearing this, the Dormouse wriggled in his sleep and began snoring,
"All you need is the ball, yay yay yay, all you need is the baaaall..." 
before falling into the teapot with a sploshy gurgle.  Alice ignored
him.

"I can understand the rTrue method", she said somewhat uncertainly,
"at least I believe I can.  That tells me whether or not I am currently
happy.  I'm quite familiar with the isIn and isCarrying methods because
Mr Dodgson (after teaching me mathematics) has been showing me how to 
use the adv.t class library.  And I can assume that Rap wants to be
happy because there is a method call somewhere telling him so.

"But what is a plan?  And why is it laid out like that with all those
brackets?  What is an rBe?  What does it all mean?"

At this the Dormouse (who had been gurgling quietly in the bottom of
the teapot) poked his head above water and sang softly, "Ah-bees
make ah-honey, they ah-live in ah-hive, to rBe or not 2rBe, ah,
that's why we're rLive" until Rap pushed his whiskers back into 
the pot and and leaned both forepaws on the lid.

"rBe," said the Mock Turtle seriously, "is a RAP opcode.  All RAP
classes and methods begin with an r.  And I know you are going to 
ask me what an opcode is - "

"I wasn't," said Alice, who was feeling contrariwise, but the Turtle
ignored her.

" - so perhaps it is time I introduced you to the RAP plan syntax, which
goes like this:

  Plan group :-

     [

       [                                <-- one parallel plan
         opcode condition parameter     
        {opcode condition parameter}    <--- one step
        {opcode...}
       ]   

       [opcode condition parameter..]   <-- an alternative parallel plan

       [...]                            <-- etcetera

     ] "


"I once met an etcetera," said the Dormouse from the teapot.  "He was 
dating an elipsis, but they broke up. She ran off with a much older 
opcode."

Everyone ignored him, especially the Turtle.

"AS YOU CAN SEE," he frowned, "each Plan Group may actually be a set 
of PARALLEL PLANS.  And each Parallel Plan may actually be a sequence of 
STEPS.  (Please ignore the curly brackets - they're just there to indicate 
repetition.  If this were a proper syntax diagram they would be square 
brackets, but I'm using those already to show TADS list structures, so 
I had to be creative.)"

"Curly brackets, squiggly wiggly, repetition, ad infinity," muttered the
Dormouse and then shut up hurriedly before anyone could throw something
at him.

"AS I WAS SAYING," harumphed the Turtle, "our friend Rap's rHappy plan is 
very simple because he has only ONE parallel plan - to be in Startroom
while holding the ball - and only TWO steps in that plan."

"So the first step would be 

  rBe rCarrying ball

and the second is

  rBe rIn startroom

?"

asked Alice, curiously.

"I must say, you have very nice whitespace formatting," remarked Rap, 
"for a Looking-Glass girl."

"I've been practicing with the Caterpillar," said Alice.  "But that's 
right, is it?  I've read Rap's top-level Plan properly?"

"Yes, indeed," nodded the Turtle.  "You've read it right, all right."

"Read, write, read, write," sang the Dormouse, blowing tea bubbles 
absently in his sleep, "sequential planning's dead, I don't know my
name so I'll backwards chain, until I get out of bed."

"Some of us," growled Rap, "have better things to do than make bad
nursery rhymes.  I know I do.  I have a plan for my next action right 
here."

"Ah," said Alice, who was starting to catch on, but slowly because her
head still hurt from all this backwards talk, "so Rap takes each step
in sequence, right?  First he picks up the ball, then he goes to the
Startroom?"

"Not precisely," whined Rap, fishing in the teapot with one paw,
while the Dormouse dodged dreamily.  "STEPS are not exactly ACTIONS.
They're not things I DO, and they're not exactly in SEQUENCE."

"But the Turtle said - "

"They're CONDITIONS, and they're arranged in order of PRIORITY," finished
Rap, withdrawing his paw from the Dormouse's teapot and licking it.

"What's the difference?"

"If they were STEPS, I would take first one, and then the other, right?
I would always _pick up the ball_, and then always follow that with
_going to the startroom_.  Right?"

"Yes, of course," said Alice, who was a very logical girl and couldn't
understand why everyone else was being so strange.

"But then," said the Dormouse, emerging from the teapot and shaking his
whiskers furiously, "we should all be back writing sequential, procedural, 
algorithmic code, and right back where we started.  Doing things 
forwards.  When as I said, backwards is the only proper way to do 
anything."  Saying which, he washed his whiskers from the outside in, 
brushed his coat from the tail up, and promptly curled up inside the 
large bubbling Klein Bottle marked -EM KNIRD-.

"Exactly," said Rap.  "If I did everything forwards, I should be very
dumb indeed.  Supposing I was already holding the ball.  Why should I
want to pick it up again?  Or supposing I was halfway to the Startroom
when a frumious Bandersnatch came galumphing out of nowhere and snatched
it away?  They do, you know.  They're a menace.  If I were only following 
a sequence of STEPS, I would keep going as if nothing had happened.  Which 
would be quite silly indeed, don't you agree?  And certainly something 
that the standard TADS library could implement quite easily without 
introducing _me_ into the picture."

"I see," said Alice doubtfully, less and less sure all the time that she
did, but not willing to admit it.  "So every CONDITION in one Parallel
Plan has to be satisfied in order, and if it is it acts like a sequence
of steps, but if one condition fails, you go back and repeat it?"

"More or less," agreed the Turtle, "more or less.  Each CONDITION in
a STEP specifies something which must be true (such as the ball being
carried by Rap, or him being in the Startroom).  If that Condition 
is true, then Rap keeps going, checking out the next condition, and 
so on.  In that way it is a little like a sequence of actions.  But 
if it's false, then it becomes a GOAL for Rap to _make_ that condition 
become true."

"Loag, noitidnoc, loag, noitidnoc," sang the Dormouse from within the
Klein Bottle, but nobody could make any sense at all of him this time
so they didn't even bother to reply.

"Hmm," said Alice, even more doubtfully, but getting a little smarter
each time she thought about this.  "And of course, Rap then looks up
THAT goal as a Condition in his - what do you call your, er -  "

"My PLANBASE," barked Rap.

"- your Planbase -"

"Which, as its name indicates, is a database of Plans," put in the 
Turtle.  "(Implemented as the rPlans methods of the entire set of
rCond and rAction objects in the game file.  But I digress.)"

".od ouy ,seY" sang the Dormouse. ".od ouy ,seY"

" - you look up that goal in your Planbase," continued Alice determinedly,
"and find all the Parallel Plans for THAT Condition.  And if that Condition
isn't true -"

"I scan each plan in parallel.  Which is why they're called Parallel
Plans," finished Rap.

"Could you explain that part, please, Mr Turtle," asked Alice.  "I don't
think we've covered that."

"He scans each plan in parallel
 And each plan he scans, it's clear as a bell
 And he scans each step in each plan as well
 Until a condition fails, then it all goes to h - "

"AHEM!" shouted Rap and the Turtle together at the Dormouse, who had
crawled out of the Klein Bottle and was now blinking at them from a few
weeks south of Last Tuesday.

"I only meant - " said the Dormouse meekly -

"That's precisely your problem," snapped the Turtle.  "A Dormouse 
shouldn't _mean_.  It should _be_."

"That's demeaning," murmured the Dormouse from Next Week.

"Oh, do stop messing up the continuum like that.  You know it's already
far too wrinkly.  Anyway - "

"What the Turtle is trying to say," said the Dormouse, now fully awake and 
dropping back into the table's gravity well with a faint splatter of 
Hawking radiation, "is that Rap evaluates each Parallel Plan in a Plan
Group IN PARALLEL.  That is, for each Parallel Plan (for a particular
goal that he's trying to make true, remember) he looks at each Condition
in sequence.  Continuing to the next Condition if it's true, or creating
a new GOAL for that condition if it's not."

"So he creates a kind of Tree of Goals, then," said Alice, whose forehead
was getting almost as wrinkly as the continuum, though still a lot 
cleaner.  "A Goal Tree?  Or a Stack?  That sounds horribly AI-ish.  Does 
it take a lot of computational resources to store this tree?  And won't 
it expand to infinity?  And break the universe or something?"

"Heavens no, child," said the Turtle, glancing at the Dormouse, who nodded.
"It's perfectly safe.  We've taken steps to stop that sort of thing.
We remove duplicate goals from the stack, so it won't explode.  And then
there's the rIf opcode -"

" - which you still haven't talked about - "

"- but I'll get to that in time.  Anyway, Rap recalculates the Goal Stack
(it's really a stack, not a tree, though the list of active goals tends 
to grow a bit like a tree) - "

"An upside down tree," murmured the Dormouse, falling asleep again, 
"with its root at the top.  But of course you knew that already."

"Yes, we did.  So anyway, let's just say that Rap is quite good enough
at keeping track of his goals and things, and that he DOES evaluate each
Plan in Parallel.  And within each Plan, he goes through it step by step,
looking at each Condition -"

"But why does he look at multiple plans at once?" said Alice, whose
head was starting to spin, just like Linda Blair.  "He can only do 
one thing at a time, surely?"

"Ah, but he can THINK about lots of things at once.  Let me demonstrate," 
said the Turtle.  "With another Plan from Rap's planbase.  This one is 
for moving between rooms.  A very typical IF thing to want to do, and
in fact what Rap's author first wrote him for."

"Hey," said the Author, "leave me out of this, okay?"

The Turtle ignored him and scribbled on his blackboard-shell again:

   rIn(actor, param)
   {
    if (param = startroom) return (
     [
        [rBe rIn room2
         rDo rGo startroom]
     ]
    ); 

    else if (param = room2) return (
     [
        [rBe rIn startroom
         rDo rGo room2]

        [rBe rIn room3
         rDo rGo room2]

        [rBe rIn room4
         rDo rGo room2]
     ]
    );

   }

Alice looked dubiously at the board, which looked like nonsense, but 
being a well-brought-up young Looking-Glass girl she felt it was her 
duty to make _some_ sense of it all.

"I suppose," she said slowly, "I can work out some of this.  This seems
to be two Plan Groups for Being In two rooms.  The first one is simple
enough.  It tells Rap how to get to Startroom -"

"Not GET TO," growled Rap.  "How to BE IN.  There's a difference.  It's
a Condition, not an Action."

"As I'm a Dormouse," yawned the Dormouse, "not a Do-mouse.  I practice 
Being, not Doing.  It's much healthier."

" - how to Be In Startroom," Alice corrected herself.  "By... let me see.
First, Being In the room 'Room2'.  Which I suppose must be next to
Startroom on the map in RAPTEST.T."

"It is," growled Rap.  "Very good, Looking-Glass girl."

"And then it does an.. oh, my.  rDo rGo startroom?  I don't believe I've
met the rDo opcode yet."

"We will, in just a minute - " said the Turtle.

"Though they're not very nice," said the Dormouse.  "Opcodes, I mean.
Just ask the etcetera."

" - after you finish working this out.  You can, can't you?"

"Well, I _think_ so.  I should imagine it means that Rap will Do an Action.
Which would be Going to the room Startroom.  Right?"

"Very good," said the Turtle, pulling a second blackboard from his shell
and writing on it:

  RAP Opcodes:
  ------------

   rBe condition param     <----  make this condition true (create a goal)
   rIf condition param     <----  check this condition, but don't
                                  make it true (used for optimisation)
   rDo action param        <----  do an action (this ends goal scanning)
        
"I see," said Alice, for about the umpteenth time.  "So rBe is the main
Condition opcode.  rIf is sort of like rBe, only it doesn't make a goal.  
Where would I want to use that?"

"The author hasn't really thought about that," said the Dormouse, blowing
more tea-bubbles.  "Have you?"

"Er, no.  But it's there if you want to use it.  For optimisation and
stuff.  It prunes the goal tree.  But you don't really need to use it
at all, generally.  Um, will you let me out of that tea-bubble?"

"Sorry."  The bubble popped, and the Author disappeared.

" - And rDo forces an Action to be made.  What do you mean by ending
goal scanning?"

"Just what it sounds like, my dear."

"It sounds painful."

"Well, it's not really.  It just means that as soon as Rap finds an
Action that he can do, he does it.  And then his move is over, and
the Player gets a move, and all sorts of game state gets updated, and
such, and then Rap can take another move and so on and so on.  This means 
that when Rap is evaluating multiple parallel plans, he does the first
Action that he can find - "

"That sounds sensible."

"- which means that generally, he chooses the shortest path between two
rooms, or the shortest sequence of actions that leads to the goal he
wants.  Which, as you say, is generally sensible."

Alice wrinkled her nose.  "Are there any cases when it wouldn't be?"

"I don't know that, either," said the Author.  "So let's just say
that it's sensible and leave it at that."

"Then I think I understand.  Now, suppose I take a look at the second
Plan Group there.  The one for Room2.  (What silly names these rooms
all have!)"

"They're very sensible names," growled Rap, batting at the Author's tea 
bubble with one paw.  The Author winced.  "Everything's numbers, when
you take it apart."

"Like you did with the White Rabbit's wristwatch," said the Dormouse
sleepily.  "Only you couldn't get the numbers back in again right.  
That's why we keep repeating this conversation."

"ANYWAY," continued Alice, "I can see there really ARE three Parallel
Plans here.  We're trying to Be In Room2, but there are three different
ways to do it:

  Either:
        [rBe rIn startroom
         rDo rGo room2]
  
  Or:

        [rBe rIn room3
         rDo rGo room2]

  Or even:

        [rBe rIn room4
         rDo rGo room2]

"Yes indeed," said the Turtle approvingly.  "And Rap tries all of these
at once.  Each one creates either an Action or a goal.  And so on.  And
the first goal that produces an Action wins."

"I really do think I'm getting it," said Alice excitedly.  "So there are
three ways to get to Room2 -"

"As you'd expect in a room with three entrances," put in Rap.

" - and the first one is to be in Startroom and then go to Room2, and 
the second is to be in Room3 and go to Room2, and so on.  Yes, it all
makes sense."

"Oh dear," the Dormouse whispered, "It's starting to make sense to her.
That means she must be starting to wake up.  And you know what that
means..."

"Wait, please!" cried Alice, jumping to her feet, who was a bright little
Looking-Glass girl who had been around the dream clock a few times and
knew just how these things worked.  

"If you're all going to vanish away _just_ when it's all making sense I 
shall be _very_ annoyed.  Because all this will go out of my head and 
straight back into Looking-Glass land when I wake up.  And I shall cry
and bang my head on my pillow and I shall give myself a splitting headache 
faster than you can type YOMIN ME WITH A FROTZED GRUE.  So please answer
my last few questions right now!"

"Very well," said the Mock Turtle, who was looking at his watch and 
hurriedly packing up his blackboard-shells without trying to look as
if he was hurrying.  "What else do you need to know?"

"Conditions.  Actions.  Parameters.  What are they and how do I use
them?  I know how do do a Plan Group, I think.  I use the rPlans method.
But what about all the rest of it, tying it into my TADS code?"

The Turtle picked up the Klein Bottle, shook it a few times, and wrote
some glowing letters in the continuum:

  Conditions --->   rCond objects
                    truth method    ---> rTrue(actor, param) 
                    plan method     ---> rPlans(actor, param)
                     
  Actions    --->   rAct objects
                    action method   ---> rAction(actor, param)
     

"These are the basics.  Actor is a parameter to all the methods because,
well, you know how all TADS verbs pass the actor, it's just a TADSy
kind of thing to do.  RAP is almost always associated with an actor,
so we pass that in case it's useful.  Param is a parameter to the action
or condition, and yes, that's the one we haven't yet talked about.  
The reason why is it's very simple.  

"A Parameter can be anything at all.  Any Object class, primitive type,
or even a List (so you can have multiple parameters in a Condition
or Action if you really want)."

Alice shuddered.  For some reason, she still didn't want to think
about any more Lists than she had to.  

"I'll try to forget that," she said.  "But I understand now.  A
Condition and an Action both need an Opcode and a Parameter.  Like, 
for example:

  rDo rGo startroom

is an rDo Opcode, an rGo Action, and a Parameter which is an Object
Reference to the room 'startroom'.  And this is all returned somewhere 
inside the rIn Condition's rPlans method.  Right?"

"Right," said Rap, carefully preening his coat and fastening his bowtie 
without trying to look like he was doing either.

"And it's all a TADS list.  So, I can use any kind of TADS tricks I like 
to create that list, right?  Like this:

  rDo rGo x

where x is a local variable in my rPlans method.  Or any kind of object
property.  Or anything.  Right?"

"Right," said the Dormouse, carefully folding up the teapot and packing
it away into a passing tea-bubble, taking very special care not to pop it.

"And... I could even generate new Plans at runtime, by modifying the
rPlans method to do all kinds of calculations... or I could maybe create
plans at compile time, maybe by scanning the map with some kind of scanning
routine..."

"Hrrmmph," said the Mock Turtle, looking at his watch.  "Oh, my goodness,
is that the time?  We really must be - "

"No!" cried Alice.  "I remember now.  You still haven't told me about
that automatic map building routine!  You simply _can't_ vanish away
and not have told me about that!"

"Sorry," said the Dormouse, folding up the last of the continuum into
his tea-bubble.  "Can't.  Rules, you know.  Sheer physics.  Space.  
Time.  Out of.  Etcetera.  Elipsis.  But if you really want to know 
more - "

"Yes?" shouted Alice, into the by now very black and empty darkness.

"Read the source," said a hollow voice.  

"And who made _you_ an authority?" said Alice, turning angrily towards
the voice.  There was an awkward pause.

"Ah.  Because I'm the, you know, thing, author."

"And that's the last straw." said Alice.  "I refuse to be talked to by
a talking tea-bubble.  This whole conversation has been one piece of
nonsense piled upon another!  I should pop you right now!"

"Er.  No, you really don't want to - "

POP.

"Oops," said Alice.

