Countdown goes fast for some reason

Hi, so I’m making a script where the enemy team players have to capture their enemy’s towns/cities. So when an enemy player captures a town, it shows that the specific town is being captured and then a 30 second countdown timer goes off. It works but the problem is that every time an enemy player stops making contact with the capture part for each town and comes back to it, the countdown goes faster for some reason.

-- Server Script for each town (town hall)
local module = require(game.ServerScriptService.Modules.TownCaptureModule)

--// Town Essentials \\--
local townhall = script.Parent
local townname = townhall.TownName
local towncolor = townhall.TownColor
local towncapturepart = townhall.TownCapturePart
local currentcountry = townhall.CurrentCountry

local debounce = false
local timer = townhall.Timer
local yellowstonecolor = Color3.fromRGB(255, 225, 0)
local lakewoodcolor = Color3.fromRGB(4, 175, 236)
local PlayersInTownHall = {}

towncapturepart.Touched:Connect(function(hit)
	local player = game.Players:GetPlayerFromCharacter(hit.Parent)
	local char = player.Character or player.CharacterAdded:Wait()
	local hum = char:FindFirstChild("Humanoid")
	local humrootpart = char:FindFirstChild("HumanoidRootPart")
	local soldierstats = char:FindFirstChild("SoldierStats")
	
	if player and not table.find(PlayersInTownHall, player) then --if player and not PlayersInTownHall[player] then
		if debounce == false then
			debounce = true
			
			table.insert(PlayersInTownHall, player)
			
			if hum and soldierstats then
				if soldierstats.NationName.Value == "Yellowstone" and currentcountry.Value == "Yellowstone" or soldierstats.NationName.Value == "Lakewood" and currentcountry.Value == "Lakewood" then
					
				elseif soldierstats.NationName.Value == "Yellowstone" and currentcountry.Value ~= "Yellowstone" or soldierstats.NationName.Value == "Lakewood" and currentcountry.Value ~= "Lakewood" then
					hum.JumpPower = 0
					module.ShowCaptureTownMessage(townname.Value, soldierstats.NationName.Value)
					module.CreateCaptureTimer(player, timer)

					while timer.Value > 0 do	--for i = timer.Value, 0, -1 do
						timer.Value -= 1
						
						towncapturepart.TouchEnded:Connect(function(touch)
							local plr = game.Players:GetPlayerFromCharacter(touch.Parent)
							
							for i = 1, #PlayersInTownHall do
								if PlayersInTownHall[i] == plr then
									--table.remove(PlayersInTownHall, i)
									--plr.PlayerGui.Main.CaptureTimeText.Visible = false
									--player.PlayerGui.Main.CaptureTimeText.Text = "30s"
									--timer = 30
									module.DestroyCaptureTimer(plr)
									hum.JumpPower = 50
									table.remove(PlayersInTownHall, i)
									timer.Value = 30
									debounce = false
									break
								end
							end
						end)
						
						hum.Died:Connect(function()
							for i = 1, #PlayersInTownHall do
								if PlayersInTownHall[i] == player then
									module.DestroyCaptureTimer(player)
									hum.JumpPower = 50
									table.remove(PlayersInTownHall, i)
									timer.Value = 30
									debounce = false
									break
								end
							end
						end)

						if timer.Value <= 0 then
							module.DestroyCaptureTimer(player)
							module.CaptureTown(townhall, townname.Value, hit.Parent.SoldierStats.FlagID.Value, hit.Parent.SoldierStats.NationName.Value)
							--player.PlayerGui.Main.CaptureTimeText.Text = "30s"
							hum.JumpPower = 50
							timer.Value = 30
							debounce = false
							break
						end
						
						wait(1)
					end
				end
			end
		end
	end
end)
-- ModuleScript for capturing towns
local module = {}

function module.CreateCaptureTimer(player, timer)
	local textlabel = Instance.new("TextLabel")
	textlabel.Parent = player.PlayerGui.Main
	textlabel.Name = "CaptureTimeText"
	textlabel.BackgroundTransparency = 1
	textlabel.BorderSizePixel = 0
	textlabel.Position = UDim2.new(.344, 0, .169, 0)
	textlabel.Size = UDim2.new(0, 600, 0, 50)
	textlabel.Font = Enum.Font.RobotoMono
	textlabel.TextScaled = true
	textlabel.TextColor3 = Color3.fromRGB(255, 255, 255)
	textlabel.TextStrokeTransparency = 0
	textlabel.TextWrapped = true
	textlabel.Text = timer.Value.."s"
	textlabel.Visible = true
	
	timer:GetPropertyChangedSignal("Value"):Connect(function()
		textlabel.Text = timer.Value.."s"
	end)
end

function module.DestroyCaptureTimer(player)
	local capturetimetext = player.PlayerGui.Main:FindFirstChild("CaptureTimeText")
	
	if capturetimetext then
		capturetimetext:Destroy()
	end
