Creating choice in custom dialogue

If I have dialogue like so for this specific NPC.

return {
	['Hardware Guy'] = {
		'Hello! Welcome to my hardware store. You can find a variety different items to customise your house with, including floor designs, wallpapers and paint!',
		'Is there anything here that interests you?'
	    {
	        'Yes there is!' = true,
	        'No there is not!' = false,
	    }
	}
}

I’m not exactly sure how to go about separating each section of the dialogue into specific sections. As the first piece of dialogue he says would need to return say a variable like ‘Question’ and have it set to false, so then my UI can show the ‘Press E to continue’, but then if the dialogue is a question, have my UI show the choice boxes. And then be able to have a response for either answer the player gives. I have already made all my UI, just not sure

Bare in mind, I’ve never looked into the Dialogue Editor, but heard mixed reviews on it, so not sure if I wanna head down that path, or just simply create my own. As well as I want my own UI for this, so not sure how to go about using the editor with my own UI. Makes more sense to just hard code it myself

3 Likes

From what I understand you want to categorise them by question or answer.

If that is what you want I’d do it like this.

return {
	["Hardware Guy"] = {
		Introduction = "Hello! Welcome to my hardware store. You can find a variety different items to customise your house with, including floor designs, wallpapers and paint!",
		Questions = {"Is there anything here that interests you?"},
	    Answers = {"Yes there is!", "No there is not!"}
	}
}

Introduction is just how he introduces himself, Questions is the questions he will ask, and Answers would be the answers that you can give

If a question can have multiple answers, I’d suggest grouping the answers in a table

{
    Questions = {"Q1", "Q2", "Q3"},
    Answers = {{"A1", "A2", "A3"}, {"A1", "A2"}, {"A1", "A2", "A3", "A4"}}
}
3 Likes

With that, how can I then get it to go in order? Or have them say multiple things before asking a question?

return {
    ["Hardware Guy"] = {
        [1] = {Msg = "", Type = "Non-Question"},
        [2] = {Msg = "", Type = "Question", Responses = {"Yes", "No"}},
    }
}

Something similar to this nature so you can switch your ui based on Type. However, that may not be the approach you’re looking for, that’s just how I’d do it.

How could I then go after the second message (Question one) and have 2 different messages, depending on whether the player answered Yes or No

You can give the Responses values

return {
    ["Hardware Guy"] = {
        [1] = {Msg = "", Type = "Non-Question"},
        [2] = {Msg = "", Type = "Question", Responses = { ["Yes"] = 3, ["No"] = 5}},
,       [3] = {Msg = "", Type = "Non-Question"},
        [4] = {Msg = "", Type = "Non-Question"},
        [5] = {Msg = "Farewell", Type = "Non-Question"}
    }
}

so it knows what index to jump to, and if the index is out of bounds then you know to exit, or just have it jump to the last index if you intend to add a “Farewell” message.

I feel like all of these maps and tables are over complicating what you want to be a logically sound system. I suggest using a tree. If you’re wondering what in the world leaves and a trunk have to do with programming, read up here. I’ll just explain in code

--Don't be fooled by the name! The variable is initialized and you would think its the whole tree but in reality we just want this to store the head node i.e. the conversation starter
local AnswerTree = { 
    Dialogues = {"Hey!",  "Wanna buy something?"}, --An array of dialogues, because you brought up the concept of multiple messages before a prompt
    Prompts = {"Yes please", "No thanks"} --should only be 0-2 of these
} 
local onBuyYes = {Dialogues = {"Ok first let me ask how is your day going"}, 
Prompts = {"Great thanks for asking", "Not too nicely"}}
AnswerTree.Node1 = onBuyYes --gonna use 1 and 2 instead of 0 and 1 because of how lua indicies work
local onBuyNo = {Dialogues = {"Stop wasting my time and get moving"}} --this is a conversation endpoint, i.e. no prompts
AnswerTree.Node2 = onBuyNo

