Dynamic Quest Generation #3: Making Quest Tasks Make Sense

Last week a fan stated: “You only wrote that article to talk about Indiana Jones.” I’m trying to be transparent, but not that transparent! 😛

This is our super secret process, and so far we’re sticking to it!

See those loops that go backwards? Ya, that was last week.

As a reminder our context is: We’re trying to make a dynamic quest generator able to spit out a simple “kill the monster for me”. If we can do that well, we believe we’ll have the tech baseline to make the other kinds of quests with all the nuances required.

From Tasks to Text

Our goal for the week is to go from basic story outline of motivations and tasks of the previous week, to generating some dialogue text.

Prepare to be underwhelmed!

Two Challenges

  1. Inappropriate Tasks - We’re generating quest task lists which may not have anything to do with the NPC’s goal. If they want a skeleton lair destroyed, but the tasks they give you are: Talk to NPC, Study a book, Fetch some Stone… it just doesn’t match the objective or feel right.

  2. Pacing and Tension - if the tasks are in a randomized order, we go from amazing stories where the tasks seemingly build from the previous, to stupid ones that make no sense.

The solution to both of these is to use Templates!

Templates

A template is a heuristic (I think i’m using that word right) to guide the hand of the generator to results we want.

For every given problem type and motivation, we can have a template for the kinds of tasks which would resolve it. Not so much a script as a trope.

Inappropriate tasks? Gone, we can use the template to define only the task types we know are appropriate.

Pacing and tension? Nolan was thrilled he can now control types of tasks and the size of them to build and release tension and build narrative progression.

I’m not afraid of some manual labor of making templates, as long as the # of templates is reasonable. I’ll define reasonable as < 300. Past that, it is too laborious to be useful to a game in active development.

Not a template like this!

We created a really rough template like this:

Quest Plot 1: Rohesia Streatfield wants Eliminate - Kill Unique

Template: cEeiraaaaa

  • The length of the template determines how many tasks (steps) are in the quest. This can vary and we can modify the hand made templates at runtime with changes so we don’t have to create tons of templates

  • Each letter of the template defines a category of task allowed.

    • c = Combat, e = Exploration, E = Economy, i = Information, r = Relationship

    • a = any category

To make this work we needed some way of defining the data pools and allow Nolan to modify it. I was sick of doing all the grunt work myself!

Like all good game devs, we use Excel to store some of our very textual data. It’s better than JSON which we use for more crunchy data like monster hitpoints, and much much easier to read and edit.

For any curious programmers, we use ExcelDataReader to work with binary Excel files in C#. I already wrote an Adapter class (for the NPC dialogue system) that gets down to the business of reading in an excel file and turning it into custom class data objects in about 3 lines of code. Unfortunately, this code was only on the game side not our tooling, so I had to integrate it in and be able to read in data like this from Excel:

It took a day to rewrite the hacky prototype code we had from class/object based to external data driven. I got it all setup and working.

I showed the results to Nolan.

It sucked.

Quest Plot 1: Rohesia Streatfield wants Eliminate - Kill Unique Template: cEeiraaaaa

  1. Rohesia Streatfield: Meet quest giver. Get introduction to quest ()

  2. Rohesia Streatfield: Capture Enemy (Combat) (Allied - Eliminate - Kill Unique)

  3. Reginald Steed: Find Town (Exploration) (Allied - Eliminate - Persuade Other NPC for Current NPC) They provide assistance

  4. Grecia Pugsley: Get Generic Item (Economy) (Allied - Eliminate - Kill Enemy in Certain Place) They provide assistance

  5. Isabella Mossman: Ask Other NPC About Topic (Information) (Allied - Eliminate - Kill Enemy in Certain Place) They provide assistance

  6. Rohesia Streatfield: Persuade Other NPC (Relationship) (Allied - Eliminate - Kill Unique)

  7. Isabella Mossman: Raise Relationship with Current NPC (Relationship) (Allied - Eliminate - Kill Enemy in Certain Place) They provide assistance

  8. Estrilda Tibbles: Find Text (Exploration) (Allied - Eliminate - Clear Lair) They provide assistance

  9. Reginald Steed: Persuade Other NPC (Optional) (Relationship) (Allied - Eliminate - Persuade Other NPC for Current NPC) They provide assistance

  10. Grecia Pugsley: Get Training (Economy) (Allied - Eliminate - Kill Enemy in Certain Place) They provide assistance

  11. Lauretta Devereux: Persuade Current NPC [End Quest] (Relationship) (Allied - Eliminate - Clear Lair) They provide assistance

