---@class Delay ---@field delay number Tick delay count ---@field curTick number Current tick countdown ---@field ready boolean Whether the delay is ready to fire ---@field active boolean Whether the delay needs to count down Delay = {} Delay.prototype = { delay = 0, curTick = 0, ready = true, active = true } Delay.mt = {} Delay.mt.__index = Delay.prototype ---Create a new Delay object ---@param o table|nil ---@return Delay function Delay.new(o) o = o or {} setmetatable(o, Delay.mt) return o end ---@class DelayManager DelayManager = {} ---@type table Delays = {} ---Add a named delay timer (returns early if name is not defined) ---@param name string ---@param delay number function DelayManager.add(name, delay) if not name then return end Delays[name] = Delay.new({ delay = delay, curTick = 0, ready = true, active = true }) end ---Remove a named delay timer ---@param name string function DelayManager.remove(name) if Delays[name] then Delays[name] = nil end end ---Get all registered delays as a name->Delay map ---@return table function DelayManager.getAll() local r = {} for k, v in pairs(Delays) do r[k] = v end return r end ---Update the delay value by name ---@param name string ---@param delay number function DelayManager.setDelay(name, delay) local d = Delays[name] if d then d.delay = delay end end ---Update the delay toggle by name ---@param name string function DelayManager.toggleDelay(name) local d = Delays[name] if d then d.active = ! d.active end end ---Get the delay toggle for by name ---@param name string function DelayManager.isActive(name) local d = Delays[name] if d then return d.active end return false end ---Check if a named delay is ready; if so, reset its countdown and arm it for the next cycle, returns false if the delay is not found ---@param name string ---@return boolean function DelayManager.ready(name) local d = Delays[name] if not d then print("DelayManager.ready: no delay found for name ", name) return false end if d.ready then d.curTick = d.delay d.ready = false return true end return false end ---Tick all or specific delay down by one. Call once per player tick. --- @param name string? function DelayManager.update(name) if not name then for k, v in pairs(Delays) do if not v.active then break --[[ break early, we don't need to tick a delay that's disabled ]] end if v.curTick <= 0 then v.ready = true break --[[ break early, we don't need to tick a delay that's already ready ]] end if v.curTick > 0 then v.curTick = v.curTick - 1 end end else local d = Delays[name] if d then if not d.active then return end if d.curTick <= 0 then d.ready = true else d.curTick = d.curTick - 1 end end end end return DelayManager