5
\$\begingroup\$

I am developing a quest system for a game and am looking for the most abstract way to go about connecting the system to the NPC conversation system. This isn't much of a question about the code to do it, but more looking for input on designs for it.

Structuring of the quest system and NPC conversation system has already been completed. What I'm trying to figure out is with my current NPC system, what is the best way to integrate the conversations and quests for the NPC.

Assume that, given my conversation system, the Conversation object holds a tree of all conversation nodes that the user will go through. I assume that each NPC will be given a Conversation object to go through in some way (whether this is directly or through a quest object is what I'm trying to decide). Some NPCs may have a standard conversation they have with a user and other NPCs might have a quest which contains conversations within it that the NPC should step through dependent on their current step in the quest. But then some NPCs might have a standard conversation and a quest or even an NPC with multiple quests and a standard conversation.

What I'm trying to figure out is what is the best way to "connect" these systems so that is abstract, dynamic, and clean. Any suggestions to help me think it out would be great.

\$\endgroup\$
2
\$\begingroup\$

Your class structure depends on the features that your game's quest system has.

This is my, rather complicated but very abstract setup. The information in these classes that I describe here isn't everything but gives you the idea.

The Character class holds textures, the Quest that it is involved with and a HashMap of questStage:Interaction objects. They also hold InteractionStageTalk objects for when the player talks to them at the wrong time etc.

The Quest class holds the name of the quest, the level required and experience rewarded. The Interaction class holds an array of InteractionStage objects, as well as requirements to enter that stage. The InteractionStage class is abstract. The InteractionStageTalk class holds a String that is said to the player by that Character as well as a delay. The InteractionStageGrant class holds an array of items to grant to the player. The player has a HashMap of their quests and the stages that they're at.

Now, if you're only giving items at the end of your quest and have a constant chat delay time, the InteractionStage business may be completely useless and replaceable with a string array.

It's very easy to add new features if you lay your classes out like this.

\$\endgroup\$
1
\$\begingroup\$

I suggest looking at the "free" tools Bethesda offers for their games, or particularly the Obsidian variant for Fallout:NV, as they are built around making very large numbers of dynamic conversion trees for NPCs and quests.

A dialog in most current RPGs consists of sequences of scripted conversion interspersed with dialog options. Selecting an option plays another sequence. A sequence could include: text spoken, audio, cutscenes, or game actions.

The actual dialog points are just a list of options. The options may have requirements: you might only be able to threaten an NPC if you have a high Strength, or only be able to say "I know who you are, let us talk" if you've reached a certain dialog point with another NPC. Each option will then direct the user to another sequence or another dialog.

The whole conversion is a graph. Yes, a graph, not a tree - there are likely multiple dialog choices that can lead into the same direction eventually, so a tree is a poor choice. The "enter" node is often an initial "hello, good day" sequence that then leads into the opening dialog options, while other times it jumps right into dialog options.

The structure of a Conversion then is a graph of nodes, where each node is either an Action (play cutscene, run Lua script, etc.) or a Dialog (a list of options).

If you were writing this in a Java-esque OOP style, you'd probably have a Conversation containing a dictionary of node names to INode objects and derived ActionNode and DialogNode classes. The ActionNode would contain a List of IAction objects like a CutsceneAction, SetQuestStateAction, ScriptAction, or GotoNodeAction. The DialogNode would contain a List of Option objects, where an Option has a script or somesuch for calculating requirements and then the name of the conversion node to enter when the option is chosen. This is probably the easiest way to think of things as a human, though it's a rather poor way to structure code.

A procedural approach would probably just use a Lua script to represent the whole thing. Such a script would have a function for each node and available procedures to perform actions, build dialog option lists, queue up animations and speech, etc.

An approach I'd prefer is a hybrid of the two. You want custom data structures and conversion code that innately understands as much about what a conversion is, how the graph works, how you can move between nodes, and so on, because you want to build nice tools for designers to create and test conversations. A raw script makes that difficult. However, you don't want to build a bloated over-engineered Java-style class hierarchy for every simple problem. A smaller flat DSL-like VM to execute conversations directly while still having enough metadata for editing and tool-supported verification works nicely. This is a relatively difficult option to engineer, though.

The tools support item is one of the trickier ones. If you build much logic into scripts, tools will not be able to reason about what the script will do. If you don't use scripts, you have to re-engineer a lot of the features you can pull off with scripts. A good balance is likely to add the ability to do all your most common actions without script but still allow script for complicated rare cases. That way, you tools and verification code can at least handle most of the conversations, and you only need technically-savvy designers and extensive manual testing for a small subset of conversations.

\$\endgroup\$

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.