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