Composite

Users

Guide


Composite Users Guide

 

Copyright 2001 by Kevin Forchione.

 

This manual is the copyrighted property of Kevin L. Forchione. Permission is granted to distribute this material by digital and/or physical means on the provision that the material is distributed in an unmodified form for non-profit purposes. It is prohibited to redistribute any sub-section from this material separately without the consent of the author. The author makes no warranty of any kind with respect to this material, and disclaims all warranties, including any implied warranties of merchantability or fitness for any particular purpose, or the continued accuracy of this manual for future versions of the product. I have made every attempt to make this documentation accurate, but will not be held responsible for any loss of productivity resulting from errors.

 

Manual version 1.0            (March 2001)

 

Written by Kevin L. Forchione,

e-mail:    Kevin@lysseus.com

 

Composite.t is Copyright 2001 by Kevin Forchione for Lysseus Dream Ltd.

 

 


Contents

 

Getting Started_ 4

Coding A Desk_ 4

The Desktop_ 5

A Set of Drawers 6

Playing the Game 7

Behavior Levels 8

Selection Rule #1_ 8

Selection Rule #2_ 8

Selection Rule #3_ 8

Selection Rule #4_ 8

BEHAVIOR_ACTIONED_ 8

BEHAVIOR_VERIFIED_ 8

BEHAVIOR_NONE_ 8

Examining and Searching_ 9

And, of course, an examination of the desktop reveals the axe. 9

Opening the Desk_ 10

Putting Things in Drawers 12

Masking Descriptions 13

Troubleshooting_ 14

 

 

 

 


Getting Started

 

Ever wanted to design a desk that has both a surface and a set of drawers? Composite class can help you do it! Simply

 

a.      plug in the module after ADV.T/STD.T/ALT/PIANOSA/WORLDCLASS

b.      add the initComposite() function to the preinit() function.

 

Coding A Desk

 

Suppose we want our foyer to have a wooden desk with a top and 3 drawers. Our desk is movable, but our drawers are not removable. Our desk would look something like the following:

 

desk: Composite, item

    location = startroom

    noun = 'desk'

    adjective = 'wooden'

    componentDesc = "wooden desk"

;

 

The first thing you’ll notice is that our desk derives from both Composite and item classes. Composite class derives from Component class, which is a mix-in class. This means that it doesn’t inherit from thing class, and must always come first in a class list.

 

 

Always list Composite and Component classes first in object definitions

 

 

Also, desk doesn’t define any sdesc. Instead the description is handled by componentDesc. This is because Composite class uses sdesc to decide whether to use the object’s componentDesc or its parent object’s componentDesc as its description.

 

 

Only define sdesc in Composite and Component class objects if you want to explicitly determine the object’s name. Use componentDesc instead to allow Composite class to decide what the object should be called.

 

 


The Desktop

 

The top of the desk is easy! The top of the desk derives from Component class and is a fixeditem surface. We can put things on it, but we can’t take it.

 

deskTop: Component, fixeditem, surface

    myComposite = desk

    location = desk

    noun = 'top'

    adjective = 'wooden' 'desk'

    componentDesc = "top of wooden desk"

;

 

deskTop uses componentDesc just as the desk object does. In certain cases the desk top will be referred to as “wooden desk top” and in other cases simply as “desk”.

 

We also indicate its location as the desk. This isn’t a requirement of Composite class. Our desk is movable, and this means that the top will go wherever the desk goes.

 

Further, we indicate that desk is the Composite object for deskTop using the myComposite property. During preinit() myComposite is used to build a list of Components for each Composite object.

 

 

Components should use the myComposite property

to indicate which object is their parent.

 

 

 


A Set of Drawers

 

Now we need to define our drawers. We’ll have a top, middle, and bottom drawer. Our descriptions and vocabulary will be a bit verbose: “top drawer of wooden desk”, for instance, to illustrate that Composite knows to put an axe in topDrawer, neatly screening out any woodenChair that might be lurking in the room, or even the deskTop.

 

class Drawer: Component, fixeditem, openable

    location = desk

    plural = 'drawers'

    noun = 'drawer'

    adjective = 'wooden' 'desk'

    pluraldesc = "wooden drawers"

    myComposite = desk

    isopen = nil

;

 

topDrawer: Drawer

    adjective = 'top'

    componentDesc = "top drawer of the wooden desk"

;

 

middleDrawer: Drawer

    adjective = 'middle'

    componentDesc = "middle drawer of the wooden desk"

;

 

bottomDrawer: Drawer

    adjective = 'bottom'

    componentDesc = "bottom drawer of the wooden desk"

;

 

The Drawer class derives from Component and defines the myComposite property. Each drawer then defines a componentDesc.

 


Playing the Game

 

After we’ve compiled the module we should see something like the following:

 