We hadn’t solved our core issue because we didn’t have enough detailed data on the NPCs actual problem. If their goal for the quest was Eliminate a Skeleton Lair we couldn’t just have any combat task at the end, we had to have a Destroy a Lair task!

I won’t make you figure it out but just tell you: There ain’t enough letters in the english alphabet to identify all the possible tasks we need now and in the future to make a letter based template work.

We were at a dead end.

I threw out what I’d done and started again with a new idea. A quote from a 1930’s journalist…

Enter Malcolm Muggeridge

Malcolm Muggeridge - British writer and social critic, was one of the most brilliant controversialists and media personalities of his generation.

All new news is old news happening to new people
— Malcolm Muggeridge

This is a fascinating insight on the human condition that we can take advantage of for game quests.

I’m playing Assassin’s Creed Valhalla right now (and will be for at least 10 more months if I want to finish the story!), and each quest more or less follows this basic template:

  1. Go talk to some person

  2. Go talk to another person

  3. Fight some soldiers in some place

  4. Go talk to the original person

Am I bored? No.

Its not just similar across AC series, but its similar to Witcher, or Pillars, or Skyrim. It’s old news (tasks) happening to new people for new and contextually relevant reasons.

Worry less about task variety, and focus on better more detailed reasons for the goal.

With this new insight I added more data to the NPC goals:

  1. A reason why the NPC wants the objective, like a Lair destroyed.

    1. The [@target] have been proliferating again.

    2. The [@target] have been venturing dangerously close to our town.

  2. A scale for how strongly the NPC feels about the goal.

    1. If they are afraid of skeletons a little bit then the tasks will be reserved and quest rewards they are willing to pay small.

    2. If their passion is dialed to 11, they’ll take the most extreme measures and pay anything, up to half their kingdom!

  3. A separate value for tracking their feeling towards each monster type in the world. Similar to Ken Levine’s Orc who hates all elves, but indifferent to goblins.

We can utilize this data in other interesting ways.

  • Events can happen that increase NPC’s passion about something.

  • Players can do/say something to change an NPCs passion scale value.

With this new approach, we created a new template system. These are comma separated lists of task ID’s that are super easy to read:

The output now looks like this. We show the task categories in ():

Quest Plot 1: Gilbert Worthington wants Eliminate - Kill Unique
Template: Ask Other NPC About Topic, Find Lair, Clear Lair, Kill Unique

  1. Gilbert Worthington: Meet quest giver. Get introduction to quest ()

  2. Gilbert Worthington: Ask Other NPC About Topic (Information) (Allied - Eliminate - Kill Unique)

  3. Eleanor Bastable: Find Lair (Exploration) (Allied - Eliminate - Get Generic Item) They provide assistance

  4. Gilbert Worthington: Clear Lair (Combat) (Allied - Eliminate - Kill Unique)

  5. Gilbert Worthington: Kill Unique [End Quest] (Combat) (Allied - Eliminate - Kill Unique)

And another

