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