Randomize PC responses after a single node

Announcements, support questions, and discussion for the Dialogue System.
Post Reply
OwNathan
Posts: 10
Joined: Fri Jul 28, 2023 8:20 am

Randomize PC responses after a single node

Post by OwNathan »

Hello!
I am part of a team currently working on a game with extremely complex and dynamic dialogues, using Dialogue System and Articy to make that work (by the way, I am deeply grateful for the integration of articy jumps).
Thanks to the built-in randomize function for NPC replies, we can already randomize all possible NPC replies while filtering them with complex conditions at the same time, but I wonder if a similar approach can be adopted for PC responses.
The issue is that PC responses are grouped between different nodes, and until now, I simply used a random number generator with a length equal to the number of possible variants, and then added a different number as a condition for the different replies.
Sadly, this is not only time-consuming, it is also useless when due to complex conditions I can't know in advance the number of potential responses available to the player. We can't also simply randomize all available options because we need the system to just pick a single option between the many nested after a specific node. Is there a way in Dialogue System to list all available responses after a certain node and only pick one for the system to use as potential response?

Thank you very much!
User avatar
Tony Li
Posts: 21679
Joined: Thu Jul 18, 2013 1:27 pm

Re: Randomize PC responses after a single node

Post by Tony Li »

Hi,

I don't think this is what you want, so I'll get it out of the way first. If you want to randomize the order of all currently-valid PC responses and show them all in a response menu, see this post.

However, it sounds like you want to randomly choose only one PC response from the list of all currently-valid PC responses. If you want to show this in a response menu, make a subclass of StandardUIMenuPanel. Override the ShowResponses() method to only add one button chosen randomly from the Response[] array. Then use your subclass in place of the response menu panel's StandardUIMenuPanel component. (See this post for replacing in-place.)
OwNathan
Posts: 10
Joined: Fri Jul 28, 2023 8:20 am

Re: Randomize PC responses after a single node

Post by OwNathan »

Thanks for the reply!
Would it be possible to get an array of all the responses present after a certain node? Let's say, for example, the PC can question an NPC about the area they are in, but that specific question is present in many variants, all of them linked to the main dialogue using a single empty connecting node after which conditions for specific responses are placed.

I only need to get a single random option from all the ones available after a specific node related to a specific question or matter to discuss, while still allowing the system to go and pick options from other theme-specific groups.

I attached an image showing one of the structures we use. In the image, there are three different groups of PC nodes circled in red, each group basically has the same line reskinned in different ways to have different flavors.
The articy hubs circled in blue are the nodes in which I would like to add a script capable of building a list of all possible nodes that have fulfilled conditions, so that I can send only one of them to the Responses menu!

Basically, I need that even if there are 10 different ways to ask an NPC about the wheater, only one of them appears, without affecting the availability of options connected to other nodes.

Thank you very much!
Attachments
Screenshot 2023-07-28 151903.png
Screenshot 2023-07-28 151903.png (235.53 KiB) Viewed 736 times
User avatar
Tony Li
Posts: 21679
Joined: Thu Jul 18, 2013 1:27 pm

Re: Randomize PC responses after a single node

Post by Tony Li »

Hi,

So you need to randomly choose a single node from the top red box, and a single node from the middle red box, and a single node from the bottom red box? (Assuming Conditions allow it.)
OwNathan
Posts: 10
Joined: Fri Jul 28, 2023 8:20 am

Re: Randomize PC responses after a single node

Post by OwNathan »

Yes! Basically after each articy hub there are flavor variants that serve the same purpose, and I only need to select one.
I attached an image showing how it appears inside Dialogue System's editor.
Screenshot 2023-07-28 151903.png
Screenshot 2023-07-28 151903.png (66.1 KiB) Viewed 731 times
User avatar
Tony Li
Posts: 21679
Joined: Thu Jul 18, 2013 1:27 pm

Re: Randomize PC responses after a single node

Post by Tony Li »

