aa4370f - Fix priest buff and add essence
[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"},
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     },
203 };
204
205 -- settings entry:
206 -- unit = unitID where to check auras, not required for totem checkers
207 -- spec = player spec index to show frame, if nil show always
208 -- auras = list of auras to track, in priority order
209 -- auraFilter = filter for UnitAura
210 -- totems = list of totem slots to track, in priority order, only checked if auras is nil
211 -- x = x position relative to UIParent bottom left
212 -- y = y position relative to UIParent bottom left
213 -- width = width
214 -- height = height
215
216 -- global frames' settings
217 local settings = {
218     {
219         unit = "player",
220         auras = {"Innervate"},
221         auraFilter = "HELPFUL",
222         x = 570,
223         y = 440,
224         width = 80,
225         height = 80,
226     },
227     {
228         unit = "player",
229         auras = {
230             "Delusions", "Entropic Blast", "Necrotic Embrace", "Flametouched", "Shadowtouched",
231             "Blazing Eruption", "Shattering Scream", "Consuming Hunger", "Unstable Soul",
232             "Time Bomb", "Broken Shard", "Demolished", "Fetid Rot", "Roiling Deceit",
233             "Putrid Blood", "Endemic Virus", "Lingering Infection", "Gigavolt Charge",
234             "Crackling Lightning", "Storm's Wail", "Death's Door", "Deathly Withering",
235             "Chilling Touch", "Volatile Charge", "Liquid Gold", "Drained Soul"
236         },
237         auraFilter = "HARMFUL",
238         x = 660,
239         y = 530,
240         width = 80,
241         height = 80,
242     },
243 };
244
245 local frames = {};
246 local units = {}; -- mapping from unitID to frames
247 local totems = {}; -- mapping to frames with totems
248 local bosses = {};
249 for i = 1, MAX_BOSS_FRAMES do
250     bosses[i] = "boss"..i;
251 end
252 local currentSpec = 0; -- 0 is invalid
253
254 local Indicators = CreateFrame("Frame", "OmaTMW", UIParent);
255
256 local function updateAuraFrame(frame)
257     local unit = frame.unit;
258     if UnitExists(unit) and (not frame.spec or frame.spec == currentSpec) then
259         local name, icon, count, duration, expires;
260         local auraFilter = frame.auraFilter;
261         local i = 1;
262         while true do
263             name, icon, count, _, duration, expires = UnitAura(unit, i, auraFilter);
264             if not name then break end
265             -- possible improvement to add spellID as an option
266             if frame.auras[name] and not frame.invert then
267                 if count > 1 then
268                     frame.stack:SetText(count);
269                     frame.stack:Show();
270                 else
271                     frame.stack:Hide();
272                 end
273                 if expires > 0 then
274                     frame.cd:SetCooldown(expires - duration, duration);
275                     frame.cd:Show();
276                 else
277                     frame.cd:Hide();
278                 end
279                 frame.icon:SetTexture(icon);
280                 frame:Show();
281                 return;
282             elseif frame.auras[name] and frame.invert then
283                 frame.icon:SetTexture(icon);
284                 frame:Hide();
285                 return;
286             end
287             i = i + 1;
288         end
289         if frame.invert then
290             frame:Show(); -- not functional without first hiding once to get SetTexture
291             return;
292         end
293     end
294     frame:Hide();
295 end
296
297 local function updateAuras(unit)
298     if units[unit] then
299         for _, i in pairs(units[unit]) do
300             updateAuraFrame(frames[i]);
301         end
302     end
303 end
304
305 local function updateTotemFrame(frame, slot)
306     local _, name, start, duration, icon = GetTotemInfo(slot);
307     if name ~= "" then
308         frame.cd:SetCooldown(start, duration);
309         frame.cd:Show();
310         frame.icon:SetTexture(icon);
311         frame:Show();
312     else
313         frame:Hide();
314     end
315 end
316
317 local function updateTotems(slot)
318     if totems[slot] then
319         for _, i in pairs(totems[slot]) do
320             updateTotemFrame(frames[i], slot);
321         end
322     end
323 end
324
325 local function createTMW(name, config, parent)
326     local frame = CreateFrame("Frame", name, parent);
327     frame:SetPoint("TOPLEFT", parent, "BOTTOMLEFT", config.x, config.y+config.height);
328     frame:SetPoint("BOTTOMRIGHT", parent, "BOTTOMLEFT", config.x+config.width, config.y);
329     frame.unit = config.unit;
330     frame.spec = config.spec;
331     if config.auras then
332         frame.auras = {};
333         for _, v in pairs(config.auras) do
334             frame.auras[v] = true;
335         end
336     end
337     frame.auraFilter = config.auraFilter;
338     frame.totems = config.totems;
339     frame.invert = config.invert;
340     frame:Hide();
341     frame.base = frame:CreateTexture(nil, "BACKGROUND");
342     frame.base:SetAllPoints();
343     frame.base:SetColorTexture(0, 0, 0, 0.6);
344     frame.icon = frame:CreateTexture(nil, "ARTWORK");
345     frame.icon:SetPoint("TOPLEFT", frame.base, "TOPLEFT", 1, -1);
346     frame.icon:SetPoint("BOTTOMRIGHT", frame.base, "BOTTOMRIGHT", -1, 1);
347     frame.icon:SetTexCoord(0.07, 0.93, 0.07, 0.93);
348     frame.stack = frame:CreateFontString(nil, "OVERLAY", "NumberFontNormalLarge");
349     frame.stack:SetPoint("TOPLEFT");
350     frame.stack:Hide();
351     frame.cd = CreateFrame("Cooldown", name.."CD", frame, "CooldownFrameTemplate");
352     frame.cd:SetReverse(true);
353     frame.cd:SetAllPoints();
354     return frame;
355 end
356
357 local function initialize()
358     Indicators:SetFrameStrata("LOW");
359     Indicators:SetPoint("BOTTOMLEFT");
360     Indicators:SetWidth(1);
361     Indicators:SetHeight(1);
362     currentSpec = GetSpecialization();
363     local name, realm = UnitFullName("player");
364     if chars[realm] and chars[realm][name] then
365         for _, config in pairs(chars[realm][name]) do
366             table.insert(settings, config)
367         end
368     end
369     for i, config in pairs(settings) do
370         if config.unit then
371             if not units[config.unit] then units[config.unit] = {} end
372             table.insert(units[config.unit], i);
373         end
374         if config.totems then
375             for _, slot in pairs(config.totems) do
376                 if not totems[slot] then totems[slot] = {} end
377                 table.insert(totems[slot], i);
378             end
379         end
380         frames[i] = createTMW("OmaTMW"..i, config, Indicators);
381     end
382
383     for _, frame in pairs(frames) do
384         if frame.auras then updateAuraFrame(frame) end
385         if frame.totems then
386             for _, slot in pairs(frame.totems) do updateTotemFrame(frame, slot) end
387         end
388     end
389 end
390
391 Indicators:RegisterEvent("UNIT_AURA");
392 Indicators:RegisterEvent("PLAYER_TARGET_CHANGED");
393 Indicators:RegisterEvent("PLAYER_TOTEM_UPDATE");
394 Indicators:RegisterEvent("INSTANCE_ENCOUNTER_ENGAGE_UNIT");
395 Indicators:RegisterEvent("PLAYER_SPECIALIZATION_CHANGED");
396 Indicators:RegisterEvent("PLAYER_LOGIN");
397 Indicators:SetScript("OnEvent", function(self, event, arg1)
398     if event == "UNIT_AURA" then
399         updateAuras(arg1);
400     elseif event == "PLAYER_TARGET_CHANGED" then
401         updateAuras("target");
402     elseif event == "PLAYER_TOTEM_UPDATE" then
403         updateTotems(arg1);
404     elseif event == "INSTANCE_ENCOUNTER_ENGAGE_UNIT" then
405         for _, boss in pairs(bosses) do
406             updateAuras(boss);
407         end
408     elseif event == "PLAYER_SPECIALIZATION_CHANGED" then
409         currentSpec = GetSpecialization();
410         for _, frame in pairs(frames) do
411             if frame.auras then updateAuraFrame(frame) end
412             if frame.totems then
413                 for _, slot in pairs(frame.totems) do updateTotemFrame(frame, slot) end
414             end
415         end
416     elseif event == "PLAYER_LOGIN" then
417         initialize();
418     end
419 end);