2d85b26 - Hide cast bar explicitly
[wowui.git] / OmaUF / Events.lua
1 -- Events.lua
2 local _;
3 local unpack = unpack;
4 local ssub = string.sub;
5 local min = math.min;
6 local ceil = math.ceil;
7 local UnitName, UnitClass, UnitExists = UnitName, UnitClass, UnitExists;
8 local UnitPower, UnitPowerMax, UnitPowerType = UnitPower, UnitPowerMax, UnitPowerType;
9 local UnitHealth, UnitHealthMax = UnitHealth, UnitHealthMax;
10 local UnitGetIncomingHeals, UnitGetTotalAbsorbs = UnitGetIncomingHeals, UnitGetTotalAbsorbs;
11 local UnitThreatSituation, GetThreatStatusColor = UnitThreatSituation, GetThreatStatusColor;
12 local UnitIsDeadOrGhost, UnitIsConnected = UnitIsDeadOrGhost, UnitIsConnected;
13 local UnitGetTotalHealAbsorbs = UnitGetTotalHealAbsorbs;
14 local UnitHasVehicleUI, UnitTargetsVehicleInRaidUI = UnitHasVehicleUI, UnitTargetsVehicleInRaidUI;
15 local UnitLevel, UnitClassification = UnitLevel, UnitClassification;
16 local UnitAffectingCombat, IsResting = UnitAffectingCombat, IsResting;
17 local UnitIsPVPFreeForAll, UnitIsPVP = UnitIsPVPFreeForAll, UnitIsPVP;
18 local UnitFactionGroup, UnitIsMercenary = UnitFactionGroup, UnitIsMercenary;
19 local UnitIsGroupLeader, UnitIsGroupAssistant = UnitIsGroupLeader, UnitIsGroupAssistant;
20 local HasLFGRestrictions = HasLFGRestrictions;
21 local UnitPlayerControlled, UnitIsPlayer = UnitPlayerControlled, UnitIsPlayer;
22 local UnitIsTapDenied, UnitSelectionColor = UnitIsTapDenied, UnitSelectionColor;
23 local GetRaidTargetIndex, SetRaidTargetIconTexture = GetRaidTargetIndex, SetRaidTargetIconTexture;
24 local RAID_CLASS_COLORS = RAID_CLASS_COLORS;
25
26 local updateAuraFrames = OmaUFAuras.UpdateAuras;
27
28 local Settings = OmaUFSettings;
29 local baseColor = Settings.BaseColor;
30 local healthColor = Settings.HealthColor;
31 local powerColors = Settings.PowerColors;
32
33 local M = {};
34 OmaUFEvents = M;
35 function M.RegisterUnitEvents(frame)
36     -- events are taken from FrameXML/CompactUnitFrame.lua and FrameXML/TargetFrame.lua
37     -- TODO player flags support (/afk, /dnd)
38     frame:RegisterEvent("RAID_TARGET_UPDATE"); -- have to register all and just check
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     if frame.mana then
44         frame:RegisterUnitEvent("UNIT_POWER", frame.unit, displayed);
45         frame:RegisterUnitEvent("UNIT_MAXPOWER", frame.unit, displayed);
46         frame:RegisterUnitEvent("UNIT_DISPLAYPOWER", frame.unit, displayed);
47         frame:RegisterUnitEvent("UNIT_POWER_BAR_SHOW", frame.unit, displayed);
48         frame:RegisterUnitEvent("UNIT_POWER_BAR_HIDE", frame.unit, displayed);
49     end
50     if frame.shield then
51         frame:RegisterUnitEvent("UNIT_ABSORB_AMOUNT_CHANGED", frame.unit, displayed);
52     end
53     if frame.healabsorb then
54         frame:RegisterUnitEvent("UNIT_HEAL_ABSORB_AMOUNT_CHANGED", frame.unit, displayed);
55     end
56     if frame.auras then
57         frame:RegisterUnitEvent("UNIT_AURA", frame.unit, displayed);
58     end
59     frame:RegisterUnitEvent("UNIT_NAME_UPDATE", frame.unit, displayed);
60     frame:RegisterUnitEvent("UNIT_THREAT_SITUATION_UPDATE", frame.unit, displayed);
61     frame:RegisterUnitEvent("UNIT_CONNECTION", frame.unit, displayed);
62     frame:RegisterUnitEvent("UNIT_FACTION", frame.unit, displayed);
63 end
64 local registerUnitEvents = M.RegisterUnitEvents;
65
66 local function updateMaxHealth(frame, unit)
67     frame.health.max = UnitHealthMax(unit);
68 end
69
70 local function updateHealth(frame, unit)
71     local current, max = UnitHealth(unit), frame.health.max;
72     if current > max or max <= 0 then
73         -- somehow current health has gone over the maximum (missed maxhealth event)
74         frame.health:SetWidth(frame.width);
75         updateMaxHealth(frame, unit);
76         frame.health:Show();
77     elseif current <= 0 or UnitIsDeadOrGhost(unit) then
78         frame.health:Hide();
79     else
80         frame.health:SetWidth(current/max*frame.width);
81         frame.health:Show();
82     end
83 end
84
85 local function updateHealthText(frame, unit)
86     if UnitIsDeadOrGhost(unit) then
87         frame.healthText:SetText("Dead");
88     elseif not UnitIsConnected(unit) then
89         frame.healthText:SetText("DC");
90     elseif frame.healthText.percent then
91         frame.healthText:SetFormattedText("%.1f", UnitHealth(unit)/frame.health.max*100);
92     else
93         local current = UnitHealth(unit);
94         if current > 1000000000 then -- 1.0B
95             frame.healthText:SetFormattedText("%.2fB", current / 1000000000);
96         elseif current > 1000000 then -- 1.0M
97             frame.healthText:SetFormattedText("%.2fM", current / 1000000);
98         elseif current > 1000 then -- 1K
99             frame.healthText:SetFormattedText("%.1fK", current / 1000);
100         else
101             frame.healthText:SetFormattedText("%d", current)
102         end
103     end
104 end
105
106 local function updateMaxPower(frame, unit)
107     frame.mana.max = UnitPowerMax(unit);
108 end
109
110 local function updatePower(frame, unit)
111     local current, max = UnitPower(unit), frame.mana.max;
112     if current <= 0 then
113         frame.mana:Hide();
114     elseif current > max or max <= 0 then
115         frame.mana:SetWidth(frame.width);
116         updateMaxPower(frame, unit);
117         frame.mana:Show();
118     else
119         frame.mana:SetWidth(current/max*frame.width);
120         frame.mana:Show();
121     end
122 end
123
124 local function updatePowerText(frame, unit)
125     local current, max = UnitPower(unit), frame.mana.max;
126     if UnitIsDeadOrGhost(unit) or not UnitIsConnected(unit) then
127         frame.manaText:Hide();
128     elseif max > 0 and current > 0 and current < max then
129         frame.manaText:SetText(ceil(current/max*100));
130         frame.manaText:Show();
131     else
132         frame.manaText:Hide();
133     end
134 end
135
136 local function updatePowerColor(frame, unit)
137     frame.mana:SetVertexColor(unpack(powerColors[UnitPowerType(unit)]));
138 end
139
140 local function updateName(frame, unit)
141     local name = UnitName(unit);
142     if not name then return end
143     frame.name:SetText(ssub(name, 1, frame.name.count));
144 end
145
146 local function updateShield(frame, unit)
147     local shield = UnitGetTotalAbsorbs(unit) or 0;
148     if shield > 0 then
149         local space = frame.width - frame.health:GetWidth();
150         shield = (shield / frame.health.max) * frame.width;
151         if space == 0 then
152             frame.shield:Hide();
153             frame.shieldhl:Show();
154         elseif space < shield then
155             frame.shield:SetWidth(space);
156             frame.shield:Show();
157             frame.shieldhl:Show();
158         else
159             frame.shield:SetWidth(shield);
160             frame.shield:Show();
161             frame.shieldhl:Hide();
162         end
163     else
164         frame.shield:Hide();
165         frame.shieldhl:Hide();
166     end
167 end
168
169 local function updateHealAbsorb(frame, unit)
170     local absorb = UnitGetTotalHealAbsorbs(unit) or 0;
171     if absorb > 0 then
172         local space = frame.health:GetWidth();
173         absorb = (absorb / frame.health.max) * frame.width;
174         frame.healabsorb:SetWidth(min(space, absorb));
175         frame.healabsorb:Show();
176     else
177         frame.healabsorb:Hide();
178     end
179 end
180
181 local function updateAuras(frame, unit)
182     if frame.auras then updateAuraFrames(frame, unit) end
183 end
184
185 local function updateAggro(frame, unit)
186     local status = UnitThreatSituation(unit);
187     if status and status > 0 then
188         frame.base:SetVertexColor(GetThreatStatusColor(status));
189     else
190         frame.base:SetVertexColor(unpack(baseColor));
191     end
192 end
193
194 -- only works for player frame
195 local function updateVehicle(frame)
196     local shouldTargetVehicle = UnitHasVehicleUI("player") and
197         UnitTargetsVehicleInRaidUI("player") and UnitExists("vehicle");
198     if shouldTargetVehicle then
199         if not frame.inVehicle then
200             frame.inVehicle = true;
201             frame.displayed = frame.vehicle;
202             registerUnitEvents(frame);
203         end
204     elseif frame.inVehicle then
205         frame.inVehicle = false;
206         frame.displayed = frame.unit;
207         registerUnitEvents(frame);
208     end
209 end
210
211 local function updateLevelText(frame, unit, levelup)
212     if levelup then
213         -- PLAYER_LEVEL_UP
214         frame.level:SetText(levelup);
215     else
216         local level = UnitLevel(unit);
217         local class = UnitClassification(unit);
218         local leveltext, classtext;
219         if level < 0 then
220             if class == "worldboss" then
221                 leveltext = "Boss";
222             else
223                 leveltext = "??";
224             end
225         else
226             leveltext = level;
227         end
228         if class == "rareelite" then
229             classtext = " Rare Elite";
230         elseif class == "elite" then
231             classtext = " Elite";
232         elseif class == "rare" then
233             classtext = " Rare";
234         else
235             classtext = "";
236         end
237         frame.level:SetFormattedText("%s%s", leveltext, classtext);
238     end
239 end
240
241 local function updateStatus(frame, unit)
242     -- coords from FrameXML/PlayerFrame.lua
243     if frame.inCombat or UnitAffectingCombat(unit) then
244         frame.status:SetTexCoord(0.5, 1, 0, 0.484375);
245         frame.status:Show();
246     elseif unit == "player" and IsResting() then
247         frame.status:SetTexCoord(0, 0.5, 0, 0.421875);
248         frame.status:Show();
249     else
250         frame.status:Hide();
251     end
252 end
253
254 local pvpIcons = {
255     Alliance = "Interface\\TARGETINGFRAME\\UI-PVP-Alliance",
256     Horde = "Interface\\TARGETINGFRAME\\UI-PVP-Horde"
257 };
258 local function updatePVP(frame, unit)
259     if UnitIsPVPFreeForAll(unit) then
260         frame.pvp:SetTexture("Interface\\TARGETINGFRAME\\UI-PVP-FFA");
261         frame.pvp:Show();
262     elseif UnitIsPVP(unit) then
263         local faction = UnitFactionGroup(unit);
264         if faction and faction ~= "Neutral" then
265             -- from FrameXML/PlayerFrame.lua, mercenary checks
266             if UnitIsMercenary(unit) then
267                 if faction == "Horde" then
268                     faction = "Alliance";
269                 elseif faction == "Alliance" then
270                     faction = "Horde";
271                 end
272             end
273             frame.pvp:SetTexture(pvpIcons[faction]);
274             frame.pvp:Show();
275         else
276             frame.pvp:Hide();
277         end
278     else
279         frame.pvp:Hide();
280     end
281 end
282
283 local function updateLeaderIcon(frame, unit)
284     if UnitIsGroupLeader(frame.unit) then
285         if HasLFGRestrictions() then
286             frame.leader:SetTexture("Interface\\LFGFrame\\UI-LFG-ICON-PORTRAITROLES");
287             frame.leader:SetTexCoord(0, 0.296875, 0.015625, 0.3125);
288         else
289             frame.leader:SetTexture("Interface\\GROUPFRAME\\UI-Group-LeaderIcon");
290             frame.leader:SetTexCoord(0, 1, 0, 1);
291         end
292         frame.leader:Show();
293     elseif UnitIsGroupAssistant(frame.unit) then
294         frame.leader:SetTexture("Interface\\GROUPFRAME\\UI-Group-AssistantIcon");
295         frame.leader:SetTexCoord(0, 1, 0, 1);
296         frame.leader:Show();
297     else
298         frame.leader:Hide();
299     end
300 end
301
302 local function updateHealthColor(frame, unit)
303     if not UnitPlayerControlled(unit) and UnitIsTapDenied(unit) then
304         frame.health:SetVertexColor(0.5, 0.5, 0.5);
305     elseif UnitIsPlayer(unit) then
306         local _, class = UnitClass(unit);
307         local color = RAID_CLASS_COLORS[class];
308         if color then
309             frame.health:SetVertexColor(color.r, color.g, color.b)
310         else
311             frame.health:SetVertexColor(unpack(healthColor))
312         end
313     elseif UnitPlayerControlled(unit) then
314         frame.health:SetVertexColor(0, 1, 0);
315     else
316         frame.health:SetVertexColor(UnitSelectionColor(unit));
317     end
318 end
319
320 local function updateRaidMarker(frame, unit)
321     local index = GetRaidTargetIndex(unit);
322     if index then
323         SetRaidTargetIconTexture(frame.targeticon, index);
324         frame.targeticon:Show();
325     else
326         frame.targeticon:Hide();
327     end
328 end
329
330 local eventFuncs = {
331     ["UNIT_HEALTH"] = function(frame)
332         updateHealth(frame, frame.displayed);
333         updateHealthText(frame, frame.displayed);
334         if frame.shield then updateShield(frame, frame.displayed) end
335         if frame.healabsorb then updateHealAbsorb(frame, frame.displayed) end
336     end,
337     ["UNIT_POWER"] = function(frame)
338         updatePower(frame, frame.displayed);
339         updatePowerText(frame, frame.displayed);
340     end,
341     ["UNIT_AURA"] = function(frame)
342         updateAuras(frame, frame.displayed);
343     end,
344     ["UNIT_ABSORB_AMOUNT_CHANGED"] = function(frame)
345         updateShield(frame, frame.displayed);
346     end,
347     ["UNIT_HEAL_ABSORB_AMOUNT_CHANGED"] = function(frame)
348         updateHealAbsorb(frame, frame.displayed);
349     end,
350     ["UNIT_THREAT_SITUATION_UPDATE"] = function(frame)
351         updateAggro(frame, frame.displayed);
352     end,
353     ["UNIT_MAXHEALTH"] = function(frame)
354         updateMaxHealth(frame, frame.displayed);
355         updateHealth(frame, frame.displayed);
356         updateHealthText(frame, frame.displayed);
357         if frame.shield then updateShield(frame, frame.displayed) end
358         if frame.healabsorb then updateHealAbsorb(frame, frame.displayed) end
359     end,
360     ["UNIT_MAXPOWER"] = function(frame)
361         updateMaxPower(frame, frame.displayed);
362         updatePower(frame, frame.displayed);
363         updatePowerText(frame, frame.displayed);
364     end,
365     ["UNIT_DISPLAYPOWER"] = function(frame)
366         updatePowerColor(frame, frame.displayed);
367         updateMaxPower(frame, frame.displayed);
368         updatePower(frame, frame.displayed);
369         updatePowerText(frame, frame.displayed);
370     end,
371     ["UNIT_NAME_UPDATE"] = function(frame)
372         if frame.name then updateName(frame, frame.displayed) end
373         updateHealthColor(frame, frame.displayed);
374     end,
375     ["UNIT_CONNECTION"] = function(frame)
376         updateHealthText(frame, frame.displayed);
377         updatePowerText(frame, frame.displayed);
378     end,
379     ["UNIT_LEVEL"] = function(frame)
380         -- if this is registered, frame has frame.level
381         updateLevelText(frame, frame.unit);
382     end,
383     ["PLAYER_LEVEL_UP"] = function(frame, arg1)
384         updateLevelText(frame, frame.unit, arg1);
385     end,
386     ["PLAYER_UPDATE_RESTING"] = function(frame)
387         -- player frame has frame.status
388         updateStatus(frame, frame.unit);
389     end,
390     ["PLAYER_REGEN_DISABLED"] = function(frame)
391         frame.inCombat = true;
392         if frame.status then updateStatus(frame, frame.unit) end
393     end,
394     ["PLAYER_REGEN_ENABLED"] = function(frame)
395         frame.inCombat = false;
396         if frame.status then updateStatus(frame, frame.unit) end
397     end,
398     ["UNIT_FACTION"] = function(frame)
399         if frame.pvp then updatePVP(frame, frame.unit) end
400         updateHealthColor(frame, frame.displayed);
401     end,
402     ["PARTY_LEADER_CHANGED"] = function(frame)
403         updateLeaderIcon(frame, frame.unit);
404     end,
405     ["RAID_TARGET_UPDATE"] = function(frame)
406         updateRaidMarker(frame, frame.displayed);
407     end,
408     ["UPDATE_ALL_BARS"] = function(frame)
409         if frame.vehicle then updateVehicle(frame) end
410         updateMaxHealth(frame, frame.displayed);
411         updateHealth(frame, frame.displayed);
412         updateHealthText(frame, frame.displayed);
413         updateHealthColor(frame, frame.displayed);
414         updateAggro(frame, frame.displayed);
415         updateRaidMarker(frame, frame.displayed);
416         if frame.mana then
417             updateMaxPower(frame, frame.displayed);
418             updatePower(frame, frame.displayed);
419             updatePowerText(frame, frame.displayed);
420             updatePowerColor(frame, frame.displayed);
421         end
422         if frame.auras then updateAuras(frame, frame.displayed) end
423         if frame.shield then updateShield(frame, frame.displayed) end
424         if frame.healabsorb then updateHealAbsorb(frame, frame.displayed) end
425         if frame.name then updateName(frame, frame.displayed) end
426         if frame.level then updateLevelText(frame, frame.unit) end
427         if frame.status then updateStatus(frame, frame.unit) end
428         if frame.pvp then updatePVP(frame, frame.unit) end
429         if frame.leader then updateLeaderIcon(frame, frame.unit) end
430     end,
431 };
432 eventFuncs["UNIT_HEALTH_FREQUENT"] = eventFuncs["UNIT_HEALTH"];
433 eventFuncs["UNIT_POWER_BAR_SHOW"] = eventFuncs["UNIT_DISPLAYPOWER"];
434 eventFuncs["UNIT_POWER_BAR_HIDE"] = eventFuncs["UNIT_DISPLAYPOWER"];
435 eventFuncs["UNIT_ENTERED_VEHICLE"] = eventFuncs["UPDATE_ALL_BARS"];
436 eventFuncs["UNIT_EXITED_VEHICLE"] = eventFuncs["UPDATE_ALL_BARS"];
437 eventFuncs["UNIT_PET"] = eventFuncs["UPDATE_ALL_BARS"];
438 eventFuncs["GROUP_ROSTER_UPDATE"] = eventFuncs["UPDATE_ALL_BARS"];
439 eventFuncs["PLAYER_ENTERING_WORLD"] = eventFuncs["UPDATE_ALL_BARS"];
440 eventFuncs["PLAYER_TARGET_CHANGED"] = eventFuncs["UPDATE_ALL_BARS"];
441 eventFuncs["INSTANCE_ENCOUNTER_ENGAGE_UNIT"] = eventFuncs["UPDATE_ALL_BARS"];
442 eventFuncs["UNIT_TARGETABLE_CHANGED"] = eventFuncs["UPDATE_ALL_BARS"];
443
444 function M.UnitEvent(self, event, arg1)
445     eventFuncs[event](self, arg1);
446 end