Entryway

       This large, formal entryway is slightly intimidating: the walls are lined with somber portraits of gray-haired men from decades past; a medieval suit of armor, posed with battle axe at the ready, towers over a single straight-backed wooden chair. The front door leads back outside to the south. A hallway leads north.

       You see a wooden desk here.

>

 

Putting the axe on the desk is simple:

 

>put the battle axe on the wooden desk

Done.

 

Next we attempt to put the axe in the desk and get a reasonably intelligent disambiguation question.

 

>put axe in desk

Which part of the wooden desk do you mean, the top drawer of the wooden desk, the middle drawer of the wooden desk, or the bottom drawer of the wooden desk?

 

>wooden

Which wooden do you mean, the top drawer of the wooden desk, the middle drawer of the wooden desk, or the bottom drawer of the wooden desk?

 

>bottom

The wooden desk is closed.

 

We’d better have a closer look at the desk:

 

>examine desk

It looks like an ordinary wooden desk to me.

 

This is simply the default long description for the desk object! There’s no mention of the desktop or drawers. This is because Composite class doesn’t override any thing class properties other than sdesc. Any mention of components in an examination will need to include them in the desk’s ldesc method’s code.


Behavior Levels

 

Composite must determine which object, the parent or one of its components, should perform the action. It does this through a simple set of rules:

 

 

 

Selection Rule #1

Determine the highest Behavior Level for the object’s list of components. If the object defines a Behavior Level greater than or equal to that of its components then the object is chosen to complete the action.

 

Selection Rule #2

If the object is not chosen to complete the action then the component with the highest Behavior Level is chosen to complete the action. If there is more than one object at this level then we create a list of these components.

 

Selection Rule #3

If we have a list of components created from Rule #2 then check to see if any of these objects fail verification and remove them from the list. If we are left with an empty list use the original from Rule #2. Otherwise use the reduced list. If we are left with 1 component then it is chosen to complete the action.

 

Selection Rule #4

If the object was the direct object for the verb then perform the command for each component in the list. If the object was the indirect object for the verb then ask a disambiguation question to reduce the list to 1 component.

 

 

 

The Behavior Levels mentioned in the Selection Rules above are straightforward, listed by order of their importance:

 

 

BEHAVIOR_ACTIONED

The object defines both the verification and action method for the verb template.

 

BEHAVIOR_VERIFIED

The object only defines the verification method for the verb template.

 

BEHAVIOR_NONE

The object does not define a verification method for the verb template.

 

 

 


Examining and Searching

 

Using these rules, examining the desk returns the desk as the object that completes the action because verDoInspect() and doInspect() are defined for the desk and all of its components.

 

Searching the desk, on the other hand, returns a different result, because verDoSearch() and doSearch() are only defined for surface and container class objects. The Drawers derive from openable class, which derives from container class. Openable objects fail verification when they are not open. So given a choice between searching two objects, one open, the other not, the parser will choose the open object. Composite class behaves exactly the same way.

 

>search desk

On the wooden desk you see a battle axe.

 

But what’s the meaning of this display? The axe isn’t actually on the desk, which is merely an item class object, and doesn’t define doPutOn(). If you tried putting the axe on an item class object you would get the default message, “There’s no good surface on the battle axe.” While the axe is actually on the deskTop, the component’s description is being masked by the use of its composite object’s componentDesc.

 

Acting on the component directly produces a different message. In this case the explicit name is always used.

 

>search desk top

On the top of the wooden desk you see a battle axe.

 

>examine desk top

On the top of the wooden desk you see a battle axe.

 

And, of course, an examination of the desktop reveals the axe.


Opening the Desk

 

According to our Selection Rules <<open the desk>> presents the Composite class initially with 5 possible candidates:

 

[ desk, deskTop, topDrawer, middleDrawer, bottomDrawer ]

 

We begin in the desk’s dobjCheck() by first invoking buildLists() and asking it to return a list composed of valid components and a formatted verification and action method pointer list.

 

We must determine the verification and action methods for the verb template, we do this by using verbinfo() and reformatting the output into a standardized format for both one-object and two-object verb templates.

 

In the case of a two-object direct object verb template the parser doesn’t constructs an action method. Most of the time this isn’t a problem, since referring to the composite object as the direct-object of a two-object command usually involves acting upon the composite object:

 

       >put the desk on the patio

 

Here the doPutOn() method of the direct-object is invoked by the ioPutOn() method of the indirect-object. But we don’t want to simply put one of the object’s components on the patio, we want to move the whole composite.

 

There are instances where we need to know the direct-object action method pointer.

 

       >turn the tv to channel 5.

 

If tv consists of a tuner and the television itself then we are actually saying the following:

 

       >turn the tv tuner to channel 5.

 

