Countdown isnt working correctly

I’m trying to make a time limit for the player to answer the question, but it seems like the player is never able to answer. It will always return false from the countdown.

local function waitForAnswer(plr, answers)
	timeUp = false
	local count = 10
	
	while timeUp == false do
		wait(1)
		sounds.Tick:Play()
		count -= 1
		print(count)
		
		if count == 0 then
			timeUp = true
			sounds.Alarm:Play()
			return false
		end
	end
	
	local msg = plr.Chatted:Wait()
	
	if table.find(answers, string.lower(msg)) and timeUp == false then
		sounds.Guess:Play()
		timeUp = true
		return true
	elseif not table.find(answers, string.lower(msg)) and timeUp == false then
		sounds.Guess:Play()
		timeUp = true
		return false
	end
end

You have return false inside the while loop. It returns false when count reaches 0, which will always happen, so it will always return false, exiting the function and not reaching the lines below.

So how would i make sure this doesn’t happen?

return false exits the function, so if you don’t want it to return there, remove that line.

1 Like

I still want it to return false if the player doesn’t answer on time, but also if they answer incorrectly.

You have return false in 2 places. The first one is before it waits for the player to chat, so it never does.

1 Like

I understand now, you meant to have both running at once. It won’t wait for the player to chat until after the while loop finishes, but that’s meant to indicate they’ve run out of time. You want these to run concurrently, so you’ll need to make use of concurrency methods like task.spawn

1 Like

The code i’m using isn’t returning anything. I’m sure i’m doing something incorrect.

local function waitForAnswer(plr, answers)
	timeUp = false
	local count = 10
	
	task.spawn(function()
		while timeUp == false do
			wait(1)
			sounds.Tick:Play()
			count -= 1
			print(count)
			
			if count == 0 then
				timeUp = true
				sounds.Alarm:Play()
				break
			end
		end
		
		return false
	end)
	
	local msg = plr.Chatted:Wait()
	
	if table.find(answers, string.lower(msg)) and timeUp == false then
		sounds.Guess:Play()
		timeUp = true
		return true
	elseif not table.find(answers, string.lower(msg)) and timeUp == false then
		sounds.Guess:Play()
		timeUp = true
		return false
	end
end

@1waffle1

Sorry to intrude but there is a better way of doing this:

sounds.Guess:Play()
timeUp = true
return (table.find(answers, string.lower(msg)) and not timeUp)

The first return here is now inside another function, so it doesn’t influence the outer function. Something easy you could do is just set a variable to false if time runs out, and once the player does chat, check that variable and return false if they ran out of time before they chatted. If you want it to return immediately when thy either chat or run out of time then that’s a bit more complex.

local function waitForAnswer(plr,answers)
	local timeUp = false
	task.spawn(function() 
		for count = 10,0,-1 do
			sounds.Tick:Play()
			task.wait(1)
		end
		timeUp = true
		sounds.Alarm:Play()
	end)
	local msg = plr.Chatted:Wait()
	if (timeUp) then
		return false;
	end
	timeUp = true
	sounds.Guess:Play()
	return (table.find(answers, string.lower(msg)) and not timeUp)
end

The more complex solution which returns immediately either when the player chats or runs out of time might look something like this (untested)

local function waitForAnswer(plr, answers)
	local main = coroutine.running()
	local chatted
	local timeout = task.spawn(function()
		for i = 1, 10 do
			task.wait(1)
			sounds.Tick:Play()
		end
		sounds.Alarm:Play()
		chatted:Disconnect() -- stop waiting for the player to chat
		coroutine.resume(main, false)
	end)
	chatted = plr.Chatted:Once(function(msg)
		sounds.Guess:Play()
		local foundAnswer = table.find(answers, msg:lower())
		coroutine.close(timeout) -- cancel the countdown
		coroutine.resume(main, foundAnswer ~= nil)
	end)
	return coroutine.yield()
end

coroutine.yield() returns whatever additional arguments were passed to coroutine.resume, so whenever either thing happens, it cancels the other and resumes the calling coroutine.

1 Like

Why do you use coroutine rather than task? Literally the threads created are named task.[insert func name].

1 Like

coroutine.running() gets the current coroutine so I can resume it from one of the others with coroutine.resume. task.spawn returns a coroutine, so when I want to cancel the countdown because the player chatted, I can call coroutine.close on it so it doesn’t continue running. task.cancel might be more appropriate, I’m not sure what the difference is.

Works just fine with no errors! Thanks everyone for their help!

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