Random Player Repsonses with some fixed inclusions

Announcements, support questions, and discussion for the Dialogue System.
Post Reply
Keiji
Posts: 17
Joined: Tue Feb 18, 2020 2:29 pm

Random Player Repsonses with some fixed inclusions

Post by Keiji »

Hey Tony!

I purchased the Dialogue System several weeks ago and (after doing a bunch of other work for my project) after reading the manual and some of the forum I am finally getting into the depth of it. I must say the good reviews that lead me to purchase weren’t exaggerating. The System does many things I thought I would have to implement myself. I am making a game about talking, so the core mechanic of the game will be conversations, but as a kind of battle of wits in an rpg type round based system. I was going to first just use the Dialogue System as a solution for the NPC conversations outside of the 'battle system' and make that myself, but I was very pleased to find that what you've built seems perfectly capable of delivering most of the whole round based conversation system, including variables for health and energy and timed replies.

Here are my two questions: I found your random answers script which you shared here, which solves many of the many of the features I was looking for:
https://pixelcrushers.com/phpbb/viewtop ... 271#p12271
1. How would you modify that script so 1 among the ten optional nodes becomes included every time randomly among the first four buttons?
Let’s say I write a node for something an npc says, which links to ten possible player answers in my dialogue tab. Since I am only using 5 Buttons in my UI, they would show a slightly different set each time, after your script shuffles the replies. But how do I make sure that at least one of the answers going to my 'correct' part of the conversation is included each time among those first 5 Buttons?
I love the way your script only randomizes nodes that lead to more than a certain amount of replies. That means that if I leave a nodes' number of responses under that amount, I have total control over the responses the Player can give, and if I want to randomize, I can just add nodes that would push it into the random category so to speak.
2. As a related and somehow less important question, would it be possible to shuffle the first 4 shown buttons but make it so button 5 is always the same action or answer? Maybe button five is always the 'run away' reply or the 'punch him' reply or the 'check your oponent and see how much determination he has left' reply.
Basically I want one correct node to be included each time, but to vary the position of that node each time. Also, I would like a ‘fixed position’ node each time, to include an action the player can take each time clicking the same position.
Do you think that is possible with the script you made? If there is a different kind of solution for this (In the above post you mentioned: ''Another approach is to use the Conditions field on the responses. '') I am very interested to hear it. How would you do that?
Sorry for being so wordy, I know it is probably not good form to make you read all that. Thanks so much for the great work already, I am excited to be using the tool you created! I'll write you guys the great asset store review your product deserves.

Keiji.
User avatar
Tony Li
Posts: 22110
Joined: Thu Jul 18, 2013 1:27 pm

Re: Random Player Repsonses with some fixed inclusions

Post by Tony Li »

Hi Keiji,

Thanks for buying the Dialogue System!
Keiji wrote: Sat Mar 07, 2020 8:59 amI am making a game about talking, so the core mechanic of the game will be conversations, but as a kind of battle of wits in an rpg type round based system. I was going to first just use the Dialogue System as a solution for the NPC conversations outside of the 'battle system' and make that myself, but I was very pleased to find that what you've built seems perfectly capable of delivering most of the whole round based conversation system, including variables for health and energy and timed replies.
I'm biased, of course, but games like Disco Elysium, which also does all of its combat through dialogue, show that the Dialogue System can certainly handle it enough for Disco to have won multiple game of the year awards.

You could use conditions, but I think the shuffling method is easier to manage. This way you don't have to fiddle with conditions to manage randomization, and can instead only use conditions like normal, to only allow responses if the player is allowed to use them (for example, if they have a high enough skill level or wield the right item).

This is how I'd approach it:

1. In the Dialogue Editor's Templates section, add a Boolean field named "Correct" to the Dialogue Entries template. Tick the field's Main checkbox to tell the editor to show the "Correct" field in the dialogue entry node's main inspector area.

2. Inspect each node that's a correct response, and set its "Correct" field true.

