Counting down from a Number (Clientside)

How would I count down from a designated number in the clientside realm? I feed it a variable (let say 10) and the text dynamic changes every 1 second.

You can do it several ways. What’s it for exactly?

I did this for my MOTD system to have the accept button disabled until the time is up, and it changes the text.

The way I did it was by doing a for i = 1, wait_time_in_seconds do loop.

Inside, this was the logic which is pretty straight forward. If it counted down to 0 ( note, this means the loop is at the end, and the wait_time - loop index integer is 0 ) then set text to LANG Accept.

Otherwise, simply set the text to LANG Accept, with a counter in parenthesis.

[lua] for i = 1, MOTD_ACCEPT_WAIT do
timer.Simple( i, function( )
if ( MOTD_ACCEPT_WAIT - i == 0 ) then
_accept:SetText( “#Accept” )
else
_accept:SetText( “#Accept” … " ( " … MOTD_ACCEPT_WAIT - i … " ) " )
end
end )
end[/lua]

So, that’s a way using timers.

Another way would be if your logic is being run in a tick/think/draw/paint/render hook where it’s being called frequently enough to call basic logic. There, you’d just create a start time, and when the end should come. Counting up, subtract the end and you have your basic counter until something happens.

I’m still a tad confused (My brain is fuzzy tonight). As an example with a fixed number, here is what it’s for.

http://cloud-4.steampowered.com/ugc/600391697141640076/BAAD47EBD0FC47AE58EDEEED64AAA5B6AC70C4FB/

This should get you started.
[lua]
local time = 10
timer.Create(ply:EntIndex()…"_respawntimer", 1, 10, function()
time = time - 1
if time == 0 then
–do stuff
end
end)
[/lua]

[lua]
//This is what I have serverside so far

function GM:PlayerDeath( ply, weapon, killer )
ply:Lock()
local time = 10
umsg.Start( “dead” );
umsg.Short( time );
umsg.End();
timer.Create(“DeathTimer”…ply:UserID(), time, 1, function()
ply:UnLock()
ply:Spawn()
end)
end
[/lua]

[lua]
//clientside
local time = data:ReadShort()
[/lua]

What is the direct way to draw the countdown?

This is something you could use as a base.
[lua]
if SERVER then
util.AddNetworkString(“ply_DeathTimer”)

local deathDelay = 10
hook.Add("PlayerDeath", "Delay.PlayerDeath", function(ply)
	ply:Lock()
	net.Start("ply_DeathTimer")
	net.Send(ply)
	timer.Simple(deathDelay, function()
		if !IsValid(ply) then return end
		ply:UnLock()
		ply:Spawn()
	end)
end)

else
net.Receive(“ply_DeathTimer”, function(len)
local deathDelay = 10
timer.Create(“Delay.DeathTimer”, 1, 10, function()
deathDelay = deathDelay - 1
end)

	hook.Add("HUDPaint", "Delay.HUDPaint", function()
		local ply = LocalPlayer()
		if !IsValid(ply) or deathDelay == 0 then 
			hook.Remove("HUDPaint", "Delay.HUDPaint") 
		end
		
		draw.RoundedBox(0, 0, 0, ScrW(), ScrH(), Color(255,0,0,150))
		draw.DrawText("You can respawn in "..deathDelay.." seconds.", "TabLarge", ScrW()/2, ScrH()/2, Color(255,255,255), TEXT_ALIGN_CENTER)
	end)
end)

end
[/lua]

My code could actually work for you. Just set the WAIT variable to 10, and where it says SetText #Accept, put you may respawn now, where it has the timer, just add your text and leave that logic the same.

So, on popup of that vgui, do that simple logic and you’re done!

Of course, a lot of these others would work fine.

Why would you use a timer for this…? It’s easier to just use CurTime.

Here’s an example of what I mean:

[lua]
local time = 0

hook.Add( “HUDPaint”, “Let’s count”, function()
if time <= CurTime() then
time = CurTime() + 10
end

local num = math.Round( time - CurTime() )

draw.SimpleText( "Countdown: "..tostring( num ), "Default", ScrW()/2, ScrH()/2, color_white, TEXT_ALIGN_CENTER )

end )[/lua]

CurTime is synchronized between the client and server, and it’s constantly increasing, so you don’t need to change the value yourself; you won’t get a small amount of difference between the client and server either, as you would if you used timers and usermessages to send and keep track of the value.

By the way, don’t lock the player. Use PlayerDeathThink.

Just for you:
[lua]
local spawnDelay = 5
if SERVER then
AddCSLuaFile()
hook.Add(“PlayerDeath”, “Delay.PlayerDeath”, function(ply)
ply.SpawnDelay = CurTime() + spawnDelay
end)

hook.Add("PlayerDeathThink", "Delay.PlayerDeathThink", function(ply)
	if (CurTime() &gt;= ply.SpawnDelay) then
		return
	end
	return false
end)

else
local timeLeft, countdown
hook.Add(“HUDPaint”, “Delay.HUDPaint”, function()
local ply = LocalPlayer()
if !IsValid(ply) then return end

	if ply:Alive() then
		if ply.SpawnDelay then
			ply.SpawnDelay = false
		end
	else
		if !ply.SpawnDelay then
			ply.SpawnDelay = CurTime() + spawnDelay
		else
			countdown = math.Round(math.Clamp(ply.SpawnDelay-CurTime(), 0, spawnDelay))
			timeLeft = "in "..countdown.." seconds."
			if countdown == 1 then
				timeLeft = "in "..countdown.." second."
			elseif countdown == 0 then
				timeLeft = "at any time."
			end
			draw.RoundedBox(0, 0, 0, ScrW(), ScrH(), Color(255,0,0,150))
			draw.DrawText("You may respawn "..timeLeft, "TabLarge", ScrW()/2, ScrH()/2, Color(255,255,255), TEXT_ALIGN_CENTER)
		end
	end
end)

end
[/lua]

That’s the thing, it depends where it’s being run. If it’s a VGUI element, I’m not going to add a Tick/Think hook unless it’s absolutely necessary. Adding 10/11 simple timers to achieve the same goal is more ideal than using a Tick/Think hook just for this purpose.

If he’s drawing this in the hud already, then yes a counter using CurTime or RealTime would work quite well. It really just depends on where it’s being called. He posted a snippet of code, which sends data via UMSG; I don’t know if on the other end it creates a Vgui element, or if it just displays it on the other end. It would be ideal to maybe create a Vgui or HUDPaint hook for the duration of the counter and then depending which route you use, a timer setup or a dynamic counter to count down and then destructing that hook when the count is finished.