Topic Entries
The topicEntry.t implements the base TopicEntry class that forms the basis of Consultables, Thoughts and the conversation system. It also defines the Consultable and ConsultTopic classes that make particular use of this base class. Since game code is unlikely to use the base TopicEntry class (except, perhaps, if a game author wants to define a custom type of TopicEntry for special purposes), we can illustrate the use of TopicEntries by moving straight to a discussion of Consultables and ConsultTopics.
A Consultable is something you can look things up in, through commands like LOOK UP ORANGES IN BLUE BOOK or CONSULT BOOK ABOUT LEMONS. To create a Consultable object in adv3Lite we first define an object of class Consultable, in much the same way as we'd define any other Thing, for example:
blueBook: Consultable 'blue book; useless trusty of[prep];dictionary information' @desk "It's your trusty dictionary of useless information. " readDesc = "It's not the sort of book you'd want to read from cover to cover; it's more for looking things up in. " ;
Each item you want the player to be able to look up in the blue book can then be represented by a ConsultTopic object. These should be defined with some combination of the following properties:
- matchObj: The game object or class or Topic this ConsultTopic matches, or a list of objects and/or classes and/or topics any one of which will match this ConsultTopic.
- matchPattern: A regular expression that this ConsultTopic matches. (Note you wouldn't define both this and the previous property, since if a matchObj is defined any matchPattern will be ignored).
- matchExactCase: A flag to indicate whether the matchPattern has to match the exact case of the player's input. The default is nil.
- matchScore: A numeric value to decide which ConsultTopic should be chosen in case there's more than one match. The ConsultTopic with the highest matchScore wins. The default value is 100.
- scoreBoost: An optional method or expression that can be used to boost the matchScore under specified circumstances (by default this is simply 0).
- isActive: A flag to indicate whether this ConsultTopic should be considered for a match. If it's nil then this ConsultTopic won't be matched. The default is true. It is intended that this property should be defined as an expression (or if necessary, a method) on the TopicEntry object rather than manipulated in code elsewhere, since treating it declaratively this way will make it much easier to read your code when you come back to it.
- topicResponse: A double-quoted string (or possibly a method) that provides this ConsultTopic's response when it's matched.
- eventList: If an EventList class is added to the class-list of this TopicEntry, we can define its eventList property, and the TopicEntry will respond with the next item in its eventList (in which case we should not also define the topicResponse property, since if we do, that will be used instead.).
- topicMatched: The topic actually matched by this TopicEntry. This is set by the matchTopic() method and is intended for use by the topicResponse() method, which can then access the Topic (or Thing) whose match triggered this TopicEntry (in case the TopicEntry can match more than one Topic or Thing).
Most of these properties can be defined through a template. The basic template for a TopicEntry looks like this:
TopicEntry template +matchScore? @matchObj | [matchObj] | 'matchPattern' "topicResponse" | [eventList] ?;
This means that a TopicEntry can optionally be defined with a + sign and a number giving its matchScore; following that (if it is present) or starting off (if it is not) you then write at @ sign immediately before the matchObj, or a list of matchObjs, or a matchPattern in single quotes. Finally you either give the topicResponse in double-quotes or else define a list of responses (typically a list of single-quoted strings) if the TopicEntry is also an EventList.
To continue the previous example, we might begin to populate our dictionary of useless information with ConsultTopics thus:
+ ConsultTopic @tLemons "Apparently they're yellow and sour. " ; + ConsultTopic 'oranges' "They're round and juicy. " ; + ConsultTopic @Door "Doors can be opened and closed, and when open you can go through them. " ; + ConsultTopic '(black|red|green) blob(s){0,1}' "They're very blobby. " ;
Finally, we probably also want a response for when the player types something for which we haven't provided a matching ConsultTopic, LOOK UP ABRAHAM LINCOLN IN BOOK or CONSULT DICTIONARY ABOUT KNOWN UNKNOWNS for example. For that purpose we use a DefaultConsultTopic which acts a catch-all for anything we haven't specifically defined:
+ DefaultConsultTopic "You thumb through the blue book in vain for any interesting information on that topic. " ;
Alternatively, we might mix in the DefaultConsultTopic with an EventList class to provide a sequence of responses:
+ DefaultConsultTopic, StopEventList [ 'You thumb through the blue book in vain for any interesting information on that topic. ', 'Once again you fail to find anything useful. ', 'You begin to wonder whether this book is much use; that\'s the third time it\'s failed to provide information on something. ', 'Oh dear! Yet again you fail to find what you\'re looking for. ' ] ;
If you don't need Consultables or any other kind of TopicEntries then you can exclude topicEntry.t from your build, but note that topicEntry must be present if you want to use thoughts.t or actor.t. or facts.t
Short Form Consult Topics
If you have a consultable object that needs to respond to several different topics with fairly pithy responses, having to define a separate ConsultTopic object for each one may feel a little verbose, if not laborious. The library therefore provides a short-form alternative to do the same job with slightly less typing. Instead of creating a separate DefaultTopic for every topic you want the Consultable to respond to, you can define a list of topics responses on the Consultable's topicEntryList property. Our previous example might then become:
blueBook: Consultable 'blue book; useless trusty of[prep];dictionary information' @desk "It's your trusty dictionary of useless information. " readDesc = "It's not the sort of book you'd want to read from cover to cover; it's more for looking things up in. " topicEntryList = [ [tLemons, 'Apparently they\'re yellow and sour. '], ['oranges', 'They\'re round and juicy. '], [Door, 'Doors can be opened and closed, and when open you can go through them. '], ['(black|red|green) blob(s){0,1}', 'They\'re very blobby. '], ['default', 'You thumb through the blue book in vain for any interesting information on that topic. '] ] ;
It should be apparent from this that the topicEntryList should contain a list of entries, each of which defines a ConsultTopic. Each entry in the list is itself a list of the form [match, response], where match is what the ConsultTopic is to match (a Thing or Topic, a list of Things or Topics, or a regular expression) and response is the ConsultTopic's response (whatever is to go into its topicResponse property), which should normally be given as single-quoted string but could conceivably be a floating method. If match is 'default' a DefaultConsultTopic will be created with the corresponding response. The possibilities are exemplified below:
book: Consultable 'big red book' "It's a book full of miscelleanous wisdom. " topicEntryList = [ ['weather', 'The weather can be difficult to predict. '], ['life', 'Life is generally to be preferred to the alternative. '], ['stairs', 'Stairs can be quite useful for connnecting floors. '], [tEconomics, 'A dark art practised by sorcerers. '], [[tFrance, tGermany], 'It\'s a country in Europe. '], ['europe', new method { "A <<one of>>complex<<or>>perplexing<<cycling>> place. " ;}], [me, '''If you're looking for flattery you're doomed to disappointment. '''], ['default', 'Unfortunately, the big red book has nothing to say on that. '] ] ;
Under the hood, this has almost exactly the same effect as defining a set of ConsultTopics by hand, it just partly automates the process by leaving it to the library to create the ConsultTopics defined in the Consultable's topicEntryList property. It's therefore perfectly legitimate to combine creating some ConsultTopics explicitly (by defining a series of ConsultTopic objects) and others via the Consultable's topicEntryList; this may be useful if some, but not all, of the ConsultTopics are too complex or unwieldy to be neatly defined on topicEntryList. Of course, there is no need to use the topicEntryList property at all; it's simply provided as a convenience for those who may wish to make use of it.