3. Make your 'fixed position' node the first link in the list of links. If you inspect the preceding node (e.g., "What do you do?"), you'll see that its links are all listed at the bottom in the "Links To:" section. You can use the up/down arrow buttons to reorder them. Include this tag in the fixed position node's Menu Text: "[position=4]". For example, the Menu Text might be "Run away.[position=4"]. If you're not using Menu Text, put it in the Dialogue Text. Since button positions are indexed from zero, [position=4] tells the menu to put this response in the 5th button. This assumes your menu's Buttons list has 5 buttons.

4. Write a script that starts with the shuffle code in the post that you linked. Make these two changes:
  • Shuffle from 1 to n, not 0 to n:

    Code: Select all

    for (int i = 1; i < n; i++)
    This prevents it from shuffling your fixed position response.
  • After shuffling, add additional code to go through the shuffled array from 1 to 4. Check if any of those responses' "Correct" field is true. If not, swap response[1] with the first correct response in the rest of the list:

    Code: Select all

    // Do the responses for the remaining buttons include a "correct" response?
    bool foundCorrectResponse = false;
    int m = Mathf.Min(5, n); // (Minimum of number of responses and number of buttons.)
    for (int i = 1; i < m; i++)
    {
        if (Field.LookupBool(response[i].destinationEntry.fields, "Correct") == true) 
        {
            foundCorrectResponse = true;
        }
    }
    
    // If the buttons don't yet include a "correct" response, find one and copy it into position 1:
    if (!foundCorrectResponse)
    {
        for (int i = m; i < n; i++)
        {
            if (Field.LookupBool(response[i].destinationEntry.fields, "Correct") == true) 
            {
                responses[1] = responses[i];
                break;
            }
        }
    }
    
Keiji
Posts: 17
Joined: Tue Feb 18, 2020 2:29 pm

Re: Random Player Repsonses with some fixed inclusions

Post by Keiji »

Hey Tony!

Thanks for the quick reply! That looks perfect! I will implement it exactly like that and get back to you if there are any more questions.

I guess all you need to say about the capabilities of the Dialogue System is: Disco Elysium. I saw that on the Games showcase tab and should've known! :) Wrote a bit of video game history there...

Ever thought of making a video/text post analyzing some of the systems in that game and how these could be achieved through your tool? There might be some real interest there from people and might lead them to your system if they search for the Disco Elysium systems.

Thanks for the super quick help!

Keiji
User avatar
Tony Li
Posts: 22110
Joined: Thu Jul 18, 2013 1:27 pm

Re: Random Player Repsonses with some fixed inclusions

Post by Tony Li »

That's a good idea. I should do a little text post at least. A lot of it is simply the magic they brought to the writing, and the creative use of the same features available to all branching dialogue authors, such as ingeniously giving lines to all of the different voices in the protagonist's head.
Keiji
Posts: 17
Joined: Tue Feb 18, 2020 2:29 pm

Re: Random Player Repsonses with some fixed inclusions

Post by Keiji »

A lot of it is simply the magic they brought to the writing, and the creative use of the same features available to all branching dialogue authors
Well, I guess, as they say: Good tools alone are not enough to make stuff. But creativity alone without some kind of tool to express it and utilize it is equally worthless. I think lots of good ideas only come while working with good tools.
Keiji
Posts: 17
Joined: Tue Feb 18, 2020 2:29 pm

Re: Random Player Repsonses with some fixed inclusions

Post by Keiji »

Case in point: I am a guy who usually just does art, and here is my kinda pathetic attempt to follow your directions from earlier and integrate the two scripts. Just been getting compiler errors.

Code: Select all

 using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using PixelCrushers.DialogueSystem;
public class ShuffleResponses : MonoBehaviour
{
    void OnConversationResponseMenu(Response[] responses)
    {
        if (responses.Length > 3) // If we have more than 3 responses, shuffle them.
        {
            int n = responses.Length; // Standard Fisher-Yates shuffle algorithm.
            for (int i = 1; i < n; i++)
            {
                int r = i + Random.Range(0, n - i);
                Response temp = array[r];
                array[r] = array[i];
                array[i] = temp;
            }
        }
    }
}

