52e5175 - Fix power bars, remove overlay color for basic unit frames
[wowui.git] / OmaRF / Events.lua
1 -- Events.lua
2 local _;
3 local unpack = unpack;
4 local ssub = string.sub;
5 local min = math.min;
6 local UnitName, UnitClass, UnitExists = UnitName, UnitClass, UnitExists;
7 local UnitDebuff, UnitIsCharmed = UnitDebuff, UnitIsCharmed;
8 local UnitPower, UnitPowerMax, UnitPowerType = UnitPower, UnitPowerMax, UnitPowerType;
9 local UnitHealth, UnitHealthMax = UnitHealth, UnitHealthMax;
10 local UnitIsAFK, UnitIsDND = UnitIsAFK, UnitIsDND;
11 local UnitGetIncomingHeals, UnitGetTotalAbsorbs = UnitGetIncomingHeals, UnitGetTotalAbsorbs;
12 local UnitThreatSituation, GetThreatStatusColor = UnitThreatSituation, GetThreatStatusColor;
13 local UnitIsDeadOrGhost, UnitIsConnected = UnitIsDeadOrGhost, UnitIsConnected;
14 local UnitHasIncomingResurrection = UnitHasIncomingResurrection;
15 local UnitGetTotalHealAbsorbs = UnitGetTotalHealAbsorbs;
16 local UnitHasVehicleUI, UnitTargetsVehicleInRaidUI = UnitHasVehicleUI, UnitTargetsVehicleInRaidUI;
17 local GetReadyCheckTimeLeft, GetReadyCheckStatus = GetReadyCheckTimeLeft, GetReadyCheckStatus;
18 local UnitGroupRolesAssigned = UnitGroupRolesAssigned;
19 local RAID_CLASS_COLORS = RAID_CLASS_COLORS;
20 local READY_CHECK_READY_TEXTURE = READY_CHECK_READY_TEXTURE;
21 local READY_CHECK_NOT_READY_TEXTURE = READY_CHECK_NOT_READY_TEXTURE;
22 local READY_CHECK_WAITING_TEXTURE = READY_CHECK_WAITING_TEXTURE;
23
24 local checkIndicators = OmaRFIndicators.CheckIndicators;
25
26 local Settings = OmaRFSettings;
27 local baseColor = Settings.BaseColor;
28 local overlayColorDispel = Settings.OverlayColorDispel;
29 local overlayColorCharm = Settings.OverlayColorCharm;
30 local overlayColorAlert = Settings.OverlayColorAlert;
31 local powerColors = Settings.PowerColors;
32 local width = Settings.Width;
33
34 local M = {};
35 OmaRFEvents = M;
36 function M.RegisterEvents(frame)
37     -- events are taken from FrameXML/CompactUnitFrame.lua
38     -- TODO raid marker support
39     local displayed = frame.unit ~= frame.displayed and frame.displayed or nil;
40     frame:RegisterUnitEvent("UNIT_HEALTH", frame.unit, displayed);
41     frame:RegisterUnitEvent("UNIT_HEALTH_FREQUENT", frame.unit, displayed);
42     frame:RegisterUnitEvent("UNIT_MAXHEALTH", frame.unit, displayed);
43     frame:RegisterUnitEvent("UNIT_POWER", frame.unit, displayed);
44     frame:RegisterUnitEvent("UNIT_MAXPOWER", frame.unit, displayed);
45     frame:RegisterUnitEvent("UNIT_DISPLAYPOWER", frame.unit, displayed);
46     frame:RegisterUnitEvent("UNIT_POWER_BAR_SHOW", frame.unit, displayed);
47     frame:RegisterUnitEvent("UNIT_POWER_BAR_HIDE", frame.unit, displayed);
48     frame:RegisterUnitEvent("UNIT_NAME_UPDATE", frame.unit, displayed);
49     frame:RegisterUnitEvent("UNIT_AURA", frame.unit, displayed);
50     frame:RegisterUnitEvent("UNIT_HEAL_PREDICTION", frame.unit, displayed);
51     frame:RegisterUnitEvent("UNIT_ABSORB_AMOUNT_CHANGED", frame.unit, displayed);
52     frame:RegisterUnitEvent("UNIT_HEAL_ABSORB_AMOUNT_CHANGED", frame.unit, displayed);
53     frame:RegisterUnitEvent("UNIT_THREAT_SITUATION_UPDATE", frame.unit, displayed);
54     frame:RegisterUnitEvent("UNIT_CONNECTION", frame.unit, displayed);
55     frame:RegisterUnitEvent("INCOMING_RESURRECT_CHANGED", frame.unit, displayed);
56     frame:RegisterUnitEvent("PLAYER_FLAGS_CHANGED", frame.unit, displayed);
57 end
58 local registerEvents = M.RegisterEvents;
59
60 local function updateHealth(frame, unit)
61     local current, max = UnitHealth(unit), frame.health.max;
62     frame.health:Show();
63     -- sanity check, occasionally UnitHealthMax gives zero
64     if current > max then
65         -- somehow current health has gone over the maximum (missed maxhealth event)
66         frame.health.max = UnitHealthMax(unit);
67         max = frame.health.max;
68         if current > max then
69             -- error state, still over maximum
70             frame.health:SetWidth(width);
71             return;
72         end
73     elseif max > 0 then
74         frame.health:SetWidth(current/frame.health.max*width);
75     else
76         frame.health:SetWidth(width);
77         return;
78     end
79
80     if UnitIsDeadOrGhost(unit) then
81         frame.health:Hide();
82     end
83 end
84
85 local function updateText(frame, unit)
86     local current, max = UnitHealth(unit), frame.health.max;
87     local healthLost = max - current;
88     if UnitIsDeadOrGhost(unit) then
89         frame.text:SetText("Dead");
90         frame.text:Show();
91     elseif not UnitIsConnected(unit) then
92         frame.text:SetText("DC");
93         frame.text:Show();
94     elseif UnitIsAFK(unit) then
95         frame.text:SetText("afk");
96         frame.text:Show();
97     elseif UnitIsDND(unit) and healthLost == 0 then
98         frame.text:SetText("dnd");
99         frame.text:Show();
100     elseif healthLost > 0 then
101         if healthLost > 1200000000 then -- 1.2B
102             frame.text:SetFormattedText("-%.1fB", healthLost / 1000000000);
103         elseif healthLost > 1200000 then -- 1.2M
104             frame.text:SetFormattedText("-%.1fM", healthLost / 1000000);
105         elseif healthLost > 1000 then -- 1K
106             frame.text:SetFormattedText("-%dK", healthLost / 1000);
107         else
108             frame.text:SetFormattedText("-%d", healthLost)
109         end
110         frame.text:Show();
111     else
112         frame.text:Hide();
113     end
114 end
115
116 local function updateIncomingRes(frame, unit)
117     if UnitHasIncomingResurrection(unit) then
118         frame.rez:Show();
119     else
120         frame.rez:Hide();
121     end
122 end
123
124 local function updateMaxHealth(frame, unit)
125     frame.health.max = UnitHealthMax(unit);
126 end
127
128 local function updatePower(frame, unit)
129     local current, max = UnitPower(unit), frame.mana.max;
130     -- sanity check, occasionally UnitPowerMax gives zero
131     if current > max then
132         frame.mana.max = UnitPowerMax(unit);
133         max = frame.mana.max;
134         if current > max then
135             -- error
136             frame.mana:SetWidth(width);
137             return;
138         end
139     elseif max > 0 then
140         frame.mana:SetWidth(UnitPower(unit)/max*width);
141     else
142         frame.mana:SetWidth(width);
143     end
144 end
145
146 local function updateMaxPower(frame, unit)
147     frame.mana.max = UnitPowerMax(unit);
148 end
149
150 local function updatePowerColor(frame, unit)
151     frame.mana:SetVertexColor(unpack(powerColors[UnitPowerType(unit)]));
152 end
153
154 local function updateName(frame, unit)
155     local name = UnitName(unit);
156     if not name then return end
157     frame.name:SetText(ssub(name, 1, 6));
158
159     local _, class = UnitClass(unit);
160     local color = RAID_CLASS_COLORS[class];
161     if color then frame.name:SetVertexColor(color.r, color.g, color.b) end
162 end
163
164 local function updateHealPred(frame, unit)
165     local incoming = UnitGetIncomingHeals(unit) or 0;
166     if incoming > 0 then
167         local max = frame.health.max;
168         local space = width - frame.health:GetWidth() + 1;
169         local pred = (incoming / max) * width;
170         frame.healpred:SetWidth(min(space, pred));
171         frame.healpred:Show();
172     else
173         frame.healpred:Hide();
174     end
175 end
176
177 local function updateShield(frame, unit)
178     local shield = UnitGetTotalAbsorbs(unit) or 0;
179     if shield > 0 then
180         local max = frame.health.max;
181         local space = width - frame.health:GetWidth();
182         shield = (shield / max) * width;
183         if space < shield then
184             frame.shield:SetWidth(space);
185             frame.shieldhl:Show();
186         else
187             frame.shield:SetWidth(shield);
188             frame.shieldhl:Hide();
189         end
190         frame.shield:Show();
191     else
192         frame.shield:Hide();
193         frame.shieldhl:Hide();
194     end
195 end
196
197 local function updateHealAbsorb(frame, unit)
198     local absorb = UnitGetTotalHealAbsorbs(unit) or 0;
199     if absorb > 0 then
200         local max = frame.health.max;
201         local space = frame.health:GetWidth();
202         absorb = (absorb / max) * width;
203         frame.healabsorb:SetWidth(min(space, absorb));
204         frame.healabsorb:Show();
205     else
206         frame.healabsorb:Hide();
207     end
208 end
209
210 local function updateAuras(frame, unit)
211     checkIndicators(frame, unit);
212     if UnitDebuff(unit, 1, "RAID") ~= nil then
213         -- something dispellable
214         if frame.overlay.color ~= overlayColorDispel then
215             frame.overlay:SetVertexColor(unpack(overlayColorDispel));
216             frame.overlay:Show();
217             frame.overlay.color = overlayColorDispel;
218         end
219     -- don't overlay charmed when in vehicle
220     elseif UnitIsCharmed(unit) and unit == frame.unit then
221         if frame.overlay.color ~= overlayColorCharm then
222             frame.overlay:SetVertexColor(unpack(overlayColorCharm));
223             frame.overlay:Show();
224             frame.overlay.color = overlayColorCharm;
225         end
226     else
227         if frame.overlay.color ~= nil then
228             frame.overlay:Hide();
229             frame.overlay.color = nil;
230         end
231     end
232 end
233
234 local function updateAggro(frame, unit)
235     local status = UnitThreatSituation(unit);
236     if status and status > 0 then
237         frame.base:SetVertexColor(GetThreatStatusColor(status));
238     else
239         frame.base:SetVertexColor(unpack(baseColor));
240     end
241 end
242
243 local function updateVehicle(frame)
244     local shouldTargetVehicle = UnitHasVehicleUI(frame.unit) and UnitTargetsVehicleInRaidUI(frame.unit) and UnitExists(frame.vehicle);
245     if shouldTargetVehicle then
246         if not frame.inVehicle then
247             frame.inVehicle = true;
248             frame.displayed = frame.vehicle;
249             registerEvents(frame);
250         end
251     elseif frame.inVehicle then
252         frame.inVehicle = false;
253         frame.displayed = frame.unit;
254         registerEvents(frame);
255     end
256 end
257
258 local function updateRole(frame, unit)
259     local role = UnitGroupRolesAssigned(unit);
260     if role == "HEALER" then
261         frame.role:SetTexCoord(0.75, 1, 0, 1);
262         frame.role:Show();
263     elseif role == "TANK" then
264         frame.role:SetTexCoord(0.5, 0.75, 0, 1);
265         frame.role:Show();
266     else
267         frame.role:Hide();
268     end
269 end
270
271 local function updateReadyCheck(frame, unit)
272     local status = GetReadyCheckStatus(unit);
273     if status == "ready" then
274         frame.ready:SetTexture(READY_CHECK_READY_TEXTURE);
275         frame.ready:Show()
276     elseif status == "notready" then
277         frame.ready:SetTexture(READY_CHECK_NOT_READY_TEXTURE);
278         frame.ready:Show()
279     elseif status == "waiting" then
280         frame.ready:SetTexture(READY_CHECK_WAITING_TEXTURE);
281         frame.ready:Show()
282     else
283         frame.ready:Hide()
284     end
285 end
286
287 local eventFuncs = {
288     ["UNIT_HEALTH"] = function(frame)
289         updateHealth(frame, frame.displayed);
290         updateText(frame, frame.displayed);
291         updateShield(frame, frame.displayed);
292         updateHealAbsorb(frame, frame.displayed);
293         -- no heal prediction update, that doesn't overflow too much
294     end,
295     ["UNIT_POWER"] = function(frame)
296         updatePower(frame, frame.displayed);
297     end,
298     ["UNIT_AURA"] = function(frame)
299         updateAuras(frame, frame.displayed);
300     end,
301     ["UNIT_HEAL_PREDICTION"] = function(frame)
302         updateHealPred(frame, frame.displayed);
303     end,
304     ["UNIT_ABSORB_AMOUNT_CHANGED"] = function(frame)
305         updateShield(frame, frame.displayed);
306     end,
307     ["UNIT_HEAL_ABSORB_AMOUNT_CHANGED"] = function(frame)
308         updateHealAbsorb(frame, frame.displayed);
309     end,
310     ["UNIT_THREAT_SITUATION_UPDATE"] = function(frame)
311         updateAggro(frame, frame.displayed);
312     end,
313     ["UNIT_MAXHEALTH"] = function(frame)
314         updateMaxHealth(frame, frame.displayed);
315         updateHealth(frame, frame.displayed);
316         updateText(frame, frame.displayed);
317         updateShield(frame, frame.displayed);
318         updateHealAbsorb(frame, frame.displayed);
319     end,
320     ["UNIT_MAXPOWER"] = function(frame)
321         updateMaxPower(frame, frame.displayed);
322         updatePower(frame, frame.displayed);
323     end,
324     ["UNIT_DISPLAYPOWER"] = function(frame)
325         updatePowerColor(frame, frame.displayed);
326         updateMaxPower(frame, frame.displayed);
327         updatePower(frame, frame.displayed);
328     end,
329     ["UNIT_NAME_UPDATE"] = function(frame)
330         updateName(frame, frame.displayed);
331     end,
332     ["UNIT_CONNECTION"] = function(frame)
333         updateText(frame, frame.displayed);
334     end,
335     ["INCOMING_RESURRECT_CHANGED"] = function(frame)
336         updateIncomingRes(frame, frame.unit);
337     end,
338     ["PARTY_MEMBER_ENABLE"] = function(frame)
339         -- new power info possibly (FrameXML/CompactUnitFrame.lua)
340         updateMaxPower(frame, frame.displayed);
341         updatePowerColor(frame, frame.displayed);
342     end,
343     ["PLAYER_ROLES_ASSIGNED"] = function(frame)
344         updateRole(frame, frame.unit);
345     end,
346     ["READY_CHECK"] = function(frame)
347         updateReadyCheck(frame, frame.unit);
348     end,
349     ["UPDATE_ALL_BARS"] = function(frame)
350         updateVehicle(frame);
351         updateMaxHealth(frame, frame.displayed);
352         updateMaxPower(frame, frame.displayed);
353         updateHealth(frame, frame.displayed);
354         updateText(frame, frame.displayed);
355         updatePower(frame, frame.displayed);
356         updateAuras(frame, frame.displayed);
357         updateShield(frame, frame.displayed);
358         updateHealPred(frame, frame.displayed);
359         updateHealAbsorb(frame, frame.displayed);
360         updatePowerColor(frame, frame.displayed);
361         updateIncomingRes(frame, frame.unit);
362         updateReadyCheck(frame, frame.unit);
363         updateAggro(frame, frame.displayed);
364         updateName(frame, frame.displayed);
365         updateRole(frame, frame.unit);
366     end,
367 };
368 eventFuncs["UNIT_HEALTH_FREQUENT"] = eventFuncs["UNIT_HEALTH"];
369 eventFuncs["PARTY_MEMBER_DISABLE"] = eventFuncs["PARTY_MEMBER_ENABLE"];
370 eventFuncs["PLAYER_FLAGS_CHANGED"] = eventFuncs["UNIT_CONNECTION"];
371 eventFuncs["UNIT_POWER_BAR_SHOW"] = eventFuncs["UNIT_DISPLAYPOWER"];
372 eventFuncs["UNIT_POWER_BAR_HIDE"] = eventFuncs["UNIT_DISPLAYPOWER"];
373 eventFuncs["READY_CHECK_CONFIRM"] = eventFuncs["READY_CHECK"];
374 eventFuncs["READY_CHECK_FINISHED"] = eventFuncs["READY_CHECK"];
375 eventFuncs["UNIT_ENTERED_VEHICLE"] = eventFuncs["UPDATE_ALL_BARS"];
376 eventFuncs["UNIT_EXITED_VEHICLE"] = eventFuncs["UPDATE_ALL_BARS"];
377 eventFuncs["UNIT_PET"] = eventFuncs["UPDATE_ALL_BARS"];
378 eventFuncs["GROUP_ROSTER_UPDATE"] = eventFuncs["UPDATE_ALL_BARS"];
379 eventFuncs["PLAYER_ENTERING_WORLD"] = eventFuncs["UPDATE_ALL_BARS"];
380 eventFuncs["PLAYER_FOCUS_CHANGED"] = eventFuncs["UPDATE_ALL_BARS"];
381
382 function M.UnitEvent(self, event)
383     eventFuncs[event](self);
384 end