Dialogue system in ModuleScript resets to intro dialogue after button click (state/index issue?)

So I have bit of weird problem. This is one section from my modulescript “DIAGHelper” which is a modulescript that handles dialogue system in my story game. I have other functions like TweenIn and TweenOut which would slide dialogue UI in-game in and out.

The real issue tho, I have this approach which is explained briefly in script. Upon joining, there’s automated intro dialogue (it have 10 lines in array), and when I clicked a object as trigger for random multiple-page dialogue sequence, it WOULDN’T work and have this bug where it would show the intro dialogue instead of the actual dialogue after clicking > button. This can be seen in clip below:

External Media

IT would get more nonsensical after more consecutive clicks which shows it’s probably skipping in index or something like that.
(I’m pretty sure this is probably scoping issue but I don’t know how to fix this)

Now if i change local dialogueIndex = 1 to local dialogueIndex = nil as to attempt close it after completion (as seen in the script with comment -- change to nil in second video example, this would happen:

External Media

What? It would work except there’s error in output and I don’t have any prior experience in modulescript, this is literally my first time because I am trying to learn from it and try something new. How would I fix this and is there any feedbacks any of you would have for me to improve upon my code?

--[[
So, we have DIAG Write function here.
p is for "paragraph", or aka single-page 
where script would default to assuming there's no "room".
Room is multi-page, seen after beating room and 
entering to next as to drive the story further.
]]


function DIAGHelper.Write(player,p,room)
	if not (room == nil) then
		local dialogueIndex = 1
		local Pages = #Rooms[room]
		
		DIAGHelper.TweenIn()
		TX.Text = Rooms[room][dialogueIndex]
		
		--print(dialogueIndex)
		
		DIAG.GO.MouseButton1Down:Connect(function()		
			if dialogueIndex == Pages then
				print("The end is reached.")
				DIAGHelper.TweenOut()
				dialogueIndex = 1 -- change to nil in second video example
				return
			end
			
			dialogueIndex += 1
			local dialogue = Rooms[room][dialogueIndex]
			TX.Text = dialogue
		end)
	else
		-- [Paragraph mode. Ignore.]
		DIAGHelper.TweenIn()
		TX.Text = p
		
		DIAG.GO.MouseButton1Down:Connect(function()
			DIAGHelper.TweenOut()
		end)
	end
end

disconnect the MouseButton1Down event when your done with it

so in your if dialogueIndex == Pages block, just disconnect MouseButton1Down

1 Like

Oh man. Everything just works now. Should had tried this again after changing the code.
Thanks so much!

For anybody reading this thread in future, I just added this to dialogueIndex == Pages block and “Paragraph mode” for single page dialogues

local Connection
Connection = DIAG.GO.MouseButton1Down:Connect(function()

--and right before return, i added this
Connection:Disconnect()

The issue you’re describing is a classic state management problem — your dialogueIndex variable isn’t properly isolated between different dialogue sequences, so they’re interfering with each other.Here’s what’s happening: when you use local dialogueIndex = 1 at the module level or within a function that persists, clicking the button increments that same index across all dialogue contexts. When you switch from intro dialogue to your clicked-object dialogue, the index doesn’t reset, so it’s reading from the wrong position in the new array.The fix is straightforward — use a table to track state per dialogue sequence:lualocal DIAGHelper = {}local dialogueStates = {} -- Track active dialogues by IDfunction DIAGHelper:StartDialogue(dialogueArray, dialogueID) dialogueID = dialogueID or "default" -- Initialize state for this specific dialogue dialogueStates[dialogueID] = { index = 1, array = dialogueArray } self:DisplayDialogue(dialogueID)endfunction DIAGHelper:NextLine(dialogueID) dialogueID = dialogueID or "default" local state = dialogueStates[dialogueID] if not state then return end state.index = state.index + 1 if state.index > #state.array then -- Dialogue complete dialogueStates[dialogueID] = nil return end self:DisplayDialogue(dialogueID)endKey changes:- Each dialogue sequence gets its own unique ID (e.g., “intro”, “trigger_001”)- State is stored in a table keyed by that ID, not as a single global index- When dialogue completes, clean up that state entryWhen your button is clicked, call DIAGHelper:NextLine("trigger_001") instead of a generic function. This way, intro dialogue stays on its own index while triggered dialogues maintain theirs independently.If you’re managing multiple simultaneous dialogues, this also scales properly without conflicts.

1 Like

This topic was automatically closed 14 days after the last reply. New replies are no longer allowed.