7250c45 - Holy Power for all paladin specs
[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 = 80,
69                 height = 80,
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                 spec = 3, -- Retribution
97                 auras = {"Judgment"},
98                 auraFilter = "PLAYER HARMFUL",
99                 x = 570, -- placed over Innervate frame
100                 y = 440,
101                 width = 80,
102                 height = 80,
103             },
104             {
105                 unit = "player",
106                 spec = 3, -- Retribution
107                 auras = {"Divine Purpose"},
108                 auraFilter = "PLAYER HELPFUL",
109                 x = 570,
110                 y = 530,
111                 width = 80,
112                 height = 80,
113             },
114             {
115                 unit = "player",
116                 spec = 2, -- Protection
117                 auras = {"Shield of the Righteous"},
118                 auraFilter = "PLAYER HELPFUL",
119                 x = 570,
120                 y = 440,
121                 width = 80,
122                 height = 80,
123             },
124             {
125                 unit = "player",
126                 auras = {"Divine Shield"},
127                 auraFilter = "PLAYER HELPFUL",
128                 x = 660,
129                 y = 440,
130                 width = 80,
131                 height = 80,
132             },
133         },
134         ["Gilden"] = {
135             {
136                 unit = "target",
137                 auras = {"Shadow Word: Pain", "Purge the Wicked"},
138                 auraFilter = "PLAYER HARMFUL",
139                 x = 660,
140                 y = 440,
141                 width = 60,
142                 height = 60,
143             },
144             {
145                 unit = "player",
146                 auras = {"Power Word: Fortitude"},
147                 auraFilter = "HELPFUL",
148                 invert = true,
149                 x = 720,
150                 y = 440,
151                 width = 60,
152                 height = 60,
153             },
154             {
155                 unit = "player",
156                 auras = {"Overcharge Mana"},
157                 auraFilter = "PLAYER HELPFUL",
158                 x = 720,
159                 y = 440,
160                 width = 60,
161                 height = 60,
162             },
163         },
164         ["Gedren"] = {
165             {
166                 totems = {1}, -- Efflorescence
167                 x = 660,
168                 y = 440,
169                 width = 80,
170                 height = 80,
171             },
172         },
173         ["Gazden"] = {
174             {
175                 unit = "player",
176                 auras = {"Tidal Waves"},
177                 auraFilter = "PLAYER HELPFUL",
178                 x = 660,
179                 y = 440,
180                 width = 40,
181                 height = 40,
182             },
183             {
184                 unit = "player",
185                 auras = {"Healing Rain"},
186                 auraFilter = "PLAYER HELPFUL",
187                 x = 700,
188                 y = 440,
189                 width = 40,
190                 height = 40,
191             },
192             {
193                 unit = "player",
194                 auras = {"Unleash Life"},
195                 auraFilter = "PLAYER HELPFUL",
196                 x = 740,
197                 y = 440,
198                 width = 40,
199                 height = 40,
200             },
201         },
202         ["Gran"] = {
203             {
204                 unit = "player",
205                 auras = {"Tidal Waves"},
206                 auraFilter = "PLAYER HELPFUL",
207                 x = 660,
208                 y = 440,
209                 width = 40,
210                 height = 40,
211             },
212             {
213                 unit = "player",
214                 auras = {"Healing Rain"},
215                 auraFilter = "PLAYER HELPFUL",
216                 x = 700,
217                 y = 440,
218                 width = 40,
219                 height = 40,
220             },
221             {
222                 unit = "player",
223                 auras = {"Unleash Life"},
224                 auraFilter = "PLAYER HELPFUL",
225                 x = 740,
226                 y = 440,
227                 width = 40,
228                 height = 40,
229             },
230         },
231         ["Gedrin"] = {
232             {
233                 unit = "pet",
234                 auras = {"Frenzy"},
235                 auraFilter = "HELPFUL",
236                 x = 660,
237                 y = 440,
238                 width = 40,
239                 height = 40,
240             },
241         },
242     },
243 };
244
245 -- settings entry:
246 -- unit = unitID where to check auras, not required for totem checkers
247 -- spec = player spec index to show frame, if nil show always
248 -- auras = list of auras to track, in priority order
249 -- auraFilter = filter for UnitAura
250 -- totems = list of totem slots to track, in priority order, only checked if auras is nil
251 -- x = x position relative to UIParent bottom left
252 -- y = y position relative to UIParent bottom left
253 -- width = width
254 -- height = height
255
256 -- global frames' settings
257 local settings = {
258     {
259         unit = "player",
260         auras = {"Innervate", "Gift of the Titans"},
261         auraFilter = "HELPFUL",
262         x = 570,
263         y = 440,
264         width = 80,
265         height = 80,
266     },
267     {
268         unit = "player",
269         auras = {"Ineffable Truth"},
270         auraFilter = "HELPFUL",
271         x = 570,
272         y = 440,
273         width = 40,
274         height = 40,
275     },
276     {
277         unit = "player",
278         auras = {
279             "Delusions", "Entropic Blast", "Necrotic Embrace", "Flametouched", "Shadowtouched",
280             "Blazing Eruption", "Shattering Scream", "Consuming Hunger", "Unstable Soul",
281             "Time Bomb", "Broken Shard", "Demolished", "Fetid Rot", "Roiling Deceit",
282             "Putrid Blood", "Endemic Virus", "Lingering Infection", "Gigavolt Charge",
283             "Crackling Lightning", "Storm's Wail", "Death's Door", "Deathly Withering",
284             "Chilling Touch", "Volatile Charge", "Liquid Gold", "Drained Soul", "Evoke Anguish",
285             "Ancient Curse", "Corrosion", "Debilitating Spit", "Tasty Morsel", "Encroaching Shadows",
286             "Corrupted Existence", "Madness Bomb"
287         },
288         auraFilter = "HARMFUL",
289         x = 660,
290         y = 530,
291         width = 80,
292         height = 80,
293     },
294     {
295         unit = "player",
296         auras = {
297             "Adaptive Membrane"
298         },
299         auraFilter = "HARMFUL",
300         x = 660,
301         y = 780,
302         width = 160,
303         height = 160,
304     },
305 };
306
307 local frames = {};
308 local units = {}; -- mapping from unitID to frames
309 local totems = {}; -- mapping to frames with totems
310 local bosses = {};
311 for i = 1, MAX_BOSS_FRAMES do
312     bosses[i] = "boss"..i;
313 end
314 local currentSpec = 0; -- 0 is invalid
315
316 local Indicators = CreateFrame("Frame", "OmaTMW", UIParent);
317
318 local function updateAuraFrame(frame)
319     local unit = frame.unit;
320     if UnitExists(unit) and (not frame.spec or frame.spec == currentSpec) then
321         local name, icon, count, duration, expires;
322         local auraFilter = frame.auraFilter;
323         local i = 1;
324         while true do
325             name, icon, count, _, duration, expires = UnitAura(unit, i, auraFilter);
326             if not name then break end
327             -- possible improvement to add spellID as an option
328             if frame.auras[name] and not frame.invert then
329                 if count > 1 then
330                     frame.stack:SetText(count);
331                     frame.stack:Show();
332                 else
333                     frame.stack:Hide();
334                 end
335                 if expires > 0 then
336                     frame.cd:SetCooldown(expires - duration, duration);
337                     frame.cd:Show();
338                 else
339                     frame.cd:Hide();
340                 end
341                 frame.icon:SetTexture(icon);
342                 frame:Show();
343                 return;
344             elseif frame.auras[name] and frame.invert then
345                 frame.icon:SetTexture(icon);
346                 frame:Hide();
347                 return;
348             end
349             i = i + 1;
350         end
351         if frame.invert then
352             frame:Show(); -- not functional without first hiding once to get SetTexture
353             return;
354         end
355     end
356     frame:Hide();
357 end
358
359 local function updateAuras(unit)
360     if units[unit] then
361         for _, i in pairs(units[unit]) do
362             updateAuraFrame(frames[i]);
363         end
364     end
365 end
366
367 local function updateTotemFrame(frame, slot)
368     local _, name, start, duration, icon = GetTotemInfo(slot);
369     if name ~= "" then
370         frame.cd:SetCooldown(start, duration);
371         frame.cd:Show();
372         frame.icon:SetTexture(icon);
373         frame:Show();
374     else
375         frame:Hide();
376     end
377 end
378
379 local function updateTotems(slot)
380     if totems[slot] then
381         for _, i in pairs(totems[slot]) do
382             updateTotemFrame(frames[i], slot);
383         end
384     end
385 end
386
387 local function createTMW(name, config, parent)
388     local frame = CreateFrame("Frame", name, parent);
389     frame:SetPoint("TOPLEFT", parent, "BOTTOMLEFT", config.x, config.y+config.height);
390     frame:SetPoint("BOTTOMRIGHT", parent, "BOTTOMLEFT", config.x+config.width, config.y);
391     frame.unit = config.unit;
392     frame.spec = config.spec;
393     if config.auras then
394         frame.auras = {};
395         for _, v in pairs(config.auras) do
396             frame.auras[v] = true;
397         end
398     end
399     frame.auraFilter = config.auraFilter;
400     frame.totems = config.totems;
401     frame.invert = config.invert;
402     frame:Hide();
403     frame.base = frame:CreateTexture(nil, "BACKGROUND");
404     frame.base:SetAllPoints();
405     frame.base:SetColorTexture(0, 0, 0, 0.6);
406     frame.icon = frame:CreateTexture(nil, "ARTWORK");
407     frame.icon:SetPoint("TOPLEFT", frame.base, "TOPLEFT", 1, -1);
408     frame.icon:SetPoint("BOTTOMRIGHT", frame.base, "BOTTOMRIGHT", -1, 1);
409     frame.icon:SetTexCoord(0.07, 0.93, 0.07, 0.93);
410     frame.stack = frame:CreateFontString(nil, "OVERLAY", "NumberFontNormalLarge");
411     frame.stack:SetPoint("TOPLEFT");
412     frame.stack:Hide();
413     frame.cd = CreateFrame("Cooldown", name.."CD", frame, "CooldownFrameTemplate");
414     frame.cd:SetReverse(true);
415     frame.cd:SetAllPoints();
416     return frame;
417 end
418
419 local function initialize()
420     Indicators:SetFrameStrata("LOW");
421     Indicators:SetPoint("BOTTOMLEFT");
422     Indicators:SetWidth(1);
423     Indicators:SetHeight(1);
424     currentSpec = GetSpecialization();
425     local name, realm = UnitFullName("player");
426     if chars[realm] and chars[realm][name] then
427         for _, config in pairs(chars[realm][name]) do
428             table.insert(settings, config)
429         end
430     end
431     for i, config in pairs(settings) do
432         if config.unit then
433             if not units[config.unit] then units[config.unit] = {} end
434             table.insert(units[config.unit], i);
435         end
436         if config.totems then
437             for _, slot in pairs(config.totems) do
438                 if not totems[slot] then totems[slot] = {} end
439                 table.insert(totems[slot], i);
440             end
441         end
442         frames[i] = createTMW("OmaTMW"..i, config, Indicators);
443     end
444
445     for _, frame in pairs(frames) do
446         if frame.auras then updateAuraFrame(frame) end
447         if frame.totems then
448             for _, slot in pairs(frame.totems) do updateTotemFrame(frame, slot) end
449         end
450     end
451 end
452
453 Indicators:RegisterEvent("UNIT_AURA");
454 Indicators:RegisterEvent("PLAYER_TARGET_CHANGED");
455 Indicators:RegisterEvent("PLAYER_TOTEM_UPDATE");
456 Indicators:RegisterEvent("INSTANCE_ENCOUNTER_ENGAGE_UNIT");
457 Indicators:RegisterEvent("PLAYER_SPECIALIZATION_CHANGED");
458 Indicators:RegisterEvent("PLAYER_LOGIN");
459 Indicators:SetScript("OnEvent", function(self, event, arg1)
460     if event == "UNIT_AURA" then
461         updateAuras(arg1);
462     elseif event == "PLAYER_TARGET_CHANGED" then
463         updateAuras("target");
464     elseif event == "PLAYER_TOTEM_UPDATE" then
465         updateTotems(arg1);
466     elseif event == "INSTANCE_ENCOUNTER_ENGAGE_UNIT" then
467         for _, boss in pairs(bosses) do
468             updateAuras(boss);
469         end
470     elseif event == "PLAYER_SPECIALIZATION_CHANGED" then
471         currentSpec = GetSpecialization();
472         for _, frame in pairs(frames) do
473             if frame.auras then updateAuraFrame(frame) end
474             if frame.totems then
475                 for _, slot in pairs(frame.totems) do updateTotemFrame(frame, slot) end
476             end
477         end
478     elseif event == "PLAYER_LOGIN" then
479         initialize();
480     end
481 end);