2 -- 2019 Aleksi Blinnikka
5 local ssub = string.sub;
7 local UnitName, UnitClass, UnitExists = UnitName, UnitClass, UnitExists;
8 local UnitDebuff, UnitIsCharmed = UnitDebuff, UnitIsCharmed;
9 local UnitHealth, UnitHealthMax = UnitHealth, UnitHealthMax;
10 local UnitIsAFK, UnitIsDND = UnitIsAFK, UnitIsDND;
11 local UnitGetIncomingHeals, UnitGetTotalAbsorbs = UnitGetIncomingHeals, UnitGetTotalAbsorbs;
12 local UnitThreatSituation, GetThreatStatusColor = UnitThreatSituation, GetThreatStatusColor;
13 local UnitIsDeadOrGhost, UnitIsConnected = UnitIsDeadOrGhost, UnitIsConnected;
14 local UnitGetTotalHealAbsorbs = UnitGetTotalHealAbsorbs;
15 local UnitHasVehicleUI, UnitTargetsVehicleInRaidUI = UnitHasVehicleUI, UnitTargetsVehicleInRaidUI;
16 local GetReadyCheckTimeLeft, GetReadyCheckStatus = GetReadyCheckTimeLeft, GetReadyCheckStatus;
17 local UnitGroupRolesAssigned = UnitGroupRolesAssigned;
18 local GetRaidTargetIndex, SetRaidTargetIconTexture = GetRaidTargetIndex, SetRaidTargetIconTexture;
19 local RAID_CLASS_COLORS = RAID_CLASS_COLORS;
20 local READY_CHECK_READY_TEXTURE = READY_CHECK_READY_TEXTURE;
21 local READY_CHECK_NOT_READY_TEXTURE = READY_CHECK_NOT_READY_TEXTURE;
22 local READY_CHECK_WAITING_TEXTURE = READY_CHECK_WAITING_TEXTURE;
26 local baseColor = {0, 0, 0};
27 local overlayColorDispel = {1, 0.5, 0, 0.5};
28 local overlayColorCharm = {0.8, 0, 1, 0.5};
29 local overlayColorAlert = {1, 0, 0, 0.5};
32 function addon.RegisterEvents(frame)
33 frame:RegisterEvent("PLAYER_ENTERING_WORLD");
34 frame:RegisterEvent("PLAYER_ROLES_ASSIGNED");
35 frame:RegisterEvent("READY_CHECK");
36 frame:RegisterEvent("READY_CHECK_FINISHED");
37 frame:RegisterEvent("GROUP_ROSTER_UPDATE");
38 frame:RegisterEvent("RAID_TARGET_UPDATE");
39 if frame.unit == "focus" then frame:RegisterEvent("PLAYER_FOCUS_CHANGED") end
42 function addon.RegisterUnitEvents(frame)
43 -- events are taken from FrameXML/CompactUnitFrame.lua
44 local displayed = frame.unit ~= frame.displayed and frame.displayed or nil;
45 frame:RegisterUnitEvent("UNIT_HEALTH_FREQUENT", frame.unit, displayed);
46 frame:RegisterUnitEvent("UNIT_MAXHEALTH", frame.unit, displayed);
47 frame:RegisterUnitEvent("UNIT_NAME_UPDATE", frame.unit, displayed);
48 frame:RegisterUnitEvent("UNIT_AURA", frame.unit, displayed);
49 --frame:RegisterUnitEvent("UNIT_HEAL_PREDICTION", frame.unit, displayed);
50 frame:RegisterUnitEvent("UNIT_ABSORB_AMOUNT_CHANGED", frame.unit, displayed);
51 frame:RegisterUnitEvent("UNIT_HEAL_ABSORB_AMOUNT_CHANGED", frame.unit, displayed);
52 frame:RegisterUnitEvent("UNIT_THREAT_SITUATION_UPDATE", frame.unit, displayed);
53 frame:RegisterUnitEvent("UNIT_CONNECTION", frame.unit, displayed);
54 frame:RegisterUnitEvent("PLAYER_FLAGS_CHANGED", frame.unit, displayed);
55 frame:RegisterUnitEvent("READY_CHECK_CONFIRM", frame.unit, displayed);
56 frame:RegisterUnitEvent("UNIT_ENTERED_VEHICLE", frame.unit, displayed);
57 frame:RegisterUnitEvent("UNIT_EXITED_VEHICLE", frame.unit, displayed);
58 frame:RegisterUnitEvent("UNIT_PET", frame.unit, displayed);
60 local registerUnitEvents = addon.RegisterUnitEvents;
62 local function updateText(frame, unit)
63 if UnitIsDeadOrGhost(unit) then
65 frame.text:SetText("Dead");
67 elseif not UnitIsConnected(unit) then
68 frame.text:SetText("DC");
70 elseif UnitIsAFK(unit) then
71 frame.text:SetText("afk");
73 elseif UnitIsDND(unit) then
74 frame.text:SetText("dnd");
80 addon.Events.UpdateText = updateText;
82 local function updateMaxHealth(frame, unit)
83 frame.health.max = UnitHealthMax(unit);
85 addon.Events.UpdateMaxHealth = updateMaxHealth;
87 local function updateHealth(frame, unit)
88 local current, max = UnitHealth(unit), frame.health.max;
89 if current == frame.prev.health then
92 frame.prev.health = current;
93 if current > max or max <= 0 then
94 -- somehow current health has gone over the maximum (missed maxhealth event possibly)
95 -- just put health bar full and update max health for next event
96 frame.health:SetWidth(width);
97 frame.health.width = width;
98 updateMaxHealth(frame, unit);
100 elseif current <= 0 or UnitIsDeadOrGhost(unit) then
102 updateText(frame, unit); -- update death
104 local w = current/max*width;
105 frame.health:SetWidth(w);
106 frame.health.width = w;
110 if frame.dead and current > 0 then
112 updateText(frame, unit); -- update revive
116 addon.Events.UpdateHealth = updateHealth;
118 local function updateName(frame, unit)
119 local name = UnitName(unit);
120 if not name then return end
121 name = ssub(name, 1, 6);
122 if frame.unit == unit then
123 frame.name:SetText(name);
125 frame.name:SetFormattedText("-%s", name);
128 local _, class = UnitClass(unit);
129 local color = RAID_CLASS_COLORS[class];
130 if color then frame.name:SetVertexColor(color.r, color.g, color.b) end
132 addon.Events.UpdateName = updateName;
134 local function updateHealPred(frame, unit)
135 local incoming = UnitGetIncomingHeals(unit) or 0;
137 incoming = (incoming / frame.health.max) * width;
138 -- always at least 1 pixel space for heal prediction
139 frame.healpred:SetWidth(min(width - frame.health.width + 1, incoming));
140 if not frame.healpred:IsShown() then frame.healpred:Show() end
142 if frame.healpred:IsShown() then frame.healpred:Hide() end
145 addon.Events.UpdateHealPred = updateHealPred;
147 local function updateShield(frame, unit)
148 local shield = UnitGetTotalAbsorbs(unit) or 0;
150 local space = width - frame.health.width;
151 shield = (shield / frame.health.max) * width;
153 if frame.shield:IsShown() then frame.shield:Hide() end
154 if not frame.shieldhl:IsShown() then frame.shieldhl:Show() end
155 elseif space < shield then
156 frame.shield:SetWidth(space);
157 if not frame.shield:IsShown() then frame.shield:Show() end
158 if not frame.shieldhl:IsShown() then frame.shieldhl:Show() end
160 frame.shield:SetWidth(shield);
161 if not frame.shield:IsShown() then frame.shield:Show() end
162 if frame.shieldhl:IsShown() then frame.shieldhl:Hide() end
165 if frame.shield:IsShown() then frame.shield:Hide() end
166 if frame.shieldhl:IsShown() then frame.shieldhl:Hide() end
169 addon.Events.UpdateShield = updateShield;
171 local function updateHealAbsorb(frame, unit)
172 local absorb = UnitGetTotalHealAbsorbs(unit) or 0;
174 absorb = (absorb / frame.health.max) * width;
175 frame.healabsorb:SetWidth(min(frame.health.width, absorb));
176 frame.healabsorb:Show();
178 frame.healabsorb:Hide();
181 addon.Events.UpdateHealAbsorb = updateHealAbsorb;
183 local function updateAuras(frame, unit)
184 -- don't overlay charmed when in vehicle
185 --[[if UnitIsCharmed(unit) and unit == frame.unit then
186 if frame.overlay.color ~= overlayColorCharm then
187 frame.overlay:SetVertexColor(unpack(overlayColorCharm));
188 frame.overlay.color = overlayColorCharm;
189 frame.overlay:Show();
192 if UnitDebuff(unit, 1, "RAID") ~= nil then
193 -- something dispellable
194 if frame.overlay.color ~= overlayColorDispel then
195 frame.overlay:SetVertexColor(unpack(overlayColorDispel));
196 frame.overlay.color = overlayColorDispel;
197 if not frame.overlay:IsShown() then frame.overlay:Show() end
200 if frame.overlay.color ~= nil then
201 frame.overlay.color = nil;
202 if frame.overlay:IsShown() then frame.overlay:Hide() end
206 addon.Events.UpdateAuras = updateAuras;
208 local function updateAggro(frame, unit)
209 local status = UnitThreatSituation(unit);
210 if status and status > 0 then
211 frame.base:SetVertexColor(GetThreatStatusColor(status));
213 frame.base:SetVertexColor(unpack(baseColor));
216 addon.Events.UpdateAggro = updateAggro;
218 local function updateVehicle(frame)
219 local shouldTargetVehicle = UnitHasVehicleUI(frame.unit) and
220 UnitTargetsVehicleInRaidUI(frame.unit) and UnitExists(frame.vehicle);
221 if shouldTargetVehicle then
222 if not frame.inVehicle then
223 frame.inVehicle = true;
224 frame.displayed = frame.vehicle;
225 registerUnitEvents(frame);
227 elseif frame.inVehicle then
228 frame.inVehicle = false;
229 frame.displayed = frame.unit;
230 registerUnitEvents(frame);
233 addon.Events.UpdateVehicle = updateVehicle;
235 local function updateRole(frame, unit)
236 local role = UnitGroupRolesAssigned(unit);
237 if role == "HEALER" then
238 frame.role:SetTexCoord(0.75, 1, 0, 1);
240 elseif role == "TANK" then
241 frame.role:SetTexCoord(0.5, 0.75, 0, 1);
247 addon.Events.UpdateRole = updateRole;
249 local function updateReadyCheck(frame, unit)
250 local status = GetReadyCheckStatus(unit);
251 if status == "ready" then
252 frame.ready:SetTexture(READY_CHECK_READY_TEXTURE);
254 elseif status == "notready" then
255 frame.ready:SetTexture(READY_CHECK_NOT_READY_TEXTURE);
257 elseif status == "waiting" then
258 frame.ready:SetTexture(READY_CHECK_WAITING_TEXTURE);
264 addon.Events.UpdateReadyCheck = updateReadyCheck;
266 local function updateRaidMarker(frame, unit)
267 local index = GetRaidTargetIndex(unit);
269 SetRaidTargetIconTexture(frame.targeticon, index);
270 frame.targeticon:Show();
272 frame.targeticon:Hide();
275 addon.Events.UpdateRaidMarker = updateRaidMarker;
278 ["UNIT_HEALTH"] = function(frame)
279 if updateHealth(frame, frame.displayed) then
280 updateShield(frame, frame.displayed);
281 updateHealAbsorb(frame, frame.displayed);
282 -- no heal prediction update, that doesn't overflow too much
285 ["UNIT_AURA"] = function(frame)
286 updateAuras(frame, frame.displayed);
288 ["UNIT_HEAL_PREDICTION"] = function(frame)
289 updateHealPred(frame, frame.displayed);
291 ["UNIT_ABSORB_AMOUNT_CHANGED"] = function(frame)
292 updateShield(frame, frame.displayed);
294 ["UNIT_HEAL_ABSORB_AMOUNT_CHANGED"] = function(frame)
295 updateHealAbsorb(frame, frame.displayed);
297 ["UNIT_THREAT_SITUATION_UPDATE"] = function(frame)
298 updateAggro(frame, frame.displayed);
300 ["UNIT_MAXHEALTH"] = function(frame)
301 updateMaxHealth(frame, frame.displayed);
302 updateHealth(frame, frame.displayed);
303 updateShield(frame, frame.displayed);
304 updateHealAbsorb(frame, frame.displayed);
306 ["UNIT_NAME_UPDATE"] = function(frame)
307 updateName(frame, frame.unit);
309 ["UNIT_CONNECTION"] = function(frame)
310 updateText(frame, frame.displayed);
312 ["PLAYER_ROLES_ASSIGNED"] = function(frame)
313 updateRole(frame, frame.unit);
315 ["READY_CHECK"] = function(frame)
316 updateReadyCheck(frame, frame.unit);
318 ["RAID_TARGET_UPDATE"] = function(frame)
319 updateRaidMarker(frame, frame.displayed);
321 ["UPDATE_ALL_BARS"] = function(frame)
322 updateRole(frame, frame.unit);
323 updateVehicle(frame);
324 updateMaxHealth(frame, frame.displayed);
325 updateHealth(frame, frame.displayed);
326 updateText(frame, frame.displayed);
327 updateAuras(frame, frame.displayed);
328 updateShield(frame, frame.displayed);
329 --updateHealPred(frame, frame.displayed);
330 updateHealAbsorb(frame, frame.displayed);
331 updateAggro(frame, frame.displayed);
332 updateName(frame, frame.unit);
333 updateReadyCheck(frame, frame.unit);
334 updateRaidMarker(frame, frame.displayed);
337 eventFuncs["UNIT_HEALTH_FREQUENT"] = eventFuncs["UNIT_HEALTH"];
338 eventFuncs["PLAYER_FLAGS_CHANGED"] = eventFuncs["UNIT_CONNECTION"];
339 eventFuncs["READY_CHECK_CONFIRM"] = eventFuncs["READY_CHECK"];
340 eventFuncs["READY_CHECK_FINISHED"] = eventFuncs["READY_CHECK"];
341 eventFuncs["UNIT_ENTERED_VEHICLE"] = eventFuncs["UPDATE_ALL_BARS"];
342 eventFuncs["UNIT_EXITED_VEHICLE"] = eventFuncs["UPDATE_ALL_BARS"];
343 eventFuncs["UNIT_PET"] = eventFuncs["UPDATE_ALL_BARS"];
344 eventFuncs["GROUP_ROSTER_UPDATE"] = eventFuncs["UPDATE_ALL_BARS"];
345 eventFuncs["PLAYER_ENTERING_WORLD"] = eventFuncs["UPDATE_ALL_BARS"];
346 eventFuncs["PLAYER_FOCUS_CHANGED"] = eventFuncs["UPDATE_ALL_BARS"];
348 function addon.UnitEvent(self, event)
349 return eventFuncs[event](self);