During the formatting of the method pointers list we need to assign an action method pointer for the direct-object in two-object commands. Without these direct-object action method pointers the possibility exists for a component to be bypassed by the selection process when indeed it handles the action of the verb.

 

The Composite module provides action method pointers for several verbs that might redirect the action of the indirect object to the direct object.

 

 

When adding ioAction() properties to a verb, consider adding a doActionPtr() method to return a direct object action method for the verb/prep combination. This enables Composite to accurately identify the correct object to use when the indirect object redirects action to the direct object.

 

 

We add the doActionPtr() method to a verb like this:

 

modify turnVerb

    doActionPtr(prep) = {

        switch(prep)

        {

            case toPrep:

                return &doTurnTo;

            case withPrep:

                return &doTurnWith;

            default:

                return nil;

        }

    }

;

 

Once we know the verification and action methods we retrieve the Behavior Level for the desk: BEHAVIOR_NONE. This becomes our highValue. We build a nounList by checking highValue against the Behavior Level for each Component in turn. If the Component has a Behavior Level greater than highValue the list building starts over, adding the Component to the list and setting highValue to the Component’s Behavior Level. If the list has elements and the Behavior Level of the Component equals the highValue for the list then it is added to the list. Otherwise it is rejected. At the end of the process we have a list that looks like the one below:

 

       [ BEHAVIOR_ACTIONED [ topDrawer, middleDrawer, bottomDrawer ]]

 

The Behavior Level for the entire list is BEHAVIOR_ACTIONED, which means that all objects in the list define both the verification and action methods for our verb. Next we check the verification method for each object  in the list. If the object passes verification then it is added to a verifiedList. If the verifiedList is not empty we replace the second element of our nounList with it.

 

Finally, buildLists() returns a list composed of nounList and verbList:

 

[[ BEHAVIOR_ACTIONED [ topDrawer, middleDrawer, bottomDrawer ]], [ verDoOpen, nil, doOpen, nil, nil ]]

 

Because the Composite was used as the direct object of the command we process all of its qualifying components:

 

>open desk

top drawer of the wooden desk: Opened.

middle drawer of the wooden desk: Opened.

bottom drawer of the wooden desk: Opened.

 


Putting Things in Drawers

 

The process is nearly the same when a composite object is the indirect object in a command. The sole difference is that the nounList must be reduced to a single component. To do this we ask a disambiguation question and then use TADS built-in functions to parse, disambiguate, and resolve the phrase into a single object.

 

>put axe in desk

Which part of the wooden desk do you mean, the top drawer of the wooden desk, the middle drawer of the wooden desk, or the bottom drawer of the wooden desk?

 

>wooden

Which wooden do you mean, the top drawer of the wooden desk, the middle drawer of the wooden desk, or the bottom drawer of the wooden desk?

 

This second question is actually posed by the TADS parser. The critical difference is that the Composite.disambiguate() method does not allow for phrases such as “all”, “both”, “him”, “her”, “it”, etc. As we only invoke this method for indirect object disambiguation, which requires a single object, phrases such as “all” or “both” are inappropriate.

 

>top

Done.

 


Masking Descriptions

 

>search desk

top drawer of the wooden desk: In the top drawer of the wooden desk you see a battle axe.

middle drawer of the wooden desk: There's nothing in the middle drawer of the wooden desk.

bottom drawer of the wooden desk: There's nothing in the bottom drawer of the wooden desk.

top of the wooden desk: There's nothing on the wooden desk.

 

>close bottom drawer and middle drawer

bottom drawer of the wooden desk: Closed.

middle drawer of the wooden desk: Closed.

 

>search desk

top drawer of the wooden desk: In the wooden desk you see a battle axe.

top of the wooden desk: There's nothing on the wooden desk.

 

>close desk

Closed.

 

>search desk

There's nothing on the wooden desk.

 

Notice the wording of the top drawer in the first and second searches, as well as the use of object prefixes. Composite uses an intelligent algorithm to determine when to refer to the object explicitly and when to mask it behind its composite name.

 

Essentially object prefixes are used in multiple direct object commands, and the objects are referred to explicitly using their componentDesc. When these objects are the only one of their class (based on first superclass) they are masked behind their composite object’s componentDesc. If more than one component of a given class is being acted upon then they are referred to explicitly by their componentDesc, both in the prefix and command display portions.

 

 

 

 


Troubleshooting

 

There are several reasons why a component might not be selected to complete the action of the verb:

 

1.      The component doesn’t point to the composite object with a myComposite property.

2.      The composite is being used as a direct-object in a two-object command, but no doActionPtr() was defined for the verb, or the doActionPtr() doesn’t return a method pointer for the preposition.

3.      The composite object defines a Behavior Level equal to or greater than the component.

4.      Another component has a Behavior Level greater than the component.