d7d3cb503f199d49a9dfbbd84ede3531515c1f01
[wowui.git] / kehys / updater.lua
1 -- updater.lua
2 -- 2019 Aleksi Blinnikka
3 --
4 -- Main update function for all frames. Gets around issues with events.
5 local _, addon = ...;
6 local unpack = unpack;
7 local min = math.min;
8 local format = string.format;
9 local UnitDebuff, UnitIsCharmed = UnitDebuff, UnitIsCharmed;
10 local UnitHealth, UnitHealthMax = UnitHealth, UnitHealthMax;
11 local UnitPower, UnitPowerMax = UnitPower, UnitPowerMax;
12 local UnitIsAFK, UnitIsDND = UnitIsAFK, UnitIsDND;
13 local UnitGetIncomingHeals, UnitGetTotalAbsorbs = UnitGetIncomingHeals, UnitGetTotalAbsorbs;
14 local UnitIsDeadOrGhost, UnitIsConnected = UnitIsDeadOrGhost, UnitIsConnected;
15 local UnitGetTotalHealAbsorbs = UnitGetTotalHealAbsorbs;
16 local InCombatLockdown, IsResting = InCombatLockdown, IsResting;
17
18 local dispelcolor = addon.Colors.OverlayColorDispel;
19 local charmcolor = addon.Colors.OverlayColorCharm;
20 local majorcolor = addon.Colors.OverlayColorAlert;
21 local healcolor = addon.Colors.OverlayColorHeal;
22
23 local ignoredAuras = {
24     [315176] = true, -- Grasping Tendrils
25 };
26
27 local powerColors = {
28     [Enum.PowerType.Mana] = {0.1, 0.5, 0.9},
29     [Enum.PowerType.Rage] = {1, 0, 0},
30     [Enum.PowerType.Pain] = {1, 0, 0},
31     [Enum.PowerType.Focus] = {1, 0.5, 0},
32     [Enum.PowerType.Energy] = {1, 0.8, 0},
33     [Enum.PowerType.Fury] = {0.8, 0.3, 0.9},
34     [Enum.PowerType.RunicPower] = {0.8, 0, 0.2},
35     [Enum.PowerType.LunarPower] = {0.3, 0.5, 0.9},
36     [Enum.PowerType.Maelstrom] = {0, 0.5, 1},
37     [Enum.PowerType.Insanity] = {0.4, 0, 0.8},
38 };
39
40 function addon.FrameUpdate(frame)
41     assert(type(frame) == "table", "FrameUpdate received invalid frame parameter!");
42
43     local unit = frame.displayed;
44     local width = frame.barwidth;
45     -- range check (doesn't have an event) frames can be marked constantly visible
46     if not frame.constant then
47         local inrange, checked = UnitInRange(unit);
48         if checked and not inrange then
49             frame:SetAlpha(0.55);
50         else
51             frame:SetAlpha(1);
52         end
53     end
54     -- states
55     if UnitIsDeadOrGhost(unit) then
56         frame.text:SetText("Dead");
57         if not frame.text:IsShown() then frame.text:Show() end
58         if frame.health:IsShown() then frame.health:Hide() end
59         if frame.shield:IsShown() then frame.shield:Hide() end
60         if frame.shieldhl:IsShown() then frame.shieldhl:Hide() end
61         if frame.healpred:IsShown() then frame.healpred:Hide() end
62         if frame.healabsorb:IsShown() then frame.healabsorb:Hide() end
63         frame.prev.health = nil;
64         frame.prev.hmax = nil;
65     elseif not UnitIsConnected(unit) then
66         frame.text:SetText("DC");
67         if not frame.text:IsShown() then frame.text:Show() end
68         if frame.health:IsShown() then frame.health:Hide() end
69         if frame.shield:IsShown() then frame.shield:Hide() end
70         if frame.shieldhl:IsShown() then frame.shieldhl:Hide() end
71         if frame.healpred:IsShown() then frame.healpred:Hide() end
72         if frame.healabsorb:IsShown() then frame.healabsorb:Hide() end
73         frame.prev.health = nil;
74         frame.prev.hmax = nil;
75     else
76         if UnitIsAFK(unit) then
77             frame.text.status = true;
78             frame.prev.htext = nil;
79             frame.text:SetText("afk");
80             if not frame.text:IsShown() then frame.text:Show() end
81         elseif UnitIsDND(unit) then
82             frame.text.status = true;
83             frame.prev.htext = nil;
84             frame.text:SetText("dnd");
85             if not frame.text:IsShown() then frame.text:Show() end
86         else
87             frame.text.status = false;
88             if frame.raid and frame.text:IsShown() then
89                 frame.text:Hide();
90             end
91         end
92         if not frame.raid and frame.unit == "player" then
93             if InCombatLockdown() then
94                 frame.status:SetTexCoord(0.5, 1, 0, 0.484375);
95                 frame.status:Show();
96             elseif IsResting() then
97                 frame.status:SetTexCoord(0, 0.5, 0, 0.421875);
98                 frame.status:Show();
99             elseif frame.status:IsShown() then
100                 frame.status:Hide();
101             end
102         end
103         -- health
104         local current, hmax = UnitHealth(unit), UnitHealthMax(unit);
105         if frame.prev.health ~= current or frame.prev.hmax ~= hmax then
106             frame.prev.health = current;
107             frame.prev.hmax = hmax;
108             if hmax < current or hmax <= 1 then
109                 frame.health:SetWidth(width);
110                 frame.health.width = width;
111                 if not frame.health:IsShown() then frame.health:Show() end
112             elseif current <= 0 then
113                 if frame.health:IsShown() then frame.health:Hide() end
114             else
115                 local w = current/hmax*width;
116                 frame.health:SetWidth(w);
117                 frame.health.width = w;
118                 if not frame.health:IsShown() then frame.health:Show() end
119             end
120         end
121         -- health text
122         if not frame.raid and not frame.text.status and frame.prev.htext ~= current then
123             frame.prev.htext = current;
124             if frame.boss then
125                 if hmax < current or hmax <= 1 then
126                     frame.text:SetText("100");
127                     if not frame.text:IsShown() then frame.text:Show() end
128                 elseif current <= 0 then
129                     if frame.text:IsShown() then frame.text:Hide() end
130                 else
131                     frame.text:SetFormattedText("%.1f", current/hmax*100);
132                     if not frame.text:IsShown() then frame.text:Show() end
133                 end
134             else
135                 if current > 1000000000 then -- 1.0B
136                     frame.text:SetFormattedText("%.2fB", current / 1000000000);
137                 elseif current > 1000000 then -- 1.0M
138                     frame.text:SetFormattedText("%.2fM", current / 1000000);
139                 elseif current > 1000 then -- 1.0K
140                     frame.text:SetFormattedText("%.1fK", current / 1000);
141                 end
142                 if not frame.text:IsShown() then frame.text:Show() end
143             end
144         end
145         -- shield
146         local hwidth = frame.health.width;
147         current = UnitGetTotalAbsorbs(unit) or 0;
148         if current > 0 then
149             local space = width - hwidth;
150             current = (current / hmax) * width;
151             if space == 0 then
152                 if frame.shield:IsShown() then frame.shield:Hide() end
153                 if not frame.shieldhl:IsShown() then frame.shieldhl:Show() end
154             elseif space < current then
155                 frame.shield:SetWidth(space);
156                 if not frame.shield:IsShown() then frame.shield:Show() end
157                 if not frame.shieldhl:IsShown() then frame.shieldhl:Show() end
158             else
159                 frame.shield:SetWidth(current);
160                 if not frame.shield:IsShown() then frame.shield:Show() end
161                 if frame.shieldhl:IsShown() then frame.shieldhl:Hide() end
162             end
163         else
164             if frame.shield:IsShown() then frame.shield:Hide() end
165             if frame.shieldhl:IsShown() then frame.shieldhl:Hide() end
166         end
167         -- heal absorb
168         current = UnitGetTotalHealAbsorbs(unit) or 0;
169         if current > 0 then
170             current = (current / hmax) * width;
171             frame.healabsorb:SetWidth(min(hwidth, current));
172             if not frame.healabsorb:IsShown() then frame.healabsorb:Show() end
173         elseif frame.healabsorb:IsShown() then
174             frame.healabsorb:Hide();
175         end
176         -- heal prediction
177         current = UnitGetIncomingHeals(unit) or 0;
178         if current > 0 then
179             current = (current / hmax) * width;
180             -- at least 1 pixel prediction shown
181             frame.healpred:SetWidth(min(width - hwidth + 1, current));
182             if not frame.healpred:IsShown() then frame.healpred:Show() end
183         elseif frame.healpred:IsShown() then
184             frame.healpred:Hide();
185         end
186         -- mana, if present
187         if frame.mana ~= nil then
188             local current, max = UnitPower(unit), UnitPowerMax(unit);
189             local ptype = UnitPowerType(unit);
190             if frame.mana.ptype ~= ptype then
191                 frame.mana.ptype = ptype;
192                 frame.mana:SetVertexColor(unpack(powerColors[ptype]));
193             end
194             if frame.prev.mana ~= current or frame.prev.mmax ~= max then
195                 frame.prev.mana = current;
196                 frame.prev.mmax = max;
197                 if max < 1 then
198                     if frame.mana:IsShown() then frame.mana:Hide() end
199                     if frame.manatext:IsShown() then frame.manatext:Hide() end
200                 elseif max < current then
201                     frame.mana:SetWidth(width);
202                     frame.manatext:SetText("100");
203                     if not frame.mana:IsShown() then frame.mana:Show() end
204                     if not frame.manatext:IsShown() then frame.manatext:Show() end
205                 elseif current <= 0 then
206                     if frame.mana:IsShown() then frame.mana:Hide() end
207                     if frame.manatext:IsShown() then frame.manatext:Hide() end
208                 else
209                     local percent = current/max;
210                     frame.mana:SetWidth(percent*width);
211                     frame.manatext:SetText(format("%d", percent*100+0.5));
212                     if not frame.mana:IsShown() then frame.mana:Show() end
213                     if not frame.manatext:IsShown() then frame.manatext:Show() end
214                 end
215             end
216         end
217         -- forced aura updates
218         if frame.rounds ~= nil then
219             frame.rounds = frame.rounds + 1;
220             if (frame.rounds > 7) then
221                 frame.tankcd = {};
222                 frame.alert = {};
223                 frame.stacks = {};
224                 frame.heal = {};
225                 frame.buff1 = {};
226                 addon.SetAuras(frame.unit, frame.guid);
227                 frame.rounds = 0;
228             end
229         end
230         if frame.raid then
231             -- tank CD marker
232             if next(frame.tankcd) then
233                 if not frame.defensive:IsShown() then frame.defensive:Show() end
234             elseif frame.defensive:IsShown() then
235                 frame.defensive:Hide();
236             end
237             -- aura stacks
238             if next(frame.stacks) then
239                 local _, amount = next(frame.stacks);
240                 frame.stack:SetText(amount);
241                 if not frame.stack:IsShown() then frame.stack:Show() end
242             elseif frame.stack:IsShown() then
243                 frame.stack:Hide();
244             end
245             -- custom buff indicator 1
246             if next(frame.buff1) then
247                 if not frame.buffind1:IsShown() then frame.buffind1:Show() end
248             elseif frame.buffind1:IsShown() then
249                 frame.buffind1:Hide();
250             end
251             -- custom buff indicator 2
252             if next(frame.buff2) then
253                 if not frame.buffind2:IsShown() then frame.buffind2:Show() end
254             elseif frame.buffind2:IsShown() then
255                 frame.buffind2:Hide();
256             end
257             -- incoming ability
258             if next(frame.incoming) then
259                 if not frame.glow:IsShown() then frame.glow:Show() end
260             elseif frame.glow:IsShown() then
261                 frame.glow:Hide();
262             end
263             -- overlays
264             if next(frame.alert) then
265                 -- major
266                 if frame.overlay.color ~= majorcolor then
267                     frame.overlay:SetVertexColor(unpack(majorcolor));
268                     frame.overlay.color = majorcolor;
269                     if not frame.overlay:IsShown() then frame.overlay:Show() end
270                 end
271             else
272                 local _, _, _, _, _, _, _, _, _, spellid = UnitDebuff(unit, 1, "RAID");
273                 if UnitIsCharmed(unit) and frame.unit == frame.displayed then
274                     -- charmed
275                     if frame.overlay.color ~= charmcolor then
276                         frame.overlay:SetVertexColor(unpack(charmcolor));
277                         frame.overlay.color = charmcolor;
278                         if not frame.overlay:IsShown() then frame.overlay:Show() end
279                     end
280                 elseif spellid ~= nil and not ignoredAuras[spellid] then
281                     -- dispellable
282                     if frame.overlay.color ~= dispelcolor then
283                         frame.overlay:SetVertexColor(unpack(dispelcolor));
284                         frame.overlay.color = dispelcolor;
285                         if not frame.overlay:IsShown() then frame.overlay:Show() end
286                     end
287                 elseif next(frame.heal) then
288                     -- major heals needed
289                     if frame.overlay.color ~= healcolor then
290                         frame.overlay:SetVertexColor(unpack(healcolor));
291                         frame.overlay.color = healcolor;
292                         if not frame.overlay:IsShown() then frame.overlay:Show() end
293                     end
294                 else
295                     if frame.overlay.color ~= nil then
296                         frame.overlay.color = nil;
297                         if frame.overlay:IsShown() then frame.overlay:Hide() end
298                     end
299                 end
300             end
301         end
302     end
303 end