Part A (§1): The BasicsKnowledge and Conversation
§3: More Advanced Techniques
(Advanced NPC Implementation, Part 2c)
n the previous section we discussed various methods of sharing knowledge between characters and customizing the dialog to match a character. This section will cover additional techniques, such as topics that change content.
A common practice when developing NPCs is to have the character say random things at various points in the game. Embedded somewhere deep in whatever daemon controls the NPC can be a couple of lines of code that cause the character to speak to the player:
Although it is certainly possible to create a dozen or so KnowledgeTopics, pick one at random each turn and have the NPC talk about it, a better way is to create a morphing topic. That is, a topic that prints something different each time it is used. Since this technique is best implemented with non-learnable topics, separating conversation from information need not be done:
Conversation Script Topics
One of the more difficult challenges that must be faced when writing believable NPC dialog via the ASK/Tell method is getting the player to ask the right questions. In many cases there is information that needs to be conveyed to the player to further the game, yet there is no viable method of forcing him/her to make the appropriate inquiries. It is true that the occasional hint can be dropped here and there, but there are often times that hints just don't seem appropriate to the game.
Having an NPC initiate conversation and thereby volunteer this information is a time-honored method of dealing with situation. In truth, this technique can be useful even if no pertinent information needs to be conveyed. People initiate conversation and volunteer trivial information as a matter of common practice. A realistic NPC should do this as well. Having an NPC follow a "conversation script" that evolves over a series of turns can help to simulate a conversation and provide pertinent information if needed.
There is a caveat or two associated with this approach, though. Many developers, myself included, have implemented this technique and rendered the player helpless for a time. That is, a situation has been created where the player can do nothing except wait until the NPC is finished talking. No amount of ingenious dialog can make up for a lack of interactivity. If the only action available to the player is to type "z", the game's "player experience" will suffer.
Another thing to consider when designing a conversation script is that people generally do not repeat the same information unless asked to. In a conversation where the player actually participates, it is possible that an NPC will be asked a question earlier than he was scripted to volunteer it. Repeating the information after it has been already been told is repetitive. What is needed is a way for the NPC to remember what has already been said and to move on to the next item in the script.
The "conversation script topic," a variation of morphing topics, is one of the more useful techniques in creating realistic, non-repeating dialog. It is particularly powerful because it can utilize other KnowledgeTopic objects so that the information can be both asked for and volunteered.
A couple of minor modifications should be implemented to facilitate knowledge scripts. The first is a method of recording whether or not a topic has been communicated before. We can accomplish this by defining and setting an attribute. Arbitrarily, we'll call this 'hasbeentold':
The next modification we can make will ensure that the NPC doesn't "double talk" or say two things at once. This can happen when the NPC is following a script and the player asks a question. If not coded correctly, the NPC will answer the question and then continue to say whatever comes next on the topic script. Game conversation seems to more closely parallel reality if the NPC only "drives" the conversation when the player isn't talking to him. To accomplish this, we can add a property to the NPC class that records the last move he/she spoke in:
These values can be updated when a topic is conveyed. The TellAbout routine, in the KnowledgeTopic class, is the obvious place:
The final new addition that we will make to the KnowledgeTopic object, which we have been developing in this article, is a routine called SayOrRecurse. The sole purpose of this routine is to facilitate a conversation script. This routine, which is called by the TellAbout routine, checks to see if the specified KnowledgeTopic has already been conveyed. If not, then it will print it and return. If so, then the TellAbout routine of the current object is called (recursively) to request the next scripted topic:
Opinions vary concerning the use of recursion. Suffice it to say, misuse of this technique can cause run-time errors in the Z-Machine interpreter. Although it can be a useful addition to your conversation repertoire, use this method with care.
Before creating a conversation script, an author should have a clear idea of how the conversation should flow. A design technique used by many authors is to write the entire conversation the way they would prefer it to read first. Once this has been done, the conversation can be logically separated into pieces. Almost always, these pieces of text can be classified into two categories: dialog that is the answer to a question which the player will possibly ask, and dialog that will never be asked about, and serves no purpose other than to make the NPC seem more believable.
The former type, which can be inquired about, is best stored in a KnowledgeTopic of it's own. Generally, these types of dialog pieces will compromise the bulk of a conversation script. The latter type more often appears at the beginning and end of a script. Generic statements, such as variations of "hello," and "goodbye", are classified in this category.
What follows is an example script object for a conversation between a doctor and the player who has just woken up in a hospital. Notice that script steps 2, 3, and 4 utilize three other KnowledgeTopics and so will be brought up, even if not directly asked about by the player.
Additionally, a believable NPC will have a collection of additional topics that are not volunteered, but are clarifications of statements made in the script. This NPC will be able to answer questions the player may have in the course of the conversation but will not volunteer this information unless directly asked about it:
Now that we have a workable script, we need an NPC capable of driving the conversation:
This simple NPC will converse with the player each turn about our script object. The conversation can happen in several different ways now. One possible play out of the script follows:
Of course this is just a basic example, but notice that the script adapts and skips over topics already asked about by the player. This technique has the advantage of ensuring that the player gets information, even if he does not think to ask the appropriate question, but also adapts to a player's questions, ensuring a more realistic conversation.
Inanimate Knowledge Transfer
It was mentioned above that characters are not the only objects that can utilize the knowledge objects. Any book, such as "Waldecks's Mayan dictionary" from the Inform Designer's Manual, or the ever-popular spell book is an ideal candidate for an inanimate object housing KnowledgeTopics. The consult verb should be extended much as the tell verb was:
Now we can create the spell book with a specialized ProcessDialog routine, specifically tailored to a reference book:
And of course a spell for the spell book:
In a sense, a journal can "learn" about a topic when someone writes in it. A good exercise for the reader would be to implement a "write" verb in which knowledge can be recorded in non-animate objects.
The reader may have noticed that, although Ask and Tell are thoroughly discussed in this article, Answer (or say) has been left relatively untouched. It has been my experience that it is often best to treat Answer and Tell as two forms of the same command. Essentially, I choose to treat:
in the same manner as I would treat:
As stated previously, my way is not the only way. Distinguishing between the two commands may be useful in a number of scenarios. The above "spell book" example, set in a world where characters cast spells, would be one such situation. For example,
would be better handled in the same manner as
This distinction is best made by the developer.
Also, in the interest of avoiding dependencies, all references to specialized print rules have been left out of the samples above. Pronoun print rules, however, are especially useful when creating the sort of conversation topics that we have been developing in this article. Techniques discussed in the previous article "Pronouns on Steroids" can be of significant aid.
About the Examples...
To aid the reader, the examples given in all three sections of this article have been bundled together in single source file.
Additionally, the ORLibrary entries ORKnowledgeTopic.h and ORNPC.h contain a complete, and somewhat more progressive, implementation of the techniques discussed in this article.
Emily Short's page on NPC design, although geared for platform independence and not for Inform specifically, is nevertheless inspirational in its discussion.
Additionally, her game "Galatea", is an exquisite example of NPC conversation.
Also, although mentioned previously, the conversation section of Roger Firth's Infact page is especially recommended.
§3: NPC Actions
§2b: Advanced Techniques