local f = OmaRF.frames; local majorFrames = OmaRF.majorFrames; local positions = OmaRF.positions; local pad = 2; local paddings = { TOPLEFT = {pad, -pad}, TOPRIGHT = {-pad, -pad}, CENTER = {0, 0}, BOTTOMLEFT = {pad, pad}, BOTTOMRIGHT = {-pad, pad} }; local watchedAuras; local majorAuras; local majorMax; local auraFilters = {"HELPFUL", "HARMFUL"}; local DEFAULT_ICON = "Interface\\AddOns\\OmaRF\\images\\rhomb"; local _; -- global functions used every update local C_TimerAfter = C_Timer.After; local GetTime = GetTime; local UnitAura = UnitAura; local UnitIsPlayer = UnitIsPlayer; local UnitIsConnected = UnitIsConnected; local UnitIsDeadOrGhost = UnitIsDeadOrGhost; local CompactRaidFrameContainer_ApplyToFrames = CompactRaidFrameContainer_ApplyToFrames; local format = string.format; local unpack = unpack; local floor = floor; local ceil = ceil; -- update current auras hooksecurefunc("CompactUnitFrame_UpdateAuras", function(frame) local frameName = frame:GetName(); if f[frameName] then for _, ind in pairs(f[frameName]) do ind.expires = nil end for _, ind in ipairs(majorFrames[frameName]) do ind.expires = nil end local name, icon, count, expires, caster, id; local unit = frame.displayedUnit; local majorI = 1; for _, filter in ipairs(auraFilters) do local i = 1; while true do name, _, icon, count, _, _, expires, caster, _, _, id = UnitAura(unit, i, filter); if not id then break end local pos = watchedAuras[id] or watchedAuras[name]; if pos then local ind = f[frameName][pos]; local config = OmaRF.db.profile.indicators[pos]; if not config.mine or UnitIsPlayer(caster) then if config.useDefaultIcon then ind.icon:SetTexture(DEFAULT_ICON); else ind.icon:SetTexture(icon); end ind.expires = expires; end end if (majorAuras[id] or majorAuras[name]) and majorI <= majorMax then local ind = majorFrames[frameName][majorI]; ind.icon:SetTexture(icon); ind.expires = expires; if count > 1 then ind.stackText:SetText(count); end majorI = majorI + 1; end i = i + 1; end end end end); local function configureIndicators(frame, name) local frameName = name or frame:GetName(); if not f[frameName] then return end local config = OmaRF.db.profile.indicators; for pos, ind in pairs(f[frameName]) do ind.text:SetFont(STANDARD_TEXT_FONT, config[pos]["textSize"]); ind.text:SetTextColor(unpack(config[pos]["textColor"])); ind.icon:SetWidth(config[pos]["iconSize"]); ind.icon:SetHeight(config[pos]["iconSize"]); ind.icon:SetTexture(DEFAULT_ICON); ind.icon:SetVertexColor(unpack(config[pos]["iconColor"])); end config = OmaRF.db.profile.majorAuras; for i, ind in ipairs(majorFrames[frameName]) do if i == 1 then ind.icon:ClearAllPoints(); ind.icon:SetPoint("CENTER", frame, "CENTER", -config.iconSize, 0); end ind.icon:SetWidth(config.iconSize); ind.icon:SetHeight(config.iconSize); ind.expireText:SetFont(STANDARD_TEXT_FONT, config["textSize"], "OUTLINE"); ind.stackText:SetFont(STANDARD_TEXT_FONT, config["textSize"], "OUTLINE"); end end -- Create the FontStrings used for indicators local function setupCompactUnitFrame(frame, name) 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 local config = OmaRF.db.profile.majorAuras; majorFrames[name] = {}; for i = 1, config.max do majorFrames[name][i] = {}; majorFrames[name][i].icon = frame:CreateTexture(nil, "OVERLAY"); if i > 1 then majorFrames[name][i].icon:SetPoint("TOPLEFT", majorFrames[name][i-1].icon, "TOPRIGHT"); end majorFrames[name][i].expireText = frame:CreateFontString(nil, "OVERLAY", "GameFontHighlightSmall"); majorFrames[name][i].expireText:SetPoint("BOTTOMRIGHT", majorFrames[name][i].icon, "BOTTOMRIGHT"); majorFrames[name][i].stackText = frame:CreateFontString(nil, "OVERLAY", "GameFontHighlightSmall"); majorFrames[name][i].stackText:SetPoint("TOPLEFT", majorFrames[name][i].icon, "TOPLEFT"); end configureIndicators(frame, name); end local function remaining(expires, current) if expires == 0 then return "" end local remain = expires - current; if remain > 60 then return format("%dm", ceil(remain/60)); end return floor(remain+0.5); end local function hide(frameName) for _, ind in pairs(f[frameName]) do ind.text:Hide(); ind.icon:Hide(); end for _, ind in ipairs(majorFrames[frameName]) do ind.icon:Hide(); ind.expireText:Hide(); ind.stackText:Hide(); end end -- Check the indicators on a frame and update the times on them local function updateIndicators(frame) local frameName = frame:GetName(); local unit = frame.unit; if not unit then return end -- possible if the frame is just being hidden -- Create indicators if needed, out of combat if forbidden if not f[frameName] then if frame:IsForbidden() then if not OmaRF.ooc_queue[frameName] then OmaRF.ooc_queue[frameName] = { func = setupCompactUnitFrame, args = { frame, frameName } }; end return; else setupCompactUnitFrame(frame, frameName); end end -- Reset current hide(frameName); -- Hide if unit is dead/disconnected if (not UnitIsConnected(unit)) or UnitIsDeadOrGhost(frame.displayedUnit) then return; end local current = GetTime(); for pos, ind in pairs(f[frameName]) do if ind.expires ~= nil then local config = OmaRF.db.profile.indicators[pos]; if config.showIcon then ind.icon:Show(); end if config.showText then ind.text:SetText(remaining(ind.expires, current)); ind.text:Show(); end end end for _, ind in ipairs(majorFrames[frameName]) do if ind.expires ~= nil then ind.icon:Show(); ind.expireText:SetText(remaining(ind.expires, current)); ind.expireText:Show(); ind.stackText:Show(); end end end -- Update all indicators function OmaRF:UpdateAllIndicators() CompactRaidFrameContainer_ApplyToFrames(CompactRaidFrameContainer, "normal", updateIndicators); if OmaRF.running then C_TimerAfter(0.15, OmaRF.UpdateAllIndicators); end end -- Used to update everything that is affected by the configuration function OmaRF:RefreshConfig() self:OnDisable(); -- clear everything if self.db.profile.enabled then CompactRaidFrameContainer_ApplyToFrames(CompactRaidFrameContainer, "normal", configureIndicators); watchedAuras = {}; for _, pos in ipairs(positions) do for _, aura in ipairs(self.db.profile.indicators[pos]["auras"]) do watchedAuras[aura] = pos; -- TODO single aura only in one position end end majorAuras = {}; for _, aura in ipairs(self.db.profile.majorAuras["auras"]) do majorAuras[aura] = true; end majorMax = OmaRF.db.profile.majorAuras["max"]; if next(watchedAuras) ~= nil or next(majorAuras) ~= nil then self.running = true; C_TimerAfter(0.15, self.UpdateAllIndicators); end end end