How to switch from MouseButtonClick to ProximityPrompt in this script?

So I have this thing where I have NPCs in a folder inside workspace, each NPC has their own dialogue in a StringValue (as lines), and I have a ScreenGui that shows this dialogue when a person clicks the NPC. Now the issue is that the script works for a ClickDetector, but I want it to work for a ProximityPrompt instead, and I have no idea how to switch from this to that, how do I do it? (I’ll attach pictures below for a better explanation)

NPC’s folder in Workspace:
image

Each NPC contains a folder with StringValues (which are the lines that the NPC will say in the dialogue) and a ProximityPrompt called (ActivateText)
image

The ScreenGui which is the dialogue of the NPC that will show to the player
image

This is how the Gui looks like

This is the Figuartion script inside the ScreenGui

local mod = require(script.ModuleScript)

local player = game:GetService("Players").LocalPlayer

local npcs = workspace:WaitForChild("Npcs")

local gui = script.Parent
local MainFrame = gui.MainFrame
local dialogue = MainFrame.Dialouge

local mouse = player:GetMouse()
local char = player.Character

local sound = script.Sound

local target
canTalk = true

local function findTarget()
	target = mouse.Target
	return target
end

local function mouseButtonClick()
	local theTarget = findTarget()

	if theTarget.Parent.Parent == npcs then
		local clicker = theTarget.Parent:FindFirstChild("ActivateText")
		clicker.MouseClick:Connect(function()
			if canTalk == true then
				canTalk = false
				local npc = clicker.Parent
				local DialogueOptions = npc.DialogueOptions
				local humanoid = char:WaitForChild("Humanoid")
				local Line1 = DialogueOptions.Line1
				local Line2 = DialogueOptions.Line2
				local Line3 = DialogueOptions.Line3
				local Line4 = DialogueOptions.Line4
				local Line5 = DialogueOptions.Line5
				local Line6 = DialogueOptions.Line6
				local Line7 = DialogueOptions.Line7
				local Line8 = DialogueOptions.Line8
				local Line9 = DialogueOptions.Line9
				humanoid.WalkSpeed = 0
				MainFrame.Visible = true
				MainFrame.Title.Text = npc.Name
				mod.typewrite(dialogue, Line1.Value, .02, sound)
				wait(4)
				mod.typewrite(dialogue, Line2.Value, .02, sound)
				wait(4)
				mod.typewrite(dialogue, Line3.Value, .02, sound)
				wait(4)
				mod.typewrite(dialogue, Line4.Value, .02, sound)
				wait(4)
				mod.typewrite(dialogue, Line5.Value, .02, sound)
				wait(4)
				mod.typewrite(dialogue, Line6.Value, .02, sound)
				wait(4)
				mod.typewrite(dialogue, Line7.Value, .02, sound)
				wait(4)
				mod.typewrite(dialogue, Line8.Value, .02, sound)
				wait(4)
				mod.typewrite(dialogue, Line9.Value, .02, sound)
				wait(4)
				MainFrame.Visible = false
				MainFrame.Dialouge.Text = " "
				humanoid.WalkSpeed = 16
				canTalk = true
			end
		end)
	end
	return theTarget
end

mouse.Button1Down:Connect(mouseButtonClick)

This is the ModuleScript inside the Figuration script

local module = {}

function module.typewrite(object , text, length, sound)
	for i = 1,#text,1 do
		object.Text = string.sub (text,1,i)
		sound:Play()
		wait (length)
	end
end

return module

Would really hope if someone could help me figure this out.

1 Like

You just gonna use triggerended or trigger event. As you made the mousebuttonclick actually they works almost same as each other

3 Likes

I don’t have much knowledge about ProximityPrompts, do you mind helping me know what part of the script I am supposed to change? I know I can just use

