1. I can't seem to figure our how to do a timer in Lua, I dont want to use any Ace Addons like candy bar yet because Im not done going thru the book as it is and Ace Addons are a whole differnt animal.

    is anyone able to share with me a way to do a countdown timer ?

     

    Chapter 19 has a section on creating a timer :)

    As Matthew said the addon in Chapter 19 uses a simple OnUpdate to simulate a timer, and that's how all of the systems that implement timers actually work.  Please feel free to post if you have any questions about it!

    Very nice!  It's good to do things like this one your own to figure out exactly how they work.  There are a few other time-like implementations out there that use different methods but if it works for you than congratulations!  If you're looking for more specific feedback feel free to say something and I'll take a deeper look ;-)

    i'll take this oppertunity to share my timer, the metatable could actually be replaced with an if check in there somewhere, but at the time i was playing with meta tables :P

    all my functions are in the GBMFunctions table, so thats about the only thing you have to change, otherwise its a cut and paste job. At the end there i have an example timer which will count to 5 and then stop. to make a new timer you just do: GBMFunctions.NewTimer(name , delay , PayloadFunction , resetvalue), if the reset value is less than the delay then the timer resets and so you have a kind of delayed for loop, in this case the payload function is passed the loop number and the number that the timer appears in the array so that the timer can be stopped . The timer is stopped with  GBMFunctions.TimerEnd(i) where i is the second argument passed to the payload function on a repeat. Delay timers stop themselves automatically. the only thing i think could be improved is currently the payload function isnt passed any custom arguments, but i dont really need that so i've not bothered.

    Im preety new to programming and im 100% self taught so any criticism / advice etc. is welcomed, here it is:

    GBMTimers = {}



    local Timermt = {} -- Meta table for data & timers



    function Timermt.__index(tbl, key) -- (Prevents timer from breaking most importantly)

    if key == "counter" then

    tbl[key] = 0

    end

    return "counter"

    end



    setmetatable(GBMTimers, Timermt)



    GBMTimers[1] = {

                            Name = "IDLEPROCESS",

                            delay = 100,

                            resetvalue = 0.1,

                            PayloadFunction = "TimerStop",

                            LoopNo = 0,

                            counter = 0,

                            }

                       



    function GBMFunctions.NewTimer(name , delay , PayloadFunction , resetvalue)

    if not GBMTimerFrame then GBMTimerFrame = CreateFrame("Frame") end



    -- Check For a timer with this name already, if it exists then remove it

    -- Needed mainly because events sometimes fire multiple times, if they call a timer then they are likely to create an error

    for i = 1, #GBMTimers do

    if (name == GBMTimers[i]["Name"]) then

    table.remove(GBMTimers, i)

    end

    end



    table.insert(GBMTimers , {

                            ["Name"] = name,

                            ["delay"] = delay,

                            ["resetvalue"] = resetvalue,

                            ["PayloadFunction"] = PayloadFunction,

                            ["LoopNo"] = 0,

                            ["counter"] = 0,



    })



        local function OnUpdate(self, elapsed)

        for i = 1, #GBMTimers do

        if (type(GBMTimers[i]["counter"]) == 'number') then --ignores the counter if it is a string (because metatable prevents error by returning string instead of nil)   counter auto- deletes at delay, but for loops have predetermined start and end values so you cant reduce number of loops.

        GBMTimers[i]["counter"] = GBMTimers[i]["counter"]+elapsed

        local PayloadFunction = GBMTimers[i]["PayloadFunction"]

        local counter = GBMTimers[i]["counter"]

        local delay = GBMTimers[i]["delay"]

        local resetvalue = GBMTimers[i]["resetvalue"]

        local name = GBMTimers[i]["Name"]

        -- DEFAULT_CHAT_FRAME:AddMessage(name .. ": " .. counter, 1, 1, 0)     -- Super Spam Counter, Use at Own Risk (debugging only)

        if (counter >= resetvalue) then

        GBMTimers[i]["counter"] = 0

        GBMTimers[i]["LoopNo"] = GBMTimers[i]["LoopNo"]+1

            if (type(GBMFunctions[PayloadFunction]) == 'function') then

            local LoopNo = GBMTimers[i]["LoopNo"]

            GBMFunctions[PayloadFunction](LoopNo , i)

            else

            GBMFunctions.out("Guild Bank Master: No Payload Function For Timer Could Be Found! Please report this error")

            end

        elseif (counter >= delay) then

            if (type(GBMFunctions[PayloadFunction]) == 'function') then

                GBMFunctions.TimerEnd(i)

                GBMFunctions[PayloadFunction]()

            else

            GBMFunctions.TimerEnd(i)

            end

        end

        end

        end

    end

    GBMTimerFrame:SetScript("OnUpdate", OnUpdate)

    GBMTimerFrame:Show()

    end



    function GBMFunctions.TimerStop() -- Stops the entire timer process when only the idle timer is running, checks every 5 s

    if #GBMTimers == 1 then

    GBMTimerFrame:Hide()

    end

    end



    function GBMFunctions.TimerEnd(i) -- ends a timer by position in the timer table, you should never "end" the IDLEPROCESS timer

    table.remove(GBMTimers, i)

    end





    function GBMFunctions.TrialTimer()

    GBMFunctions.NewTimer("TrialTimer" , 100 , "TrialTimerStop" , 1)

    end

    function GBMFunctions.TrialTimerStop(loopNo, i)

    DEFAULT_CHAT_FRAME:AddMessage("Trial Timer has reached loop number: " .. loopNo, 1, 1, 0)

    if loopNo >= 5 then

    GBMFunctions.TimerEnd(i)

    end

    end

    nahh it was just abit of sharing :) but i have to say its much easier to read with syntax hilighting