1 Indicators = LibStub("AceAddon-3.0"):NewAddon( "Indicators", "AceTimer-3.0");
2 local media = LibStub:GetLibrary("LibSharedMedia-3.0");
3 local f = {}; -- Indicator objects
6 local watchedAuras; -- all watched auras
7 local indicatorAuras; -- watched auras per indicator
8 local auraFilters = {"HELPFUL", "HARMFUL"};
9 local DEFAULT_ICON = "Interface\\AddOns\\RaidFrameCustomization\\images\\rhomb";
11 -- global functions used every update
12 local GetTime = GetTime;
13 local UnitAura = UnitAura;
14 local UnitIsUnit = UnitIsUnit;
15 local UnitIsConnected = UnitIsConnected;
16 local UnitIsDeadOrGhost = UnitIsDeadOrGhost;
18 -- list of important auras TODO try to use spellIDs
23 local function dPrint(s)
24 DEFAULT_CHAT_FRAME:AddMessage("Indicators: ".. tostring(s));
27 -- Hide buff/debuff icons
28 local function hideBlizzardBuffs(frame)
29 -- used in CompactUnitFrame_UpdateAuras (Buffs, Debuffs, DispellableDebuffs)
30 if frame.optionTable.displayBuffs then
31 frame.optionTable.displayBuffs = false
33 if frame.optionTable.displayDebuffs then
34 frame.optionTable.displayDebuffs = false
37 if frame.optionTable.displayDispelDebuffs then
38 frame.optionTable.displayDispelDebuffs = false
41 hooksecurefunc("DefaultCompactUnitFrameSetup", hideBlizzardBuffs);
43 -- Set the appearance of the FontStrings
44 local function setupIndicatorAppearance(frame)
45 local frameName = frame:GetName();
46 if not f[frameName] then return end
47 local font = media and media:Fetch('font', Indicators.db.profile.indicatorFont) or STANDARD_TEXT_FONT;
50 for i, ind in ipairs(f[frameName]) do
51 ind.text:SetFont(font, Indicators.db.profile["textSize"..i], "");
52 ind.icon:SetWidth(Indicators.db.profile["iconSize"..i]);
53 ind.icon:SetHeight(Indicators.db.profile["iconSize"..i]);
54 if Indicators.db.profile["showIcon"..i] then
62 -- Create the FontStrings used for indicators
63 local function setupCompactUnitFrame(frame)
64 local frameName = frame:GetName();
67 "TOPLEFT", "TOPRIGHT", "CENTER", "BOTTOMLEFT", "BOTTOMRIGHT"
70 {pad, -pad}, {-pad, -pad}, {0, 0}, {pad, pad}, {-pad, pad}
77 f[frameName][i].text = frame:CreateFontString(nil, "OVERLAY", "GameFontHighlightSmall");
78 f[frameName][i].text:SetPoint(positions[i], frame, positions[i], paddings[i][1], paddings[i][2]);
79 f[frameName][i].icon = frame:CreateTexture(nil, "OVERLAY");
80 f[frameName][i].icon:SetPoint(positions[i], frame, positions[i], paddings[i][1], paddings[i][2]);
82 setupIndicatorAppearance(frame);
86 local function getAuras(unit)
88 local auraName, icon, count, expires, caster, debuffType, spellId;
93 for _, filter in ipairs(auraFilters) do
96 auraName, _, icon, count, debuffType, _, expires, caster, _, _, spellId = UnitAura(unit, i, filter);
97 if not spellId then break end
98 if watchedAuras[auraName] or watchedAuras[spellId] or watchedAuras[debuffType] then
100 aura.auraName = auraName;
101 aura.spellId = spellId;
103 aura.expires = expires;
104 aura.mine = UnitIsUnit(caster, "player");
106 aura.debuffType = debuffType;
107 table.insert(unitAuras, aura);
115 -- Check the indicators on a frame and update the times on them
116 local function updateIndicator(frame)
117 if not frame.unit then return end
118 local unit = frame.unit;
119 local frameName = frame:GetName();
122 -- Check if the indicator object exists, else create it
123 if not f[frameName] then setupCompactUnitFrame(frame) end
124 -- Hide if unit is dead/disconnected
125 if (not UnitIsConnected(unit)) or UnitIsDeadOrGhost(frame.displayedUnit) then
126 for _, ind in pairs(f[frameName]) do
127 ind.text:SetText("");
128 ind.icon:SetTexture("");
133 local unitAuras = getAuras(unit);
134 for i, ind in ipairs(f[frameName]) do
135 -- try to find matching aura
137 for _, aura in pairs(unitAuras) do
138 if indicatorAuras[i][aura.auraName] or indicatorAuras[i][aura.spellId] or
139 indicatorAuras[i][aura.debuffType] then
141 -- break on first matching buff/debuff cast by me
142 -- otherwise continue through
143 if aura.mine then break end
148 if Indicators.db.profile["mine"..i] and not found.mine then
150 ind.icon:SetTexture("");
151 ind.text:SetText("");
153 if Indicators.db.profile["showIcon"..i] then
154 -- show icon TODO coloring
155 if Indicators.db.profile["useDefaultIcon"..i] then
156 ind.icon:SetTexture(DEFAULT_ICON);
158 ind.icon:SetTexture(found.icon);
161 -- TODO make show text into general setting
162 -- under which you can select what text to show
163 if Indicators.db.profile["showText"..i] then
166 local remaining = found.expires - GetTime();
167 if remaining > 60 then
168 text = string.format("%dm", ceil(remaining/60));
170 text = string.format("%d", floor(remaining+0.5));
173 if Indicators.db.profile["stack"..i] and found.count > 0 then
175 text = found.count.."-"..text;
182 ind.text:SetTextColor(
183 Indicators.db.profile["color"..i].r,
184 Indicators.db.profile["color"..i].g,
185 Indicators.db.profile["color"..i].b,
186 Indicators.db.profile["color"..i].a
188 if Indicators.db.profile["debuffColor"..i] then
189 if found.debuffType then
190 if found.debuffType == "Curse" then
191 ind.text:SetTextColor(0.6,0,1,1);
192 elseif found.debuffType == "Disease" then
193 ind.text:SetTextColor(0.6,0.4,0,1);
194 elseif found.debuffType == "Magic" then
195 ind.text:SetTextColor(0.2,0.6,1,1);
196 elseif found.debuffType == "Poison" then
197 ind.text:SetTextColor(0,0.6,0,1);
202 ind.text:SetText(text);
206 -- not found, show nothing
207 ind.icon:SetTexture("");
208 ind.text:SetText("");
213 -- Update all indicators
214 function Indicators:UpdateAllIndicators()
215 CompactRaidFrameContainer_ApplyToFrames(CompactRaidFrameContainer, "normal", updateIndicator);
218 -- Used to update everything that is affected by the configuration
219 function Indicators:RefreshConfig()
220 CompactRaidFrameContainer_ApplyToFrames(CompactRaidFrameContainer, "normal", setupIndicatorAppearance);
221 -- Format aura strings
226 indicatorAuras[i] = {};
227 for auraName in string.gmatch(Indicators.db.profile["auras"..i], "[^\n]+") do -- Grab each line
228 auraName = string.gsub(auraName, "^%s*(.-)%s*$", "%1"); -- Strip any whitespaces
229 if tonumber(auraName) then
230 watchedAuras[tonumber(auraName)] = true;
231 indicatorAuras[i][tonumber(auraName)] = true;
233 watchedAuras[auraName] = true;
234 indicatorAuras[i][auraName] = true;
239 self:CancelAllTimers();
240 if next(watchedAuras) ~= nil then
241 self.updateTimer = self:ScheduleRepeatingTimer("UpdateAllIndicators", 0.15);
245 function Indicators:OnInitialize()
247 self.db.RegisterCallback(self, "OnProfileChanged", "RefreshConfig");
248 self.db.RegisterCallback(self, "OnProfileCopied", "RefreshConfig");
249 self.db.RegisterCallback(self, "OnProfileReset", "RefreshConfig");
252 function Indicators:OnEnable()
253 if self.db.profile.enabled then
254 Indicators:RefreshConfig();
258 function Indicators:OnDisable()
260 self:CancelAllTimers();
261 for _, frame in pairs(f) do
262 for _, ind in pairs(frame) do
263 ind.text:SetText("");
264 ind.icon:SetTexture("");