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