Handling dialogue in a script

currently i have a script that when the player buys something, the shopkeeper will spit out a line, but the way is handled is through what i like to call plinko code (or just defining a math.random() and doing if then elseif then elseif for every possible result) but i want a better way of doing this
considered alternatives:
tables: depending on the amount of items i will have, this will become a excessive amount… probably

A table is most likely the way to go.

You said that it will likely become an excessive amount [of values in the table]. Can you please elaborate on why that will be the case / why it’s problematic that way? Are you planning to have unique dialogue options for each item or something?

well it would be boring to the user to have someone whose meant to have personality spit out the same three lines everytime they buy a item, so with the current amount of items, there would be five tables with four dialogue options each

So you would want e.g. 4 dialogue options per item?

You can still have this in a table quite easily. (Technically, a dictionary).

If you have items called “Pizza”, “Bread”, “Rock”, you could set up a table with the dialogue like this:

local Options = {
	Pizza = {
		"With pineapple, just how you like it!",
		"Don't forget to cut it",
		"The cheese is under the sauce"
	},
	Bread = {
		"Are you going to make a sandwich?",
		"Makes good toast, so I'm told", 
		"Freshly made within the last 10 weeks!"
	},
	Rock = {
		"Please don't eat this",
		"Highly inedible",
		"It's a rock."
	}
}

Then, when you want to get a random dialogue for the specific item, you would do