//for (int i = 1; i < n; i++)
// Do the responses for the remaining buttons include a "correct" response?
bool foundCorrectResponse = false;
int m = Mathf.Min(5, n); // (Minimum of number of responses and number of buttons.)
for (int i = 1; i<m; i++)
{
    if (Field.LookupBool(response[i].destinationEntry.fields, "Correct") == true) 
    {
        foundCorrectResponse = true;
    }
}

// If the buttons don't yet include a "correct" response, find one and copy it into position 1:
if (!foundCorrectResponse)
{
    for (int i = m; i<n; i++)
    {
        if (Field.LookupBool(response[i].destinationEntry.fields, "Correct") == true) 
        {
            responses[1] = responses[i];
            break;
        }
    }
}
  
I think bool on the template worked, however: Image
Attachments
BoolTemplate.JPG
BoolTemplate.JPG (54.69 KiB) Viewed 1427 times
User avatar
Tony Li
Posts: 22110
Joined: Thu Jul 18, 2013 1:27 pm

Re: Random Player Repsonses with some fixed inclusions

Post by Tony Li »

Hi,

You're close! The code needs to be inside the OnConversationResponseMenu() method. Here's an example scene with a working copy of the script:

DS_RandomizedResponsesExample_2020-03-08.unitypackage

I took the opportunity to add a couple lines of code that automatically determine how many buttons the dialogue UI has, so you don't have to hard-code a number in the script.

The script looks like this:

ShuffleResponses2.cs

Code: Select all

using UnityEngine;
using PixelCrushers.DialogueSystem;

public class ShuffleResponses2 : MonoBehaviour
{
    void OnConversationResponseMenu(Response[] responses)
    {
        // How many buttons does the dialogue UI have?
        var standardDialogueUI = DialogueManager.dialogueUI as StandardDialogueUI;
        int numButtons = standardDialogueUI.conversationUIElements.defaultMenuPanel.buttons.Length;

        // If we have more responses than buttons, shuffle responses:
        if (responses.Length > numButtons) 
        {
            // Standard Fisher-Yates shuffle algorithm:
            // Note: We skip response[0], since this is a response that we always
            // want to include in the menu.
            int n = responses.Length; 
            for (int i = 1; i < n; i++)
            {
                int r = i + Random.Range(0, n - i);
                Response temp = responses[r];
                responses[r] = responses[i];
                responses[i] = temp;
            }

            // After shuffling, make sure the responses that will be shown 
            // include a "correct" response:
            bool foundCorrectResponse = false;
            int m = Mathf.Min(numButtons, n); // (Minimum of number of responses and number of buttons.)
            for (int i = 1; i < m; i++)
            {
                if (Field.LookupBool(responses[i].destinationEntry.fields, "Correct") == true)
                {
                    foundCorrectResponse = true;
                }
            }

            // If the buttons don't yet include a "correct" response, 
            // find one and copy it into position 1:
            if (!foundCorrectResponse)
            {
                for (int i = m; i < n; i++)
                {
                    if (Field.LookupBool(responses[i].destinationEntry.fields, "Correct") == true)
                    {
                        responses[1] = responses[i];
                        break;
                    }
                }
            }

        }
    }
}
Keiji
Posts: 17
Joined: Tue Feb 18, 2020 2:29 pm

Re: Random Player Repsonses with some fixed inclusions

Post by Keiji »

Hey Tony! Just wanted to say thanks so much for your help with this!

The script works great! After working with the script for a while I ended up wanting to shuffle all responses of the Nodes and use the 'Run Away' Type fixed node at a later point of the conversation. So I simply changed

Code: Select all

(int i = 1; i < n; i++)
back to:

Code: Select all

(int i = 0; i < n; i++)
Your code works just like I wanted: Shuffling the answers and Including a 'correct' Answer each time. Thanks so much for the great work, Tony.

Wishing you all the best,

Keiji
User avatar
Tony Li
Posts: 22110
Joined: Thu Jul 18, 2013 1:27 pm

Re: Random Player Repsonses with some fixed inclusions

Post by Tony Li »

Glad to help!
Post Reply