Populate your virtual world with realistic virtual characters.
Previous hacks have explained how to create, compile, and run an Inform game ( [Hack #85] ), create and manipulate objects ( [Hack #86] ), and challenge the player with puzzles ( [Hack #87] ). That’s enough for an interesting game right there.
Why stop at merely “interesting,” though? If you have fond memories about Infocom’s heydey, you may remember the infamous thief and Dungeon Master from the Zorks, a paranoid android and his contrary door from The Hitchhiker’s Guide to the Galaxy, and the lovable Floyd from Planetfall and Stationfall. What gave these games such character? In part, unforgettable nonplayer characters.
Let’s return to the cyberspace game developed in the previous three hacks. Once you have the identity token, the next step is to give it to the access controller back in Router NP-462, off to the north. Start by walking north:
> n
Router NP-462What just happened?
First of all, you moved from one room to another simply by typing a
one-letter abbreviation for the direction in which you wanted to
travel. This is standard practice in IF; typing n
at the prompt is exactly the same as typing go
north, except for saving keystrokes. Inform
handles this behavior automatically.
The program moved back into the original room and notified you of
this fact by printing out the name of the room and nothing else. This
is the default behavior of an Inform program. If you want to see the
description of every room every time you enter it, type
verbose at the prompt. If, in your capacity as
author of this game, you decide you want all players to be in verbose
mode by default, add an extra line to Initialise:
[ Initialise;
lookmode = 2;
location = Router;
move catalog to player;
];While we’re adding stuff, let’s
throw in a message to make it more explicit that
you’re moving back to the initial location. Find the
Scanner object, and rewrite the
n_to property:
n_to [;
print "You glide northward, and soon find yourself back in...^";
return Router;
];So you recompile and start the game anew, as explained in [Hack #85] ; collect the token again, and pick up where you left off:
>n
You glide northward, and soon find yourself back in...
Router NP-462
This little data interchange is run-down, shabby, and rather sad. You
can't see any traffic -- besides yourself -- and cobwebs of noisy static
hang in the dusty corners. The meat-side that this router serves must be
a bare hallway, almost no hardware.
A broad network connection leads east, and a serial line runs south. The
network connection is barred by a fierce-eyed access controller.
>give token to controller
You can only do that to something animate.Whoops. Well, that’s easily remedied. You simply
have to return to the controller object and change
the has scenery line to has animate scenery, and it’s alive, sort of.
You still haven’t told the program what should
happen when the player character gives the token to the access
controller. There is a default message; the only difference is that
now it says The access
controller
doesn't seem
interested. This won’t do.
You’ll have to add a block of code to deal with the
fate of the token. Since your ultimate goal is to proceed eastward,
you also need some code to fiddle with the (currently nonexistent)
eastern exit to allow you to pass.
Let’s start by adding a life
block to the controller. This is much like a
before routine—indeed, some verbs run
equally well in a before or a
life block—but the point of
life is to handle verbs unique to animate objects.
life [;
Give:
if (noun = = token) {
give token general;
remove token;
"The access controller takes the token from you and
messily devours it. ~IT IS TASTY ENOUGH!~ the controller
shrieks. ~YOU MAY PASS!~";
}
Show:
if (noun = = token) {
"~GIVE TO ME!~ the controller demands.";
}
],Here’s what you’ve just done. You
needed to set a flag indicating that the access control has indeed
taken the token. While you could have given the controller a
received_token property, Inform supplies an
attribute called general, which is very handy for
one-shot flags such as this, provided you remember what they mean.
You’ve removed the token from the world of the game,
but the program is still aware of it. You can easily have it reappear
later in the game if you wish.
As you’ve probably guessed, the tildes in the previous strings appear as quotation marks in the game output.
By having the controller enthusiastically ingest the token,
you’re also giving it a bit of personality. You
should go back to the token object at some point
and add a clever response to the Eat verb (and
make devour a synonym for eat
... remember, every line you write may give the player
ideas). Finally, add a response to the Show verb
to avoid misleading the player; without this code, showing the token
to the controller produces a default message saying the controller
isn’t interested in it, which could hardly be
farther from the truth.
Now let’s tackle that exit. Add the following code
to the Router object:
e_to [;
if (token hasnt general) "~NONE SHALL PASS WITHOUT AN IDENTITY
TOKEN!~ the access controller screams, forcing you back.";
print "You brush past the access controller and step into
empty space...^";
return Wireless;
],If the token doesn’t have the
general attribute—which it
won’t until the player character gives it to the
access controller—the program prints a message indicating that
the player needs to do something else to proceed eastward. It then
returns true, stopping without executing the code that follows. If
the token does have the
general attribute, the program skips to the part
that moves the Player object to the designated
room. Here’s that code:
Object Wireless "Wireless Connection X-771"
has light,
with
description
"You are hovering in a featureless void. Your instincts tell you
which direction is which, but it's always a bit nauseating to move
around with no reference points to confirm that your bearings
are correct. From here you can travel in any direction, including
up and down.",
w_to "No sense in backtracking. You've seen all that router had to
offer and weren't impressed.";At present, the line promising unimpeded travel is a fib, but
we’ll deal with that in a moment.
Let’s do a bit more with the access controller
first. It seems to be rather irascible, suggesting that it
won’t react well to an attack.
Let’s allow the player character to take one free
swing and then come to an untimely end with the second. Add this to
the access controller’s life
block:
Attack:
if (self hasnt general) {
give self general;
"~The access controller sneers at your ineffectual
attack. ~DO THAT AGAIN AND I WILL KILL YOU!~ it
threatens.";
}
deadflag = 1;
"The access controller wards off your clumsy assault and
grabs you before you can beat a retreat. As it crushes the
life out of you, you think, ~Maybe violence wasn't the
answer to this one.~";The general attribute appears again, this time for
something entirely different: here it indicates that the access
controller’s patience has elapsed.
You’ve also used the global variable
deadflag, which has a value of 0 as long as the
game continues to run; the game ends the moment a statement returns
true with deadflag set to any nonzero value. A
deadflag set to 1 produces a
***
You
have
died
*** ending. Set to 2, the
program cheerfully announces that ***
You
have
won
***. Values above 2 allow for customized sendoffs.
Now the character has a little character. It’s not quite real yet; it needs to be able to move and communicate. That’s the stuff of [Hack #89] and [Hack #90] .