How To Populate a Limited Pool of Conversations from a Larger Pool?

Announcements, support questions, and discussion for the Dialogue System.
Post Reply
pruri
Posts: 3
Joined: Sun Mar 30, 2025 12:26 pm

How To Populate a Limited Pool of Conversations from a Larger Pool?

Post by pruri »

Idea: I am looking for suggestions to implement dating sim style options where we are keeping track of unique traits the player is learning about the partner through conversations and some variables in the Dialogue Database to feed to a UI stat sheet.

I would like to be able to do several things:
(a) limit the maximum responses a player has to three from a pool of x questions which are randomized (preferably defined in Conversations tab);
(b) remove questions from the pool if certain conditions are met (e.g., don't populate the potential questions with something if learnedTrait = true); and,
(c) add new things to the pool if certain conditions are met (e.g., do have the partner ask new things about the learnedTrait if it is true).

Current Setup:

We have Database variables to hold information about various traits. For example, strings: Job, Sign, and Season (with values of "Dancer", "Aries" and "Summer"). In our Database, we also have corresponding bools such as LearnedJob, LearnedSign, LearnedSeason.

Here is our example code to feed "Job" over to the TextMeshProUGUI string:

Code: Select all

 public void UpdateStatSheetUI()
    {
        // Check if the "learnedJob" boolean is true
        if (DialogueLua.GetVariable("LearnedJob").AsBool)
        {
            // Retrieve the "Job" string variable and update the jobText
            string learnedJob = DialogueLua.GetVariable("Job").AsString;
            jobText.text = $"Job: {learnedJob}";
        }
        else
        {
            // Default text if the job is not learned
            jobText.text = "Job: ???";
        }
        // ... rest of the variables below 
We have established a very limited way in which we can randomize the questions presented to the player by flipping a coin as to the set of 3 questions they may get, using in the script tab of the first conversant entry:

Code: Select all

x = math.random(2)
Obviously, of course, this only randomizes 2 options, and the 3 questions are always the same. It also does not handle the removal of a question from a pool in the event something is learned.
Screenshot 2025-03-30 at 11.42.11 AM.png
Screenshot 2025-03-30 at 11.42.11 AM.png (93.87 KiB) Viewed 188 times
What Works: The text variables display the conversant's assigned traits in-game, and we are successfully keeping track of if the player has learned them and populating our stat sheet. Minimal randomization through coin flip math.random method.

Objective: We'd like to make it so that all 6 of these response entries are pooled (if a trait is not yet learned) to be among only 3 responses that the player will be presented with (and introduce therefore greater randomization). If the trait has been learned, remove the corresponding response option from pool. If the trait has been learned, potentially populate with some other response option.
User avatar
Tony Li
Posts: 22886
Joined: Thu Jul 18, 2013 1:27 pm

Re: How To Populate a Limited Pool of Conversations from a Larger Pool?

Post by Tony Li »

Hi,

1. Remove the "Flipping coin" node.

2. Add a custom Number field to your dialogue entry template to specify how many of the linked responses should be shown. For example, you could add a custom field named "Max Responses". Give it a default value of -1.

3. Link a single "Something you want to know..." node to all 6 responses. Set the node's "Max Responses" field to 3.

4. Set Conditions on each response so that they're only true under the circumstances you specify, such as the trait being already learned.

5. Make a subclass of StandardUIMenuPanel that overrides ShowResponses(). On your dialogue UI, replace the StandardUIMenuPanel component with your subclass in-place. Example overridden method:

Code: Select all

void ShowResponses(Subtitle subtitle, Response[] responses, Transform target)
{
    var maxResponses = Field.LookupInt(subtitle.dialogueEntry.fields, "Max Responses");
    if (maxResponses > 0)
    {
        var allResponses = new List<Response>(responses);
        allResponses.Shuffle();
        var responsesToInclude = new List<Response>();
        for (int i = 0; i < Mathf.Min(maxResponses, allResponses.Count); i++)
        {
            responsesToInclude.Add(allResponses[i]));
        }
        responses = responsesToInclude.ToArray();
    }
    base.ShowResponses(subtitle, responses, target);
}
pruri
Posts: 3
Joined: Sun Mar 30, 2025 12:26 pm

Re: How To Populate a Limited Pool of Conversations from a Larger Pool?

Post by pruri »

Thank you so much for the almost immediate reply Tony, you're just the best!

I was able to implement the above code by providing an extension method for "Shuffle" as follows:

Code: Select all

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

public class StandardUIMenuSubclass : StandardUIMenuPanel
{
    //private static Random rng = new Random();
    public override void ShowResponses(Subtitle subtitle, Response[] responses, Transform target)
    {
        var maxResponses = Field.LookupInt(subtitle.dialogueEntry.fields, "Max Responses");
        if (maxResponses > 0)
        {
            var allResponses = new List<Response>(responses);

            allResponses.Shuffle();
            var responsesToInclude = new List<Response>();
            for (int i = 0; i < Mathf.Min(maxResponses, allResponses.Count); i++)
            {
                responsesToInclude.Add(allResponses[i]);
            }
            responses = responsesToInclude.ToArray();
        }
        base.ShowResponses(subtitle, responses, target);
    }


}
    public static class IListExtensions {
    /// <summary>
    /// Shuffles the element order of the specified list.
    /// </summary>
    public static void Shuffle<T>(this IList<T> ts) {
        var count = ts.Count;
        var last = count - 1;
        for (var i = 0; i < last; ++i) {
            var r = UnityEngine.Random.Range(i, count);
            var tmp = ts[i];
            ts[i] = ts[r];
            ts[r] = tmp;
        }
    }
}
And then following the in-place instructions to replace the script.
User avatar
Tony Li
Posts: 22886
Joined: Thu Jul 18, 2013 1:27 pm

Re: How To Populate a Limited Pool of Conversations from a Larger Pool?

Post by Tony Li »

Hi,

Include this line at the top of your script to get the Shuffle() extension method for Lists:

Code: Select all

using PixelCrushers;
pruri
Posts: 3
Joined: Sun Mar 30, 2025 12:26 pm

Re: How To Populate a Limited Pool of Conversations from a Larger Pool?

Post by pruri »

Thanks again Tony! Not sure how I missed that using directive.

The above solution works like a charm for the randomization of all traits and we can set conditions like the below to make sure that the question is only asked once:

Code: Select all

//example of stuff that goes into the Inspector's "Conditions" field.
Variable["LearnedJob"] == false
If we wanted to now add some new conversation element based on the fact that we've learned the job (e.g., "Do you remember what I said about my job"), should we use this same conversation? Doesn't seem like a natural child node of "Something you want to know..." and for testing purposes when it was set to true using conditions it had a tendency to always trump the other options anyway.
User avatar
Tony Li
Posts: 22886
Joined: Thu Jul 18, 2013 1:27 pm

Re: How To Populate a Limited Pool of Conversations from a Larger Pool?

Post by Tony Li »

When a node links to two or more NPC nodes (gray nodes) whose Conditions are true, the conversation will always use the first node. You can change the order by inspecting the parent node's "Links To:" section. The exception to this is if the parent node has RandomizeNextEntry() in its Script or Sequence field, in which case it will randomly choose among the child nodes whose Conditions are true.

However, in this scenario you won't want to use RandomizeNextEntry(). Instead, consider using a group node. Here's an example:

groups.png
groups.png (45.29 KiB) Viewed 144 times

To make a group node, tick the node's Group checkbox. Group nodes are by default passthrough nodes. The "Something you wanna know?" node will pass through both of the "{group}<>" nodes and evaluate the player responses in both branches.
Post Reply