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