JIT
enhancing dialogue and movement in your game code
this code. -- Server Script local Players = game:GetService("Players") local Debris = game:GetService("Debris") local ReplicatedStorage = game:GetService("ReplicatedStorage") local SoundService = game:GetService("SoundService") local dialogueEvent = ReplicatedStorage:FindFirstChild("DialogueEvent") or Instance.new("RemoteEvent", ReplicatedStorage) dialogueEvent.Name = "DialogueEvent" local choiceEvent = ReplicatedStorage:FindFirstChild("ChoiceEvent") or Instance.new("RemoteEvent", ReplicatedStorage) choiceEvent.Name = "ChoiceEvent" local soundFolder = SoundService:FindFirstChild("CutsceneSounds") or Instance.new("Folder", SoundService) soundFolder.Name = "CutsceneSounds" local function playSound(id, vol, pit) local s = Instance.new("Sound") s.SoundId = id s.Volume = vol s.Pitch = pit s.Parent = soundFolder s:Play() Debris:AddItem(s, 2) end local Dialogues = { { text="Oh hey uhh...", textSpeed=0.125, delayBeforeNext=1 }, { text="Ig im here for testing", textSpeed=0.065, delayBeforeNext=1, choices={ { text="Mirror Man?", nextIndex=3 }, { text="End chat", nextIndex=5 }, { text="Replay intro", nextIndex=1 }, }, }, { text="I'm Metal Man, not Mirror Man.", textSpeed=0.075, delayBeforeNext=2, choices={ { text="Oh.", nextIndex=4 }, }, }, { text="Wanna test more?", textSpeed=0.0575, delayBeforeNext=1, choices={ { text="Yes", nextIndex=2 }, { text="No", nextIndex=5 }, { text="Loop question", nextIndex=4 }, }, }, { text="Alright, bye!", textSpeed=0.1, delayBeforeNext=0.5 }, } local triggered = {} local clickPart = script.Parent local detector = clickPart:FindFirstChildOfClass("ClickDetector") or Instance.new("ClickDetector", clickPart) detector.MouseClick:Connect(function(player) if triggered[player] then return end triggered[player] = true spawn(function() dialogueEvent:FireClient(player, "start") local idx = 1 while Dialogues[idx] do local d = Dialogues[idx] playSound("rbxassetid://129600471584011", 1, 0.925) task.wait(0.35) for i = 1, #d.text do dialogueEvent:FireClient(player, "updateText", d.text:sub(1, i)) playSound("rbxassetid://129600471584011", 0.65, 1.5) task.wait(d.textSpeed) end task.wait(d.delayBeforeNext) if d.choices then dialogueEvent:FireClient(player, "choices", d.choices) local choice, conn conn = choiceEvent.OnServerEvent:Connect(function(p, sel) if p == player then choice = sel conn:Disconnect() end end) repeat task.wait() until choice dialogueEvent:FireClient(player, "clear") -- clear after choice idx = d.choices[choice].nextIndex else dialogueEvent:FireClient(player, "clear") idx = idx + 1 end end dialogueEvent:FireClient(player, "end") triggered[player] = nil end) end) make it that if it is a humanoid then make it look at the player with 8 directions. local Players = game:GetService("Players") local RunService = game:GetService("RunService") local p = Players.LocalPlayer local function setupMovement(char) local h = char:WaitForChild("Humanoid") local hrp = char:WaitForChild("HumanoidRootPart") h.AutoRotate = false RunService.RenderStepped:Connect(function() local d = h.MoveDirection if d.Magnitude > 0 then local a = math.atan2(d.X, d.Z) local step = math.pi/4 a = math.floor(a/step + 0.5) * step local dir = Vector3.new(math.sin(a), 0, math.cos(a)) hrp.CFrame = CFrame.new(hrp.Position, hrp.Position + dir) h:Move(dir, false) end end) end if p.Character then setupMovement(p.Character) end p.CharacterAdded:Connect(setupMovement) -- Local Script local player = game.Players.LocalPlayer local gui = Instance.new("ScreenGui", player:WaitForChild("PlayerGui")) gui.Name = "DialogueUI" gui.Enabled = false local box = Instance.new("TextLabel", gui) box.Size = UDim2.new(0.6,0,0.15,0) box.Position = UDim2.new(0.2,0,0.8,0) box.BackgroundColor3 = Color3.new(0,0,0) box.BackgroundTransparency = 0.25 box.TextColor3 = Color3.new(1,1,1) box.TextScaled = true box.Font = Enum.Font.SourceSansBold local choiceBG = Instance.new("Frame", gui) choiceBG.Size = UDim2.new(0.6,0,0,0) choiceBG.Position = UDim2.new(0.2,0,0.75,0) choiceBG.BackgroundColor3 = Color3.new(0,0,0) choiceBG.BackgroundTransparency = 0.25 choiceBG.Visible = false local choiceFrame = Instance.new("Frame", choiceBG) choiceFrame.Size = UDim2.new(1,0,1,0) choiceFrame.Position = UDim2.new(0,0,0,0) choiceFrame.BackgroundTransparency = 1 local function clearChoices() for _, c in ipairs(choiceFrame:GetChildren()) do if c:IsA("TextButton") then c:Destroy() end end choiceBG.Visible = false choiceBG.Size = UDim2.new(0.6,0,0,0) end local function showChoices(choices) clearChoices() local count = #choices local height = 30 choiceBG.Size = UDim2.new(0.6,0,0, height+8) choiceBG.Visible = true for i, opt in ipairs(choices) do local btn = Instance.new("TextButton", choiceFrame) btn.Size = UDim2.new(1/count, -4, 0, height) btn.Position = UDim2.new((i-1)/count, 2, 0, 4) btn.BackgroundTransparency = 1 btn.BorderSizePixel = 1 btn.BorderColor3 = Color3.new(1,1,1) btn.TextColor3 = Color3.new(1,1,1) btn.TextScaled = true btn.Font = Enum.Font.SourceSans btn.Text = opt.text btn.MouseButton1Click:Connect(function() clearChoices() game.ReplicatedStorage:WaitForChild("ChoiceEvent"):FireServer(i) end) end end game.ReplicatedStorage:WaitForChild("DialogueEvent").OnClientEvent:Connect(function(cmd, data) if cmd=="start" then gui.Enabled = true elseif cmd=="updateText" then box.Text = data elseif cmd=="choices" then showChoices(data) elseif cmd=="clear" then box.Text = "" elseif cmd=="end" then gui.Enabled = false clearChoices() end end)

I'll help modify the code to make the humanoid look at the player with 8 directions. Here's the updated version:

Updated files
v1
make it that after the dialogue ends they will go back to their original rotation

Here's the updated version that saves and restores the original rotation:

Updated files
v2
modified the codes. -- Server Script local Players = game:GetService("Players") local Debris = game:GetService("Debris") local ReplicatedStorage = game:GetService("ReplicatedStorage") local SoundService = game:GetService("SoundService") local dialogueEvent = ReplicatedStorage:FindFirstChild("DialogueEvent") or Instance.new("RemoteEvent", ReplicatedStorage) dialogueEvent.Name = "DialogueEvent" local choiceEvent = ReplicatedStorage:FindFirstChild("ChoiceEvent") or Instance.new("RemoteEvent", ReplicatedStorage) choiceEvent.Name = "ChoiceEvent" local soundFolder = SoundService:FindFirstChild("CutsceneSounds") or Instance.new("Folder", SoundService) soundFolder.Name = "CutsceneSounds" local function playSound(id, vol, pit) local s = Instance.new("Sound") s.SoundId = id s.Volume = vol s.Pitch = pit s.Parent = soundFolder s:Play() Debris:AddItem(s, 2) end local Dialogues = { { text="Oh hey uhh...", textSpeed=0.125, delayBeforeNext=1 }, { text="Ig im here for testing", textSpeed=0.065, delayBeforeNext=1, choices={ { text="Mirror Man?", nextIndex=3 }, }, }, { text="I'm Metal Man, not Mirror Man.", textSpeed=0.075, delayBeforeNext=2, choices={ { text="Oh.", nextIndex=4 }, }, }, { text="Smart guy.", textSpeed=0.0575, delayBeforeNext=1, choices={ { text="Whatever Man.", nextIndex=5 }, }, }, { text="Hate how you guys keep on mistaking me for that mugen freak.", textSpeed=0.05, delayBeforeNext=2 }, { text="Anyways you should meet Tape Recorder Guy.", textSpeed=0.05, delayBeforeNext=2 }, { text="He should give you a tape to progress since he owns this place.", textSpeed=0.05, delayBeforeNext=4 }, } local triggered = {} local clickPart = script.Parent local detector = clickPart:FindFirstChildOfClass("ClickDetector") or Instance.new("ClickDetector", clickPart) local function get8DirectionLookAngle(player, npcHumanoid) local npcRoot = npcHumanoid.RootPart local playerRoot = player.Character and player.Character:FindFirstChild("HumanoidRootPart") if not npcRoot or not playerRoot then return end local direction = (playerRoot.Position - npcRoot.Position) * Vector3.new(1, 0, 1) if direction.Magnitude < 0.1 then return end local angle = math.atan2(direction.X, direction.Z) local step = math.pi/4 angle = math.floor(angle/step + 0.5) * step return CFrame.new(npcRoot.Position, npcRoot.Position + Vector3.new(math.sin(angle), 0, math.cos(angle))) end detector.MouseClick:Connect(function(player) if triggered[player] then return end triggered[player] = true local npcHumanoid = script.Parent:FindFirstChildOfClass("Humanoid") local lookConnection local originalAutoRotate = true local originalCFrame = npcHumanoid and npcHumanoid.RootPart.CFrame if npcHumanoid then originalAutoRotate = npcHumanoid.AutoRotate npcHumanoid.AutoRotate = false lookConnection = game:GetService("RunService").Heartbeat:Connect(function() local targetCFrame = get8DirectionLookAngle(player, npcHumanoid) if targetCFrame then npcHumanoid.RootPart.CFrame = targetCFrame end end) end spawn(function() dialogueEvent:FireClient(player, "start") local idx = 1 while Dialogues[idx] do local d = Dialogues[idx] playSound("rbxassetid://129600471584011", 1, 0.925) task.wait(0.35) for i = 1, #d.text do dialogueEvent:FireClient(player, "updateText", d.text:sub(1, i)) playSound("rbxassetid://129600471584011", 0.65, 1.5) task.wait(d.textSpeed) end task.wait(d.delayBeforeNext) if d.choices then dialogueEvent:FireClient(player, "choices", d.choices) local choice, conn conn = choiceEvent.OnServerEvent:Connect(function(p, sel) if p == player then choice = sel conn:Disconnect() end end) repeat task.wait() until choice dialogueEvent:FireClient(player, "clear") -- clear after choice idx = d.choices[choice].nextIndex else dialogueEvent:FireClient(player, "clear") idx = idx + 1 end end dialogueEvent:FireClient(player, "end") triggered[player] = nil if lookConnection then lookConnection:Disconnect() if npcHumanoid then npcHumanoid.AutoRotate = originalAutoRotate if originalCFrame then npcHumanoid.RootPart.CFrame = originalCFrame end end end end) end) -- Local Script local player = game.Players.LocalPlayer local gui = Instance.new("ScreenGui", player:WaitForChild("PlayerGui")) gui.Name = "DialogueUI" gui.Enabled = false local box = Instance.new("TextLabel", gui) box.Size = UDim2.new(0.6,0,0.15,0) box.Position = UDim2.new(0.2,0,0.8,0) box.BackgroundColor3 = Color3.new(0,0,0) box.BackgroundTransparency = 0.25 box.TextColor3 = Color3.new(1,1,1) box.TextScaled = true box.Font = Enum.Font.SourceSansBold local choiceBG = Instance.new("Frame", gui) choiceBG.Size = UDim2.new(0.6,0,0,0) choiceBG.Position = UDim2.new(0.2,0,0.75,0) choiceBG.BackgroundColor3 = Color3.new(0,0,0) choiceBG.BackgroundTransparency = 0.25 choiceBG.Visible = false local choiceFrame = Instance.new("Frame", choiceBG) choiceFrame.Size = UDim2.new(1,0,1,0) choiceFrame.Position = UDim2.new(0,0,0,0) choiceFrame.BackgroundTransparency = 1 local function clearChoices() for _, c in ipairs(choiceFrame:GetChildren()) do if c:IsA("TextButton") then c:Destroy() end end choiceBG.Visible = false choiceBG.Size = UDim2.new(0.6,0,0,0) end local function showChoices(choices) clearChoices() local count = #choices local height = 30 choiceBG.Size = UDim2.new(0.6,0,0, height+8) choiceBG.Visible = true for i, opt in ipairs(choices) do local btn = Instance.new("TextButton", choiceFrame) btn.Size = UDim2.new(1/count, -4, 0, height) btn.Position = UDim2.new((i-1)/count, 2, 0, 4) btn.BackgroundTransparency = 1 btn.BorderSizePixel = 1 btn.BorderColor3 = Color3.new(1,1,1) btn.TextColor3 = Color3.new(1,1,1) btn.TextScaled = true btn.Font = Enum.Font.SourceSans btn.Text = opt.text btn.MouseButton1Click:Connect(function() clearChoices() game.ReplicatedStorage:WaitForChild("ChoiceEvent"):FireServer(i) end) end end game.ReplicatedStorage:WaitForChild("DialogueEvent").OnClientEvent:Connect(function(cmd, data) if cmd=="start" then gui.Enabled = true elseif cmd=="updateText" then box.Text = data elseif cmd=="choices" then showChoices(data) elseif cmd=="clear" then box.Text = "" elseif cmd=="end" then gui.Enabled = false clearChoices() end end) make it that dialogues dont override each other. (aka prevent overlapping)

Here's the modified version that prevents dialogue overlaps by adding a queue system:

Key changes made:

  1. Replaced triggered table with activeDialogues to track ongoing dialogues per player
  2. Moved dialogue processing into a separate processDialogue function
  3. Added checks to prevent new dialogues from starting if one is already active for a player
  4. Simplified the click handler to just check for active dialogues and start processing
  5. Maintained all existing functionality while preventing overlaps
Updated files
v3
and i mean for every other script that has the dialogue. like this one. -- Server Script local Players = game:GetService("Players") local Debris = game:GetService("Debris") local ReplicatedStorage = game:GetService("ReplicatedStorage") local SoundService = game:GetService("SoundService") local dialogueEvent = ReplicatedStorage:FindFirstChild("DialogueEvent") or Instance.new("RemoteEvent", ReplicatedStorage) dialogueEvent.Name = "DialogueEvent" local choiceEvent = ReplicatedStorage:FindFirstChild("ChoiceEvent") or Instance.new("RemoteEvent", ReplicatedStorage) choiceEvent.Name = "ChoiceEvent" local soundFolder = SoundService:FindFirstChild("CutsceneSounds") or Instance.new("Folder", SoundService) soundFolder.Name = "CutsceneSounds" local function playSound(id, vol, pit) local s = Instance.new("Sound") s.SoundId = id s.Volume = vol s.Pitch = pit s.Parent = soundFolder s:Play() Debris:AddItem(s, 2) end local Dialogues = { { text="HEllo im the TPG!!1!!!", textSpeed=0.065, delayBeforeNext=1, choices={ { text="Hey. I need a Tape Recorder.", nextIndex=2 }, }, }, { text="OHKAY HERES U YOU'RE gOES!", textSpeed=0.075, delayBeforeNext=2, choices={ { text="Thanks.", nextIndex=3 }, }, }, { text="YOURRRRRR WELCOME!!!!!!!!!!!!!!!!", textSpeed=0.025, delayBeforeNext=3 }, } local activeDialogues = {} -- Tracks active dialogues per player local clickPart = script.Parent local detector = clickPart:FindFirstChildOfClass("ClickDetector") or Instance.new("ClickDetector", clickPart) local function get8DirectionLookAngle(player, npcHumanoid) local npcRoot = npcHumanoid.RootPart local playerRoot = player.Character and player.Character:FindFirstChild("HumanoidRootPart") if not npcRoot or not playerRoot then return end local direction = (playerRoot.Position - npcRoot.Position) * Vector3.new(1, 0, 1) if direction.Magnitude < 0.1 then return end local angle = math.atan2(direction.X, direction.Z) local step = math.pi/4 angle = math.floor(angle/step + 0.5) * step return CFrame.new(npcRoot.Position, npcRoot.Position + Vector3.new(math.sin(angle), 0, math.cos(angle))) end local function processDialogue(player, npcHumanoid) if activeDialogues[player] then return end activeDialogues[player] = true local lookConnection local originalAutoRotate = true local originalCFrame = npcHumanoid and npcHumanoid.RootPart.CFrame if npcHumanoid then originalAutoRotate = npcHumanoid.AutoRotate npcHumanoid.AutoRotate = false lookConnection = game:GetService("RunService").Heartbeat:Connect(function() local targetCFrame = get8DirectionLookAngle(player, npcHumanoid) if targetCFrame then npcHumanoid.RootPart.CFrame = targetCFrame end end) end dialogueEvent:FireClient(player, "start") local idx = 1 while Dialogues[idx] do local d = Dialogues[idx] playSound("rbxassetid://7361292522", 0.75, 2.25) task.wait(0.35) for i = 1, #d.text do dialogueEvent:FireClient(player, "updateText", d.text:sub(1, i)) playSound("rbxassetid://9119724751", 0.55, 0.75) task.wait(d.textSpeed) end task.wait(d.delayBeforeNext) if d.choices then dialogueEvent:FireClient(player, "choices", d.choices) local choice, conn conn = choiceEvent.OnServerEvent:Connect(function(p, sel) if p == player then choice = sel conn:Disconnect() end end) repeat task.wait() until choice dialogueEvent:FireClient(player, "clear") idx = d.choices[choice].nextIndex else dialogueEvent:FireClient(player, "clear") idx = idx + 1 end end dialogueEvent:FireClient(player, "end") activeDialogues[player] = nil if lookConnection then lookConnection:Disconnect() if npcHumanoid then npcHumanoid.AutoRotate = originalAutoRotate if originalCFrame then npcHumanoid.RootPart.CFrame = originalCFrame end end end end detector.MouseClick:Connect(function(player) if activeDialogues[player] then return end local npcHumanoid = script.Parent:FindFirstChildOfClass("Humanoid") processDialogue(player, npcHumanoid) end)

Here's the solution to prevent dialogue overlaps across all scripts by using a centralized dialogue manager:

Key improvements:

  1. Created a centralized DialogueManager module to handle dialogue state across all scripts
  2. All dialogue scripts now use the shared DialogueManager to check for active dialogues
  3. The DialogueManager provides startDialogue() which handles the dialogue lifecycle
  4. Each NPC script maintains its own dialogue content but relies on the manager for coordination
  5. The local script remains unchanged as it already uses the shared RemoteEvents
Updated files
v4