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