See how it works? You can easily traverse this tree by seeing the index of the response, and then indexing the tree by currentLevel["Node"..index] where current level is your current data set (will start off as answer tree) and index is the index of the response out of the prompts that were given. Using a tree will help you create a smooth dialogue script that won’t be a formidable mess in code. If you have troubles with trees or organizing let me know.

2 Likes
Prompts = {"Great thanks for asking", "Not too nicely"}
1 Like

Unable to really test this as I’m about to head to bed, but I’m unsure of how exactly this actually works? Seems incredibly confusing.

local AnswerTree = { 
    Dialogues = {"Hey!",  "Wanna buy something?"},
    Prompts = {"Yes please", "No thanks"} 
} 

How can you tell from Dialogues, which need to prompts and which don’t? ‘Hey!’ wouldn’t require a prompt, but the question would. And I’m guessing the onBuyYes and onBuyNo are in response to whatever option the player has chosen?

Ideally you will only want to prompt the user after all the dialogues in that particular step have been run through, right? And yes, the two nodes are meant to act as “children” of the head node so you can recursively continue a dialogue as long as you want. Example of how you would employ this concept:

local currentStep = AnswerTree --default; where you want to start
while currentStep.Prompts do --keep the conversation going as long as there's prompts to keep it going
    runThroughDialogues(currentStep.Dialogues) --have all the messages of that step run through
    for promptIndex, text in pairs(currentStep.Prompts) do
        local button = addPromptButton(text) --make a button to select this prompt
        local currentIndex = promptIndex --promptIndex is a changing variable; make a local one for this specific button
        local conn
        conn = button.MouseButton1Click:Connect()
            conn:Disconnect()
            currentStep = currentStep["Node"..currentIndex] --move on to the next step we selected
        end)
    end

end

That’s why I went through all the trouble of adding nodes and whatnot, it might confuse you setting it up but in function all it is is a loop.

Keep in mind, that first node I put is not the entire dialogue. It is merely a step, and it happens to be the first.

This would probably be a fairly simple if not explicit implementation, I would suggest looking into those pick your ending goosebump books or something similar. Each entry is a page, some with a choice that makes you jump to a new spot, some you just continue sequentially to the next page.

1 Like

If you want more dynamic dialogue to fit the context of the situation, you could do dialogue like how I did in an [attempted :frowning:] RPG that I made awhile ago.

Basically, I had a table with every interaction in it, and every entry would have a function that does its own logic.

["Dummy"] = function(player) --here, you could give the function any arguments you want, like the player name, player data, etc.
    local answer = chat:Say(
        "Speaker",
        "[y/n]This is a yes/no question. Would you like to answer " .. player.Name .. "?"
    ) 
    --i made a custom dialogue thing which parsed the text for 
    --"[y/n]", which would then prompt the player with options and yield until the player responded
    if answer then --basic logic
        chat:Say("Speaker","you said yes")
    else
	    chat:Say("Speaker","you said no")
    end
end

Of course, this is a very simple snippet. This could be used to interact with the world, like opening doors, initiating cutscenes, etc.

For more flair, you could implement one of those markdown text modules that people have released to add color to your dialogue. (like this RichText module by Defaultio)

I’m fairly sure that I implemented a feature to have more custom options than “Yes” or “No”, but I cannot find examples of those because I haven’t worked on this project in awhile.

The Roblox Dialogue Editor handles this perfectly. It is currently broken and unmaintained though, so you’ll have to use a version that someone is actively updating and maintaining or one that has fixed applied.

1 Like

Using that, here’s what I got so far:

return {
	['Hardware Sam'] = {
		[1] = {Msg = 'Hello! Welcome to my hardware store. You can find a variety different items to customise your house with, including floor designs, wallpapers and paint!', Type = 'Dialogue'},
		[2] = {Msg = 'Is there anything here that interests you?', Type = 'Question', Responses = { ['Yes'] = 3, ['No'] = 4}},
		[3] = {Msg = 'Take a look!', Type = 'Dialogue'},
		[4] = {Msg = 'Farewell', Type = 'Dialogue'}
	}
}

