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