4
\$\begingroup\$

I'm making a little demo game where roughly half of the NPCs in a little town have a profession, as well as a personality. I'm trying to have the game procedurally create dialogue, so when an NPC is talking about what they do, they describe it with some personality.

So for example, I may have a farmer who's an over achiever. He may have dialogue like this: "I farm from sun up to sun down. And I have the most cows around!" In another incarnation, a brainiac farmer may say, "Hi, my farm has exactly five cows, and is run very efficiently."

In the demo, the town will be procedurally generated, with a small number of townsfolk (around ten or twelve). Some will be peasants, others will be farmers. One or two will be merchants/shopkeepers. When the player talks to some of these folk, the NPC may greet the player and say something about what they do. Or they may describe themselves, as well as something about their town. On occasion, the NPC will also say something about their family.

I have thought of using a templating system, where it would fill in some of the dialogue. But I would like the sentences to vary with each playthough. I have also thought of using parts of speech so as to create sentences. The problem with using parts of speech (at least with using NLTK) is that I need some form of grammar to string them all together, and this is mainly meant for a small demo. Another option is to use a natural language generator (NLG), but that's getting into the realm of advanced AI. And I would like to steer away from that.

So should I use a templating system for the dialogue (I have tried using Rant, but I got into some really complicated syntax with that)? Or, should I use a dialogue system that uses parts of speech, and strings them together with some kind of grammar?

For what it's worth, I'm restricting the NPCs to a group of personalities. Also, some of what they say is based upon their stats. So if their intelligence is low, yet their charisma is high, maybe they'll be a xenophobe, or an over achiever.

\$\endgroup\$
  • \$\begingroup\$ Couldn't you create a big batch of possible dialogues for a certain profession and keep track trough each playtrough which has already been said? \$\endgroup\$ – Sidar Jul 20 '17 at 1:08
5
\$\begingroup\$

There's a great GDC Talk by Elan Ruskin of Valve on what they call "AI-Driven Dialogue through Fuzzy Pattern Matching" or "Rule Databases for Contextual Dialogue and Game Logic" - it's the system that powers contextual dialogue in the Left4Dead games, for example.

The core idea is that you can tag your dialogue with arbitrarily deep criteria for when it would be relevant/appropriate, and then rapidly search your dialogue database for the best dialogue to match any particular moment that arises in your game.

So rather than a fixed matrix like n lines for each combination of profession + personality template times the number of distinct conversation beats, you can mix and match criteria as needed.

It might look something like this:

// Very generic rule, can act as a catch-all if no other combination matches.
[Event = Greeting] "Hello"

// Adding an extra condition can start to make more characterful lines,
// while still having a broad pool of matches that different NPCs can share.
[Event = Greeting, NPC Has Trait Friendly] "Howdy!"

// Breaking up conversations into beats lets you mix & match lines for more combinations
[Event = Greeting Follow-Up, NPC Profession = Farmer]
 "Just taking a break from the fields"

// You can of course mix and match this with procedural replacement 
// to add more specificity to the lines
[Event = Greeting Follow-Up, NPC Profession = Farmer]
  "{Crop}'s coming in well, don't you think?"

// You can also key off of gameplay state variables
[Event = Greeting Follow-Up, Times Talked to This NPC = 1]
"I don't think we've met. I'm {NPC Name}"

// Stacking more can create more specific modular lines...
[Event = Greeting Follow-Up, Times Talked to This NPC > 1, NPC Has Trait Friendly]
"Nice to see you again, {Player Name}"

// Expressing fairly unique conversation situations in a reusable way.
[Event = Greeting Follow-Up, Times Talked to This NPC > 1,
 NPC Has Trait Friendly, NPC Has Trait Forgetful]
"Nice to see you again, um... er... sorry, what was your name again?"

Where this can become super powerful is that a line of dialogue that's matched the current gameplay context and played can then set its own variables into the gameplay state, or fire off its own conversation beat event to direct where the conversation goes from there (which can itself have any number of context-sensitive matches...)

So instead of writing explicit trees of dialogue, you effectively create a set of connection points between them, and they assemble themselves on the fly in reaction to the gameplay context in the moment, like proteins folding & linking according to the makeup of their chemical soup.

