3c2cef6 - Decrease high healing overlay opacity
[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             "Putrid Blood",
195         },
196         auraFilter = "HARMFUL",
197         x = 660,
198         y = 530,
199         width = 80,
200         height = 80,
201     },
202 };
203
204 local frames = {};
205 local units = {}; -- mapping from unitID to frames
206 local totems = {}; -- mapping to frames with totems
207 local bosses = {};
208 for i = 1, MAX_BOSS_FRAMES do
209     bosses[i] = "boss"..i;
210 end
211 local currentSpec = 0; -- 0 is invalid
212
213 local Indicators = CreateFrame("Frame", "OmaTMW", UIParent);
214
215 local function updateAuraFrame(frame)
216     local unit = frame.unit;
217     if UnitExists(unit) and (not frame.spec or frame.spec == currentSpec) then
218         local name, icon, count, duration, expires;
219         local auraFilter = frame.auraFilter;
220         local i = 1;
221         while true do
222             name, icon, count, _, duration, expires = UnitAura(unit, i, auraFilter);
223             if not name then break end
224             -- possible improvement to add spellID as an option
225             if frame.auras[name] then
226                 if count > 1 then
227                     frame.stack:SetText(count);
228                     frame.stack:Show();
229                 else
230                     frame.stack:Hide();
231                 end
232                 if expires > 0 then
233                     frame.cd:SetCooldown(expires - duration, duration);
234                     frame.cd:Show();
235                 else
236                     frame.cd:Hide();
237                 end
238                 frame.icon:SetTexture(icon);
239                 frame:Show();
240                 return;
241             end
242             i = i + 1;
243         end
244     end
245     frame:Hide();
246 end
247
248 local function updateAuras(unit)
249     if units[unit] then
250         for _, i in pairs(units[unit]) do
251             updateAuraFrame(frames[i]);
252         end
253     end
254 end
255
256 local function updateTotemFrame(frame, slot)
257     local _, name, start, duration, icon = GetTotemInfo(slot);
258     if name ~= "" then
259         frame.cd:SetCooldown(start, duration);
260         frame.cd:Show();
261         frame.icon:SetTexture(icon);
262         frame:Show();
263     else
264         frame:Hide();
265     end
266 end
267
268 local function updateTotems(slot)
269     if totems[slot] then
270         for _, i in pairs(totems[slot]) do
271             updateTotemFrame(frames[i], slot);
272         end
273     end
274 end
275
276 local function createTMW(name, config, parent)
277     local frame = CreateFrame("Frame", name, parent);
278     frame:SetPoint("TOPLEFT", parent, "BOTTOMLEFT", config.x, config.y+config.height);
279     frame:SetPoint("BOTTOMRIGHT", parent, "BOTTOMLEFT", config.x+config.width, config.y);
280     frame.unit = config.unit;
281     frame.spec = config.spec;
282     if config.auras then
283         frame.auras = {};
284         for _, v in pairs(config.auras) do
285             frame.auras[v] = true;
286         end
287     end
288     frame.auraFilter = config.auraFilter;
289     frame.totems = config.totems;
290     frame:Hide();
291     frame.base = frame:CreateTexture(nil, "BACKGROUND");
292     frame.base:SetAllPoints();
293     frame.base:SetColorTexture(0, 0, 0, 0.6);
294     frame.icon = frame:CreateTexture(nil, "ARTWORK");
295     frame.icon:SetPoint("TOPLEFT", frame.base, "TOPLEFT", 1, -1);
296     frame.icon:SetPoint("BOTTOMRIGHT", frame.base, "BOTTOMRIGHT", -1, 1);
297     frame.icon:SetTexCoord(0.07, 0.93, 0.07, 0.93);
298     frame.stack = frame:CreateFontString(nil, "OVERLAY", "NumberFontNormalLarge");
299     frame.stack:SetPoint("TOPLEFT");
300     frame.stack:Hide();
301     frame.cd = CreateFrame("Cooldown", name.."CD", frame, "CooldownFrameTemplate");
302     frame.cd:SetReverse(true);
303     frame.cd:SetAllPoints();
304     return frame;
305 end
306
307 local function initialize()
308     Indicators:SetFrameStrata("LOW");
309     Indicators:SetPoint("BOTTOMLEFT");
310     Indicators:SetWidth(1);
311     Indicators:SetHeight(1);
312     currentSpec = GetSpecialization();
313     local name, realm = UnitFullName("player");
314     if chars[realm] and chars[realm][name] then
315         for _, config in pairs(chars[realm][name]) do
316             table.insert(settings, config)
317         end
318     end
319     for i, config in pairs(settings) do
320         if config.unit then
321             if not units[config.unit] then units[config.unit] = {} end
322             table.insert(units[config.unit], i);
323         end
324         if config.totems then
325             for _, slot in pairs(config.totems) do
326                 if not totems[slot] then totems[slot] = {} end
327                 table.insert(totems[slot], i);
328             end
329         end
330         frames[i] = createTMW("OmaTMW"..i, config, Indicators);
331     end
332
333     for _, frame in pairs(frames) do
334         if frame.auras then updateAuraFrame(frame) end
335         if frame.totems then
336             for _, slot in pairs(frame.totems) do updateTotemFrame(frame, slot) end
337         end
338     end
339 end
340
341 Indicators:RegisterEvent("UNIT_AURA");
342 Indicators:RegisterEvent("PLAYER_TARGET_CHANGED");
343 Indicators:RegisterEvent("PLAYER_TOTEM_UPDATE");
344 Indicators:RegisterEvent("INSTANCE_ENCOUNTER_ENGAGE_UNIT");
345 Indicators:RegisterEvent("PLAYER_SPECIALIZATION_CHANGED");
346 Indicators:RegisterEvent("PLAYER_LOGIN");
347 Indicators:SetScript("OnEvent", function(self, event, arg1)
348     if event == "UNIT_AURA" then
349         updateAuras(arg1);
350     elseif event == "PLAYER_TARGET_CHANGED" then
351         updateAuras("target");
352     elseif event == "PLAYER_TOTEM_UPDATE" then
353         updateTotems(arg1);
354     elseif event == "INSTANCE_ENCOUNTER_ENGAGE_UNIT" then
355         for _, boss in pairs(bosses) do
356             updateAuras(boss);
357         end
358     elseif event == "PLAYER_SPECIALIZATION_CHANGED" then
359         currentSpec = GetSpecialization();
360         for _, frame in pairs(frames) do
361             if frame.auras then updateAuraFrame(frame) end
362             if frame.totems then
363                 for _, slot in pairs(frame.totems) do updateTotemFrame(frame, slot) end
364             end
365         end
366     elseif event == "PLAYER_LOGIN" then
367         initialize();
368     end
369 end);