What's in a Name?
Once the charcoal burner has revealed his name, we want three things to happen. First, we want his short name (the one that's displayed in room descriptions) to change from 'the charcoal burner' to 'Joe Black'; second we want the program to treat the name as a proper name, so we don't get messages like 'The Joe Black is holding a spade' or 'You see a Joe Black here'; and third, we want the parser to recognize joe, joe black or black as referring to Joe. The first two steps are straightforward. The third is a little more complicated.
To carry out the first two steps we simply need to execute:
|
isProperName = true;
|
name = properName;
|
|
Since finding out an actor's name some way through a game is a situation that could arise quite often, it makes sense to make all this happen as a modification of the Actor class (which will then work for everything of class Actor or one of is subclasses) rather than something specific to the burner object. The appropriate code then looks like this:
|
makeProper
{
if(isProperName == nil && properName != nil)
{
isProperName = true;
name = properName;
local tokList = Tokenizer.tokenize(properName);
for (local i = 1, local cnt = tokList.length() ; i <= cnt ; ++i)
{
if(i < cnt)
cmdDict.addWord(self, getTokVal(tokList[i]), &adjective);
cmdDict.addWord(self, getTokVal(tokList[i]), &noun);
}
}
}
;
The purpose of the check if(isProperName == nil && properName != nil) is to stop the makeProper method doing anything either if the actor has already been defined as having a proper name (perhaps through a previous call to makeProper) or if the actor has no properName property defined.
Apart from cmdDict.addWord(), the only thing that might be really unfamiliar here is the for loop towards the end of the makeProper method. If you didn't read about it in chapter 1 (or you did but you've now forgotten exactly how it works), now might be a good time to refer back to p. 26 to see how it works.
You should copy the above code into your source file (perhaps near the top after the definition of the endGame function) and check that it works. And then I'll confess that all along there was a somewhat simpler way we could have achieved almost the same effect without either that complicated for loop or
cmdDict.addWord
. Instead we could have replaced all the code after name = properName; (apart from the necessary closing braces) with initializeVocabWith(properName);, and it would have worked just as well. The only difference is that 'joe' would have been entered into the dictionary only as an adjective, and not also as a noun, but in practice that almost certainly doesn't matter. You may want to test this out.
But you can't test it out just yet: for either method to actually do anything in our program we need to call it somewhere. We can do this by simply adding <<burner.makeProper>> in the response string of AskTopic @burner, perhaps just after <.convnode burner-mud>.
There's just one more job we need to do before we can leave Joe Black. As things stand at the moment, if the player asks Joe about himself a second time, he'll still introduce himself the same way, which we obviously don't want. We could fix this by using a EventList, since although <<burner.makeProper>> won't work inside a single-quoted string, we can get round this by using a function within the EventList; but rather than introduce that complication right now, we'll simply use another AltTopic. Since the burner's isProperName property is nil before he introduces himself and true afterwards (thanks to <<burner.makeProper>>), we can use burner.isProperName as the test in the isActive property of the AltTopic. The AskTopic and AltTopic then look like this:
|
"<q>My name's Heidi.</q> you announce. <q>What's yours?</q><.p>
<q><<burner.properName>>,</q> he replies, <q>Mind you, it'll soon be
mud.</q> <.convnode burner-mud><<burner.makeProper>>"
;
+++ AltTopic, StopEventList
[
'<q>Have you been a charcoal burner long?</q> you ask.<.p>
<q>About ten years.</q> he replies. ',
'<q>Do you like being a charcoal burner?</q> you wonder, <q>It seems
rather messy!</q><.p>
<q>It\'s better than being cooped up in some office or factory all day,
at any rate.</q> he tells you. ',
'<q>What do you do when you\'re not burning charcoal?</q> you
enquire.<.p>
<q>Oh -- this and that.</q> he shrugs. '
]
isActive = (burner.isProperName)
;
|
|
|
tOxfordBlue: Topic 'oxford blue/cheese';
|
|
One further feature you may want to try out is the <.reveal> tag, which you can use to keep track of what's already been said. This works by keeping track of a list of arbitrary strings (or 'keys') that have been revealed, either through the gReveal() macro, for example gReveal('foo'), or through a <.reveal foo> tag inserted into a string (either single-quoted or double-quoted). You can then test whether the key has been revealed using gRevealed(), e.g. in a declaration like isActive = gRevealed('foo') on an AskTopic. For example, at the end of Joe's reply to Heidi's question on Oxford Blue cheese, you might append a <.reveal oxford-blue> tag so that other AskTopics or AltTopics can test whether this part of the conversation has taken place.
At this point you might like to experiment with increasing Joe's conversational range before moving on to the next chapter. If you want to be particularly adventurous, after trying out a few AskTopics and TellTopics, you could try adding some AltTopics and maybe even the odd extra ConvNode or two, complete with some more SpecialTopics.
|
Getting Started in TADS 3
[Main]
[Previous] [Next]