How to Generate Dynamic Responses Through Script?

Announcements, support questions, and discussion for the Dialogue System.
Post Reply
skartcher
Posts: 14
Joined: Thu Dec 26, 2024 6:17 am

How to Generate Dynamic Responses Through Script?

Post by skartcher »

Hey,

I'm working on a turn-based combat system that uses Dialogue System to handle interactions. When it's the player's turn, they get a choice of actions. If they choose "Attack," I want to dynamically generate a response menu listing all available enemy names so they can pick a target.

I’ve been trying to create responses through script, looping through enemies and adding them to DialogueManager.currentConversationState.pcResponses, then calling DialogueManager.UpdateResponses(), but the response menu just doesn’t show up. Debugs confirm everything runs, and the responses are added. At one point, I even ran into a memory leak.

Any tips or sample code would be a huge help!

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

Re: How to Generate Dynamic Responses Through Script?

Post by Tony Li »

Hi,

You'll either need to make a temporary dialogue database and conversation for this (see How To: Create Dialogue Database At Runtime) or make a subclass of StandardUIMenuPanel for your menu panel. If you make a subclass, override the ShowResponses() method to detect when it needs to generate dynamic responses, and add response buttons for those instead of using the Response[] array that was passed to ShowResponses().

In version 2.5 (no release date yet), OnConversationResponseMenu(Response[]) will change to OnConversationResponseMenu(List<Response>) so you can change the response list in your own script at runtime. Until then, you'll have to use either of the two techniques above.
skartcher
Posts: 14
Joined: Thu Dec 26, 2024 6:17 am

Re: How to Generate Dynamic Responses Through Script?

Post by skartcher »

Hey, thanks for the reply.

I went with the second option, overriding the StandardUIMenuPanel and adding a second Menu Panel for target selection. I used setPanel to show the target selection Menu and automatically trigger ShowResponses. Here is the current code:

Code: Select all

public override void ShowResponses(Subtitle subtitle, Response[] responses, Transform target)
{       
    if (waitForClose && dialogueUI != null)
    {
        if (dialogueUI.AreAnyPanelsClosing())
        {
            DialogueManager.instance.StartCoroutine(ShowAfterPanelsClose(subtitle, responses, target));
            return;
        }
    }
    ShowDynamicEnemyResponses(subtitle, target);
}

// Generates dynamic responses by gathering available enemy names
protected void ShowDynamicEnemyResponses(Subtitle subtitle, Transform target)
{
    List<Combatant> enemyCombatants = CombatManager.Instance.GetEnemyTargets();
    if (enemyCombatants == null || enemyCombatants.Count == 0)
    {       
        ShowResponsesNow(subtitle, new Response[0], target);
        return;
    }

    // Create a new Response array with one entry per enemy
    Response[] dynamicResponses = new Response[enemyCombatants.Count];
    for (int i = 0; i < enemyCombatants.Count; i++)
    {
        dynamicResponses[i] = new Response(new FormattedText(), new DialogueEntry());
        dynamicResponses[i].formattedText.text = enemyCombatants[i].CombatantName;

        // Set up the callback for when the button is clicked.
        dynamicResponses[i].onClick = () => {
           
            CombatManager.Instance.PlayerAction("Attack");  // Temporarily attack callback
        };
    }

    ShowResponsesNow(subtitle, dynamicResponses, target);
}
The Menu is correctly showing the available enemies as buttons, but when I click on one of them, I get this error:

Code: Select all

Dialogue System: Lua code 'Dialog = Conversation[0].Dialog' threw exception 'Lookup of field 'Dialog' in the table element failed because the table element itself isn't in the table.'
Any idea on how to fix it?

I'll provide a screenshot of the conversation nodes just in case:
image_2025-04-10_125719493.png
image_2025-04-10_125719493.png (73.58 KiB) Viewed 1308 times
User avatar
Tony Li
Posts: 23250
Joined: Thu Jul 18, 2013 1:27 pm

Re: How to Generate Dynamic Responses Through Script?

Post by Tony Li »

Hi,

You can override ShowResponsesNow() instead of ShowResponses() to avoid having to run that wait code. Make sure you assign a destination dialogue entry. The destination dialogue entry is what the response represents. In the example script below, both responses point to the equivalent of your <Target Selection> entry.

Code: Select all

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

public class CustomMenuPanel : StandardUIMenuPanel
{
    protected override void ShowResponsesNow(Subtitle subtitle, Response[] responses, Transform target)
    {
        var conversation = DialogueManager.masterDatabase.GetConversation(DialogueManager.lastConversationStarted);
        var destination = conversation.GetDialogueEntry(subtitle.dialogueEntry.outgoingLinks[0].destinationDialogueID);
        var list = new List<Response>();
        list.Add(new Response(FormattedText.Parse("Attack"), destination));
        list.Add(new Response(FormattedText.Parse("Flee"), destination));
        base.ShowResponsesNow(subtitle, list.ToArray(), target);
    }
}
Here's an example scene:

DS_TestOverrideResponses_2025-04-10.unitypackage
skartcher
Posts: 14
Joined: Thu Dec 26, 2024 6:17 am

Re: How to Generate Dynamic Responses Through Script?

Post by skartcher »

Thanks, man, I appreciate your effort, but the response buttons now are always pointing back to the Attack node, and the ShowPanel sequence line keeps on triggering. I'm not sure if I'm doing something wrong here.
Also, the onclick action is not functioning. I tried to play around with it a bit, but I couldn't.
User avatar
Tony Li
Posts: 23250
Joined: Thu Jul 18, 2013 1:27 pm

Re: How to Generate Dynamic Responses Through Script?

Post by Tony Li »

Hi,

You hadn't specified where you want it to go, so I arbitrarily pointed it back to that node. What do you want to happen when the player clicks one of the dynamic responses? You could create some dialogue entries at runtime for it. But you'll want to remember to remove them when you're done.
skartcher
Posts: 14
Joined: Thu Dec 26, 2024 6:17 am

Re: How to Generate Dynamic Responses Through Script?

Post by skartcher »

For each button I want to call:

Code: Select all

dynamicResponses[i].onClick = () => {
           
            CombatManager.Instance.PlayerAction("Attack", enemy);  
};
which will stop the conversation and handle the rest of the logic,
User avatar
Tony Li
Posts: 23250
Joined: Thu Jul 18, 2013 1:27 pm

Re: How to Generate Dynamic Responses Through Script?

Post by Tony Li »

In that case, you could set up the buttons to do that extra stuff. Here's an updated example:

DS_TestOverrideResponses_2025-04-11.unitypackage

It adds an ExampleCombatMenu.

The menu subclass checks if the response entry has a custom Boolean field named "CustomMenu" that's set to true. If so, it does the combat menu. The combat menu sets up buttons that opens the ExampleCombatMenu. The next dialogue entry waits for the sequencer message "CombatDone". The ExampleCombatMenu's button closes the ExampleCombatMenu and sends this sequencer message.
skartcher
Posts: 14
Joined: Thu Dec 26, 2024 6:17 am

Re: How to Generate Dynamic Responses Through Script?

Post by skartcher »

I love you man, thank you so much :D
User avatar
Tony Li
Posts: 23250
Joined: Thu Jul 18, 2013 1:27 pm

Re: How to Generate Dynamic Responses Through Script?

Post by Tony Li »

Happy to help!
Post Reply