Would my script cause a stack overflow?

Hello! I’m making a turn-based RPG and I came across a recursion error while implementing a new feature today. The error kinda happens at random and I’m not sure how I triggered it. I’ve been spending most of today trying to figure out what is causing it as I haven’t had any problems while testing it for the past few weeks. Unfortunately I wasn’t thinking right and didn’t screen cap my error. But it said that the error came from a boolean value and I don’t believe it told me where it was having said error.

The new feature shouldn’t have anything to do with it as it’s disabled until it needs to be used. So I’m thinking it’s the main battle script that is causing the problem or I had a bad plugin. I updated my plugins and doubled checked to make sure they weren’t made by shady accounts. I’ve updated a few lines in the main script. So far I haven’t been able to get the recursion error again but I just want to double check and make sure that there isn’t major flaws that I’m missing.

Below is the current main battle script.

game.ReplicatedStorage.RemoteEvents.SpawnerEvent:FireServer(script, script)
local battleCanStart = false
local winNum = 1
local turnList = {}
game.ReplicatedStorage.RemoteEvents.TurnTableDataSendEvent.OnClientEvent:Connect(function(turnTable, enemyNum, partyNum)
	turnList = turnTable
	winNum = enemyNum
	battleCanStart = true
end)
local function turnStart() -- Starts the next unit's turn
	if 	script.EnemiesDefeated.Value ~= winNum then
		script.TurnOver.Value = false
		if turnList[1][1].Stats.IsInLineUp.Value == true then
			local curTurnPart = workspace.AreaMovementPoints.CurrentTurn
			local unit = turnList[1][1]
			script.Parent.BattleTextBlack.Text = turnList[1][1].Stats.UnitModel.Value.Name .. "'s turn..."
			wait(1)
			game.ReplicatedStorage.RemoteEvents.MoveAUnit:FireServer(unit, curTurnPart, turnList[1][5], 1.5)
			game.ReplicatedStorage.RemoteEvents.CameraMove:FireServer(turnList[1][4])
			turnList[1][1].Stats.Fight.Disabled = false
		elseif turnList[1][1].Stats.IsInLineUp.Value == false then -- Checks to see if the unit who is next in line is an active party memeber. If they aren't they are skipped.
			script.TurnOver.Value = true
		end
	end
end


script.TurnOver.Changed:Connect(function() -- once the current unit has acted it moves them to the end of the turn list.
	if script.TurnOver.Value == true and turnList[1][1].Stats.HP.Value > 0 then
		local newLastPlace =  turnList[1]
		local num = table.getn(turnList)
		local unit = turnList[1][1]
		game.ReplicatedStorage.RemoteEvents.MoveAUnit:FireServer(unit, turnList[1][3], turnList[1][5], 1,5)
		table.remove(turnList, 1)
		table.insert(turnList,num, newLastPlace)
		turnStart()
	elseif script.TurnOver.Value == true and turnList[1][1].Stats.HP.Value <= 0 then
		local newLastPlace =  turnList[1]
		local num = table.getn(turnList)
		local unit = turnList[1][1]
		table.remove(turnList, 1)
		table.insert(turnList,num, newLastPlace)
		turnStart()
	end
end)


repeat wait()
	

until battleCanStart == true
script.Parent.BattleTextBlack.Text = "Enemies approach!"
wait(5)
turnStart()


script.EnemiesDefeated.Changed:Connect(function() -- Ends battle once all enemies are defeated.
	if script.EnemiesDefeated.Value == winNum then
		wait(2.5)
		script.Parent.BattleTextBlack.Text = "All enemies have been defeated!"
		local party = workspace.TheParty:GetChildren()
		wait(1.5)
		local cam = workspace.Camera
		local brandNewCam = workspace.CameraParts.BattleEndCam.CFrame
		local TweenService = game:GetService("TweenService")
		local function tween(startcam, unitCam)

			local tweenInfo = TweenInfo.new(
				1,
				Enum.EasingStyle.Sine,
				Enum.EasingDirection.In,
				0,
				false,
				0
			)

			cam.CameraType = Enum.CameraType.Scriptable

			local tween = TweenService:Create(cam, tweenInfo, {CFrame = unitCam})
			tween:Play()
		end
		tween(workspace.CameraParts.BattleStartCam, brandNewCam)
		wait(2)
		local time = 0.001
		for i = workspace.BGMandSE.Music.NormalBattle.Volume, 0, -0.01  do
			wait(time)
			workspace.BGMandSE.Music.NormalBattle.Volume = i
		end
		workspace.BGMandSE.Music.NormalBattle:Stop()
		workspace.BGMandSE.Music.NormalBattle.Volume = workspace.BGMandSE.Music.Volume
		workspace.Camera.CameraType = Enum.CameraType.Custom
		game.ReplicatedStorage.RemoteEvents.PutBack:FireServer(party)
		local enemyButtons = script.Parent.EnemyList.EnemyListFrame:GetChildren()
		for i,v in pairs(enemyButtons) do
			if v.Name ~= "UIGridLayout" then
				v:Destroy()
			end
		end
		script.Parent.Parent.Parent.Character.Humanoid.WalkSpeed = 25
		script.AreaScript.Value.Disabled = false
		script.Parent.BattleTextBlack.Visible = false
		script.Parent.BattleTextWhite.Visible = false
		script.Parent.BattleTextBG.Visible = false
		script.Parent.CurrentPartyStats.Enabled = false
		script.EnemiesDefeated.Value = 0
		script.Disabled = true
	end
end)


script.Fleeing.Changed:Connect(function()
	if script.Fleeing.Value == true then
		wait(2)
		local time = 0.001
		for i = workspace.BGMandSE.Music.NormalBattle.Volume, 0, -0.01  do
			wait(time)
			workspace.BGMandSE.Music.NormalBattle.Volume = i
		end
		workspace.BGMandSE.Music.NormalBattle:Stop()
		workspace.BGMandSE.Music.NormalBattle.Volume = workspace.BGMandSE.Music.Volume
		workspace.Camera.CameraType = Enum.CameraType.Custom
		local enemies = workspace.Enemies:GetChildren()
		local enemyButtons = script.Parent.EnemyList.EnemyListFrame:GetChildren()
		game.ReplicatedStorage.RemoteEvents.RemoveEnemy:FireServer(enemies)
		local party = workspace.TheParty:GetChildren()
		game.ReplicatedStorage.RemoteEvents.PutBack:FireServer(party)
		local enemies = script.Parent.EnemyList:GetChildren()
		for i,v in pairs(enemyButtons) do
			if v.Name ~= "UIGridLayout" then
				v:Destroy()
			end
		end
		script.Parent.Parent.Parent.Character.Humanoid.WalkSpeed = 25
		script.Parent.BattleChoices.Swap.CurrentPerson.Value.Fight.Disabled = true
		script.AreaScript.Value.Disabled = false
		script.Parent.BattleTextBlack.Visible = false
		script.Parent.BattleTextWhite.Visible = false
		script.Parent.BattleTextBG.Visible = false
		script.Parent.CurrentPartyStats.Enabled = false
		script.Fleeing.Value = false
		script.Disabled = true
	end
end)

What I’m most concerned about is the changed event that’s right after the turnStart() function. Because I call this function within the event and the function changes the value, would this cause an recursion? If it does what would be a good work around? Also any other critiques are welcomed!

Thank you in advance! =)

1 Like

It shouldn’t since you changing TurnOver is dependent on another variable and not itself

3 Likes

Yeah from what I can tell I probably just had a bad plugin. So I’m gonna just label your post as the solution. Thank you for your help!

1 Like