local media = LibStub:GetLibrary("LibSharedMedia-3.0"); local f = RaidFrameCustomization.frames; local positions = RaidFrameCustomization.positions; local pad = 2; local paddings = { TOPLEFT = {pad, -pad}, TOPRIGHT = {-pad, -pad}, CENTER = {0, 0}, BOTTOMLEFT = {pad, pad}, BOTTOMRIGHT = {-pad, pad} }; local watchedAuras; -- all watched auras local indicatorAuras; -- watched auras per indicator local auraFilters = {"HELPFUL", "HARMFUL"}; local DEFAULT_ICON = "Interface\\AddOns\\RaidFrameCustomization\\images\\rhomb"; local _; -- global functions used every update local GetTime = GetTime; local UnitAura = UnitAura; local UnitIsUnit = UnitIsUnit; local UnitIsConnected = UnitIsConnected; local UnitIsDeadOrGhost = UnitIsDeadOrGhost; local CompactRaidFrameContainer_ApplyToFrames = CompactRaidFrameContainer_ApplyToFrames; -- list of important auras TODO try to use spellIDs local centerAuras = { "Power Word: Shield" }; local function configureIndicators(frame) local frameName = frame:GetName(); if not f[frameName] then return end local config = RaidFrameCustomization.db.profile; local font = media and media:Fetch('font', config.indicatorFont) or STANDARD_TEXT_FONT; for pos, ind in pairs(f[frameName]) do ind.text:SetFont(font, config[pos]["textSize"]); ind.text:SetTextColor(unpack(config[pos]["color"])); ind.icon:SetWidth(config[pos]["iconSize"]); ind.icon:SetHeight(config[pos]["iconSize"]); ind.icon:SetTexture(DEFAULT_ICON); if config[pos]["showIcon"] then ind.icon:Show(); else ind.icon:Hide(); end end end -- Create the FontStrings used for indicators local function setupCompactUnitFrame(frame) local name = frame:GetName(); f[name] = {}; for _, pos in ipairs(positions) do f[name][pos] = {}; f[name][pos].text = frame:CreateFontString(nil, "OVERLAY", "GameFontHighlightSmall"); f[name][pos].text:SetPoint(pos, frame, pos, paddings[pos][1], paddings[pos][2]); f[name][pos].icon = frame:CreateTexture(nil, "OVERLAY"); f[name][pos].icon:SetPoint(pos, frame, pos, paddings[pos][1], paddings[pos][2]); end configureIndicators(frame); end -- Get all unit auras TODO change to event driven, only remaining updating with timer local function getAuras(unit) local unitAuras = {}; local auraName, icon, count, expires, caster, debuffType, spellId; local filter; for _, filter in ipairs(auraFilters) do local i = 1; while true do auraName, _, icon, count, debuffType, _, expires, caster, _, _, spellId = UnitAura(unit, i, filter); if not spellId then break end if watchedAuras[auraName] or watchedAuras[spellId] or watchedAuras[debuffType] then local aura = {}; aura.auraName = auraName; aura.spellId = spellId; aura.count = count; aura.expires = expires; aura.mine = UnitIsUnit(caster, "player"); aura.icon = icon; aura.debuffType = debuffType; table.insert(unitAuras, aura); end i = i + 1; end end return unitAuras; end -- Check the indicators on a frame and update the times on them local function updateIndicators(frame) if not frame.unit then return end local unit = frame.unit; local frameName = frame:GetName(); -- Check if the indicator object exists, else create it if not f[frameName] then setupCompactUnitFrame(frame) end -- Hide if unit is dead/disconnected if (not UnitIsConnected(unit)) or UnitIsDeadOrGhost(frame.displayedUnit) then for _, ind in pairs(f[frameName]) do ind.text:SetText(""); ind.icon:SetTexture(""); end return; end local unitAuras = getAuras(unit); for pos, ind in pairs(f[frameName]) do -- try to find matching aura local found, aura; for _, aura in pairs(unitAuras) do if indicatorAuras[pos][aura.auraName] or indicatorAuras[pos][aura.spellId] or indicatorAuras[pos][aura.debuffType] then found = aura; -- break on first matching buff/debuff cast by me -- otherwise continue through if aura.mine then break end end end local config = RaidFrameCustomization.db.profile[pos]; if found then if config.mine and not found.mine then -- don't show ind.icon:SetTexture(""); ind.text:SetText(""); else if config.showIcon and not config.useDefaultIcon then -- show icon TODO coloring ind.icon:SetTexture(found.icon); end -- TODO make show text into general setting -- under which you can select what text to show if config.showText then -- show text local text; local remaining = found.expires - GetTime(); if remaining > 60 then text = string.format("%dm", ceil(remaining/60)); else text = string.format("%d", floor(remaining+0.5)); end if config.stack and found.count > 0 then if text then text = found.count.."-"..text; else text = found.count; end end ind.text:SetText(text); end end else -- not found, show nothing ind.icon:SetTexture(""); ind.text:SetText(""); end end end -- Update all indicators function RaidFrameCustomization:UpdateAllIndicators() CompactRaidFrameContainer_ApplyToFrames(CompactRaidFrameContainer, "normal", updateIndicators); end -- Used to update everything that is affected by the configuration function RaidFrameCustomization:RefreshConfig() self:OnDisable(); -- clear everything if self.db.profile.enabled then CompactRaidFrameContainer_ApplyToFrames(CompactRaidFrameContainer, "normal", configureIndicators); -- Format aura strings watchedAuras = {}; indicatorAuras = {}; for _, pos in ipairs(positions) do indicatorAuras[pos] = {}; for _, aura in ipairs(self.db.profile[pos]["auras"]) do watchedAuras[aura] = true; indicatorAuras[pos][aura] = true; end end if next(watchedAuras) ~= nil then self.updateTimer = self:ScheduleRepeatingTimer("UpdateAllIndicators", 0.15); end end end