96ad366 - Add Shaman settings
[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 function updatePVP(frame, unit)
255     if UnitIsPVPFreeForAll(unit) then
256         frame.pvp:SetTexture("Interface\\TARGETINGFRAME\\UI-PVP-FFA");
257         frame.pvp:Show();
258     elseif UnitIsPVP(unit) then
259         local faction = UnitFactionGroup(unit);
260         if faction and faction ~= "Neutral" then
261             -- from FrameXML/PlayerFrame.lua, mercenary checks
262             if UnitIsMercenary(unit) then
263                 if faction == "Horde" then
264                     faction = "Alliance";
265                 elseif faction == "Alliance" then
266                     faction = "Horde";
267                 end
268             end
269             frame.pvp:SetTexture("Interface\\TARGETINGFRAME\\UI-PVP-"..faction);
270             frame.pvp:Show();
271         else
272             frame.pvp:Hide();
273         end
274     else
275         frame.pvp:Hide();
276     end
277 end
278
279 local function updateLeaderIcon(frame, unit)
280     if UnitIsGroupLeader(frame.unit) then
281         if HasLFGRestrictions() then
282             frame.leader:SetTexture("Interface\\LFGFrame\\UI-LFG-ICON-PORTRAITROLES");
283             frame.leader:SetTexCoord(0, 0.296875, 0.015625, 0.3125);
284         else
285             frame.leader:SetTexture("Interface\\GROUPFRAME\\UI-Group-LeaderIcon");
286             frame.leader:SetTexCoord(0, 1, 0, 1);
287         end
288         frame.leader:Show();
289     elseif UnitIsGroupAssistant(frame.unit) then
290         frame.leader:SetTexture("Interface\\GROUPFRAME\\UI-Group-AssistantIcon");
291         frame.leader:SetTexCoord(0, 1, 0, 1);
292         frame.leader:Show();
293     else
294         frame.leader:Hide();
295     end
296 end
297
298 local function updateHealthColor(frame, unit)
299     if not UnitPlayerControlled(unit) and UnitIsTapDenied(unit) then
300         frame.health:SetVertexColor(0.5, 0.5, 0.5);
301     elseif UnitIsPlayer(unit) then
302         local _, class = UnitClass(unit);
303         local color = RAID_CLASS_COLORS[class];
304         if color then
305             frame.health:SetVertexColor(color.r, color.g, color.b)
306         else
307             frame.health:SetVertexColor(unpack(healthColor))
308         end
309     elseif UnitPlayerControlled(unit) then
310         frame.health:SetVertexColor(0, 1, 0);
311     else
312         frame.health:SetVertexColor(UnitSelectionColor(unit));
313     end
314 end
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
326 local eventFuncs = {
327     ["UNIT_HEALTH"] = function(frame)
328         updateHealth(frame, frame.displayed);
329         updateHealthText(frame, frame.displayed);
330         if frame.shield then updateShield(frame, frame.displayed) end
331         if frame.healabsorb then updateHealAbsorb(frame, frame.displayed) end
332     end,
333     ["UNIT_POWER"] = 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_HEAL_ABSORB_AMOUNT_CHANGED"] = function(frame)
344         updateHealAbsorb(frame, frame.displayed);
345     end,
346     ["UNIT_THREAT_SITUATION_UPDATE"] = function(frame)
347         updateAggro(frame, frame.displayed);
348     end,
349     ["UNIT_MAXHEALTH"] = function(frame)
350         updateMaxHealth(frame, frame.displayed);
351         updateHealth(frame, frame.displayed);
352         updateHealthText(frame, frame.displayed);
353         if frame.shield then updateShield(frame, frame.displayed) end
354         if frame.healabsorb then updateHealAbsorb(frame, frame.displayed) end
355     end,
356     ["UNIT_MAXPOWER"] = function(frame)
357         updateMaxPower(frame, frame.displayed);
358         updatePower(frame, frame.displayed);
359         updatePowerText(frame, frame.displayed);
360     end,
361     ["UNIT_DISPLAYPOWER"] = function(frame)
362         updatePowerColor(frame, frame.displayed);
363         updateMaxPower(frame, frame.displayed);
364         updatePower(frame, frame.displayed);
365         updatePowerText(frame, frame.displayed);
366     end,
367     ["UNIT_NAME_UPDATE"] = function(frame)
368         if frame.name then updateName(frame, frame.displayed) end
369         updateHealthColor(frame, frame.displayed);
370     end,
371     ["UNIT_CONNECTION"] = function(frame)
372         updateHealthText(frame, frame.displayed);
373         updatePowerText(frame, frame.displayed);
374     end,
375     ["UNIT_LEVEL"] = function(frame)
376         -- if this is registered, frame has frame.level
377         updateLevelText(frame, frame.unit);
378     end,
379     ["PLAYER_LEVEL_UP"] = function(frame, arg1)
380         updateLevelText(frame, frame.unit, arg1);
381     end,
382     ["PLAYER_UPDATE_RESTING"] = function(frame)
383         -- player frame has frame.status
384         updateStatus(frame, frame.unit);
385     end,
386     ["PLAYER_REGEN_DISABLED"] = function(frame)
387         frame.inCombat = true;
388         if frame.status then updateStatus(frame, frame.unit) end
389     end,
390     ["PLAYER_REGEN_ENABLED"] = function(frame)
391         frame.inCombat = false;
392         if frame.status then updateStatus(frame, frame.unit) end
393     end,
394     ["UNIT_FACTION"] = function(frame)
395         if frame.pvp then updatePVP(frame, frame.unit) end
396         updateHealthColor(frame, frame.displayed);
397     end,
398     ["PARTY_LEADER_CHANGED"] = function(frame)
399         updateLeaderIcon(frame, frame.unit);
400     end,
401     ["RAID_TARGET_UPDATE"] = function(frame)
402         updateRaidMarker(frame, frame.displayed);
403     end,
404     ["UPDATE_ALL_BARS"] = function(frame)
405         if frame.vehicle then updateVehicle(frame) end
406         updateMaxHealth(frame, frame.displayed);
407         updateHealth(frame, frame.displayed);
408         updateHealthText(frame, frame.displayed);
409         updateHealthColor(frame, frame.displayed);
410         updateAggro(frame, frame.displayed);
411         updateRaidMarker(frame, frame.displayed);
412         if frame.mana then
413             updateMaxPower(frame, frame.displayed);
414             updatePower(frame, frame.displayed);
415             updatePowerText(frame, frame.displayed);
416             updatePowerColor(frame, frame.displayed);
417         end
418         if frame.auras then updateAuras(frame, frame.displayed) end
419         if frame.shield then updateShield(frame, frame.displayed) end
420         if frame.healabsorb then updateHealAbsorb(frame, frame.displayed) end
421         if frame.name then updateName(frame, frame.displayed) end
422         if frame.level then updateLevelText(frame, frame.unit) end
423         if frame.status then updateStatus(frame, frame.unit) end
424         if frame.pvp then updatePVP(frame, frame.unit) end
425         if frame.leader then updateLeaderIcon(frame, frame.unit) end
426     end,
427 };
428 eventFuncs["UNIT_HEALTH_FREQUENT"] = eventFuncs["UNIT_HEALTH"];
429 eventFuncs["UNIT_POWER_BAR_SHOW"] = eventFuncs["UNIT_DISPLAYPOWER"];
430 eventFuncs["UNIT_POWER_BAR_HIDE"] = eventFuncs["UNIT_DISPLAYPOWER"];
431 eventFuncs["UNIT_ENTERED_VEHICLE"] = eventFuncs["UPDATE_ALL_BARS"];
432 eventFuncs["UNIT_EXITED_VEHICLE"] = eventFuncs["UPDATE_ALL_BARS"];
433 eventFuncs["UNIT_PET"] = eventFuncs["UPDATE_ALL_BARS"];
434 eventFuncs["GROUP_ROSTER_UPDATE"] = eventFuncs["UPDATE_ALL_BARS"];
435 eventFuncs["PLAYER_ENTERING_WORLD"] = eventFuncs["UPDATE_ALL_BARS"];
436 eventFuncs["PLAYER_TARGET_CHANGED"] = eventFuncs["UPDATE_ALL_BARS"];
437 eventFuncs["INSTANCE_ENCOUNTER_ENGAGE_UNIT"] = eventFuncs["UPDATE_ALL_BARS"];
438 eventFuncs["UNIT_TARGETABLE_CHANGED"] = eventFuncs["UPDATE_ALL_BARS"];
439
440 function M.UnitEvent(self, event, arg1)
441     eventFuncs[event](self, arg1);
442 end