4 local GetSpecialization = GetSpecialization;
5 local UnitExists = UnitExists;
6 local UnitAura = UnitAura;
7 local GetTotemInfo = GetTotemInfo;
9 -- character specific frames
10 -- TODO try with auraFilter, remove characters, change to classes
13 ["PLAYER HELPFUL"] = {
16 auras = {["Divine Shield"]=1, ""},
31 ["PLAYER HELPFUL"] = {
34 auras = {["Judgment"]=1},
41 ["PLAYER HARMFUL"] = {
53 spec = 3, -- Retribution
55 auraFilter = "PLAYER HARMFUL",
56 x = 570, -- placed over Innervate frame
63 spec = 3, -- Retribution
64 auras = {"Divine Purpose"},
65 auraFilter = "PLAYER HELPFUL",
73 spec = 2, -- Protection
74 auras = {"Shield of the Righteous"},
75 auraFilter = "PLAYER HELPFUL",
83 auras = {"Divine Shield"},
84 auraFilter = "PLAYER HELPFUL",
96 auras = {"Bursting With Pride"},
97 auraFilter = "HELPFUL",
98 x = 570, -- placed over Innervate frame
105 auras = {"Divine Purpose"},
106 auraFilter = "PLAYER HELPFUL",
114 spec = 2, -- Protection
115 auras = {"Shield of the Righteous"},
116 auraFilter = "PLAYER HELPFUL",
124 auras = {"Seraphim", "Righteous Verdict"},
125 auraFilter = "PLAYER HELPFUL",
133 auras = {"Divine Shield"},
134 auraFilter = "PLAYER HELPFUL",
142 auras = {"Devotion Aura"},
143 auraFilter = "HELPFUL",
154 auras = {"Shadow Word: Pain", "Purge the Wicked"},
155 auraFilter = "PLAYER HARMFUL",
163 auras = {"Power Word: Fortitude"},
164 auraFilter = "HELPFUL",
173 auras = {"Overcharge Mana"},
174 auraFilter = "PLAYER HELPFUL",
183 totems = {1}, -- Efflorescence
193 auras = {"Tidal Waves"},
194 auraFilter = "PLAYER HELPFUL",
202 auras = {"Healing Rain"},
203 auraFilter = "PLAYER HELPFUL",
211 auras = {"Unleash Life"},
212 auraFilter = "PLAYER HELPFUL",
222 auras = {"Tidal Waves"},
223 auraFilter = "PLAYER HELPFUL",
231 auras = {"Healing Rain"},
232 auraFilter = "PLAYER HELPFUL",
240 auras = {"Unleash Life"},
241 auraFilter = "PLAYER HELPFUL",
252 auraFilter = "HELPFUL",
263 -- unit = unitID where to check auras, not required for totem checkers
264 -- spec = player spec index to show frame, if nil show always
265 -- auras = list of auras to track, in priority order
266 -- auraFilter = filter for UnitAura
267 -- totems = list of totem slots to track, in priority order, only checked if auras is nil
268 -- x = x position relative to UIParent bottom left
269 -- y = y position relative to UIParent bottom left
273 -- global frames' settings
277 auras = {"Innervate", "Gift of the Titans", "Power Infusion"},
278 auraFilter = "HELPFUL",
286 auras = {"Ineffable Truth"},
287 auraFilter = "HELPFUL",
296 "Delusions", "Entropic Blast", "Necrotic Embrace", "Flametouched", "Shadowtouched",
297 "Blazing Eruption", "Shattering Scream", "Consuming Hunger", "Unstable Soul",
298 "Time Bomb", "Broken Shard", "Demolished", "Fetid Rot", "Roiling Deceit",
299 "Putrid Blood", "Endemic Virus", "Lingering Infection", "Gigavolt Charge",
300 "Crackling Lightning", "Storm's Wail", "Death's Door", "Deathly Withering",
301 "Chilling Touch", "Volatile Charge", "Liquid Gold", "Drained Soul", "Evoke Anguish",
302 "Ancient Curse", "Corrosion", "Debilitating Spit", "Tasty Morsel", "Encroaching Shadows",
303 "Corrupted Existence", "Madness Bomb", "Crimson Chorus", "Essence Sap", "Bloodlight",
304 "Arcane Vulnerability", "Wicked Laceration", "Withering Touch"
306 auraFilter = "HARMFUL",
315 "Adaptive Membrane", "Gluttonous Miasma"
317 auraFilter = "HARMFUL",
326 local units = {}; -- mapping from unitID to frames
327 local totems = {}; -- mapping to frames with totems
329 for i = 1, MAX_BOSS_FRAMES do
330 bosses[i] = "boss"..i;
332 local currentSpec = 0; -- 0 is invalid
334 local Indicators = CreateFrame("Frame", "OmaTMW", UIParent);
336 local function updateAuraFrame(frame)
337 local unit = frame.unit;
338 if UnitExists(unit) and (not frame.spec or frame.spec == currentSpec) then
339 local name, icon, count, duration, expires;
340 local auraFilter = frame.auraFilter;
343 name, icon, count, _, duration, expires = UnitAura(unit, i, auraFilter);
344 if not name then break end
345 -- possible improvement to add spellID as an option
346 if frame.auras[name] and not frame.invert then
348 frame.stack:SetText(count);
354 frame.cd:SetCooldown(expires - duration, duration);
359 frame.icon:SetTexture(icon);
362 elseif frame.auras[name] and frame.invert then
363 frame.icon:SetTexture(icon);
370 frame:Show(); -- not functional without first hiding once to get SetTexture
377 local function updateAuras(unit)
379 for _, i in pairs(units[unit]) do
380 updateAuraFrame(frames[i]);
385 local function updateTotemFrame(frame, slot)
386 local _, name, start, duration, icon = GetTotemInfo(slot);
388 frame.cd:SetCooldown(start, duration);
390 frame.icon:SetTexture(icon);
397 local function updateTotems(slot)
399 for _, i in pairs(totems[slot]) do
400 updateTotemFrame(frames[i], slot);
405 local function createTMW(name, config, parent)
406 local frame = CreateFrame("Frame", name, parent);
407 frame:SetPoint("TOPLEFT", parent, "BOTTOMLEFT", config.x, config.y+config.height);
408 frame:SetPoint("BOTTOMRIGHT", parent, "BOTTOMLEFT", config.x+config.width, config.y);
409 frame.unit = config.unit;
410 frame.spec = config.spec;
413 for _, v in pairs(config.auras) do
414 frame.auras[v] = true;
417 frame.auraFilter = config.auraFilter;
418 frame.totems = config.totems;
419 frame.invert = config.invert;
421 frame.base = frame:CreateTexture(nil, "BACKGROUND");
422 frame.base:SetAllPoints();
423 frame.base:SetColorTexture(0, 0, 0, 0.6);
424 frame.icon = frame:CreateTexture(nil, "ARTWORK");
425 frame.icon:SetPoint("TOPLEFT", frame.base, "TOPLEFT", 1, -1);
426 frame.icon:SetPoint("BOTTOMRIGHT", frame.base, "BOTTOMRIGHT", -1, 1);
427 frame.icon:SetTexCoord(0.07, 0.93, 0.07, 0.93);
428 frame.stack = frame:CreateFontString(nil, "OVERLAY", "NumberFontNormalLarge");
429 frame.stack:SetFont(STANDARD_TEXT_FONT, 26, "OUTLINE");
430 frame.stack:SetPoint("TOPLEFT");
432 frame.cd = CreateFrame("Cooldown", name.."CD", frame, "CooldownFrameTemplate");
433 frame.cd:SetReverse(true);
434 frame.cd:SetAllPoints();
438 local function initialize()
439 Indicators:SetFrameStrata("LOW");
440 Indicators:SetPoint("BOTTOMLEFT");
441 Indicators:SetWidth(1);
442 Indicators:SetHeight(1);
443 currentSpec = GetSpecialization();
444 local name, realm = UnitFullName("player");
445 if chars[realm] and chars[realm][name] then
446 for _, config in pairs(chars[realm][name]) do
447 table.insert(settings, config)
450 for i, config in pairs(settings) do
452 if not units[config.unit] then units[config.unit] = {} end
453 table.insert(units[config.unit], i);
455 if config.totems then
456 for _, slot in pairs(config.totems) do
457 if not totems[slot] then totems[slot] = {} end
458 table.insert(totems[slot], i);
461 frames[i] = createTMW("OmaTMW"..i, config, Indicators);
464 for _, frame in pairs(frames) do
465 if frame.auras then updateAuraFrame(frame) end
467 for _, slot in pairs(frame.totems) do updateTotemFrame(frame, slot) end
472 Indicators:RegisterEvent("UNIT_AURA");
473 Indicators:RegisterEvent("PLAYER_TARGET_CHANGED");
474 Indicators:RegisterEvent("PLAYER_TOTEM_UPDATE");
475 Indicators:RegisterEvent("INSTANCE_ENCOUNTER_ENGAGE_UNIT");
476 Indicators:RegisterEvent("PLAYER_SPECIALIZATION_CHANGED");
477 Indicators:RegisterEvent("PLAYER_LOGIN");
478 Indicators:SetScript("OnEvent", function(self, event, arg1)
479 if event == "UNIT_AURA" then
481 elseif event == "PLAYER_TARGET_CHANGED" then
482 updateAuras("target");
483 elseif event == "PLAYER_TOTEM_UPDATE" then
485 elseif event == "INSTANCE_ENCOUNTER_ENGAGE_UNIT" then
486 for _, boss in pairs(bosses) do
489 elseif event == "PLAYER_SPECIALIZATION_CHANGED" then
490 currentSpec = GetSpecialization();
491 for _, frame in pairs(frames) do
492 if frame.auras then updateAuraFrame(frame) end
494 for _, slot in pairs(frame.totems) do updateTotemFrame(frame, slot) end
497 elseif event == "PLAYER_LOGIN" then