ProximityPrompt.Triggered:connect(function(player)

but I don’t know how do I make it so that it can detect every ProximityPrompt inside of each NPC that is found inside a folder?

1 Like

If you set the variable inside of npc’s proximityprompt yes.

By the way if this is a script which is screengui and if you want to make it appear when just clicked to proximityprompt then;

script.Parent.TriggerEnded:Connect(function(Player)
	Player.StarterGui."YourGui".Visible = true -- IF THIS IS DIFFERENT TO YOU THEN YOU CAN CARRY GUI TO PLAYER'S GUI AND YOU CAN MAKE IT 
end)
1 Like

First add proximity prompts to all of the npc’s HumanoidRootParts in studio. You could also do it with code but then they would all have the same action+object text. Make sure all your npcs have humanoid root parts with proximity prompts.

local setUpNPC(npc)
    local hrp = npc:WaitForChild("HumanoidRootPart")
    local prompt = hrp:WaitForChild("ProximityPrompt")
    prompt.Triggered:Connect(function()
		local clicker = npc:FindFirstChild("ActivateText")
		clicker.MouseClick:Connect(function()
			if canTalk == true then
				canTalk = false
				local npc = clicker.Parent
				local DialogueOptions = npc.DialogueOptions
				local humanoid = char:WaitForChild("Humanoid")
				local Line1 = DialogueOptions.Line1
				local Line2 = DialogueOptions.Line2
				local Line3 = DialogueOptions.Line3
				local Line4 = DialogueOptions.Line4
				local Line5 = DialogueOptions.Line5
				local Line6 = DialogueOptions.Line6
				local Line7 = DialogueOptions.Line7
				local Line8 = DialogueOptions.Line8
				local Line9 = DialogueOptions.Line9
				humanoid.WalkSpeed = 0
				MainFrame.Visible = true
				MainFrame.Title.Text = npc.Name
				mod.typewrite(dialogue, Line1.Value, .02, sound)
				wait(4)
				mod.typewrite(dialogue, Line2.Value, .02, sound)
				wait(4)
				mod.typewrite(dialogue, Line3.Value, .02, sound)
				wait(4)
				mod.typewrite(dialogue, Line4.Value, .02, sound)
				wait(4)
				mod.typewrite(dialogue, Line5.Value, .02, sound)
				wait(4)
				mod.typewrite(dialogue, Line6.Value, .02, sound)
				wait(4)
				mod.typewrite(dialogue, Line7.Value, .02, sound)
				wait(4)
				mod.typewrite(dialogue, Line8.Value, .02, sound)
				wait(4)
				mod.typewrite(dialogue, Line9.Value, .02, sound)
				wait(4)
				MainFrame.Visible = false
				MainFrame.Dialouge.Text = " "
				humanoid.WalkSpeed = 16
				canTalk = true
			end
		end)


    end)
end

for _, npc in ipairs(npcs:GetChildren()) do
    setUpNPC(npc)
end
npcs.ChildAdded:Connect(setUpNPC)
1 Like

you would have to loop through the folder and see if it has a proximity prompt by using FindFirstChildWhichIsA

--example
for _, npc in pairs(workspace.Npcs:GetChildren()) do
    local proximityPrompt = npc:FindFirstChildWhichIsA("ProximityPrompt")
    if proximityPrompt then
        proximityPrompt.Triggered:Connect(function()
            --code here
        end)
    end
end
2 Likes

So I should change the Figuration script to become like this? (I tried it and it didn’t work, I’m pretty sure I did something wrong…)

local mod = require(script.ModuleScript)

local player = game:GetService("Players").LocalPlayer

local npcs = workspace:WaitForChild("Npcs")

local gui = script.Parent
local MainFrame = gui.MainFrame
local dialogue = MainFrame.Dialouge

local mouse = player:GetMouse()
local char = player.Character

local sound = script.Sound

local target
canTalk = true

local function findTarget()
	target = mouse.Target
	return target
end

local function mouseButtonClick()
	local theTarget = findTarget()

	--example
	for _, npc in pairs(workspace.Npcs:GetChildren()) do
		local proximityPrompt = npc:FindFirstChildWhichIsA("ProximityPrompt")
		if proximityPrompt then
			proximityPrompt.Triggered:Connect(function()
			if canTalk == true then
				canTalk = false
				local DialogueOptions = npc.DialogueOptions
				local humanoid = char:WaitForChild("Humanoid")
				local Line1 = DialogueOptions.Line1
				local Line2 = DialogueOptions.Line2
				local Line3 = DialogueOptions.Line3
				local Line4 = DialogueOptions.Line4
				local Line5 = DialogueOptions.Line5
				local Line6 = DialogueOptions.Line6
				local Line7 = DialogueOptions.Line7
				local Line8 = DialogueOptions.Line8
				local Line9 = DialogueOptions.Line9
				humanoid.WalkSpeed = 0
				MainFrame.Visible = true
				MainFrame.Title.Text = npc.Name
				mod.typewrite(dialogue, Line1.Value, .02, sound)
				wait(4)
				mod.typewrite(dialogue, Line2.Value, .02, sound)
				wait(4)
				mod.typewrite(dialogue, Line3.Value, .02, sound)
				wait(4)
				mod.typewrite(dialogue, Line4.Value, .02, sound)
				wait(4)
				mod.typewrite(dialogue, Line5.Value, .02, sound)
				wait(4)
				mod.typewrite(dialogue, Line6.Value, .02, sound)
				wait(4)
				mod.typewrite(dialogue, Line7.Value, .02, sound)
				wait(4)
				mod.typewrite(dialogue, Line8.Value, .02, sound)
				wait(4)
				mod.typewrite(dialogue, Line9.Value, .02, sound)
				wait(4)
				MainFrame.Visible = false
				MainFrame.Dialouge.Text = " "
				humanoid.WalkSpeed = 16
				canTalk = true
			end
		end)
	end
	return theTarget
end
1 Like

no mouseButtonClick isn’t being ran
this should probably work (full script)

local mod = require(script.ModuleScript)

local player = game:GetService("Players").LocalPlayer

local npcs = workspace:WaitForChild("Npcs")

local gui = script.Parent
local MainFrame = gui.MainFrame
local dialogue = MainFrame.Dialouge

local char = player.Character

local sound = script.Sound

canTalk = true

local function proximityPromptTriggered(npc)
	if canTalk == true then
		canTalk = false
		local DialogueOptions = npc.DialogueOptions
		local humanoid = char:WaitForChild("Humanoid")
		local Line1 = DialogueOptions.Line1
		local Line2 = DialogueOptions.Line2
		local Line3 = DialogueOptions.Line3
		local Line4 = DialogueOptions.Line4
		local Line5 = DialogueOptions.Line5
		local Line6 = DialogueOptions.Line6
		local Line7 = DialogueOptions.Line7
		local Line8 = DialogueOptions.Line8
		local Line9 = DialogueOptions.Line9
		humanoid.WalkSpeed = 0
		MainFrame.Visible = true
		MainFrame.Title.Text = npc.Name
		mod.typewrite(dialogue, Line1.Value, .02, sound)
		wait(4)
		mod.typewrite(dialogue, Line2.Value, .02, sound)
		wait(4)
		mod.typewrite(dialogue, Line3.Value, .02, sound)
		wait(4)
		mod.typewrite(dialogue, Line4.Value, .02, sound)
		wait(4)
		mod.typewrite(dialogue, Line5.Value, .02, sound)
		wait(4)
		mod.typewrite(dialogue, Line6.Value, .02, sound)
		wait(4)
		mod.typewrite(dialogue, Line7.Value, .02, sound)
		wait(4)
		mod.typewrite(dialogue, Line8.Value, .02, sound)
		wait(4)
		mod.typewrite(dialogue, Line9.Value, .02, sound)
		wait(4)
		MainFrame.Visible = false
		MainFrame.Dialouge.Text = " "
		humanoid.WalkSpeed = 16
		canTalk = true
	end
end

for _, npc in pairs(workspace.Npcs:GetChildren()) do
	local proximityPrompt = npc:FindFirstChildWhichIsA("ProximityPrompt")
	if proximityPrompt then
		proximityPrompt.Triggered:Connect(function()
			proximityPromptTriggered(npc)
		end)
	end
end
2 Likes

It’s working perfectly, thank you so much!!!

2 Likes

One small issue, when I used the ProximityPrompt for the first NPC it worked perfectly, but then I tried to speak with the NPC again after the dialogue was over, and it didn’t work. I also tried to talk to the other NPC’s and it didn’t work as well, how do I make it so that you can replay the dialogue as much as you want after its over & make it so that you can also use the dialogue for other NPC’s multiple times too?

1 Like

This is an amazing solution however I feel that the repetitiveness of declaring a variable for each line of text is a bit too much and a looping function would be ideal. However, I may not understand the larger picture and the code I provided below will only work with the current format (Line + Dialogue Num)

(proximity prompt function)

local function proximityPromptTriggered(npc)
	if canTalk == true then
		canTalk = false
		local DialogueOptions = npc.DialogueOptions
		local humanoid = char:WaitForChild("Humanoid")
		humanoid.WalkSpeed = 0
		
                MainFrame.Visible = true
		MainFrame.Title.Text = npc.Name

                for i = 1, 9 do -- 9 is the number of lines.
                       mod.typewrite(dialogue, DialogueOptions["Line" .. i].Value, .02, sound)
                       wait(4)
                end
		
		MainFrame.Visible = false
		MainFrame.Dialouge.Text = " "
		humanoid.WalkSpeed = 16
		canTalk = true
	end
end

This provides the same answer as MeowzzMr but in a more simple formatted way.

2 Likes

Most likely the canTalk variable isn’t being set correctly, try doing print(canTalk) at the start of the proximityPromptTriggered function and see what it prints. (it should print true unless you are currently in dialogue)
If the walkSpeed is being set back to 16 after being set to 0 then it should be set correctly but you can try doing the same print function (print(canTalk)) before and after canTalk = true at the end of the function. (it should print false then true afterwards)
And yes do what @MarsSquirrel said unless you want something else to happen in between lines.

1 Like

I’m not sure why but for some reason the script didn’t work :[

I tried what you told me to do and you’re correct it did print in the order you said. But the issue of trying to talk to other NPC’s is still there. It shows me this error in Output:

Could it be that because some NPC’s have 3 lines or something? Because not all the NPC’s have the same amount of lines, could that be the issue? (The first NPC that worked had 9 lines)

If that is the case, I’m still really confused on how to fix that issue

Yes, this means that Line4 doesn’t exist in the DialogueOptions of the NPC.
This should detect all the lines in DialogueOptions (also fixes and improves a couple minor things)

local mod = require(script.ModuleScript)

local player = game:GetService("Players").LocalPlayer

local npcs = workspace:WaitForChild("Npcs")

local gui = script.Parent
local MainFrame = gui.MainFrame
local dialogue = MainFrame.Dialouge

local sound = script.Sound

canTalk = true

local function proximityPromptTriggered(npc)
	local DialogueOptions = npc:FindFirstChild("DialogueOptions")
	if canTalk == true and DialogueOptions then -- makes sure npc has DialogueOptions
		canTalk = false
		
		local char = player.Character --[[ gets current Character, saving it in variable outside this function will 
		cause it to store the wrong Character whenever they respawn ]]

		local humanoid = char:WaitForChild("Humanoid")
		humanoid.WalkSpeed = 0

		MainFrame.Visible = true
		MainFrame.Title.Text = npc.Name

		local lines = {}

		for _, v in pairs(DialogueOptions:GetChildren()) do
			if v:IsA("StringValue") and v.Name:sub(0, 4) == "Line" and v.Name:match("%d+") then --checks if the instance is a StringValue, has the word line at the beginning, and has numbers in it 
				table.insert(lines, v.Name:match("%d+"), v.Value) -- insert the value of the line (string) into the lines table, index is the number in the name of the value
			end
		end

		for _, line in ipairs(lines) do
			mod.typewrite(dialogue, line, .02, sound)
			task.wait(4) --faster and more accurate than wait(n), see https://devforum.roblox.com/t/task-library-now-available/1387845
		end

		MainFrame.Visible = false
		MainFrame.Dialouge.Text = " "
		humanoid.WalkSpeed = 16
		canTalk = true
	end
end

for _, npc in pairs(workspace.Npcs:GetChildren()) do
	local proximityPrompt = npc:FindFirstChildWhichIsA("ProximityPrompt")
	if proximityPrompt then
		proximityPrompt.Triggered:Connect(function()
			proximityPromptTriggered(npc)
		end)
	end
end
1 Like

It seems to be working perfectly now, except for the first NPC (the only NPC that has 9 lines), it only shows his first line and ends the dialogue for some reason (the rest of NPCs have 2-4 lines.)

See what the lines table prints.
The StringValues could not be named correctly or parented under the wrong thing but most likely not. Try doing print(v) under where it loops through the children of DialogueOptions and see if it prints all the lines.

1 Like

I put the print(v) in here in the script, I hope that is where you wanted me to place it (fingers crossed I placed it correctly this time lol)

Now for the first NPC (the only NPC that has 9 lines) this is what shows in OutPut:
(for some reason it only shows the first 2 lines now and then the dialogue ends)

image

Also, another NPC that has 4 lines only shows 2 lines of the dialogue as well and then the dialogue ends

This is what shows in the OutPut for that NPC:

image

It’s weird because all the other NPC’s have only 2 or 3 lines and they work perfectly fine, but the main NPC that has 9 lines and the last NPC that has 4 lines seem to have this issue.

All the lines should be added to the lines table then. Try doing print(lines) and see if the table is correctly in order. If it isn’t then thats why it ends early. If switching ipairs to pairs fixes the issue and seems to not cause any issue with the order then I would do that. (ipairs makes sure it gets iterated in numerical order).
If switching it does cause issues with the order of the dialogue then I’ll try to figure out why.

1 Like