29d93c0 - change raid frame position as mage
[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                 spec = 2, -- Fire
273                 auras = {"Sun King's Blessing"},
274                 auraFilter = "PLAYER HELPFUL",
275                 x = 784,
276                 y = 386,
277                 width = 40,
278                 height = 40,
279             },
280             {
281                 unit = "player",
282                 spec = 2, -- Fire
283                 auras = {"Infernal Cascade"},
284                 auraFilter = "PLAYER HELPFUL",
285                 x = 928,
286                 y = 386,
287                 width = 48,
288                 height = 48,
289             },
290             {
291                 unit = "player",
292                 spec = 2, -- Fire
293                 auras = {"Combustion"},
294                 auraFilter = "PLAYER HELPFUL",
295                 x = 976,
296                 y = 386,
297                 width = 48,
298                 height = 48,
299             },
300
301             {
302                 unit = "player",
303                 auras = {"Arcane Intellect"},
304                 auraFilter = "HELPFUL",
305                 invert = true,
306                 x = 720,
307                 y = 460,
308                 width = 60,
309                 height = 60,
310             },
311             {
312                 unit = "target",
313                 spec = 3, -- Frost
314                 auras = {"Winter's Chill"},
315                 auraFilter = "PLAYER HARMFUL",
316                 x = 700,
317                 y = 460,
318                 width = 40,
319                 height = 40,
320             },
321             {
322                 unit = "player",
323                 spec = 3, -- Frost
324                 auras = {"Icy Veins"},
325                 auraFilter = "PLAYER HELPFUL",
326                 x = 660,
327                 y = 420,
328                 width = 40,
329                 height = 40,
330             },
331             {
332                 unit = "player",
333                 auras = {"Alter Time"},
334                 auraFilter = "PLAYER HELPFUL",
335                 x = 700,
336                 y = 420,
337                 width = 40,
338                 height = 40,
339             },
340         },
341     },
342 };
343
344 -- settings entry:
345 -- unit = unitID where to check auras, not required for totem checkers
346 -- spec = player spec index to show frame, if nil show always
347 -- auras = list of auras to track, in priority order
348 -- auraFilter = filter for UnitAura
349 -- totems = list of totem slots to track, in priority order, only checked if auras is nil
350 -- x = x position relative to UIParent bottom left
351 -- y = y position relative to UIParent bottom left
352 -- width = width
353 -- height = height
354
355 -- global frames' settings
356 local settings = {
357     {
358         unit = "player",
359         auras = {"Innervate", "Gift of the Titans", "Power Infusion"},
360         auraFilter = "HELPFUL",
361         x = 570,
362         y = 440,
363         width = 80,
364         height = 80,
365     },
366     {
367         unit = "player",
368         auras = {"Ineffable Truth"},
369         auraFilter = "HELPFUL",
370         x = 570,
371         y = 440,
372         width = 40,
373         height = 40,
374     },
375     {
376         unit = "player",
377         auras = {
378             "Delusions", "Entropic Blast", "Necrotic Embrace", "Flametouched", "Shadowtouched",
379             "Blazing Eruption", "Shattering Scream", "Consuming Hunger", "Unstable Soul",
380             "Time Bomb", "Broken Shard", "Demolished", "Fetid Rot", "Roiling Deceit",
381             "Putrid Blood", "Endemic Virus", "Lingering Infection", "Gigavolt Charge",
382             "Crackling Lightning", "Storm's Wail", "Death's Door", "Deathly Withering",
383             "Chilling Touch", "Volatile Charge", "Liquid Gold", "Drained Soul", "Evoke Anguish",
384             "Ancient Curse", "Corrosion", "Debilitating Spit", "Tasty Morsel", "Encroaching Shadows",
385             "Corrupted Existence", "Madness Bomb", "Crimson Chorus", "Essence Sap", "Bloodlight",
386             "Arcane Vulnerability", "Wicked Laceration", "Withering Touch", "Fragment of Destiny",
387             "Flameclasp Eruption", "Wailing Arrow", "Frozen Destruction",
388             "Remnant: Mort'regar's Echoes", "Barbed Arrow", "Scorn", "Ire", "Song of Dissolution",
389             "Grim Portent", "Exposed Threads of Fate", "Despair", "Shadowsteel Chains", "Ignite Soul"
390         },
391         auraFilter = "HARMFUL",
392         x = 660,
393         y = 530,
394         width = 80,
395         height = 80,
396     },
397     {
398         unit = "player",
399         auras = {
400             "Adaptive Membrane", "Gluttonous Miasma", "Remnant: Soulforge Heat"
401         },
402         auraFilter = "HARMFUL",
403         x = 660,
404         y = 780,
405         width = 160,
406         height = 160,
407     },
408 };
409
410 local frames = {};
411 local units = {}; -- mapping from unitID to frames
412 local totems = {}; -- mapping to frames with totems
413 local bosses = {};
414 for i = 1, MAX_BOSS_FRAMES do
415     bosses[i] = "boss"..i;
416 end
417 local currentSpec = 0; -- 0 is invalid
418
419 local Indicators = CreateFrame("Frame", "OmaTMW", UIParent);
420
421 local function updateAuraFrame(frame)
422     local unit = frame.unit;
423     if UnitExists(unit) and (not frame.spec or frame.spec == currentSpec) then
424         local name, icon, count, duration, expires, id;
425         local auraFilter = frame.auraFilter;
426         local i = 1;
427         while true do
428             name, icon, count, _, duration, expires, _, _, _, id = UnitAura(unit, i, auraFilter);
429             if not name then break end
430             -- possible improvement to add spellID as an option
431             if frame.auras[name] and not frame.invert then
432                 if count > 1 then
433                     frame.stack:SetText(count);
434                     frame.stack:Show();
435                 else
436                     frame.stack:Hide();
437                 end
438                 if expires > 0 then
439                     frame.cd:SetCooldown(expires - duration, duration);
440                     frame.cd:Show();
441                 else
442                     frame.cd:Hide();
443                 end
444                 frame.icon:SetTexture(icon);
445                 frame:Show();
446                 return;
447             elseif frame.auras[name] and frame.invert then
448                 frame.icon:SetTexture(icon);
449                 frame:Hide();
450                 return;
451             end
452             i = i + 1;
453         end
454         if frame.invert then
455             frame:Show(); -- not functional without first hiding once to get SetTexture
456             return;
457         end
458     end
459     frame:Hide();
460 end
461
462 local function updateAuras(unit)
463     if units[unit] then
464         for _, i in pairs(units[unit]) do
465             updateAuraFrame(frames[i]);
466         end
467     end
468 end
469
470 local function updateTotemFrame(frame, slot)
471     local _, name, start, duration, icon = GetTotemInfo(slot);
472     if name ~= "" then
473         frame.cd:SetCooldown(start, duration);
474         frame.cd:Show();
475         frame.icon:SetTexture(icon);
476         frame:Show();
477     else
478         frame:Hide();
479     end
480 end
481
482 local function updateTotems(slot)
483     if totems[slot] then
484         for _, i in pairs(totems[slot]) do
485             updateTotemFrame(frames[i], slot);
486         end
487     end
488 end
489
490 local function createTMW(name, config, parent)
491     local frame = CreateFrame("Frame", name, parent);
492     frame:SetPoint("TOPLEFT", parent, "BOTTOMLEFT", config.x, config.y+config.height);
493     frame:SetPoint("BOTTOMRIGHT", parent, "BOTTOMLEFT", config.x+config.width, config.y);
494     frame.unit = config.unit;
495     frame.spec = config.spec;
496     if config.auras then
497         frame.auras = {};
498         for _, v in pairs(config.auras) do
499             frame.auras[v] = true;
500         end
501     end
502     frame.auraFilter = config.auraFilter;
503     frame.totems = config.totems;
504     frame.invert = config.invert;
505     frame:Hide();
506     frame.base = frame:CreateTexture(nil, "BACKGROUND");
507     frame.base:SetAllPoints();
508     frame.base:SetColorTexture(0, 0, 0, 0.6);
509     frame.icon = frame:CreateTexture(nil, "ARTWORK");
510     frame.icon:SetPoint("TOPLEFT", frame.base, "TOPLEFT", 1, -1);
511     frame.icon:SetPoint("BOTTOMRIGHT", frame.base, "BOTTOMRIGHT", -1, 1);
512     frame.icon:SetTexCoord(0.07, 0.93, 0.07, 0.93);
513     frame.stack = frame:CreateFontString(nil, "OVERLAY", "NumberFontNormalLarge");
514     frame.stack:SetFont(STANDARD_TEXT_FONT, 26, "OUTLINE");
515     frame.stack:SetPoint("TOPLEFT");
516     frame.stack:Hide();
517     frame.cd = CreateFrame("Cooldown", name.."CD", frame, "CooldownFrameTemplate");
518     frame.cd:SetReverse(true);
519     frame.cd:SetAllPoints();
520     return frame;
521 end
522
523 local function initialize()
524     Indicators:SetFrameStrata("LOW");
525     Indicators:SetPoint("BOTTOMLEFT");
526     Indicators:SetWidth(1);
527     Indicators:SetHeight(1);
528     currentSpec = GetSpecialization();
529     local name, realm = UnitFullName("player");
530     if chars[realm] and chars[realm][name] then
531         for _, config in pairs(chars[realm][name]) do
532             table.insert(settings, config)
533         end
534     end
535     for i, config in pairs(settings) do
536         if config.unit then
537             if not units[config.unit] then units[config.unit] = {} end
538             table.insert(units[config.unit], i);
539         end
540         if config.totems then
541             for _, slot in pairs(config.totems) do
542                 if not totems[slot] then totems[slot] = {} end
543                 table.insert(totems[slot], i);
544             end
545         end
546         frames[i] = createTMW("OmaTMW"..i, config, Indicators);
547     end
548
549     for _, frame in pairs(frames) do
550         if frame.auras then updateAuraFrame(frame) end
551         if frame.totems then
552             for _, slot in pairs(frame.totems) do updateTotemFrame(frame, slot) end
553         end
554     end
555 end
556
557 Indicators:RegisterEvent("UNIT_AURA");
558 Indicators:RegisterEvent("PLAYER_TARGET_CHANGED");
559 Indicators:RegisterEvent("PLAYER_TOTEM_UPDATE");
560 Indicators:RegisterEvent("INSTANCE_ENCOUNTER_ENGAGE_UNIT");
561 Indicators:RegisterEvent("PLAYER_SPECIALIZATION_CHANGED");
562 Indicators:RegisterEvent("PLAYER_LOGIN");
563 Indicators:SetScript("OnEvent", function(self, event, arg1)
564     if event == "UNIT_AURA" then
565         updateAuras(arg1);
566     elseif event == "PLAYER_TARGET_CHANGED" then
567         updateAuras("target");
568     elseif event == "PLAYER_TOTEM_UPDATE" then
569         updateTotems(arg1);
570     elseif event == "INSTANCE_ENCOUNTER_ENGAGE_UNIT" then
571         for _, boss in pairs(bosses) do
572             updateAuras(boss);
573         end
574     elseif event == "PLAYER_SPECIALIZATION_CHANGED" then
575         currentSpec = GetSpecialization();
576         for _, frame in pairs(frames) do
577             if frame.auras then updateAuraFrame(frame) end
578             if frame.totems then
579                 for _, slot in pairs(frame.totems) do updateTotemFrame(frame, slot) end
580             end
581         end
582     elseif event == "PLAYER_LOGIN" then
583         initialize();
584     end
585 end);