fac8827 - aura updates
[wowui.git] / OmaTMW / TellMeWhen.lua
1 -- TellMeWhen.lua
2 local _;
3 local pairs = pairs;
4 local GetSpecialization = GetSpecialization;
5 local UnitExists = UnitExists;
6 local UnitAura = UnitAura;
7 local GetTotemInfo = GetTotemInfo;
8
9 -- character specific frames
10 -- TODO try with auraFilter, remove characters, change to classes
11 --[[local classes = {
12     ["PALADIN"] = {
13         ["PLAYER HELPFUL"] = {
14             {
15                 unit = "player",
16                 auras = {["Divine Shield"]=1, ""},
17                 frames = {
18                     [1] = {
19                         x = 0,
20                         y = 0,
21                         width = 1,
22                         height = 1,
23                     },
24                 },
25             },
26         },
27     },
28 };
29 local specs = {
30     [retSpecid] = {
31         ["PLAYER HELPFUL"] = {
32             {
33                 unit = "player",
34                 auras = {["Judgment"]=1},
35                 frames = {
36                     [1] = {
37                     },
38                 },
39             },
40         },
41         ["PLAYER HARMFUL"] = {
42             {
43             },
44         },
45     },
46 };
47 --]]
48 local chars = {
49     ["Sylvanas"] = {
50         ["Vildana"] = {
51             {
52                 unit = "target",
53                 spec = 3, -- Retribution
54                 auras = {"Judgment"},
55                 auraFilter = "PLAYER HARMFUL",
56                 x = 570, -- placed over Innervate frame
57                 y = 440,
58                 width = 80,
59                 height = 80,
60             },
61             {
62                 unit = "player",
63                 spec = 3, -- Retribution
64                 auras = {"Divine Purpose"},
65                 auraFilter = "PLAYER HELPFUL",
66                 x = 570,
67                 y = 530,
68                 width = 40,
69                 height = 40,
70             },
71             {
72                 unit = "player",
73                 spec = 2, -- Protection
74                 auras = {"Shield of the Righteous"},
75                 auraFilter = "PLAYER HELPFUL",
76                 x = 570,
77                 y = 440,
78                 width = 80,
79                 height = 80,
80             },
81             {
82                 unit = "player",
83                 auras = {"Divine Shield"},
84                 auraFilter = "PLAYER HELPFUL",
85                 x = 660,
86                 y = 440,
87                 width = 80,
88                 height = 80,
89             },
90         },
91     },
92     ["Stormreaver"] = {
93         ["Vildan"] = {
94             {
95                 unit = "target",
96                 auras = {"Bursting With Pride"},
97                 auraFilter = "HELPFUL",
98                 x = 570, -- placed over Innervate frame
99                 y = 440,
100                 width = 80,
101                 height = 80,
102             },
103             {
104                 unit = "player",
105                 auras = {"Divine Purpose"},
106                 auraFilter = "PLAYER HELPFUL",
107                 x = 570,
108                 y = 530,
109                 width = 40,
110                 height = 40,
111             },
112             {
113                 unit = "player",
114                 spec = 2, -- Protection
115                 auras = {"Shield of the Righteous"},
116                 auraFilter = "PLAYER HELPFUL",
117                 x = 570,
118                 y = 440,
119                 width = 60,
120                 height = 60,
121             },
122             {
123                 unit = "player",
124                 spec = 2, -- Protection
125                 auras = {"Shining Light"},
126                 auraFilter = "PLAYER HELPFUL",
127                 x = 630,
128                 y = 440,
129                 width = 60,
130                 height = 60,
131             },
132             {
133                 unit = "player",
134                 auras = {"Seraphim", "Righteous Verdict"},
135                 auraFilter = "PLAYER HELPFUL",
136                 x = 570,
137                 y = 480,
138                 width = 40,
139                 height = 40,
140             },
141             {
142                 unit = "player",
143                 auras = {"Divine Shield"},
144                 auraFilter = "PLAYER HELPFUL",
145                 x = 660,
146                 y = 440,
147                 width = 80,
148                 height = 80,
149             },
150             {
151                 unit = "player",
152                 auras = {"Devotion Aura"},
153                 auraFilter = "HELPFUL",
154                 invert = true,
155                 x = 720,
156                 y = 440,
157                 width = 60,
158                 height = 60,
159             },
160         },
161         ["Gilden"] = {
162             {
163                 unit = "target",
164                 auras = {"Shadow Word: Pain", "Purge the Wicked"},
165                 auraFilter = "PLAYER HARMFUL",
166                 x = 660,
167                 y = 440,
168                 width = 60,
169                 height = 60,
170             },
171             {
172                 unit = "player",
173                 auras = {"Power Word: Fortitude"},
174                 auraFilter = "HELPFUL",
175                 invert = true,
176                 x = 720,
177                 y = 440,
178                 width = 60,
179                 height = 60,
180             },
181             {
182                 unit = "player",
183                 auras = {"Overcharge Mana"},
184                 auraFilter = "PLAYER HELPFUL",
185                 x = 720,
186                 y = 440,
187                 width = 60,
188                 height = 60,
189             },
190         },
191         ["Gedren"] = {
192             {
193                 totems = {1}, -- Efflorescence
194                 x = 660,
195                 y = 440,
196                 width = 80,
197                 height = 80,
198             },
199         },
200         ["Gazden"] = {
201             {
202                 unit = "player",
203                 auras = {"Tidal Waves"},
204                 auraFilter = "PLAYER HELPFUL",
205                 x = 660,
206                 y = 440,
207                 width = 40,
208                 height = 40,
209             },
210             {
211                 unit = "player",
212                 auras = {"Healing Rain"},
213                 auraFilter = "PLAYER HELPFUL",
214                 x = 700,
215                 y = 440,
216                 width = 40,
217                 height = 40,
218             },
219             {
220                 unit = "player",
221                 auras = {"Unleash Life"},
222                 auraFilter = "PLAYER HELPFUL",
223                 x = 740,
224                 y = 440,
225                 width = 40,
226                 height = 40,
227             },
228         },
229         ["Gran"] = {
230             {
231                 unit = "player",
232                 auras = {"Tidal Waves"},
233                 auraFilter = "PLAYER HELPFUL",
234                 x = 660,
235                 y = 440,
236                 width = 40,
237                 height = 40,
238             },
239             {
240                 unit = "player",
241                 auras = {"Healing Rain"},
242                 auraFilter = "PLAYER HELPFUL",
243                 x = 700,
244                 y = 440,
245                 width = 40,
246                 height = 40,
247             },
248             {
249                 unit = "player",
250                 auras = {"Unleash Life"},
251                 auraFilter = "PLAYER HELPFUL",
252                 x = 740,
253                 y = 440,
254                 width = 40,
255                 height = 40,
256             },
257         },
258         ["Gedrin"] = {
259             {
260                 unit = "pet",
261                 auras = {"Frenzy"},
262                 auraFilter = "HELPFUL",
263                 x = 660,
264                 y = 440,
265                 width = 40,
266                 height = 40,
267             },
268         },
269         ["Iled"] = {
270             {
271                 unit = "player",
272                 auras = {"Arcane Intellect"},
273                 auraFilter = "HELPFUL",
274                 invert = true,
275                 x = 720,
276                 y = 460,
277                 width = 60,
278                 height = 60,
279             },
280             {
281                 unit = "player",
282                 auras = {"Rune of Power"},
283                 auraFilter = "PLAYER HELPFUL",
284                 x = 660,
285                 y = 460,
286                 width = 40,
287                 height = 40,
288             },
289             {
290                 unit = "target",
291                 spec = 3, -- Frost
292                 auras = {"Winter's Chill"},
293                 auraFilter = "PLAYER HARMFUL",
294                 x = 700,
295                 y = 460,
296                 width = 40,
297                 height = 40,
298             },
299             {
300                 unit = "player",
301                 spec = 2, -- Fire
302                 auras = {"Sun King's Blessing"},
303                 auraFilter = "PLAYER HELPFUL",
304                 x = 700,
305                 y = 460,
306                 width = 40,
307                 height = 40,
308             },
309             {
310                 unit = "player",
311                 spec = 3, -- Frost
312                 auras = {"Icy Veins"},
313                 auraFilter = "PLAYER HELPFUL",
314                 x = 660,
315                 y = 420,
316                 width = 40,
317                 height = 40,
318             },
319             {
320                 unit = "player",
321                 spec = 2, -- Fire
322                 auras = {"Combustion"},
323                 auraFilter = "PLAYER HELPFUL",
324                 x = 660,
325                 y = 420,
326                 width = 40,
327                 height = 40,
328             },
329             {
330                 unit = "player",
331                 spec = 2, -- Fire
332                 auras = {"Infernal Cascade"},
333                 auraFilter = "PLAYER HELPFUL",
334                 x = 620,
335                 y = 420,
336                 width = 40,
337                 height = 40,
338             },
339             {
340                 unit = "player",
341                 auras = {"Alter Time"},
342                 auraFilter = "PLAYER HELPFUL",
343                 x = 700,
344                 y = 420,
345                 width = 40,
346                 height = 40,
347             },
348         },
349     },
350 };
351
352 -- settings entry:
353 -- unit = unitID where to check auras, not required for totem checkers
354 -- spec = player spec index to show frame, if nil show always
355 -- auras = list of auras to track, in priority order
356 -- auraFilter = filter for UnitAura
357 -- totems = list of totem slots to track, in priority order, only checked if auras is nil
358 -- x = x position relative to UIParent bottom left
359 -- y = y position relative to UIParent bottom left
360 -- width = width
361 -- height = height
362
363 -- global frames' settings
364 local settings = {
365     {
366         unit = "player",
367         auras = {"Innervate", "Gift of the Titans", "Power Infusion"},
368         auraFilter = "HELPFUL",
369         x = 570,
370         y = 440,
371         width = 80,
372         height = 80,
373     },
374     {
375         unit = "player",
376         auras = {"Ineffable Truth"},
377         auraFilter = "HELPFUL",
378         x = 570,
379         y = 440,
380         width = 40,
381         height = 40,
382     },
383     {
384         unit = "player",
385         auras = {
386             "Delusions", "Entropic Blast", "Necrotic Embrace", "Flametouched", "Shadowtouched",
387             "Blazing Eruption", "Shattering Scream", "Consuming Hunger", "Unstable Soul",
388             "Time Bomb", "Broken Shard", "Demolished", "Fetid Rot", "Roiling Deceit",
389             "Putrid Blood", "Endemic Virus", "Lingering Infection", "Gigavolt Charge",
390             "Crackling Lightning", "Storm's Wail", "Death's Door", "Deathly Withering",
391             "Chilling Touch", "Volatile Charge", "Liquid Gold", "Drained Soul", "Evoke Anguish",
392             "Ancient Curse", "Corrosion", "Debilitating Spit", "Tasty Morsel", "Encroaching Shadows",
393             "Corrupted Existence", "Madness Bomb", "Crimson Chorus", "Essence Sap", "Bloodlight",
394             "Arcane Vulnerability", "Wicked Laceration", "Withering Touch", "Fragment of Destiny",
395             "Flameclasp Eruption", "Wailing Arrow", "Frozen Destruction",
396             "Remnant: Mort'regar's Echoes", "Barbed Arrow", "Scorn", "Ire", "Song of Dissolution",
397             "Grim Portent", "Exposed Threads of Fate", "Despair"
398         },
399         auraFilter = "HARMFUL",
400         x = 660,
401         y = 530,
402         width = 80,
403         height = 80,
404     },
405     {
406         unit = "player",
407         auras = {
408             "Adaptive Membrane", "Gluttonous Miasma", "Remnant: Soulforge Heat"
409         },
410         auraFilter = "HARMFUL",
411         x = 660,
412         y = 780,
413         width = 160,
414         height = 160,
415     },
416 };
417
418 local frames = {};
419 local units = {}; -- mapping from unitID to frames
420 local totems = {}; -- mapping to frames with totems
421 local bosses = {};
422 for i = 1, MAX_BOSS_FRAMES do
423     bosses[i] = "boss"..i;
424 end
425 local currentSpec = 0; -- 0 is invalid
426
427 local Indicators = CreateFrame("Frame", "OmaTMW", UIParent);
428
429 local function updateAuraFrame(frame)
430     local unit = frame.unit;
431     if UnitExists(unit) and (not frame.spec or frame.spec == currentSpec) then
432         local name, icon, count, duration, expires, id;
433         local auraFilter = frame.auraFilter;
434         local i = 1;
435         while true do
436             name, icon, count, _, duration, expires, _, _, _, id = UnitAura(unit, i, auraFilter);
437             if not name then break end
438             -- possible improvement to add spellID as an option
439             if frame.auras[name] and not frame.invert then
440                 if count > 1 then
441                     frame.stack:SetText(count);
442                     frame.stack:Show();
443                 else
444                     frame.stack:Hide();
445                 end
446                 if expires > 0 then
447                     frame.cd:SetCooldown(expires - duration, duration);
448                     frame.cd:Show();
449                 else
450                     frame.cd:Hide();
451                 end
452                 frame.icon:SetTexture(icon);
453                 frame:Show();
454                 return;
455             elseif frame.auras[name] and frame.invert then
456                 frame.icon:SetTexture(icon);
457                 frame:Hide();
458                 return;
459             end
460             i = i + 1;
461         end
462         if frame.invert then
463             frame:Show(); -- not functional without first hiding once to get SetTexture
464             return;
465         end
466     end
467     frame:Hide();
468 end
469
470 local function updateAuras(unit)
471     if units[unit] then
472         for _, i in pairs(units[unit]) do
473             updateAuraFrame(frames[i]);
474         end
475     end
476 end
477
478 local function updateTotemFrame(frame, slot)
479     local _, name, start, duration, icon = GetTotemInfo(slot);
480     if name ~= "" then
481         frame.cd:SetCooldown(start, duration);
482         frame.cd:Show();
483         frame.icon:SetTexture(icon);
484         frame:Show();
485     else
486         frame:Hide();
487     end
488 end
489
490 local function updateTotems(slot)
491     if totems[slot] then
492         for _, i in pairs(totems[slot]) do
493             updateTotemFrame(frames[i], slot);
494         end
495     end
496 end
497
498 local function createTMW(name, config, parent)
499     local frame = CreateFrame("Frame", name, parent);
500     frame:SetPoint("TOPLEFT", parent, "BOTTOMLEFT", config.x, config.y+config.height);
501     frame:SetPoint("BOTTOMRIGHT", parent, "BOTTOMLEFT", config.x+config.width, config.y);
502     frame.unit = config.unit;
503     frame.spec = config.spec;
504     if config.auras then
505         frame.auras = {};
506         for _, v in pairs(config.auras) do
507             frame.auras[v] = true;
508         end
509     end
510     frame.auraFilter = config.auraFilter;
511     frame.totems = config.totems;
512     frame.invert = config.invert;
513     frame:Hide();
514     frame.base = frame:CreateTexture(nil, "BACKGROUND");
515     frame.base:SetAllPoints();
516     frame.base:SetColorTexture(0, 0, 0, 0.6);
517     frame.icon = frame:CreateTexture(nil, "ARTWORK");
518     frame.icon:SetPoint("TOPLEFT", frame.base, "TOPLEFT", 1, -1);
519     frame.icon:SetPoint("BOTTOMRIGHT", frame.base, "BOTTOMRIGHT", -1, 1);
520     frame.icon:SetTexCoord(0.07, 0.93, 0.07, 0.93);
521     frame.stack = frame:CreateFontString(nil, "OVERLAY", "NumberFontNormalLarge");
522     frame.stack:SetFont(STANDARD_TEXT_FONT, 26, "OUTLINE");
523     frame.stack:SetPoint("TOPLEFT");
524     frame.stack:Hide();
525     frame.cd = CreateFrame("Cooldown", name.."CD", frame, "CooldownFrameTemplate");
526     frame.cd:SetReverse(true);
527     frame.cd:SetAllPoints();
528     return frame;
529 end
530
531 local function initialize()
532     Indicators:SetFrameStrata("LOW");
533     Indicators:SetPoint("BOTTOMLEFT");
534     Indicators:SetWidth(1);
535     Indicators:SetHeight(1);
536     currentSpec = GetSpecialization();
537     local name, realm = UnitFullName("player");
538     if chars[realm] and chars[realm][name] then
539         for _, config in pairs(chars[realm][name]) do
540             table.insert(settings, config)
541         end
542     end
543     for i, config in pairs(settings) do
544         if config.unit then
545             if not units[config.unit] then units[config.unit] = {} end
546             table.insert(units[config.unit], i);
547         end
548         if config.totems then
549             for _, slot in pairs(config.totems) do
550                 if not totems[slot] then totems[slot] = {} end
551                 table.insert(totems[slot], i);
552             end
553         end
554         frames[i] = createTMW("OmaTMW"..i, config, Indicators);
555     end
556
557     for _, frame in pairs(frames) do
558         if frame.auras then updateAuraFrame(frame) end
559         if frame.totems then
560             for _, slot in pairs(frame.totems) do updateTotemFrame(frame, slot) end
561         end
562     end
563 end
564
565 Indicators:RegisterEvent("UNIT_AURA");
566 Indicators:RegisterEvent("PLAYER_TARGET_CHANGED");
567 Indicators:RegisterEvent("PLAYER_TOTEM_UPDATE");
568 Indicators:RegisterEvent("INSTANCE_ENCOUNTER_ENGAGE_UNIT");
569 Indicators:RegisterEvent("PLAYER_SPECIALIZATION_CHANGED");
570 Indicators:RegisterEvent("PLAYER_LOGIN");
571 Indicators:SetScript("OnEvent", function(self, event, arg1)
572     if event == "UNIT_AURA" then
573         updateAuras(arg1);
574     elseif event == "PLAYER_TARGET_CHANGED" then
575         updateAuras("target");
576     elseif event == "PLAYER_TOTEM_UPDATE" then
577         updateTotems(arg1);
578     elseif event == "INSTANCE_ENCOUNTER_ENGAGE_UNIT" then
579         for _, boss in pairs(bosses) do
580             updateAuras(boss);
581         end
582     elseif event == "PLAYER_SPECIALIZATION_CHANGED" then
583         currentSpec = GetSpecialization();
584         for _, frame in pairs(frames) do
585             if frame.auras then updateAuraFrame(frame) end
586             if frame.totems then
587                 for _, slot in pairs(frame.totems) do updateTotemFrame(frame, slot) end
588             end
589         end
590     elseif event == "PLAYER_LOGIN" then
591         initialize();
592     end
593 end);