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