2 local unpack, ipairs, pairs, ceil, floor = unpack, ipairs, pairs, ceil, floor;
3 local UnitIsConnected, UnitIsDeadOrGhost = UnitIsConnected, UnitIsDeadOrGhost;
4 local UnitAura, UnitIsPlayer, GetTime = UnitAura, UnitIsPlayer, GetTime;
5 local UnitName, C_TimerAfter = UnitName, C_Timer.After;
6 local IsInGroup, IsInRaid, GetNumGroupMembers = IsInGroup, IsInRaid, GetNumGroupMembers;
7 local format = string.format;
9 local positions = OmaRF.positions;
10 local auraFilters = {"HELPFUL", "HARMFUL"};
11 local DEFAULT_ICON = "Interface\\AddOns\\OmaRF\\images\\rhomb";
16 local watchedAuras = {};
17 local majorAuras = {};
19 local partyState = "solo";
20 local partyMembers = {"player", "party1", "party2", "party3", "party4"};
22 local function remaining(expires, current)
23 if expires == 0 then return "" end
24 local remain = expires - current;
26 return format("%dm", ceil(remain/60));
28 return floor(remain+0.5);
31 local function showIndicator(ind, icon, caster, expires, current, config)
32 if not config.mine or UnitIsPlayer(caster) then
33 if config.showIcon then
34 if config.useDefaultIcon then
35 ind.icon:SetTexture(DEFAULT_ICON);
37 ind.icon:SetTexture(icon);
39 if not ind.icon:IsShown() then ind.icon:Show() end
41 ind.expires = expires;
42 if config.showText then
43 ind.text:SetText(remaining(expires, current));
44 if not ind.text:IsShown() then ind.text:Show() end
49 local function showMajorIndicator(ind, icon, count, expires, current)
50 ind.icon:SetTexture(icon);
51 ind.expires = expires;
52 ind.expireText:SetText(remaining(expires, current));
54 ind.stackText:SetText(count);
55 if not ind.stackText:IsShown() then ind.stackText:Show() end
57 if ind.stackText:IsShown() then ind.stackText:Hide() end
59 if not ind.icon:IsShown() then ind.icon:Show() end
60 if not ind.expireText:IsShown() then ind.expireText:Show() end
63 -- update current auras TODO add bar coloring back with extra options
64 local function updateAuras(frame, unit)
65 for _, ind in pairs(frame.inds) do ind.expires = nil end
66 for _, ind in ipairs(frame.majorInds) do ind.expires = nil end
68 local name, icon, count, expires, caster, id;
70 local current = GetTime();
71 for _, filter in ipairs(auraFilters) do
74 name, _, icon, count, _, _, expires, caster, _, _, id = UnitAura(unit, i, filter);
75 if not id then break end
76 local pos = watchedAuras[id] or watchedAuras[name];
79 frame.inds[pos], icon, caster, expires, current,
80 OmaRF.db.profile.indicators[pos]
83 if (majorAuras[id] or majorAuras[name]) and majorPos <= majorMax then
84 showMajorIndicator(frame.majorInds[majorPos], icon, count, expires, current);
85 majorPos = majorPos + 1;
92 -- Check the indicators on a frame and update the times on them
93 local function updateIndicators(frame, i)
94 local unit = "player";
95 if partyState == "solo" then
96 if frame:IsShown() then frame:Hide() end
98 elseif partyState == "raid" then
101 -- party frames have player separate
102 unit = partyState..(i-1);
105 if not UnitExists(unit) then
107 elseif not UnitIsConnected(unit) or UnitIsDeadOrGhost(unit) then
108 if frame:IsShown() then frame:Hide() end
110 elseif not frame:IsShown() then
114 local current = GetTime();
115 for pos, ind in pairs(frame.inds) do
116 if ind.expires ~= nil then
117 if OmaRF.db.profile.indicators[pos].showText then
118 ind.text:SetText(remaining(ind.expires, current));
121 if ind.icon:IsShown() then ind.icon:Hide() end
122 if ind.text:IsShown() then ind.text:Hide() end
125 for _, ind in ipairs(frame.majorInds) do
126 if ind.expires ~= nil then
127 ind.expireText:SetText(remaining(ind.expires, current));
129 if ind.icon:IsShown() then ind.icon:Hide() end
130 if ind.expireText:IsShown() then ind.expireText:Hide() end
131 if ind.stackText:IsShown() then ind.stackText:Hide() end
136 local function configureIndicators(frame)
137 local config = OmaRF.db.profile.indicators;
138 for pos, ind in pairs(frame.inds) do
139 ind.text:SetFont(STANDARD_TEXT_FONT, config[pos]["textSize"]);
140 ind.text:SetTextColor(unpack(config[pos]["textColor"]));
141 ind.icon:SetWidth(config[pos]["iconSize"]);
142 ind.icon:SetHeight(config[pos]["iconSize"]);
143 ind.icon:SetTexture(DEFAULT_ICON);
144 ind.icon:SetVertexColor(unpack(config[pos]["iconColor"]));
147 config = OmaRF.db.profile.majorAuras;
148 for i, ind in ipairs(frame.majorInds) do
150 ind.icon:ClearAllPoints();
151 ind.icon:SetPoint("CENTER", frame, "CENTER", -config["iconSize"], 0);
153 ind.icon:SetWidth(config["iconSize"]);
154 ind.icon:SetHeight(config["iconSize"]);
155 ind.expireText:SetFont(STANDARD_TEXT_FONT, config["textSize"], "OUTLINE");
156 ind.stackText:SetFont(STANDARD_TEXT_FONT, config["textSize"], "OUTLINE");
160 local function createIndicators(frame)
162 for _, pos in ipairs(positions) do
163 frame.inds[pos] = {};
164 frame.inds[pos].text = frame:CreateFontString(nil, "OVERLAY", "GameFontHighlightSmall");
165 frame.inds[pos].text:SetPoint(pos, frame, pos);
166 frame.inds[pos].icon = frame:CreateTexture(nil, "OVERLAY");
167 frame.inds[pos].icon:SetPoint(pos, frame, pos);
170 frame.majorInds = {};
171 majorMax = OmaRF.db.profile.majorAuras.max;
172 for i = 1, majorMax do
173 frame.majorInds[i] = {};
174 local ind = frame.majorInds[i];
175 ind.icon = frame:CreateTexture(nil, "OVERLAY");
177 ind.icon:SetPoint("TOPLEFT", frame.majorInds[i-1].icon, "TOPRIGHT");
179 ind.expireText = frame:CreateFontString(nil, "OVERLAY", "GameFontHighlightSmall");
180 ind.expireText:SetPoint("BOTTOMRIGHT", ind.icon, "BOTTOMRIGHT");
181 ind.stackText = frame:CreateFontString(nil, "OVERLAY", "GameFontHighlightSmall");
182 ind.stackText:SetPoint("TOPLEFT", ind.icon, "TOPLEFT");
185 configureIndicators(frame);
188 -- Update all indicators
189 local function updateAllIndicators()
190 for i, frame in ipairs(frames) do
191 updateIndicators(frame, i);
193 if OmaRF.running then C_TimerAfter(0.15, updateAllIndicators) end
196 -- Used to update everything that is affected by the configuration
197 function OmaRF:RefreshConfig()
198 self:OnDisable(); -- clear everything
199 if self.db.profile.enabled then
200 for _, f in pairs(frames) do configureIndicators(f) end
203 for _, pos in ipairs(positions) do
204 for _, aura in ipairs(self.db.profile.indicators[pos]["auras"]) do
205 watchedAuras[aura] = pos; -- TODO single aura only in one position
209 for _, aura in ipairs(self.db.profile.majorAuras["auras"]) do
210 majorAuras[aura] = true;
213 if next(watchedAuras) ~= nil or next(majorAuras) ~= nil then
214 if not frameBase:IsShown() then frameBase:Show() end
216 C_TimerAfter(0.15, updateAllIndicators);
221 local function updateStatusText(self, unit)
222 if not UnitIsConnected(unit) then
223 self.statusText:SetText("DC");
224 elseif UnitIsDeadOrGhost(unit) then
225 self.statusText:SetText("rip");
227 local healthLost = UnitHealthMax(unit) - UnitHealth(unit);
228 if healthLost <= 0 then
229 self.statusText:SetText("");
234 if healthLost > 1200000000 then -- 1.2B
235 prettyHealth = format("-%.1fB", healthLost / 1000000000);
236 elseif healthLost > 1200000 then -- 1.2M
237 prettyHealth = format("-%.1fM", healthLost / 1000000);
238 elseif healthLost > 1000 then -- 1K
239 prettyHealth = format("-%dK", healthLost / 1000);
241 prettyHealth = format("-%d", healthLost)
244 self.statusText:SetText(prettyHealth);
248 local function frameEvent(self, event, ...)
249 local arg1, arg2, arg3, arg4 = ...;
250 if event == "UNIT_HEALTH" or event == "UNIT_HEALTH_FREQUENT" then
251 updateStatusText(self, arg1);
252 elseif event == "UNIT_AURA" then
253 updateAuras(self, arg1);
257 --[[ TODO powerBar display and bar coloring
258 if options.displayPowerBar and role ~= "HEALER" then
259 frame.healthBar:SetPoint("BOTTOMRIGHT", frame, "BOTTOMRIGHT", -1, 1);
260 frame.powerBar:Hide();
264 --local update_ooc = false;
265 local function updateFrames()
266 if not IsInGroup() or GetNumGroupMembers() == 1 then
269 local frame = frames[1];
270 frame:UnregisterAllEvents();
271 frame:RegisterUnitEvent("UNIT_AURA", "player");
272 frame:RegisterUnitEvent("UNIT_HEALTH", "player");
273 frame:RegisterUnitEvent("UNIT_HEALTH_FREQUENT", "player");
277 for i, frame in ipairs(frames) do
278 local name = partyState..i;
279 if not UnitExists(name) then break end
280 frame:UnregisterAllEvents();
281 frame:RegisterUnitEvent("UNIT_AURA", name);
282 frame:RegisterUnitEvent("UNIT_HEALTH", name);
283 frame:RegisterUnitEvent("UNIT_HEALTH_FREQUENT", name);
286 partyState = "party";
287 for i, name in ipairs(partyMembers) do
288 local frame = frames[i];
289 if not UnitExists(name) then break end
290 frame:UnregisterAllEvents();
291 frame:RegisterUnitEvent("UNIT_AURA", name);
292 frame:RegisterUnitEvent("UNIT_HEALTH", name);
293 frame:RegisterUnitEvent("UNIT_HEALTH_FREQUENT", name);
297 --[[for name, frame in pairs(frames) do
298 local unitFrame = _G[name];
300 if not frame.unitFrameSetup then
301 if InCombatLockdown() then
304 unitFrame.name:SetFont(STANDARD_TEXT_FONT, 12, "");
305 unitFrame.optionTable.displayBuffs = false;
306 unitFrame.optionTable.displayDebuffs = false;
307 unitFrame.optionTable.displayDispelDebuffs = false;
308 frame.unitFrameSetup = true;
311 local unit = unitFrame.unit;
313 if InCombatLockdown() then
316 local name = UnitName(unit);
317 unitFrame.name:SetText(name);
324 local function createStatusText(frame)
325 frame.statusText = frame:CreateFontString(nil, "OVERLAY", "GameFontHighlightSmall");
326 frame.statusText:SetPoint("CENTER", frame, "CENTER");
327 frame.statusText:SetFont(STANDARD_TEXT_FONT, 14, "");
330 local function initialize(frame)
331 frames[1] = CreateFrame("Frame", "OmaRF1", frameBase);
332 frames[1]:SetAllPoints("CompactRaidFrame1"); -- only connection to blizzard frames
333 frames[1]:SetScript("OnEvent", frameEvent);
335 createStatusText(frames[1]);
336 createIndicators(frames[1]);
338 -- TODO size could change
339 local width, height = frames[1]:GetWidth(), frames[1]:GetHeight();
341 frames[i] = CreateFrame("Frame", "OmaRF"..i, frameBase);
342 frames[i]:SetPoint("TOPLEFT", frames[i-1], "BOTTOMLEFT");
343 frames[i]:SetWidth(width);
344 frames[i]:SetHeight(height);
345 frames[i]:SetScript("OnEvent", frameEvent);
347 createStatusText(frames[i]);
348 createIndicators(frames[i]);
353 frames[i] = CreateFrame("Frame", "OmaRF"..i, frameBase);
354 frames[i]:SetPoint("TOPLEFT", frames[x*5+y], "TOPRIGHT");
355 frames[i]:SetWidth(width);
356 frames[i]:SetHeight(height);
357 frames[i]:SetScript("OnEvent", frameEvent);
359 createStatusText(frames[i]);
360 createIndicators(frames[i]);
364 C_TimerAfter(0.01, updateFrames);
367 local function baseEvent(self, event, ...)
368 if event == "GROUP_ROSTER_UPDATE" then
369 -- not sure if fired before LayoutFrames, wait a bit
370 C_TimerAfter(0.01, updateFrames);
371 --[[elseif event == "PLAYER_REGEN_ENABLED" then
376 elseif event == "PLAYER_LOGIN" then
381 frameBase = CreateFrame("Frame", nil, UIParent);
382 frameBase:SetFrameStrata("HIGH");
383 frameBase:RegisterEvent("PLAYER_LOGIN");
384 frameBase:RegisterEvent("PLAYER_REGEN_ENABLED");
385 frameBase:RegisterEvent("GROUP_ROSTER_UPDATE");
386 frameBase:SetScript("OnEvent", baseEvent);
387 OmaRF.frameBase = frameBase;
389 -- hide buffs, debuffs from Blizzard frames
390 --DefaultCompactUnitFrameOptions.displayBuffs = false;
391 --DefaultCompactUnitFrameOptions.displayDebuffs = false;
392 --DefaultCompactUnitFrameOptions.displayDispelDebuffs = false;