end

function module.ShowCaptureTownMessage(townname, nationname)
	for i, player in pairs(game.Players:GetPlayers()) do		
		local textlabel = Instance.new("TextLabel")
		textlabel.Parent = player.PlayerGui.Main
		textlabel.Name = "TownIsBeingCapturedText"
		textlabel.BackgroundTransparency = 1
		textlabel.BorderSizePixel = 0
		textlabel.Position = UDim2.new(.344, 0, .1, 0)
		textlabel.Size = UDim2.new(0, 600, 0, 50)
		textlabel.Font = Enum.Font.RobotoMono
		textlabel.TextScaled = true
		textlabel.TextColor3 = Color3.fromRGB(255, 255, 255)
		textlabel.TextStrokeTransparency = 0
		textlabel.TextWrapped = true
		textlabel.Text = townname.." is being captured by "..nationname
		textlabel.Visible = true

		wait(3)
		textlabel:Destroy()
	end
end

function module.PlayCaptureSound()
	local sound = Instance.new("Sound")
	sound.Parent = workspace.Map.Sounds
	sound.Name = "CaptureSound"
	sound.Volume = 10
	sound.SoundId = "rbxassetid://233422074"
	sound:Play()
end

function module.CaptureTown(townhall, townname, flagid, currentcountry)
	townhall.CurrentCountry.Value = currentcountry

	for i, player in pairs(game.Players:GetPlayers()) do
		local textlabel = Instance.new("TextLabel")
		textlabel.Parent = player.PlayerGui.Main
		textlabel.Name = "TownCapturedText"
		textlabel.BackgroundTransparency = 1
		textlabel.BorderSizePixel = 0
		textlabel.Position = UDim2.new(.344, 0, .1, 0)
		textlabel.Size = UDim2.new(0, 600, 0, 50)
		textlabel.Font = Enum.Font.RobotoMono
		textlabel.TextScaled = true
		textlabel.TextColor3 = Color3.fromRGB(255, 255, 255)
		textlabel.TextStrokeTransparency = 0
		textlabel.TextWrapped = true
		textlabel.Text = townname.." has been captured by "..currentcountry
		textlabel.Visible = true
		
		module.PlayCaptureSound()
		
		for i, flagpart in pairs(townhall.Flag.Flag:GetChildren()) do
			flagpart.TextureID = flagid
		end

		wait(3)
		textlabel:Destroy()
	end
end

return module

He does have a wait(1) towards the end of the code

Actually, it does have a wait and it’s on the bottom of the loop. It doesn’t matter if it’s on the top or bottom. And I tried using a for loop and it didn’t solve the issue.

But the thing is you have it set to everytime you hit the object it starts up the decrement, its probably because you don’t break the while loop, it continues to decrement and keeps making multiple while loops everytime you touch. Consider breaking the entire while loop immediately when player steps off

Well, I did add the break keyword, shouldn’t it completely break the loop? In multiple conditions such as the TouchEnded event and the player’s Died event should break the loop completely.

your break in this particular instance appears to just be breaking the for loop within not the entirety of the while loop

if timer.Value <= 0 then
							module.DestroyCaptureTimer(player)
							module.CaptureTown(townhall, townname.Value, hit.Parent.SoldierStats.FlagID.Value, hit.Parent.SoldierStats.NationName.Value)
							--player.PlayerGui.Main.CaptureTimeText.Text = "30s"
							hum.JumpPower = 50
							timer.Value = 30
							debounce = false
							break
						end

this section will break the while loop due to it just being an if statement and its in the while loop so it will break the while loop

Oh crap, you’re right. So then where do I put the other break statement then? I obviously can’t put it inside the TouchEnded event and if I put it inside the loop, it’ll just break the loop without waiting for the timer to hit 0.

It depends how you want condition to be established, i.e. what are your goals with touchended event?

are you checking if there are no players on the object or everytime a person steps off it resets timer? I can’t really tell what your purpose I just see you checking if player exists in townhall table then destroy timer and then set timer to 30?

i just might have a hard time understanding it so idk if i can help any further

You know how king of the hill (KOTH) works? Players have to defend their hill from being captured by the enemy, the hill has a little capture part where anyone can step on it to capture the hill and if the player steps away from the hill, then the hill stops its capture progress. Same thing here, I need the TouchEnded event so that if the player steps away or dies, then the capture progress should not continue. Otherwise, all the player has to do is step on the capture part and leave to the next town hall and it’s not going to be fair. And the timer is there to count the amount of time you need to capture the town, which takes 30 seconds. If the player leaves the town/town hall, then the timer has to reset.

Maybe I’m not understanding, but can you just use wait()

There’s already a wait function which waits 1 second so that the timer can decrease by 1 (second). Plus, if I had left it as wait() then it would wait its default value which is .33 milliseconds and would decrease the timer by .33 milliseconds which would be too fast for a countdown like that.