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