Sass, growl, flirt, threaten, and cajole players.
A good writer can say a lot with a few words. One of the best tricks in interactive fiction is make players do exactly what you want them to do while maintaining the illusion that they have free will. Nowhere is this more evident than in NPC conversations.
Ideally, your NPCs should drop hints, help solve puzzles, and converse with, and ocasionally bedevil, players. How do you predict what players will say? How do you know how to respond? In general, you don’t, but there are a few tricks to make your NPCs seem like living, thinking beings.
Inform comes with a few built-in methods of talking to NPCs. The
centerpiece of the default conversational model is the
Ask verb. Let’s make this our
means of chatting with the access controller. The
game’s parser will take a command such as
ask the access controller about the token, toss
out the articles, figure out that the operative verb is
ask, set the variable noun to
controller, and then, as the key part, place the
word token into the variable
second. If you type ask the access
controller
about
oatmeal, the word
oatmeal goes into the variable
second, even though there is no
oatmeal object in the game. This makes
conversation trivial to implement. Add this to the
controller’s
life block:
Ask:
switch (second) {
'id', 'identity', 'token', 'tokens':
if (token has general)
"~YES, TOKEN WAS ACCEPTABLE!~ the access controller
barks. ~YOU MAY PROCEED!";
"~DO YOU HAVE A TOKEN?~ the access controller shoots
back. ~IF SO, GIVE TO ME AND YOU MAY PASS! QUICKLY!
SO VERY HUNGRY...~";
'access', 'controller', 'itself':
"~I AM GATEKEEPER TO WORLD BEYOND!~ the access
controller declares, preening.";
'oatmeal':
"~HUH? NOT KNOW WHAT IS!~ the access controller says.
~SOUNDS TASTY WITH BUTTER AND BROWN SUGAR, THOUGH!~";
}
"That topic doesn't strike you as very promising.";You can add as many topics as you like. As you saw earlier, using
synonyms is a good idea. You’ve probably also
noticed the safety-net line that catches topics that fall through the
switch statement. It’s impossible
to anticipate every single topic a player might try, so
you’ll need some way to fend off topics for which
you haven’t written a response; historically, games
often made NPCs deaf, distracted, ignorant, uncooperative, or all
four at once. Here we’ll just overrule the question
instead.
This is by no means a complete discussion of the topic. NPC conversation is so engrossing a challenge that an entire genre of games has developed that do nothing but simulate a chat with an NPC; some of these games create a model of the NPC’s emotional state, monitor the topics discussed, check the conversation for coherence, and so forth.
The process of ordering characters around is somewhat more
complicated than asking questions and telling[19] characters
about various subjects. Inform supports directed commands such as
cow, jump
over
the
moon. Let’s try implementing the
order controller, take the token (and, while
we’re at it, controller, eat the token). Add this block to the controller
object:
orders [;
Eat, Take:
if (noun = = token) <<Give token self>>;
"~ONLY WANT TOKEN!~ the access controller screams.";
default: "~DO NOT ORDER ME AROUND!~ the access controller
bellows.";
],Note that the access controller takes the token only if the player
has it to give; otherwise, the default response prints. This is
exactly what we want, because controller,
take
the
token while the token is in the other room
suggests that the player wants the controller to fetch the token from
the other room. That’s too easy.
Let’s make the player work for it.
For the security daemon, let’s try something a bit different: implementing menu-based conversation like that employed in most graphical adventures. Some players dislike menu conversation because they feel restricted in their choice of topics, but it does keep conversations from becoming a string of default “I don’t know much about that” responses. It’s also a great way to include wisecracks. Inform doesn’t provide for menu-based conversation automatically, so you’ll have to use one of the modules available on the IF archive or hack together a system from scratch. The title of this book suggests the latter approach, but be warned: the degree of difficulty here is about to spike upward.
To make things interesting, let’s make the player
figure out how to initiate a conversation with the daemon. Add the
following routines to the pixie object:
life [;
Ask, Tell: "The security daemon replies with a crescendo of
wordless music.";
],
orders [;
"The security daemon replies with a crescendo of wordless music.";
],This serves as an initial hint that the player should try to
sing to the daemon. If your playtesters seem
unable to guess this, you can add more explicit hinting later on.
Let’s begin by specifying a class of objects to
serve as songs. Put the following right after the Include "VerbLib" line:
Class Song
with
number 0,
has scenery;Inform already has a Sing verb, but it is
intransitive (which means it doesn’t take a direct
object), so you’ll have to replace it. Add the
following lines after the Include "Grammar" line:
Extend 'sing' replace
* 'to' noun -> SingTo;
[ SingToSub x count choice;
if (noun = = player)
"Singing to yourself is a sign of impending mental collapse.";
if (noun = = controller)
"~NO SINGING IN THE ROUTER!~ the controller barks.";
if (noun hasnt animate)
"You can only do that to something animate.";
print "Please select one:^^";
objectloop (x ofclass Song) {
x.number = 0;
if (x in noun) {
count++;
x.number = count;
print "(", x.number, ") ", (name) x, "^";
}
}
do {
print "^Select an option or 0 to say nothing >> ";
read buffer parse DrawStatusLine;
choice = TryNumber(1);
} until ((choice >= 0) && (choice <= count));
if (choice = = 0) "^You decide not to sing after all.";
objectloop (x ofclass Song) {
if (x.number = = choice) <<ChooseSong x>>;
}
"Singing routine failed! [BUG]";
];
[ ChooseSongSub; rtrue; ];Holy crow. That is a lot of new stuff. Let’s walk through it.
First, you’re accounting for what happens if the player tries to sing to a creature other than the security daemon. This really should go in the objects themselves, but since there are only two of them for now, you can deal with it here. Also make sure the thing you’re singing to is animate.
Next, look at every Song in the entire game. Clear
its number field, and then if
it’s in the object we want (currently always
pixie), give it a number and stick it on a list.
Next, have the player type the number of the song he wants to sing.
Finally, send a ChooseSong call to that song.
ChooseSong is a dummy verb, a fake action that the
player cannot trigger directly.
Let’s write some songs:
Song deathmetal "(death metal) ~STOP OR I WILL KILL YOU!~" pixie
with
before [;
ChooseSong:
deadflag = 1;
"^The security daemon lets out an alarmed trill and, deciding
quarantine is insufficient, deletes you.";
];
Song folk "(earnest folk) ~Surely we can be friends...~" pixie
with
before [;
ChooseSong:
remove self; remove deathmetal; remove aria;
move seductive to pixie; move lullaby to pixie;
"^The security daemon murmurs some skeptical notes at you.";
];
Song aria "(operatic aria) ~Looook! There is some SPAAAAM behind you!
You'd better go CHAAAASE it!~" pixie
with
before [;
ChooseSong:
remove self;
"^The security daemon isn't buying it. Apparently she wasn't
compiled yesterday.";
];
Song seductive "(seductive R&B) ~Oh, yeah, baby, I got what you need.~"
with
before [;
ChooseSong:
deadflag = 1;
"^The security daemon lets out an alarmed trill and, deciding
quarantine is insufficient, deletes you.";
];
Song lullaby "(lullaby) ~It's all right... don't be scared... I've been
granted legal access...~"
with
before [;
ChooseSong:
StopDaemon(pixie); remove pixie;
"^The security daemon circles around you uncertainly and
flies off to check with the access controller. At last, a
moment's peace.";
];Now you have a slapdash conversational menu. The player types
sing to
daemon (or even just
sing, when she’s in sight), and
the SingToSub routine creates a list of available
songs and prompts the player to choose one. The
ChooseSong part of the selected
song’s before block then runs
whatever code the player likes: rearranging the list of available
songs, killing the player, switching off the security
daemon’s daemon code, or whatever
you like.
Now the player is free to continue exploring the game world, but the shape the rest of that world will take is up to you.
The Inform manual (http://www.inform-fiction.org/manual/), which links to downloadable versions of both Graham Nelson’s Inform Designer’s Manual and Roger Firth and Sonja Kesserich’s Inform Beginner’s Guide .
The Interactive Fiction Archive (http://ifarchive.org/) is the chief repository for all modern interactive fiction, from games to compilers to players to hint files and more.