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