and this is how I iterate through the text

	for i, v in pairs(DialogueData[NPC]) do
		for iter = 1, #v.Msg do
			Desc.Text =  string.sub(v.Msg, 1, iter)
			wait()
		end
		
		if v.Type == 'Dialogue' then
			Action.Visible = true
		else
			QuestionAsked = true
			Action.Visible = false
			Choice1.Visible = true
			Choice2.Visible = true
			
			Choice1.Activated:Connect(function()
				Continue = true
				QuestionAsked = false
			end)
			
			Choice2.Activated:Connect(function()
				Continue = true
				QuestionAsked = false
			end)
		end
		
		TextFinished = true
		
		repeat wait() until Continue

		Action.Visible = false
		Continue = false
		TextFinished = false
	end

How can I then include the choice buttons to make choices?
robloxapp-20190818-0955412

Currently, picking clicking either one will make the text say
‘Farewell’
and then
‘Take a look!’

So not sure why it’s showing Farewell before Take a look considering farewell is the last thing in the table

Instead of iterating through the table, you should only need to reference the first item.
table[1] – starting point
if its a dialogue you continue to the next item,
table[2]
if its a question, the choice picks the next spot
answer = no
table[4]

-- start talking
inConvo = true
nextSpeech = 1
while inConvo do
   v = DialogueDate[NPC][nextSpeech] 
     for iter = 1, #v.Msg do
	   Desc.Text =  string.sub(v.Msg, 1, iter)
	   wait()
     end
		
   if v.Type == 'Dialogue' then
     Action.Visible = true
     nextSpeech =  nextSpeech + 1
   elseif v.Type == 'Farewell' then
     inConvo = false
   else
     QuestionAsked = true
     Action.Visible = false
     Choice1.Visible = true
     Choice2.Visible = true
			
     Choice1.Activated:Connect(function()
        Continue = true
        QuestionAsked = false
        nextSpeech = v.Responses.Yes
    end)
			
    Choice2.Activated:Connect(function()
        Continue = true
        QuestionAsked = false
        nextSpeech = v.Responses.No
    end)
    end

    repeat wait() until Continue
    Action.Visible = false
    Continue = false
end

Something like that. After the first item, the next one is decided by type of speech and the player interaction.
with the current set up though, you can only do yes/no questions

Don’t know what was causing your double response though :confused:

Seems to work well enough, however, is there a reason why if I choose yes, it still shows the farewell message?? Is there a way to just have it show the next message? And is there ways to incorporate a functions or something into this? As I want UI to appear, camera manipulation, etc. to occur when certain choices are picked

Did you leave a Take a look in your code elsewhere? It really doesn’t make sense with what you’ve shown here.
That or could your buttons be getting triggered when they shouldn’t?

Think I managed to fix it, but still wondering how to add functions to this efficiently?

1 Like

Create a table for questions and one for answers. It will make your script a lot easier to use.

(This isn’t in Lua form but the formatting should help.)

Ex:

if (user) is talking to (npc type),
ask user (question from table)

provide user with (answer1, answer2)

  if player selects (answer1)
      ask user (question from table)
   if player selects (answer2)
      (your function)

I can’t script but if you get the general idea of what I’m saying it should help a little.

I’m trying to have the function inside the dialogue data tho

return {
	['Hardware Sam'] = {
		[1] = {Msg = 'Hello! Welcome to my hardware store. You can find a variety different items to customise your house with, including floor designs, wallpapers and paint!', Type = 'Dialogue'},
		[2] = {Msg = 'Is there anything here that interests you?', Type = 'Question', Responses = {['Yes'] = 3, ['No'] = 4}},
		[3] = function()
			print(1)
		end,
		[4] = {Msg = 'Goodbye', Type = 'Farewell'}
	},
}

However it just errors out

1 Like