Roger Firth's IF pages | ![]() |
InfAct -- about Inform NPCs | ![]() |
![]() |
An NPC -- Non-Player Character -- is just another Inform object. Well, ok, that "just" is maybe a little glib; it's probably truer to say that creating good NPCs is one of the hardest part of any game. Tricky, certainly; impossible, no. And many players would agree that the ability to interact with a well-written NPC is one of the characteristics making a memorable and satisfying game. So let's get started.
The features that distinguish an NPC from any other Inform object are easily listed:
You may also need other properties like daemon and each_turn, but they aren't so closely tied to NPC-specific behaviour.
Creating the bare bones of an NPC is really easy.
Object usher "gentleman usher" cloakroom
with name 'usher' 'gentleman' 'gentle' 'man',
description "The usher is smartly uniformed.",
has animate male;
|
From these humble beginnings, anything is possible. What currently happens is fairly modest, but still a tribute to the power of the Inform library.
>SHOW CLOAK TO THE USHER (the velvet cloak to the usher) The usher is unimpressed. >ASK USHER ABOUT THE THEATRE There is no reply. |
One easy way to inject some life is to have the NPC notice your comings and goings.
Object usher "gentleman usher" cloakroom
with name 'usher' 'gentleman' 'gentle' 'man',
description "The usher is smartly uniformed.",
react_before [;
Go: print "The usher nods politely as you leave.^"; rfalse;
Examine: if (noun == player)
"~If I may say so, as good-looking as ever.~";
],
react_after [;
Go: print "~Good evening.~^"; rfalse;
Drop: if (noun == cloak) {
move cloak to player;
"~Oops - let me pick that up for you.~";
}
],
has animate male;
|
The react_ properties enable the NPC to passively comment on (with the rfalse) or actively affect (with the rtrue) actions that would happen normally in another location.
>WEST "Good evening." Cloakroom The walls of this small room were clearly once lined with hooks, though now only one remains. The exit is a door to the east. You can see a gentleman usher here. >EXAMINE USHER The usher is smartly uniformed. >EXAMINE ME "If I may say so, as good-looking as ever." >REMOVE CLOAK. DROP IT (the velvet cloak) You take off the velvet cloak. "Oops - let me pick that up for you." >EAST The usher nods politely as you leave. |
Another straightforward approach is to use a daemon or timer of some sort which causes the NPC to make his presence felt. Here's a first attempt, using the each_turn property:
Object usher "gentleman usher" cloakroom
with name 'usher' 'gentleman' 'gentle' 'man',
description "The usher is smartly uniformed.",
each_turn [; switch(random(10)) {
1: "^~Welcome to the Opera.~";
2: "^~Shall I hang your cloak on this hook?~";
3: "^~Still raining, I see?~";
4: "^The usher clears his throat apologetically.~";
5: "^The usher shifts position slightly.";
default: ; ! values 6-10 are ignored
}
],
has animate male;
|
Using this simple method, the NPC will make a random remark roughly five turns out of ten; you can easily add to the repertoire of remarks and adjust the probability of one being made. However, hearing the same remark more than once soon gives the game away, so a better idea uses an array of logical flags to prevent this:
Array UsherSaid -> 6; ! 0=unused, 1-5=true/false flags
[ UsherSays num str;
if (UsherSaid->num) rfalse;
UsherSaid->num = true;
print_ret (string) str;
];
Object usher "gentleman usher" cloakroom
with name 'usher' 'gentleman' 'gentle' 'man',
description "The usher is smartly uniformed.",
each_turn [; switch(random(10)) {
1: UsherSays(1, "^~Welcome to the Opera.~");
2: UsherSays(2, "^~Shall I hang your cloak on this hook?~");
3: UsherSays(3, "^~Still raining, I see?~");
4: UsherSays(4, "^The usher clears his throat apologetically.");
5: UsherSays(5, "^The usher shifts position slightly.");
default: ; ! values 6-10 are ignored
}
],
has animate male;
|
You could use the library package Flags.h to manage the logical flags as bits rather than bytes. Also, a more sophisticated implementation would permit random NPC remarks only in turns when the player hasn't already interacted with the NPC.
Next, other forms of silent interaction.