Starting conversations without using components

Announcements, support questions, and discussion for the Dialogue System.
Post Reply
tylerwsavatronix
Posts: 33
Joined: Tue Jul 05, 2016 6:18 pm

Starting conversations without using components

Post by tylerwsavatronix »

Hey there,

So I'm in a position where using the built in conversation trigger components is undesirable.
1) Each NPC can have potentially hundreds of conversations, and having hundreds of different trigger components attached sounds like bad juju.

2) There are other ways a player can interact with an NPC using the same interact button, depending on context. For example, the player could be holding an item, and in that context hitting the interact button would gift said item instead of starting a conversation. So using the built in trigger would require a different button be used for every type of NPC interaction, and that's not a great user experience.

3) NPCs are dynamically generated for modability, and it would be a better experience to somehow dynamically figure out which conversations an NPC has instead of manually having to create triggers, or in our case manually specifying a list of conversation ids in JSON.

At the moment, NPCs have an Interact method that gets triggered when any other character interacts with it (it can tell player from NPC and such). For early prototyping I just had the method use DialogueManager.StartConversation() with a hardcoded conversation id and a test DB.

Now that I'm beyond the initial prototyping, I instead need to be able to figure out which conversation should be started and that's where I'm not entirely sure how to proceed.

Is there already built in functionality to query the DB to find the first valid conversation for a given NPC, or is this something I need to build out myself?

If the latter, do you have an opinion as to how best accomplish that? Off the top of my head I'm thinking I'd have to parse the DB at game start for every conversation a given NPC starts, and then when interact happens roll through the list testing if the conversations criteria is met (I was thinking of using the first dialogue node's condition inside the conversation to have the conditions for that conversation since I didn't see a formal "conversation conditions" property anywhere other than conversation trigger, which I'm not using) and select the first conversation that passes.

I'm not even sure if that's possible or advisable though, and am totally open to any advice you have.

Thanks!
User avatar
Tony Li
Posts: 20764
Joined: Thu Jul 18, 2013 1:27 pm

Re: Starting conversations without using components

Post by Tony Li »

Hi,

You'll need to implement it yourself. This is kind of a disgression, but: the Dialogue System is designed so you can re-use conversations for multiple NPCs, even if you've assigned a specific NPC as the conversation's primary Conversant in the dialogue database. The classic example I use in the documentation is the "shopkeeper" conversation. You can write one conversation and re-use it for shopkeepers in every village in your world. You can use [var=Conversant] to reference the conversant's name in dialogue text, such as:
  • Dialogue Text: "I'm [var=Conversant]. Welcome to my shop!"
(Similarly, you can use Variable["Conversant"] in Conditions and Script fields.)

So, anyway, you'll need to query DialogueManager.MasterDatabase. This property represents the sum of all dialogue databases that have been loaded into memory. In most games, only the database assigned to the Dialogue Manager's Initial Database is loaded. It's much simpler to use one database, and it provides a better workflow with third party editors such as articy:draft and Chat Mapper. (If you're using multiple databases, be sure to read How to Use Multiple Dialogue Databases.)

You can use a single Linq query if you like. Here's a simple proof of concept:

Code: Select all

using UnityEngine;
using System.Linq;
using PixelCrushers.DialogueSystem;

public class ListActorConversations : MonoBehaviour {

    public string actorName;

    void Start() {
        var actorID = DialogueManager.MasterDatabase.GetActor(actorName).id;
        var actorConversations = 
            from conversation in DialogueManager.MasterDatabase.conversations
            where conversation.ConversantID == actorID
            select conversation;
        foreach (var conversation in actorConversations) {
            Debug.Log(conversation.Title);
        }
    }
} 
tylerwsavatronix
Posts: 33
Joined: Tue Jul 05, 2016 6:18 pm

Re: Starting conversations without using components

Post by tylerwsavatronix »

Thanks for that reply. We're planning on using one DB, or (if it's a supported thing) merging in modded DBs (I'm not entirely sure how we're going to do that yet. We may just output everything to ChatMapper json and load it in, letting mod authors just mess around with json to add dialogue).

