2deb9a3d024b1ffa69f5485557b6397f0726a0e4
[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 local chars = {
11     ["Stormreaver"] = {
12         ["Vildan"] = {
13             {
14                 unit = "target",
15                 spec = 3, -- Retribution
16                 auras = {"Judgment"},
17                 auraFilter = "PLAYER HARMFUL",
18                 x = 570, -- placed over Innervate frame
19                 y = 440,
20                 width = 80,
21                 height = 80,
22             },
23             {
24                 unit = "player",
25                 spec = 3, -- Retribution
26                 auras = {"Divine Purpose"},
27                 auraFilter = "PLAYER HELPFUL",
28                 x = 570,
29                 y = 530,
30                 width = 80,
31                 height = 80,
32             },
33             {
34                 unit = "player",
35                 spec = 2, -- Protection
36                 auras = {"Shield of the Righteous"},
37                 auraFilter = "PLAYER HELPFUL",
38                 x = 570,
39                 y = 440,
40                 width = 80,
41                 height = 80,
42             },
43             {
44                 unit = "player",
45                 auras = {"Divine Shield"},
46                 auraFilter = "PLAYER HELPFUL",
47                 x = 660,
48                 y = 440,
49                 width = 80,
50                 height = 80,
51             },
52         },
53         ["Gedren"] = {
54             {
55                 totems = {1}, -- Efflorescence
56                 x = 660,
57                 y = 440,
58                 width = 80,
59                 height = 80,
60             },
61         },
62         ["Gazden"] = {
63             {
64                 unit = "player",
65                 auras = {"Tidal Waves"},
66                 auraFilter = "PLAYER HELPFUL",
67                 x = 660,
68                 y = 440,
69                 width = 40,
70                 height = 40,
71             },
72             {
73                 unit = "player",
74                 auras = {"Healing Rain"},
75                 auraFilter = "PLAYER HELPFUL",
76                 x = 700,
77                 y = 440,
78                 width = 40,
79                 height = 40,
80             },
81         },
82     },
83 };
84
85 -- settings entry:
86 -- unit = unitID where to check auras, not required for totem checkers
87 -- spec = player spec index to show frame, if nil show always
88 -- auras = list of auras to track, in priority order
89 -- iterateAuras = iterate over UnitAura() instead of auras list
90 -- auraFilter = filter for UnitAura
91 -- totems = list of totem slots to track, in priority order, only checked if auras is nil
92 -- x = x position relative to UIParent bottom left
93 -- y = y position relative to UIParent bottom left
94 -- width = width
95 -- height = height
96
97 -- global frames' settings
98 local settings = {
99     {
100         unit = "player",
101         auras = {"Innervate"},
102         auraFilter = "HELPFUL",
103         x = 570,
104         y = 440,
105         width = 80,
106         height = 80,
107     },
108     {
109         unit = "player",
110         auras = {
111             "Delusions", "Entropic Blast", "Necrotic Embrace", "Flametouched", "Shadowtouched",
112             "Blazing Eruption", "Shattering Scream", "Consuming Hunger", "Unstable Soul",
113             "Time Bomb", "Broken Shard", "Demolished", "Fetid Rot",
114         },
115         iterateAuras = true, -- typically fewer debuffs on player than this list
116         auraFilter = "HARMFUL",
117         x = 660,
118         y = 530,
119         width = 80,
120         height = 80,
121     },
122 };
123
124 local frames = {};
125 local units = {}; -- mapping from unitID to frames
126 local totems = {}; -- mapping to frames with totems
127 local bosses = {};
128 for i = 1, MAX_BOSS_FRAMES do
129     bosses[i] = "boss"..i;
130 end
131 local currentSpec = 0; -- 0 is invalid
132
133 local Indicators = CreateFrame("Frame", "OmaTMW", UIParent);
134
135 local function updateAuraFrame(frame)
136     local unit = frame.unit;
137     if UnitExists(unit) and (not frame.spec or frame.spec == currentSpec) then
138         local name, icon, count, duration, expires;
139         local auraFilter = frame.auraFilter;
140         if frame.iterateAuras then
141             local i = 1;
142             while true do
143                 name, _, icon, count, _, duration, expires = UnitAura(unit, i, auraFilter);
144                 if not name then break end
145                 -- possible improvement to add spellID as an option
146                 if frame.auras[name] then
147                     if count > 0 then
148                         frame.stack:SetText(count);
149                         frame.stack:Show();
150                     else
151                         frame.stack:Hide();
152                     end
153                     if expires > 0 then
154                         frame.cd:SetCooldown(expires - duration, duration);
155                         frame.cd:Show();
156                     else
157                         frame.cd:Hide();
158                     end
159                     frame.icon:SetTexture(icon);
160                     frame:Show();
161                     return;
162                 end
163                 i = i + 1;
164             end
165         else
166             for _, aura in pairs(frame.auras) do
167                 name, _, icon, count, _, duration, expires = UnitAura(unit, aura, nil, auraFilter);
168                 if name then
169                     if count > 0 then
170                         frame.stack:SetText(count);
171                         frame.stack:Show();
172                     else
173                         frame.stack:Hide();
174                     end
175                     if expires > 0 then
176                         frame.cd:SetCooldown(expires - duration, duration);
177                         frame.cd:Show();
178                     else
179                         frame.cd:Hide();
180                     end
181                     frame.icon:SetTexture(icon);
182                     frame:Show();
183                     return;
184                 end
185             end
186         end
187     end
188     frame:Hide();
189 end
190
191 local function updateAuras(unit)
192     if units[unit] then
193         for _, i in pairs(units[unit]) do
194             updateAuraFrame(frames[i]);
195         end
196     end
197 end
198
199 local function updateTotemFrame(frame, slot)
200     local _, name, start, duration, icon = GetTotemInfo(slot);
201     if name ~= "" then
202         frame.cd:SetCooldown(start, duration);
203         frame.cd:Show();
204         frame.icon:SetTexture(icon);
205         frame:Show();
206     else
207         frame:Hide();
208     end
209 end
210
211 local function updateTotems(slot)
212     if totems[slot] then
213         for _, i in pairs(totems[slot]) do
214             updateTotemFrame(frames[i], slot);
215         end
216     end
217 end
218
219 local function createTMW(name, config, parent)
220     local frame = CreateFrame("Frame", name, parent);
221     frame:SetPoint("TOPLEFT", parent, "BOTTOMLEFT", config.x, config.y+config.height);
222     frame:SetPoint("BOTTOMRIGHT", parent, "BOTTOMLEFT", config.x+config.width, config.y);
223     frame.unit = config.unit;
224     frame.spec = config.spec;
225     frame.iterateAuras = config.iterateAuras;
226     if frame.iterateAuras then
227         frame.auras = {};
228         for _, v in pairs(config.auras) do
229             frame.auras[v] = true;
230         end
231     else
232         frame.auras = config.auras;
233     end
234     frame.auraFilter = config.auraFilter;
235     frame.totems = config.totems;
236     frame:Hide();
237     frame.base = frame:CreateTexture(nil, "BACKGROUND");
238     frame.base:SetAllPoints();
239     frame.base:SetColorTexture(0, 0, 0, 0.6);
240     frame.icon = frame:CreateTexture(nil, "ARTWORK");
241     frame.icon:SetPoint("TOPLEFT", frame.base, "TOPLEFT", 1, -1);
242     frame.icon:SetPoint("BOTTOMRIGHT", frame.base, "BOTTOMRIGHT", -1, 1);
243     frame.icon:SetTexCoord(0.07, 0.93, 0.07, 0.93);
244     frame.stack = frame:CreateFontString(nil, "OVERLAY", "NumberFontNormalLarge");
245     frame.stack:SetPoint("TOPLEFT");
246     frame.stack:Hide();
247     frame.cd = CreateFrame("Cooldown", name.."CD", frame, "CooldownFrameTemplate");
248     frame.cd:SetReverse(true);
249     frame.cd:SetAllPoints();
250     return frame;
251 end
252
253 local function initialize()
254     Indicators:SetFrameStrata("LOW");
255     Indicators:SetPoint("BOTTOMLEFT");
256     Indicators:SetWidth(1);
257     Indicators:SetHeight(1);
258     currentSpec = GetSpecialization();
259     local name, realm = UnitFullName("player");
260     if chars[realm] and chars[realm][name] then
261         for _, config in pairs(chars[realm][name]) do
262             table.insert(settings, config)
263         end
264     end
265     for i, config in pairs(settings) do
266         if config.unit then
267             if not units[config.unit] then units[config.unit] = {} end
268             table.insert(units[config.unit], i);
269         end
270         if config.totems then
271             for _, slot in pairs(config.totems) do
272                 if not totems[slot] then totems[slot] = {} end
273                 table.insert(totems[slot], i);
274             end
275         end
276         frames[i] = createTMW("OmaTMW"..i, config, Indicators);
277     end
278
279     for _, frame in pairs(frames) do
280         if frame.auras then updateAuraFrame(frame) end
281         if frame.totems then
282             for _, slot in pairs(frame.totems) do updateTotemFrame(frame, slot) end
283         end
284     end
285 end
286
287 Indicators:RegisterEvent("UNIT_AURA");
288 Indicators:RegisterEvent("PLAYER_TARGET_CHANGED");
289 Indicators:RegisterEvent("PLAYER_TOTEM_UPDATE");
290 Indicators:RegisterEvent("INSTANCE_ENCOUNTER_ENGAGE_UNIT");
291 Indicators:RegisterEvent("PLAYER_SPECIALIZATION_CHANGED");
292 Indicators:RegisterEvent("PLAYER_LOGIN");
293 Indicators:SetScript("OnEvent", function(self, event, arg1)
294     if event == "UNIT_AURA" then
295         updateAuras(arg1);
296     elseif event == "PLAYER_TARGET_CHANGED" then
297         updateAuras("target");
298     elseif event == "PLAYER_TOTEM_UPDATE" then
299         updateTotems(arg1);
300     elseif event == "INSTANCE_ENCOUNTER_ENGAGE_UNIT" then
301         for _, boss in pairs(bosses) do
302             updateAuras(boss);
303         end
304     elseif event == "PLAYER_SPECIALIZATION_CHANGED" then
305         currentSpec = GetSpecialization();
306         for _, frame in pairs(frames) do
307             if frame.auras then updateAuraFrame(frame) end
308             if frame.totems then
309                 for _, slot in pairs(frame.totems) do updateTotemFrame(frame, slot) end
310             end
311         end
312     elseif event == "PLAYER_LOGIN" then
313         initialize();
314     end
315 end);