Queueing conversation to run after another

Announcements, support questions, and discussion for the Dialogue System.
Post Reply
User avatar
Tony Li
Posts: 22049
Joined: Thu Jul 18, 2013 1:27 pm

Queueing conversation to run after another

Post by Tony Li »

A Dialogue System user asked:
tl:dr: I need a convenient way to start a secondary conversation on a short delay after the end of a first WITHOUT using hundreds of TimedEvent components on empty gameObjects.

Context:

I'm using the dialogue system in what amounts to a 4X strategy game where the player is not a 3d character in the world but is abstracted - effectively they are looking at a map for most of the game.

Nevertheless as the leader of their faction they are engaged in interactive conversations with NPC's from time to time in a CYOA style. But Civilisation style – effectivelyconversations just happen depending on actions the player has taken on the map, UI button clicks etc.

Maybe 60 to 70% of the conversations in the game going to be in the form of one or 2 stage, 3 or 4 node conversations where the player is presented with a strategic choice by the narrator character – spend money on guns, build a hospital, buy a big gold statue of yourself, that sort of thing.

Desired behaviour is:
Conversation 1 - they make a choice without knowing what effect it will have.
Conversation 2 - Shortly afterwards (30 secs) they get the good or bad news.
the outcome of their choice which affects their key variables – health,
morale and so on. This could be an alert or conversation but preferably conversation.
There doesn't need to be any player character response menu or subtitles in this conversation.

I've tried deriving my own UIDialogue class as you suggested another post and overriding the Show Alert () methods.

It would be ideal if I could just use Invoke() on ShowAlert() but because it takes a string parameter I can't use Invoke()

I've tried using a coroutine and calling that in the overridden method but when I tried out the alert still shows immediately after the conversation, ignoring the coroutine.
Spoiler

Code: Select all

using System;
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using PixelCrushers.DialogueSystem;

namespace PixelCrushers.DialogueSystem
{

    public class MyDialogueUI : StandardDialogueUI
    {



        public override void ShowAlert(string message, float duration)
        {
            StartCoroutine(Test());
            base.ShowAlert(message, duration);
            // Report that an alert message has started, such as:
         //   DialogueManager.instance.SendMessage("OnAlertStart");
        }

        public override void HideAlert()
        {
            base.HideAlert();
           // DialogueManager.instance.SendMessage("OnAlertEnd");
        }

        IEnumerator Test()
        {
            yield return new WaitForSeconds(15);
        }

    }
}
Maybe I am missing something. I appreciate I can use a timed event component to set a conversation triggered to be active say 30 seconds after the end of each conversation but I don't really fancy doing that for several hundred conversations.

I have about 18 months experience programming in Java and PHP but I'm relatively new to she C# in unity –

So my question is is there a more straightforward way to do this?

Could I alter the template conversation in the database to take a timed event object with a default time… And a string value to be the title of the desired delayed conversation conversation to display the result?

could I extend the TimeEvent class to include a method which takes a string conversation title and include a conversation trigger by default and then call that programmatically by passing in the string conversation title and the delay float?

the dream solution would be being able to call a function in the sequence of the final node in a conversation which would send a message (string title, float delay) to enable a single master timed event script which would wait 30 seconds, triigger a specific "result conversation" to play in the database – disable itself and reset ready to receive a new time and conversation on its next enable.

This way I could avoid having to have hundreds of empty game objects containing timed events in the scene. And I would really like to handle all the conversation stuff in the database and have very few game objects in the actual scene beyond the prefabs.
I recommend writing a method to queue a conversation to play after a duration. Then register this method with Lua (tutorial) so you can call it in the last node's Script field. Rough example:

Code: Select all

public class ConversationQueue : MonoBehaviour // Add me to the Dialogue Manager GameObject.
{
    private void Awake()
    {
        Lua.RegisterFunction("QueueConversation", this, SymbolExtensions.GetMethodInfo(() => GameObjectExists(string.Empty, (double)0)));
    }

    public void QueueConversation(string conversationTitle, double seconds)
    {
        StartCoroutine(StartConversationAfterSeconds(conversationTitle, (float)seconds));
    }

    IEnumerator StartConversationAfterSeconds(string conversationTitle, float seconds)
    {
        yield return new WaitForSeconds(seconds);
        DialogueManager.StartConversation(conversationTitle);
    }
}

Alternatively to registering the method with Lua, you could write custom sequencer command script (tutorials) that calls the QueueConversation method above.
Post Reply