Hi, I am working on my game which features a dialog system to locally chat with NPCs. When an NPC presents a question, it invokes a BindableFunction (named DialogChoice) which the client receives. This opens up the choice box. There are multiple answer choices for the player, which DialogChoice returns to the NPC as a string. However, while the player can read the string value and send it successfully, the NPC is unable to receive it, and the result of DialogChoice prints “nil.”
Here is a snippet of the dialog code for the NPC, found within a Script set to Client RunContext inside a ProximityPrompt inside their character:
Prompt.Triggered:Connect(function(plr)
if plr ~= Player then return end
Prompt.Enabled = false
Title.PlayerToHideFrom = Player
local Initial = {
"Ahoy! I'm William of the Single Sea, the greatest pirate ever! I see you are...",
Player.DisplayName.."! That's right! I heard about you from the locals around here.",
}
for i,v in pairs(Initial) do
TextEvent:Fire(v)
Voice.SoundId = "rbxassetid://"..NeutralVoices[math.random(#NeutralVoices)]
repeat wait() until Voice.IsLoaded
Voice:Stop()
Voice:Play()
TextAnimator.typeWrite(Title.invisible, v, 0.05)
task.wait(2)
end
local q1 = "Say, how does a good ol' treasure hunt sound? It should only take a few minutes."
local response = ChoiceEvent:Invoke(q1, 5)
print(response)
end)
As shown above, the NPC reads the first few initial lines to the player. Then, it presents the first question by invoking the ChoiceEvent.
Here is a snippet of the LocalScript inside a ScreenGui in the Client’s PlayerGui:
local function Choice(questionText, timerAmount)
assert(questionText, "Invalid string.")
assert(timerAmount, "Invalid number.")
local tInfo = TweenInfo.new(timerAmount, Enum.EasingStyle.Linear)
local TimerTween = ts:Create(Timer, tInfo, {Size = UDim2.new(0,0,0.1,0)})
local oldpos = ChoiceBox.Position
ChoiceBox.Position = oldpos+UDim2.new(0,0,0.5,0)
ChoiceBox:TweenPosition(oldpos, Enum.EasingDirection.Out, Enum.EasingStyle.Sine, 1)
ChoiceBox.Visible = true
Timer.Size = UDim2.new(1,0,0.1,0)
Dialog.Enabled = true
Choices.Visible = false
Timer.Visible = false
Header.Visible = false
task.wait(1)
TextAnimator.typeWrite(Question, questionText, 0.05)
Choices.Visible = true
Timer.Visible = true
Header.Visible = true
local active = true
for i,v in pairs(Choices:GetChildren()) do
if v:IsA("TextButton") then
local connection
connection = v.MouseButton1Click:Connect(function()
if not active then return end
active = false
TimerTween:Cancel()
connection:Disconnect()
game.SoundService.ui_Click:Stop()
game.SoundService.ui_Click:Play()
ChoiceBox.Visible = false
return v.Name
end)
end
end
TimerTween:Play()
TimerTween.Completed:Wait()
if active then
active = false
for i,v in pairs(Choices:GetChildren()) do
if v:IsA("TextButton") then
game.SoundService.ui_Click:Stop()
game.SoundService.ui_Click:Play()
ChoiceBox.Visible = false
return v.Name
end
end
end
end
TextEvent.Event:Connect(function(promptText)
if not promptText then
DialogText.Text = ""
DialogText.Visible = false
end
DialogText.Visible = true
TextAnimator.typeWrite(DialogText, promptText, 0.05)
end)
ChoiceEvent.OnInvoke = Choice
The Choice function is the core of the script, as it handles the majority of the work. The TextEvent function handles the initial prompts by the NPC. One thing I would like to mention is that the “v” value in the for loops represents the TextButtons, which represent the answer choices that the player can select.
At the moment, the player is able to read and print v.Name all the way up until the function returns the value. On the other hand, the NPC receives the result but cannot read the value, thus printing “nil.”