I recently implemented this in Unity for a narrative game, and so far I'm loving the flexibility it gives - especially when working with writers. They can work entirely in the rule database, creating new triggers and variations, whole gameplay sequences and consequences, without waiting on code or level design support to script it for them.

\$\endgroup\$
  • \$\begingroup\$ This is a great idea, @DMGregory. I'll see what I can do with it. \$\endgroup\$ – Ertain Jul 20 '17 at 19:06
  • \$\begingroup\$ Heads-up that it's a bit of a rabbit hole. I started trying to implement it three or four times before I finally got it working end-to-end. Ultimately it entailed writing my own parser for a narrative script format to make it easy to create these rules, and a virtual machine scripting system to fire off game events from each scene. You can probably do it with a much smaller scope, just plan thoroughly and pare down features aggressively. It's easy to get carried away with systems like this. ;) \$\endgroup\$ – DMGregory Jul 20 '17 at 19:11
  • \$\begingroup\$ Oh, I know the feeling. I've been planning and testing this thing for weeks. :-p Thanks for the heads-up. \$\endgroup\$ – Ertain Jul 20 '17 at 19:39
2
\$\begingroup\$

If you want some procedurally generated dialog which should 1. vary and 2. keep the context in mind, you could write your dialog lines with placeholder tokens which are inserted at runtime:

{{salutation}} {{playername}}. I heard we will have {{weather_prognosis}} today. That makes me {{weather_opinion}}.

Now how these tags are replaced at runtime is a matter of how complex you want to be in each individual case. There are several strategies which you could use:

  1. Direct replacement. A token like {{playername}} is directly bound to the value of a game variable. This is the most trivial replacement strategy.
  2. Randomness. Tokens which have a list of strings from which one is picked at random. {{salutation}} could use such a list with strings like "Hi", "Hello", "Good day" etc.
  3. Context-sensitive replacement. Tokens like {{weather_prognosis}} check the state of your weather system to have the NPC says something appropriate. {{weather_opinion}} also takes personality variables of the current NPC into account.
  4. Context-sensitive randomness. Combination of the previous two points. It might seem more natural if the {{salutation}} used by the NPC is not completely random. An NPC would use different salutations depending on how refined the NPCs manners are and how well they know the player-character, but they still wouldn't use the same salutation every time. To implement this, you could use weighted randomness and have the weight of each entry being dependent on the current state of various variables.

You could make this system even more powerful by allowing nested replacement tokens. The phrase above could be one entry of a list of phrases which are the replacement for the {{generic_smalltalk}} token.

The nice thing about this system is that you won't be forced to implement the full complexity from the start. You could start with a simple string-to-string replacement for most tokens to get the game to a playable state and then add more complex substitution rules for each token later.

A disadvantage of this system is that it makes translating a lot more difficult. Different languages have different rules for how relationships affect word choice and grammar (look at the convoluted rules for honorifics in Japanese, for examples). You and your primary writers won't be able to anticipate all these nuances. So translators might have to tweak the algorithms which pick appropriate responses or even add completely new tokens. That will require programming skills. But you will have that problem with any system which generates text procedurally.

\$\endgroup\$
0
\$\begingroup\$

I can see two options here :

  • Probably the best in terms of results : Write each possible combination job/personality by hand. You have control on the output but it takes a lot a time and is not much fun. Furthermore it gets complicated if you want to add text in the future.
  • Using a template such as @Philipp said is probably the easiest solution for you. You can add personality in those texts by varying the punctuation and vocabulary. For instance a depressive character would have sentences ended with '...' and his vocabulary would include adjectives like 'sad', 'depressing' etc. A happier character would have a lot of '!' and interjections such as 'Hey !' or 'Wow !'.

The NLG would be the coolest feature and really create new dialogues each time but I'm not sure if it's relevant for a demo. It would take much more time than making the game itself.

\$\endgroup\$
  • \$\begingroup\$ Yeah, the NLG would be really cool. However, I'm just throwing something together for the time being. \$\endgroup\$ – Ertain Jul 20 '17 at 19:02

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.