The shopkeeper example is still doable if we have generic shopkeeps (right now we're planning to have 0 generic characters), since we can just do a similar query on various generic character names (like "shopkeeper") and add those lines to the stored list.

How would/should I go about handling the conversation conditions? Is there a way to test the first dialogue nodes conditions, or should I instead do some type of customization to add that as a property on conversations?

Basically, excluding event-specific conversations, I'd like to be able to set conditions for conversations to be valid. It's not difficult to iterate through and test the conditions in code, I'm just not sure where the best place to use those conditions is (OOB it would be on the ConversationTrigger as I understand it instead of on the actual conversation).
User avatar
Tony Li
Posts: 20764
Joined: Thu Jul 18, 2013 1:27 pm

Re: Starting conversations without using components

Post by Tony Li »

Hi,
tylerwsavatronix wrote:We're planning on using one DB, or (if it's a supported thing) merging in modded DBs (I'm not entirely sure how we're going to do that yet. We may just output everything to ChatMapper json and load it in, letting mod authors just mess around with json to add dialogue).
It's supported. (BTW, Chat Mapper format is XML, not JSON.) See How To Import Chat Mapper At Runtime. If you use multiple databases, the internal ID numbers generally need to be unique across them. If you can't otherwise guarantee that they'll be unique, you can use the DatabaseMerger class to merge multiple databases into a single database with unique IDs.
tylerwsavatronix wrote:How would/should I go about handling the conversation conditions? Is there a way to test the first dialogue nodes conditions, or should I instead do some type of customization to add that as a property on conversations?
Use DialogueManager.ConversationHasValidEntry(). There are two versions. One accepts GameObjects for the actor and conversant participants, in case your conditions need to run checks against specific participants.
tylerwsavatronix
Posts: 33
Joined: Tue Jul 05, 2016 6:18 pm

Re: Starting conversations without using components

Post by tylerwsavatronix »

Tony Li wrote: It's supported. (BTW, Chat Mapper format is XML, not JSON.)
ChatMapper now supports exporting from json
http://www.chatmapper.com/features/

Though I'm guessing DS doesn't yet. Got plans for that to be supported eventually?
Use DialogueManager.ConversationHasValidEntry(). There are two versions. One accepts GameObjects for the actor and conversant participants, in case your conditions need to run checks against specific participants.
Ah, sweet. Thanks much!
User avatar
Tony Li
Posts: 20764
Joined: Thu Jul 18, 2013 1:27 pm

Re: Starting conversations without using components

Post by Tony Li »

tylerwsavatronix wrote:
Tony Li wrote:(BTW, Chat Mapper format is XML, not JSON.)
ChatMapper now supports exporting from json
http://www.chatmapper.com/features/

Though I'm guessing DS doesn't yet. Got plans for that to be supported eventually?
Yes, in version 2.0. The minimum Unity version for Dialogue System v1.x is Unity 4.6.5. Dialogue System v2.0 (which is a way down the road) will bump the minimum up to Unity 5.4 to simplify a lot of Unity version-dependent compiler defines and also to take advantage of JsonUtility. Since all features are available with Chat Mapper XML, and it's been battle tested in many games, there isn't a pressing reason to add Chat Mapper JSON support until then.
tylerwsavatronix
Posts: 33
Joined: Tue Jul 05, 2016 6:18 pm

Re: Starting conversations without using components

Post by tylerwsavatronix »

Yeah, I wasn't expecting it in any short term.

We probably won't be putting in that capability for another year or so at a minimum (It's not a thing that's going to be going into the demo we're currently building), and worst case scenario we could just write our own json importer.

But since the plan is to have all modable files make use of json it doesn't make long term sense in our case to have an oddball xml file to deal with, heh.
tylerwsavatronix
Posts: 33
Joined: Tue Jul 05, 2016 6:18 pm

Re: Starting conversations without using components

Post by tylerwsavatronix »

Since I'm trying to do some dependency injection on the class I'm creating to do these things (so I can mock and do unit tests) I have quick question:

Is the DialogueSystemController property DialogueManager.Instance functionally equivalent to the DialogueManager?

I'm assuming it is what the static DialogueManager methods/properties are referencing under the hood and is what I should take in as a dependency (which will allow me to mock it for unit testing), but just want to verify before taking road that's ill advised.
User avatar
Tony Li
Posts: 20764
Joined: Thu Jul 18, 2013 1:27 pm

Re: Starting conversations without using components

Post by Tony Li »

Hi,

Yes. Under the hood, the DialogueManager static methods are just wrappers for the DialogueSystemController Instance property.
Post Reply