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;
25 local baseColor = {0, 0, 0};
26 local overlayColorDispel = {1, 0.5, 0, 0.5};
27 local overlayColorCharm = {0.8, 0, 1, 0.5};
28 local overlayColorAlert = {1, 0, 0, 0.5};
31 function addon.RegisterEvents(frame)
32 frame:RegisterEvent("PLAYER_ENTERING_WORLD");
33 frame:RegisterEvent("PLAYER_ROLES_ASSIGNED");
34 frame:RegisterEvent("READY_CHECK");
35 frame:RegisterEvent("READY_CHECK_FINISHED");
36 frame:RegisterEvent("GROUP_ROSTER_UPDATE");
37 frame:RegisterEvent("RAID_TARGET_UPDATE");
38 if frame.unit == "focus" then frame:RegisterEvent("PLAYER_FOCUS_CHANGED") end
41 function addon.RegisterUnitEvents(frame)
42 -- events are taken from FrameXML/CompactUnitFrame.lua
43 local displayed = frame.unit ~= frame.displayed and frame.displayed or nil;
44 frame:RegisterUnitEvent("UNIT_HEALTH_FREQUENT", frame.unit, displayed);
45 frame:RegisterUnitEvent("UNIT_MAXHEALTH", frame.unit, displayed);
46 frame:RegisterUnitEvent("UNIT_NAME_UPDATE", frame.unit, displayed);
47 frame:RegisterUnitEvent("UNIT_AURA", frame.unit, displayed);
48 frame:RegisterUnitEvent("UNIT_HEAL_PREDICTION", frame.unit, displayed);
49 frame:RegisterUnitEvent("UNIT_ABSORB_AMOUNT_CHANGED", frame.unit, displayed);
50 frame:RegisterUnitEvent("UNIT_HEAL_ABSORB_AMOUNT_CHANGED", frame.unit, displayed);
51 frame:RegisterUnitEvent("UNIT_THREAT_SITUATION_UPDATE", frame.unit, displayed);
52 frame:RegisterUnitEvent("UNIT_CONNECTION", frame.unit, displayed);
53 frame:RegisterUnitEvent("PLAYER_FLAGS_CHANGED", frame.unit, displayed);
54 frame:RegisterUnitEvent("READY_CHECK_CONFIRM", frame.unit, displayed);
55 frame:RegisterUnitEvent("UNIT_ENTERED_VEHICLE", frame.unit, displayed);
56 frame:RegisterUnitEvent("UNIT_EXITED_VEHICLE", frame.unit, displayed);
57 frame:RegisterUnitEvent("UNIT_PET", frame.unit, displayed);
59 local registerUnitEvents = addon.RegisterUnitEvents;
61 local function updateText(frame, unit)
62 if UnitIsDeadOrGhost(unit) then
64 frame.text:SetText("Dead");
66 elseif not UnitIsConnected(unit) then
67 frame.text:SetText("DC");
69 elseif UnitIsAFK(unit) then
70 frame.text:SetText("afk");
72 elseif UnitIsDND(unit) then
73 frame.text:SetText("dnd");
80 local function updateMaxHealth(frame, unit)
81 frame.health.max = UnitHealthMax(unit);
84 local function updateHealth(frame, unit)
85 local current, max = UnitHealth(unit), frame.health.max;
86 if current > max or max <= 0 then
87 -- somehow current health has gone over the maximum (missed maxhealth event possibly)
88 -- just put health bar full and update max health for next event
89 frame.health:SetWidth(width);
90 frame.health.width = width;
91 updateMaxHealth(frame, unit);
93 elseif current <= 0 or UnitIsDeadOrGhost(unit) then
95 return updateText(frame, unit); -- update death
97 local w = current/max*width;
98 frame.health:SetWidth(w);
99 frame.health.width = w;
103 if frame.dead and current > 0 then
105 updateText(frame, unit); -- update revive
109 local function updateName(frame, unit)
110 local name = UnitName(unit);
111 if not name then return end
112 name = ssub(name, 1, 6);
113 if frame.unit == unit then
114 frame.name:SetText(name);
116 frame.name:SetFormattedText("-%s", name);
119 local _, class = UnitClass(unit);
120 local color = RAID_CLASS_COLORS[class];
121 if color then frame.name:SetVertexColor(color.r, color.g, color.b) end
124 local function updateHealPred(frame, unit)
125 local incoming = UnitGetIncomingHeals(unit) or 0;
127 incoming = (incoming / frame.health.max) * width;
128 -- always at least 1 pixel space for heal prediction
129 frame.healpred:SetWidth(min(width - frame.health.width + 1, incoming));
130 frame.healpred:Show();
132 frame.healpred:Hide();
136 local function updateShield(frame, unit)
137 local shield = UnitGetTotalAbsorbs(unit) or 0;
139 local space = width - frame.health.width;
140 shield = (shield / frame.health.max) * width;
143 frame.shieldhl:Show();
144 elseif space < shield then
145 frame.shield:SetWidth(space);
147 frame.shieldhl:Show();
149 frame.shield:SetWidth(shield);
151 frame.shieldhl:Hide();
155 frame.shieldhl:Hide();
159 local function updateHealAbsorb(frame, unit)
160 local absorb = UnitGetTotalHealAbsorbs(unit) or 0;
162 absorb = (absorb / frame.health.max) * width;
163 frame.healabsorb:SetWidth(min(frame.health.width, absorb));
164 frame.healabsorb:Show();
166 frame.healabsorb:Hide();
170 local function updateAuras(frame, unit)
171 -- don't overlay charmed when in vehicle
172 if UnitIsCharmed(unit) and unit == frame.unit then
173 if frame.overlay.color ~= overlayColorCharm then
174 frame.overlay:SetVertexColor(unpack(overlayColorCharm));
175 frame.overlay.color = overlayColorCharm;
176 frame.overlay:Show();
178 elseif UnitDebuff(unit, 1, "RAID") ~= nil then
179 -- something dispellable
180 if frame.overlay.color ~= overlayColorDispel then
181 frame.overlay:SetVertexColor(unpack(overlayColorDispel));
182 frame.overlay.color = overlayColorDispel;
183 frame.overlay:Show();
186 if frame.overlay.color ~= nil then
187 frame.overlay.color = nil;
188 frame.overlay:Hide();
193 local function updateAggro(frame, unit)
194 local status = UnitThreatSituation(unit);
195 if status and status > 0 then
196 frame.base:SetVertexColor(GetThreatStatusColor(status));
198 frame.base:SetVertexColor(unpack(baseColor));
202 local function updateVehicle(frame)
203 local shouldTargetVehicle = UnitHasVehicleUI(frame.unit) and
204 UnitTargetsVehicleInRaidUI(frame.unit) and UnitExists(frame.vehicle);
205 if shouldTargetVehicle then
206 if not frame.inVehicle then
207 frame.inVehicle = true;
208 frame.displayed = frame.vehicle;
209 registerUnitEvents(frame);
211 elseif frame.inVehicle then
212 frame.inVehicle = false;
213 frame.displayed = frame.unit;
214 registerUnitEvents(frame);
218 local function updateRole(frame, unit)
219 local role = UnitGroupRolesAssigned(unit);
220 if role == "HEALER" then
221 frame.role:SetTexCoord(0.75, 1, 0, 1);
223 elseif role == "TANK" then
224 frame.role:SetTexCoord(0.5, 0.75, 0, 1);
231 local function updateReadyCheck(frame, unit)
232 local status = GetReadyCheckStatus(unit);
233 if status == "ready" then
234 frame.ready:SetTexture(READY_CHECK_READY_TEXTURE);
236 elseif status == "notready" then
237 frame.ready:SetTexture(READY_CHECK_NOT_READY_TEXTURE);
239 elseif status == "waiting" then
240 frame.ready:SetTexture(READY_CHECK_WAITING_TEXTURE);
247 local function updateRaidMarker(frame, unit)
248 local index = GetRaidTargetIndex(unit);
250 SetRaidTargetIconTexture(frame.targeticon, index);
251 frame.targeticon:Show();
253 frame.targeticon:Hide();
258 ["UNIT_HEALTH"] = function(frame)
259 updateHealth(frame, frame.displayed);
260 updateShield(frame, frame.displayed);
261 updateHealAbsorb(frame, frame.displayed);
262 -- no heal prediction update, that doesn't overflow too much
264 ["UNIT_AURA"] = function(frame)
265 updateAuras(frame, frame.displayed);
267 ["UNIT_HEAL_PREDICTION"] = function(frame)
268 updateHealPred(frame, frame.displayed);
270 ["UNIT_ABSORB_AMOUNT_CHANGED"] = function(frame)
271 updateShield(frame, frame.displayed);
273 ["UNIT_HEAL_ABSORB_AMOUNT_CHANGED"] = function(frame)
274 updateHealAbsorb(frame, frame.displayed);
276 ["UNIT_THREAT_SITUATION_UPDATE"] = function(frame)
277 updateAggro(frame, frame.displayed);
279 ["UNIT_MAXHEALTH"] = function(frame)
280 updateMaxHealth(frame, frame.displayed);
281 updateHealth(frame, frame.displayed);
282 updateShield(frame, frame.displayed);
283 updateHealAbsorb(frame, frame.displayed);
285 ["UNIT_NAME_UPDATE"] = function(frame)
286 updateName(frame, frame.unit);
288 ["UNIT_CONNECTION"] = function(frame)
289 updateText(frame, frame.displayed);
291 ["PLAYER_ROLES_ASSIGNED"] = function(frame)
292 updateRole(frame, frame.unit);
294 ["READY_CHECK"] = function(frame)
295 updateReadyCheck(frame, frame.unit);
297 ["RAID_TARGET_UPDATE"] = function(frame)
298 updateRaidMarker(frame, frame.displayed);
300 ["UPDATE_ALL_BARS"] = function(frame)
301 updateRole(frame, frame.unit);
302 updateVehicle(frame);
303 updateMaxHealth(frame, frame.displayed);
304 updateHealth(frame, frame.displayed);
305 updateText(frame, frame.displayed);
306 updateAuras(frame, frame.displayed);
307 updateShield(frame, frame.displayed);
308 updateHealPred(frame, frame.displayed);
309 updateHealAbsorb(frame, frame.displayed);
310 updateAggro(frame, frame.displayed);
311 updateName(frame, frame.unit);
312 updateReadyCheck(frame, frame.unit);
313 updateRaidMarker(frame, frame.displayed);
316 eventFuncs["UNIT_HEALTH_FREQUENT"] = eventFuncs["UNIT_HEALTH"];
317 eventFuncs["PLAYER_FLAGS_CHANGED"] = eventFuncs["UNIT_CONNECTION"];
318 eventFuncs["READY_CHECK_CONFIRM"] = eventFuncs["READY_CHECK"];
319 eventFuncs["READY_CHECK_FINISHED"] = eventFuncs["READY_CHECK"];
320 eventFuncs["UNIT_ENTERED_VEHICLE"] = eventFuncs["UPDATE_ALL_BARS"];
321 eventFuncs["UNIT_EXITED_VEHICLE"] = eventFuncs["UPDATE_ALL_BARS"];
322 eventFuncs["UNIT_PET"] = eventFuncs["UPDATE_ALL_BARS"];
323 eventFuncs["GROUP_ROSTER_UPDATE"] = eventFuncs["UPDATE_ALL_BARS"];
324 eventFuncs["PLAYER_ENTERING_WORLD"] = eventFuncs["UPDATE_ALL_BARS"];
325 eventFuncs["PLAYER_FOCUS_CHANGED"] = eventFuncs["UPDATE_ALL_BARS"];
327 function addon.UnitEvent(self, event)
328 return eventFuncs[event](self);