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.
Prompts = {"Great thanks for asking", "Not too nicely"}
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.
If you want more dynamic dialogue to fit the context of the situation, you could do dialogue like how I did in an [attempted ] 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.
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?
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
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?
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
I’m pretty sure one of the options can’t be the function itself. However if you made it so after selecting an option, it runs that function, that should work.
The function has to stay in the dialogue data like so tho. As I can’t run the function from the UI, as there’s gonna be hundreds of different results from dialogue, and the UI can’t handle each individual one. Basically all I need is if the Yes option is selected, it to run the Yes option from the Dialogue (ie, numero 3, which thus is a function inside)
It seems like this should work fine, and I’m surprised it isn’t. I’m sure if you review the code a few times and play around with it you should be able to find a solution. But hey, I’m not a scripter.
I wish you the best of luck.
Sorry, I just woke up, also happy the code I gave you helped a bit.
if type(v) == "function" then
v()
break;
end
Try adding this above the for iter = 1, #v.Msg do. As v is no longer a table, and doesn’t know how to handle a function from the looks of the code in those lines. However, if I wanted to do something along these lines, I wouldn’t have altered the table structure format, but instead concatenated a “function” variable into the table itself.
[3] = {Msg = 'Take a look!', Type = 'Dialogue', Function = function() end}
That way you can simply use
if v.Function then v.Function() end