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