Among the nodes in each group, is the text the only difference? Or will there be expressions in input or output pins, or differences in where they link? If text is the only difference, you could put all of the texts in a single dialogue fragment and process it at runtime.

For example, say in articy you have an empty dialogue fragment that links to 3 player-assigned text fragments: "Hi", "Hello", and "Howdy".

You could replace the empty fragment and the 3 text fragments with a single text fragment containing, say, "Hi // Hello // Howdy".

In Unity, add a script to the Dialogue Manager that has an OnConversationResponseMenu method that processes this text. Something like:

Code: Select all

void OnConversationResponseMenu(Response[] responses)
{
    foreach (var response in responses)
    {
        var text = response.formattedText.text;
        if (text.Contains("//"))
        {
            var lines = text.Split("//");
            response.formattedText.text = lines[Random.Range(0, lines.Length)].Trim();
        }
    }
}
OwNathan
Posts: 10
Joined: Fri Jul 28, 2023 8:20 am

Re: Randomize PC responses after a single node

Post by OwNathan »

Sadly different nodes may have different scripts or conditions, so we need them to be separate. I just need to know if there any way to identify all player nodes recursively after a specific group, after that we can modify Dialogue System on our end to change the Responses array by removing all excess responses for each group and keeping just one!
User avatar
Tony Li
Posts: 21679
Joined: Thu Jul 18, 2013 1:27 pm

Re: Randomize PC responses after a single node

Post by Tony Li »

Got it. You'll need to write a bit of code (or use the code below). Make a subclass of StandardDialogueUI, and override the ShowResponses() method to pare down the responses. Here's an example scene:

DS_RandomResponsesExample_2023-07-28.unitypackage

It uses this script:

Code: Select all

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

public class RandomResponsesDialogueUI : StandardDialogueUI
{

    public override void ShowResponses(Subtitle subtitle, Response[] responses, float timeout)
    {
        // Make list of all response dialogue entries:
        var responseEntries = new List<DialogueEntry>();
        foreach (Response response in responses) { responseEntries.Add(response.destinationEntry); }

        // Group response entries into buckets by parent (group node):
        var dict = new Dictionary<DialogueEntry, List<DialogueEntry>>();
        var conversation = DialogueManager.masterDatabase.GetConversation(DialogueManager.currentConversationState.subtitle.dialogueEntry.conversationID);
        foreach (var parentEntry in conversation.dialogueEntries)
        {
            foreach (var link in parentEntry.outgoingLinks)
            {
                var childEntry = DialogueManager.masterDatabase.GetDialogueEntry(link);
                var isResponseEntry = responseEntries.Contains(childEntry);
                if (isResponseEntry)
                {
                    // Move from response entries to bucket:
                    responseEntries.Remove(childEntry);
                    if (!dict.ContainsKey(parentEntry)) dict.Add(parentEntry, new List<DialogueEntry>());
                    dict[parentEntry].Add(childEntry);
                }
            }
        }

        // Add one response in each bucket back to responseEntries:
        foreach (var kvp in dict)
        {
            var bucket = kvp.Value;
            responseEntries.Add(bucket[Random.Range(0, bucket.Count)]);
        }

        // Create new response[] array:
        var responseList = new List<Response>(responses);
        responseList.RemoveAll(response => !responseEntries.Contains(response.destinationEntry));
        responses = responseList.ToArray();

        // Show responses:
        base.ShowResponses(subtitle, responses, timeout);
    }
}
See also: How To: Replace Script with Subclass and Keep Field Assignments
OwNathan
Posts: 10
Joined: Fri Jul 28, 2023 8:20 am

Re: Randomize PC responses after a single node

Post by OwNathan »

Thank you! You have been really helpful!
User avatar
Tony Li
Posts: 21679
Joined: Thu Jul 18, 2013 1:27 pm

Re: Randomize PC responses after a single node

Post by Tony Li »

Glad to help!
Post Reply