Quest Plot 1: Agnes Cloyne wants Eliminate - Clear Lair - (Underlying reason: NEW ENEMY LEADER) Template: Find Text, Find Lair, Track Enemy, Kill Enemy in Certain Place

  1. Agnes Cloyne: Meet quest giver. Get introduction to quest ()

  2. Geoffrey Dartrey: Find Text (Exploration) (Allied - Eliminate - Kill Enemy in Certain Place) They provide assistance

  3. Beneger Meeson: Kill Unique (Optional) (Combat)

  4. Aytrop Pannell: Find Lair (Exploration) (Allied - Eliminate - Persuade Other NPC for Current NPC) They provide assistance

  5. Aytrop Pannell: Kill Unique (Optional) (Combat)

  6. Amice Nutt: Track Enemy (Exploration) (Allied - Eliminate - Get Generic Item) They provide assistance

  7. Agnes Cloyne: Kill Enemy in Certain Place [End Quest] (Combat) (Allied - Eliminate - Clear Lair)

There is nothing special about these quests. Many a junior designer has made quests like these across many games. But that is precisely the point! The algorithm is popping out intern or junior designer quality level quests! Progress!

This is all very difficult. And it’s not as if someone wrote a book on how to do it!

Oh wait, there is a book on how to do this. I’ve read it. I’ll say we are beyond what is covered in the book.

Hey! What About the Text Gen Goal?

With all the work (and rework) last week I did squeak in a tiny start on the quest giver dialogue. It’s pretty bad, but hey, everything is bad until it isn’t! Here is what the system currently spits out:

Quest Plot 1: Bardulf Samways wants Eliminate - Get Generic Item - (Underlying reason: DON’T UNDERSTAND THEM)
Template: Find Text, Find Lair, Track Enemy, Kill Enemy in Certain Place

  1. Bardulf Samways: Find Text (Exploration) (Allied - Eliminate - Get Generic Item)
    Well met. We’ve got a problem. These Skeleton are a mystery. Nobody understands them.I need you to Find Text

  2. Walter Maunder: Find Lair (Exploration) (Allied - Eliminate - Clear Lair) They provide assistance
    I need you to Find Lair

  3. Alan Lugg: Track Enemy (Exploration) (Allied - Eliminate - Clear Lair) They provide assistance I need you to Track Enemy

  4. Richard Mabbs: Kill Unique (Optional) (Combat)
    I need you to Kill Unique

  5. Bardulf Samways: Kill Enemy in Certain Place [End Quest] (Combat) (Allied - Eliminate - Get Generic Item)
    I need you to Kill Enemy in Certain Place

Additional Discoveries

  1. Totally random stinks, use templates BUT allow totally random sometimes to keep it spicey.

  2. I wanted to push off data importing to a later time. When prototyping speed is king. But the data started to get unweildly. Nolan typing things up in confluence and then me recreating it in code was slower not faster. Also, enabling Nolan to iterate in parallel with me gets us to the end result faster.

  3. There wasn’t a good place to bring this up in the narrative above, but we had a really significant realization on how to do this better in an open world. A reward for making it this far in the article!

    When the player has a task, like needing some knowledge from a scribe, or a blacksmith to sharpen a blade, we use domains of knowledge - a system we created for the NPC Update #1 to answer knowledge questions - to lead you to the correct person.

    1. So if the task is to find out some knowledge about Skeletons, that could be a Scribe level 3 knowledge requirement. The game will then point you to an NPC with that knowledge (like Gandalf or Eliminster). It will try to reuse experts. So in Quest 1 you need knowledge you go to town A and ask Expert X. In Quest 8 if you need similar knowledge, it will point you back to Expert X in Town A. This reuse makes the world feel real, and the people matter!

    2. Based on relationship (to you or the quest giver), the expert may not help you, unless you do some task for them. Once you do, they will then give you what you need.

    3. This now allows the player to play strategically. If they come across a field expert they can purposefully build relationship with them, so that when they get to a quest and need their expert knowledge, the person just gives it to them, no quid-pro-quo!

    4. If that expert dies (goblin attack, old age), time to find someone new! The game stays fresh.

    5. I hope I explained this clearly. It’s a pretty exciting new idea we’ll take advantage of later.