-- Indicators.lua local pairs, ipairs = pairs, ipairs; local floor = math.floor; local GetTime = GetTime; local UnitExists = UnitExists; local UnitAura = UnitAura; local CreateFrame = CreateFrame; local UnitIsDeadOrGhost, UnitIsConnected = UnitIsDeadOrGhost, UnitIsConnected; local CTimerAfter = C_Timer.After; local Settings = OmaRFSettings; local majorAuras = Settings.MajorAuras; local watchedAuras = {}; local updaters = {}; local updating = {}; local updateAuras; local M = {}; OmaRFIndicators = M; M.Class = {}; function M.SetupIndicators(frame, class) frame.indBase = CreateFrame("Frame", nil, frame); frame.indBase:SetAllPoints(); frame.indBase:Hide(); if M.Class[class] then watchedAuras = M.Class[class].Auras; frame.inds = M.Class[class].Setup(frame.indBase); else frame.inds = {}; end frame.majorBase = CreateFrame("Frame", nil, frame); frame.majorBase:SetPoint("TOPLEFT", frame, "TOPLEFT", 4, -10); frame.majorBase:SetPoint("BOTTOMRIGHT"); frame.majors = {}; for i = 1,3 do local tex = frame.majorBase:CreateTexture(nil, "OVERLAY"); tex = frame.majorBase:CreateTexture(nil, "OVERLAY"); if i == 1 then tex:SetPoint("TOPLEFT", frame.majorBase, "TOPLEFT"); else tex:SetPoint("TOPLEFT", frame.majors[i-1], "TOPRIGHT"); end tex:SetWidth(20); tex:SetHeight(20); tex:Hide(); tex.text = frame.majorBase:CreateFontString(nil, "OVERLAY", "GameFontHighlight"); tex.text:SetPoint("CENTER", tex, "BOTTOMRIGHT", -2, 2); tex.text:Hide(); tex.stack = frame.majorBase:CreateFontString(nil, "OVERLAY", "GameFontHighlight"); tex.stack:SetPoint("CENTER", tex, "TOPLEFT", 1, 0); tex.stack:Hide(); tex.icon = true; frame.majors[i] = tex; end frame.throttle = function() frame.throttled = nil; if UnitExists(frame.displayed) then return updateAuras(frame, frame.displayed); end end; end local function remaining(text, expires, current) if expires == 0 then text:SetText(""); return false; end local remain = expires - current; if remain > 8 then text:SetText(""); else text:SetText(floor(remain+0.5)); end return true; end local function updateIndicators(frame) local unit = frame.displayed; if not frame:IsShown() or not UnitIsConnected(unit) or UnitIsDeadOrGhost(unit) then updating[frame] = nil; return; end local needUpdate = false; local current = GetTime(); for _, ind in pairs(frame.inds) do if ind.text and ind.text.expires ~= nil then needUpdate = remaining(ind.text, ind.text.expires, current) or needUpdate; end end for _, ind in pairs(frame.majors) do if ind.text and ind.text.expires ~= nil then needUpdate = remaining(ind.text, ind.text.expires, current) or needUpdate; end end if needUpdate then CTimerAfter(0.20, updaters[frame]); else updating[frame] = nil; end end local function showInd(ind, expires, current, count, icon) local needUpdate = false; if ind.icon then ind:SetTexture(icon); end if ind.text then needUpdate = remaining(ind.text, expires, current); ind.text.expires = expires; ind.text:Show(); end if ind.stack and count > 1 then ind.stack:SetText(count); ind.stack:Show(); end ind:Show(); return needUpdate; end local function hideInd(ind) if ind.text then ind.text.expires = nil; ind.text:Hide(); end if ind.stack then ind.stack:Hide() end ind:Hide(); end function M.UpdateAuras(frame, unit) local current = GetTime(); if frame.throttled then return; elseif frame.prevUpdate and current - frame.prevUpdate < 0.2 then frame.throttled = true; return CTimerAfter(0.2, frame.throttle); end frame.prevUpdate = current; for _, ind in pairs(frame.inds) do hideInd(ind); end local icon, count, expires, id; local showInds, needUpdate = false, false; local i = 1; while true do _, icon, count, _, _, expires, _, _, _, id = UnitAura(unit, i, "PLAYER HELPFUL"); if not id then break end local pos = watchedAuras[id]; if pos then needUpdate = showInd(frame.inds[pos], expires, current, count, icon) or needUpdate; showInds = true; end i = i + 1; end if showInds then frame.indBase:Show(); if needUpdate and not updating[frame] then updating[frame] = true; -- race? -- create a function for updating the indicator local func = updaters[frame]; if not func then func = function() updateIndicators(frame) end; updaters[frame] = func; end CTimerAfter(0.20, func); end else frame.indBase:Hide(); end end updateAuras = M.UpdateAuras; function M.UpdateMajorAuras(frame, unit) for _, ind in pairs(frame.majors) do hideInd(ind); end if UnitIsDeadOrGhost(unit) then return end local name, icon, count, expires, id; local showMajors, needUpdate = false, false; local majorPos = 1; local alert = false; -- color the whole bar local current = GetTime(); local i = 1; while true do name, icon, count, _, _, expires, _, _, _, id = UnitAura(unit, i, "HARMFUL"); if not id or majorPos > 3 then break end local major = majorAuras[id] or majorAuras[name]; if major then if not major.noicon then needUpdate = showInd(frame.majors[majorPos], expires, current, count, icon) or needUpdate; end if major.bar then alert = major.bar end showMajors = true; majorPos = majorPos + 1; end i = i + 1; end if showMajors then frame.majorBase:Show(); if needUpdate and not updating[frame] then updating[frame] = true; -- race? -- create a function for updating the indicator local func = updaters[frame]; if not func then func = function() updateIndicators(frame) end; updaters[frame] = func; end CTimerAfter(0.20, func); end else frame.majorBase:Hide(); end return alert; end