Here's an article I wrote a couple of months ago in response to someone
asking the same question as you:
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Edward Armstrong <inwards@granite.sentex.net> wrote:
> What is the best way in Inform to create an Encylcopaedia Frobozzica?
I will assume that you're using version 5/7 (release 941214) or later of
the Inform library, which makes consulting books easier - if not, then
fetch the latest version (5/9) from ftp.gmd.de.
If you look at Grammar.h, you'll see that the "consult" verb is defined
using lines like
Verb "consult" * noun "about" ConTopic -> Consult
where the "ConTopic" routine just parses any old rubbish that the player
might type, but sets the variable `consult_from' to the number of the
first word in the rubbish, and the variable `consult_words' to the
number of words in the rubbish. You can then examine the results using
code like this:
Object Encyclopaedia "Encyclopaedia Frobozzica"
with name "encyclopaedia" "encyclopedia" "frobozzica" "book",
description "The Encyclopaedia is so packed full of amazing \
facts that you'll have to look them up one at a time.",
before [ w1 w2 w3;
Consult:
if (consult_words == 0)
"You must say what you want to look up.";
wn = consult_from;
w1 = NextWord(); w2 = NextWord(); w3 = NextWord();
if (consult_words == 1 && w1 == 'zork')
"~The Great Underground Empire, renowned for ...~";
if (consult_words == 3 && w1 == 'wizard' &&
w2 == 'of' && w3 == 'frobozz')
"~The Wizard of Frobozz is a curious character ...~";
"You can't find what you want in the Encyclopaedia.";
];
The above approach is adequate for some purposes, but gets a bit
clumsy after a while - after all, why do all the work of parsing the
player's text when you can get the parser to do it for you?
So here's an alternative approach:
Class TopicClass
has proper
with short_name "that";
Object Topics "topics";
Nearby TopicZork "Zork" class TopicClass
with name "zork" "great" "underground" "empire" "gue";
Nearby TopicWizard "Wizard of Frobozz" class TopicClass
with name "wizard" "of" "frobozz";
[ TopicScope;
if (scope_stage == 1) rfalse;
if (scope_stage == 2) {
ScopeWithin(Topics);
rtrue;
}
"** Error: input should have matched a later line in grammar **";
];
[ NewConsultSub;
print "You discover nothing of interest in ";
DefArt(noun);
".";
];
[ NewConsultRSub; <<NewConsult second noun>>; ];
Extend "look" first
* -> Look
* "up" scope=TopicScope "in" noun -> NewConsultR;
Extend "consult" first
* noun "about" scope=TopicScope -> NewConsult
* noun "on" scope=TopicScope -> NewConsult;
Extend "read" first
* "about" scope=TopicScope "in" noun -> NewConsultR
* scope=TopicScope "in" noun -> NewConsultR;
Object Encyclopaedia "Encyclopaedia Frobozzica"
with name "encyclopaedia" "encyclopedia" "frobozzica" "book",
description "The Encyclopaedia is so packed full of amazing \
facts that you'll have to look them up one at a time.",
before [;
NewConsult:
if (second == TopicZork)
"~The Great Underground Empire, renowned for ...~";
if (second == TopicWizard)
"~The Wizard of Frobozz is a curious character ...~";
"You can't find what you want in the Encyclopaedia.";
];
A short exaplanation is probably in order. The code is based on that
for answering questions like "what is a grue", given in Chapter 16 of
the Designer's Manual. For each line of grammar leading to a Consult
action (like the one given at the start of this article), we supply
another line of grammar that does much the same thing, but where the
original line parsed any old rubbish from the player, the new line tries
to match the player's text to one of the objects contained the `Topic'
object. Thus, the input
look up wizard in encyclopaedia
will match the word `wizard' to the object TopicWizard, whereas the
input
look up foo in encyclopaedia
will not match any object, and will be parsed by the original grammar.
The original grammar acts as a `catch all' so that the player can't find
out which words are valid topics except by looking them up in the
correct book.
I hope this helps. Send me e-mail if you have any queries.
-- Gareth Rees