236 lines
9.2 KiB
Plaintext
236 lines
9.2 KiB
Plaintext
Building Sentient Non-Player Characters
|
|
The Nightmare IV Object Library
|
|
written by Descartes of Borg 951127
|
|
|
|
One thing most everyone wants to see are monsters that react more
|
|
intelligently to user input. The fact is, however, that most monsters
|
|
in the game only need a small, basic behaviour set. Nevertheless, in
|
|
order to make an area interesting, there should be some monsters which
|
|
stand out as unique and purposeful. The problem about building such
|
|
monsters is that they use a lot of processing time.
|
|
|
|
In order to make sure most monsters which do not need such
|
|
intelligence do not waste processing time on such activities, the
|
|
Nightmare Object Library separates non-player characters into two
|
|
classes: dumb monsters, which are basic mindless automata and
|
|
sentients, monsters which react more intelligently to their
|
|
environment.
|
|
|
|
This document describes sentients. Before looking at this document,
|
|
it is highly recommended that you be familiar with the document
|
|
/doc/build/NPC which details non-player characters. Sentients are
|
|
non-player characters, so everthing which applies to non-player
|
|
characters also applies to sentients.
|
|
|
|
*****
|
|
|
|
Currently, a few basic behaviours distinguish sentients from normal
|
|
npcs. Those behaviours are the ability to intelligently move about
|
|
the mud and to react to user speech. Nightmare thus provides the
|
|
following functions to allow you to easily have an sentient enact
|
|
those behaviours:
|
|
|
|
mapping SetTalkResponses(mapping mp);
|
|
mixed AddTalkResponse(string str, mixed val);
|
|
int RemoveTalkResponse(string str);
|
|
|
|
mapping SetCommandResponses(mapping mp);
|
|
mixed AddCommandResponse(string str, mixed val);
|
|
int RemoveCommandResponse(string str);
|
|
|
|
varargs int SetWander(int speed, string *path, int recurse);
|
|
string *SetWanderPath(string *path);
|
|
|
|
int SetWanderRecurse(int x);
|
|
|
|
int SetWanderSpeed(int x);
|
|
|
|
*****
|
|
|
|
Making NPCs react to user speech
|
|
|
|
You may want to have NPCs react to things players say. To that end,
|
|
the following functions exist:
|
|
|
|
mapping SetTalkResponses(mapping mp);
|
|
mixed AddTalkResponse(string str, mixed val);
|
|
int RemoveTalkResponse(string str);
|
|
|
|
Function: mapping SetTalkResponses(mapping mp)
|
|
Example: SetTalkResponses( ([ "square" : "The square is east of here.",
|
|
"house" : "Isn't that an ugly house?" ]) );
|
|
|
|
This function allows you to set a list of responses to given phrases.
|
|
For example, if you put this code in a sentient and a player said
|
|
"Where is the square?" or "Your frog is certainly square.", your NPC
|
|
would have said "The square is east of here.". Note therefore that
|
|
the NPC is only looking for the keys you place in there. You could
|
|
have restricted it to "where is the square" instead of "square", but
|
|
then someone asking "Where's the square" would be missed.
|
|
|
|
Also note that phrases should be in lower case. It will match to
|
|
upper case words automatically.
|
|
|
|
Finally, you can either give a string or a function as the match to a
|
|
phrase. If the match is a string, the NPC simply says the string in
|
|
the NPC's native tongue. If, however, the match is a function, that
|
|
function will get called.
|
|
|
|
*****
|
|
|
|
Function: mixed AddTalkResponse(string str, mixed val);
|
|
Example: AddTalkResponse("in the house", (: HouseFunc :));
|
|
|
|
Matches an individual phrase to a string or function. As with
|
|
SetTalkResponses(), if the match is a string, the NPC simply says the
|
|
string in response to the phrase. If it is a function, that function
|
|
gets called.
|
|
|
|
*****
|
|
|
|
Function: int RemoveTalkResponse(string str);
|
|
Example: RemoveTalkResponse("house");
|
|
|
|
Removes the previous set or added talk response from the NPC.
|
|
|
|
*****
|
|
|
|
Making NPCs react to user directives
|
|
|
|
Nightmare supports a special command, the "ask" command. A player may
|
|
use the ask command to ask an NPC to perform a certain task. For
|
|
example, "ask the healer to mend my right leg". There is a special
|
|
event in NPC's which responds to this called eventAsk(). In order to
|
|
make responding to this easier, however, Nightmare has the
|
|
CommandResponse functions. The command response functions allow NPC's
|
|
to respond based on commands, like "mend".
|
|
|
|
*****
|
|
|
|
Function: mapping SetCommandResponses(mapping mp);
|
|
Example: SetCommandResponses( ([ "heal", "I cannot heal people" ]) );
|
|
|
|
Allows you to match commands to either strings or functions. Matched
|
|
functions get called with the command as the first argument, and
|
|
command arguments as the second argument. For example, if you had:
|
|
SetCommandResponses("give", (: give :));
|
|
Your give() function would get called with "give" as the first
|
|
argument and "me the sword" as the second argument in response to a
|
|
player issuing the command "ask the monster to give me the sword".
|
|
|
|
*****
|
|
|
|
Function: mixed AddCommandResponse(string str, mixed val);
|
|
Example: AddCommandResponse("give", (: give :));
|
|
|
|
This allows you to add to the list of commands to which the NPC
|
|
responds. The NPC responds to those commands as outlined for
|
|
SetCommandResponses().
|
|
|
|
*****
|
|
|
|
Function: int RemoveCommandResponse(string str);
|
|
Example: RemoveCommandResponse("give")
|
|
|
|
Removes a previously set command response.
|
|
|
|
*****
|
|
|
|
Making NPCs move about the game intelligently
|
|
|
|
A sticky subject on most muds is that of wandering monsters. When
|
|
done poorly, they can waste resources to a great degree. Nightmare,
|
|
however, works to avoid wasting resources while getting the most out
|
|
of allowing monsters to move about.
|
|
|
|
Nightmare supports two types of wandering monsters: those which have
|
|
pre-determined paths and others which are true wanderers. True
|
|
wanderers, those who simply randomly choose paths are subject to the
|
|
following restrictions:
|
|
They may not move into rooms not yet loaded in memory.
|
|
They will not try to open closed doors.
|
|
The first restriction is the most important to note. This means that
|
|
the NPC will not wander into rooms that have not been recently visited
|
|
by some player. This avoids the problem NPCs cause on many muds of
|
|
uselessly loading rooms that only the monster will ever see.
|
|
|
|
Monsters given specific paths to wander are not subject to the above
|
|
restrictions. Of course, they cannot wander through closed doors.
|
|
But you can make part of their path to open a closed door. In
|
|
addition, since such monsters have very specific sets of rooms into
|
|
which they can travel, they are not in danger of needlessly loading a
|
|
zillion rooms.
|
|
|
|
*****
|
|
|
|
Function: varargs int SetWander(int speed, string *path, int recurse);
|
|
Examples:
|
|
SetWander(5);
|
|
SetWander(5, ({ "go north", "open door", "enter hut", "go west" }));
|
|
SetWander(5, ({ "go north", "open door", "enter hut", "go west",
|
|
"go south" }), 1);
|
|
|
|
This is the function you will almost always use in create() to make a
|
|
sentient wander. Only one of the three possible arguments is
|
|
mandatory, that being the speed. The speed is simply the number of
|
|
heart beats between attempts to move. Thus, the higher the number,
|
|
the slower the movement of the monster.
|
|
|
|
The second argument, if given, is a list of commands which will be
|
|
executed in order by the monster. If it is not given, the monster
|
|
will be assumed to be a true wanderer. In other words, the first time
|
|
the monster tries to wander, the monster will "go north". The second
|
|
time, he will "open door". The third, he will "enter hut", etc.
|
|
|
|
The third argument is either 1 or 0. If 1, that means once the
|
|
monster has completed the path, it will use the first command in the
|
|
list the next time it tries to wander. If 0, it will cease to issue
|
|
commands once it has cycled through the list.
|
|
|
|
You might note that between the time the above monster opens the door
|
|
and enters the hut, somebody could come along and shut the door. How
|
|
can you deal with that? You could do:
|
|
SetWander(5, ({ "go north", ({ "open door", "enter hut" }) }));
|
|
You will notice here that the second member of the command array is
|
|
itself an array instead of a string. In that case, all members of
|
|
that array get executed as part of that wander. In this case it helps
|
|
make sure no one closes the door between when the monster tries to
|
|
open it and when it tries to pass through the door.
|
|
|
|
For even more flexibility, you can make elements of the array into
|
|
functions. Instead of executing a command in a wander turn, the
|
|
function you provide instead gets called. For example:
|
|
SetWander(5, ({ "go north", (: kill_anyone :), "go south" }), 1);
|
|
Where the function kill_anyone() has the monster kill any players in
|
|
that room. Thus, this monster sits in its room and occasionally pops
|
|
its head one room to the north to kill anyone sitting there.
|
|
|
|
*****
|
|
|
|
Function: string *SetWanderPath(string *path);
|
|
Example: SetWanderPath(({ "go north", "go south" }))
|
|
|
|
Allows you to set the monster's wander path independent of other
|
|
settings. The wander path will never get executed, however, unless
|
|
the monster's wander speed is greater than 0.
|
|
|
|
*****
|
|
|
|
Function: int SetWanderRecurse(int x);
|
|
Example: SetWanderRecurse(1);
|
|
|
|
Allows you to make the monster's wander path recurse independent of
|
|
other settings. This is meaningless, however, unless the monster's
|
|
wander speed is greater than 0 and a wander path is set for it.
|
|
|
|
*****
|
|
|
|
Function: int SetWanderSpeed(int x);
|
|
Example: SetWanderSpeed(5);
|
|
|
|
Allows you to set the monster's wander speed independent of other
|
|
settings. This is NOT the same as SetWander(5). SetWander() will
|
|
clear out any previous wander path and wander recurse settings. This
|
|
function has no effect on the monster's wander path or wander recurse.
|
|
|