local Item = "Bread"
local Options = DialogueOptions[Item]
local Dialogue = Options[math.random(#Options)]

print(Dialogue) 

(If the item name starts with a non-letter character, you may need to define it in the dictionary as ["ITEMNAME"] rather than as just ITEMNAME)

Also, you could put this into a module script, to keep your main script from becoming cluttered with a lot of dialogue options. Simply return the table above in the module script, then you can access it like

local DialogueOptions = require(script.ModuleScript)

Hey, I was recently trying to figure out the same thing. The following resource helped a lot, but you should customize it for your own use (especially the frontend if you want to make it unique to your game):

You can add custom nodes that feature randomization on connected nodes. Do note that it hasn’t had an update since May.

oh yea i forgot the core principle of scripting, if it looks messy, throw it elsewhere /j

personally, i like doing my own code, also this might not work for my case scenario since the shopkeeper uses a animalese-esc dialogue noise and its cooped up in a shop ui

1 Like

hash dictionary buys itself only if its like 25+ options.
Once again depends a lot on implementation.
I use dictionaries for switch tables a lot:

local switch:{[string]:(...any)->(...any)} = {
kfc = function(count:number):()
return count
end;


}
local def = function():()

end;

local function Option(str:string,...:any):...any
return (switch[str] or def)(...)
end


print(Option("kfc",4))

whaaaaaa

where do you learn these structures? i feel like a noob whenever i see your posts btw

this looks like a bunch of goolby goop!

btw i was also unironically looking into animalese tts

have you figured out solutions for displaying it?

i came across this:

1 Like

Nothing is complicated; you just have not researched it yet.
Having that is a little more optimized than a bunch of ifnotjump (if statements basically) instructions internally.

Essentially, it tries to index “kfc” and if it doesn’t find such, it defaults to the “def” function.
Switch cases are very common in other programming languages like C/Java.
Although they can be pretty easily implemented in Lua/Luau, as you can see with the use of tables.

1 Like

my way of doing was
having 26 sounds for each letter + 1 for stuff like punctuation and other miscellaneous characters (preferably stored in replicatedstorage)
and it works with a typewriter effect
script below

function speaker(text: string)
	script.Parent.MaxVisibleGraphemes = 0
	script.Parent.Text = text
	local textlength = string.len(text)
	for i = 1, textlength, 1 do
		local charaacter = string.sub(text, i, i)
		if string.match(charaacter, "%s") then
			-- do nothing
		elseif string.match(charaacter, "%A") then
			local charactersound = game.ReplicatedStorage.passive_automaton_voice.pa_misc:Clone()
			charactersound.Parent = workspace
			charactersound:Play()
			Debris:AddItem(charactersound, charactersound.TimeLength)
		elseif string.match(charaacter, "%p") then
			local charactersound = game.ReplicatedStorage.passive_automaton_voice.pa_misc:Clone()
			charactersound.Parent = workspace
			charactersound:Play()
			Debris:AddItem(charactersound, charactersound.TimeLength)
		elseif string.match(charaacter, "%u") then
			local charactersound = game.ReplicatedStorage.passive_automaton_voice["pa_" .. string.lower(charaacter)]:Clone()
			charactersound.Parent = workspace
			charactersound.Volume = 1.5
			charactersound:Play()
			Debris:AddItem(charactersound, charactersound.TimeLength)
		elseif string.match(charaacter, "%l") then
			local charactersound = game.ReplicatedStorage.passive_automaton_voice["pa_" .. charaacter]:Clone()
			charactersound.Parent = workspace
			charactersound:Play()
			Debris:AddItem(charactersound, charactersound.TimeLength)
		else
			local charactersound = game.ReplicatedStorage.passive_automaton_voice.pa_misc:Clone()
			charactersound.Parent = workspace
			charactersound:Play()
			Debris:AddItem(charactersound, charactersound.TimeLength)
		end
		script.Parent.MaxVisibleGraphemes += 1
		task.wait(0.037)
	end
	task.wait(1.337) -- i forgot why this was here
end
1 Like

have you considered how it will work if the dialogue text is localized to a different language?

1 Like

no, but it should be easily extendable, expect for CJK… jesus how would that even work

tested it with the entering dialogue, worked, assuming it will work with the rest of the dialogues
(tested, worked for all items, even the special case one)

1 Like

I’m not sure and I’m not the best at languages, but I’d assume that someone could make it work by spamming the syllables or mora cached, maybe created with AudioTextToSpeech | Documentation - Roblox Creator Hub

Holy retroslop what kind of warcrime is that? :cold_face:

Cache services at least, bro :skull:

I hope you are aware what this string patterns actually mean? String Patterns - What on earth are they?

Also please reuse instances instead as much as you can.
Instance pooling needs to be more used and please declear functions with “local”.

local Debris = game:GetService("Debris")
local ReplicatedStorage = game:GetService("ReplicatedStorage")

local txt = script.Parent::TextLabel
local function speaker(text: string):()
	txt.MaxVisibleGraphemes = 0
	txt.Text = text
	local textlength = #text
	for i = 1, textlength, 1 do
		local charaacter = string.sub(text, i, i)
		if string.match(charaacter, "%s") then
			-- do nothing
		elseif string.match(charaacter, "%A") then
			local charactersound = ReplicatedStorage.passive_automaton_voice.pa_misc:Clone()
			charactersound.Parent = workspace
			charactersound:Play()
			Debris:AddItem(charactersound, charactersound.TimeLength)
		elseif string.match(charaacter, "%p") then
			local charactersound = ReplicatedStorage.passive_automaton_voice.pa_misc:Clone()
			charactersound.Parent = workspace
			charactersound:Play()
			Debris:AddItem(charactersound, charactersound.TimeLength)
		elseif string.match(charaacter, "%u") then
			local charactersound = ReplicatedStorage.passive_automaton_voice["pa_" .. string.lower(charaacter)]:Clone()
			charactersound.Parent = workspace
			charactersound.Volume = 1.5
			charactersound:Play()
			Debris:AddItem(charactersound, charactersound.TimeLength)
		elseif string.match(charaacter, "%l") then
			local charactersound = ReplicatedStorage.passive_automaton_voice["pa_" .. charaacter]:Clone()
			charactersound.Parent = workspace
			charactersound:Play()
			Debris:AddItem(charactersound, charactersound.TimeLength)
		else
			local charactersound = ReplicatedStorage.passive_automaton_voice.pa_misc:Clone()
			charactersound.Parent = workspace
			charactersound:Play()
			Debris:AddItem(charactersound, charactersound.TimeLength)
		end
		txt.MaxVisibleGraphemes += 1
		task.wait(0.037)
	end
	task.wait(1.337) -- i forgot why this was here
end
1 Like

using audiotexttospeech would depend on if you want the built in service or a unique voice, maybe cjk could just be updated with the new characters per every written voiceline (which is really stupid but would work probably)

you… didn’t do anything to the script?
(checked using a diff checker, barely different)

1 Like