4fb3576 - Add pet and target frames
[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.status = true;
73             frame.text:SetText("afk");
74             if not frame.text:IsShown() then frame.text:Show() end
75         elseif UnitIsDND(unit) then
76             frame.text.status = true;
77             frame.text:SetText("dnd");
78             if not frame.text:IsShown() then frame.text:Show() end
79         else
80             frame.text.status = false;
81             if not (frame.nonraid and frame.unit == "target") and frame.text:IsShown() then
82                 frame.text:Hide();
83             end
84         end
85         if frame.nonraid and frame.unit == "player" then
86             if InCombatLockdown() then
87                 frame.status:SetTexCoord(0.5, 1, 0, 0.484375);
88                 frame.status:Show();
89             elseif IsResting() then
90                 frame.status:SetTexCoord(0, 0.5, 0, 0.421875);
91                 frame.status:Show();
92             elseif frame.status:IsShown() then
93                 frame.status:Hide();
94             end
95         end
96         -- TODO incoming res, maybe just with events?
97         -- health
98         local current, hmax = UnitHealth(unit), UnitHealthMax(unit);
99         if frame.prev.health ~= current or frame.prev.hmax ~= hmax then
100             if frame.nonraid and frame.unit == "target" and frame.prev.htext ~= current then
101                 frame.prev.htext = current;
102                 if current > 1000000000 then -- 1.0B
103                     frame.text:SetFormattedText("%.2fB", current / 1000000000);
104                 elseif current > 1000000 then -- 1.0M
105                     frame.text:SetFormattedText("%.2fM", current / 1000000);
106                 elseif current > 1000 then -- 1.0K
107                     frame.text:SetFormattedText("%.1fK", current / 1000);
108                 end
109                 if not frame.text:IsShown() then frame.text:Show() end
110             end
111             frame.prev.health = current;
112             frame.prev.hmax = hmax;
113             if hmax < current or hmax <= 1 then
114                 frame.health:SetWidth(width);
115                 frame.health.width = width;
116                 if not frame.health:IsShown() then frame.health:Show() end
117             elseif current <= 0 then
118                 if frame.health:IsShown() then frame.health:Hide() end
119             else
120                 local w = current/hmax*width;
121                 frame.health:SetWidth(w);
122                 frame.health.width = w;
123                 if not frame.health:IsShown() then frame.health:Show() end
124             end
125         end
126         -- shield
127         local hwidth = frame.health.width;
128         current = UnitGetTotalAbsorbs(unit) or 0;
129         if current > 0 then
130             local space = width - hwidth;
131             current = (current / hmax) * width;
132             if space == 0 then
133                 if frame.shield:IsShown() then frame.shield:Hide() end
134                 if not frame.shieldhl:IsShown() then frame.shieldhl:Show() end
135             elseif space < current then
136                 frame.shield:SetWidth(space);
137                 if not frame.shield:IsShown() then frame.shield:Show() end
138                 if not frame.shieldhl:IsShown() then frame.shieldhl:Show() end
139             else
140                 frame.shield:SetWidth(current);
141                 if not frame.shield:IsShown() then frame.shield:Show() end
142                 if frame.shieldhl:IsShown() then frame.shieldhl:Hide() end
143             end
144         else
145             if frame.shield:IsShown() then frame.shield:Hide() end
146             if frame.shieldhl:IsShown() then frame.shieldhl:Hide() end
147         end
148         -- heal absorb
149         current = UnitGetTotalHealAbsorbs(unit) or 0;
150         if current > 0 then
151             current = (current / hmax) * width;
152             frame.healabsorb:SetWidth(min(hwidth, current));
153             if not frame.healabsorb:IsShown() then frame.healabsorb:Show() end
154         elseif frame.healabsorb:IsShown() then
155             frame.healabsorb:Hide();
156         end
157         -- heal prediction
158         current = UnitGetIncomingHeals(unit) or 0;
159         if current > 0 then
160             current = (current / hmax) * width;
161             -- at least 1 pixel prediction shown
162             frame.healpred:SetWidth(min(width - hwidth + 1, current));
163             if not frame.healpred:IsShown() then frame.healpred:Show() end
164         elseif frame.healpred:IsShown() then
165             frame.healpred:Hide();
166         end
167         -- mana, if present
168         if frame.mana ~= nil then
169             local current, max = UnitPower(unit), UnitPowerMax(unit);
170             local ptype = UnitPowerType(unit);
171             if frame.mana.ptype ~= ptype then
172                 frame.mana.ptype = ptype;
173                 frame.mana:SetVertexColor(unpack(powerColors[ptype]));
174             end
175             if frame.prev.mana ~= current or frame.prev.mmax ~= max then
176                 frame.prev.mana = current;
177                 frame.prev.mmax = max;
178                 if max < current or max <= 1 then
179                     frame.mana:SetWidth(width);
180                     frame.manatext:SetText("100");
181                     if not frame.mana:IsShown() then frame.mana:Show() end
182                     if not frame.manatext:IsShown() then frame.manatext:Show() end
183                 elseif current <= 0 then
184                     if frame.mana:IsShown() then frame.mana:Hide() end
185                     if frame.manatext:IsShown() then frame.manatext:Hide() end
186                 else
187                     local percent = current/max;
188                     frame.mana:SetWidth(percent*width);
189                     frame.manatext:SetText(format("%d", percent*100+0.5));
190                     if not frame.mana:IsShown() then frame.mana:Show() end
191                     if not frame.manatext:IsShown() then frame.manatext:Show() end
192                 end
193             end
194         end
195         -- forced aura updates
196         if frame.rounds ~= nil then
197             frame.rounds = frame.rounds + 1;
198             if (frame.rounds > 7) then
199                 frame.tankcd = {};
200                 frame.alert = {};
201                 frame.stacks = {};
202                 frame.heal = {};
203                 frame.buff1 = {};
204                 addon.SetAuras(frame.unit, frame.guid);
205                 frame.rounds = 0;
206             end
207         end
208         if not frame.nonraid then
209             -- tank CD marker
210             if next(frame.tankcd) then
211                 if not frame.defensive:IsShown() then frame.defensive:Show() end
212             elseif frame.defensive:IsShown() then
213                 frame.defensive:Hide();
214             end
215             -- aura stacks
216             if next(frame.stacks) then
217                 local _, amount = next(frame.stacks);
218                 frame.stack:SetText(amount);
219                 if not frame.stack:IsShown() then frame.stack:Show() end
220             elseif frame.stack:IsShown() then
221                 frame.stack:Hide();
222             end
223             -- custom buff indicator 1
224             if next(frame.buff1) then
225                 if not frame.buffind1:IsShown() then frame.buffind1:Show() end
226             elseif frame.buffind1:IsShown() then
227                 frame.buffind1:Hide();
228             end
229             -- custom buff indicator 2
230             if next(frame.buff2) then
231                 if not frame.buffind2:IsShown() then frame.buffind2:Show() end
232             elseif frame.buffind2:IsShown() then
233                 frame.buffind2:Hide();
234             end
235             -- incoming ability
236             if next(frame.incoming) then
237                 if not frame.glow:IsShown() then frame.glow:Show() end
238             elseif frame.glow:IsShown() then
239                 frame.glow:Hide();
240             end
241             -- overlays
242             if next(frame.alert) then
243                 -- major
244                 if frame.overlay.color ~= majorcolor then
245                     frame.overlay:SetVertexColor(unpack(majorcolor));
246                     frame.overlay.color = majorcolor;
247                     if not frame.overlay:IsShown() then frame.overlay:Show() end
248                 end
249             else
250                 local _, _, _, _, _, _, _, _, _, spellid = UnitDebuff(unit, 1, "RAID");
251                 if UnitIsCharmed(unit) and frame.unit == frame.displayed then
252                     -- charmed
253                     if frame.overlay.color ~= charmcolor then
254                         frame.overlay:SetVertexColor(unpack(charmcolor));
255                         frame.overlay.color = charmcolor;
256                         if not frame.overlay:IsShown() then frame.overlay:Show() end
257                     end
258                 elseif spellid ~= nil and not ignoredAuras[spellid] then
259                     -- dispellable
260                     if frame.overlay.color ~= dispelcolor then
261                         frame.overlay:SetVertexColor(unpack(dispelcolor));
262                         frame.overlay.color = dispelcolor;
263                         if not frame.overlay:IsShown() then frame.overlay:Show() end
264                     end
265                 elseif next(frame.heal) then
266                     -- major heals needed
267                     if frame.overlay.color ~= healcolor then
268                         frame.overlay:SetVertexColor(unpack(healcolor));
269                         frame.overlay.color = healcolor;
270                         if not frame.overlay:IsShown() then frame.overlay:Show() end
271                     end
272                 else
273                     if frame.overlay.color ~= nil then
274                         frame.overlay.color = nil;
275                         if frame.overlay:IsShown() then frame.overlay:Hide() end
276                     end
277                 end
278             end
279         end
280     end
281 end