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