3 local unpack, pairs, ipairs = unpack, pairs, ipairs;
4 local ssub = string.sub;
6 local UnitName, UnitClass = UnitName, UnitClass;
7 local UnitInRange, UnitDebuff, UnitIsCharmed = UnitInRange, UnitDebuff, UnitIsCharmed;
8 local UnitPower, UnitPowerMax, UnitPowerType = UnitPower, UnitPowerMax, UnitPowerType;
9 local UnitHealth, UnitHealthMax = UnitHealth, UnitHealthMax;
10 local UnitInParty, UnitInRaid = UnitInParty, UnitInRaid;
11 local UnitGetIncomingHeals, UnitGetTotalAbsorbs = UnitGetIncomingHeals, UnitGetTotalAbsorbs;
12 local UnitThreatSituation, GetThreatStatusColor = UnitThreatSituation, GetThreatStatusColor;
13 local UnitIsDeadOrGhost, UnitIsConnected = UnitIsDeadOrGhost, UnitIsConnected;
14 local UnitHasIncomingResurrection = UnitHasIncomingResurrection;
15 local UnitGetTotalHealAbsorbs = UnitGetTotalHealAbsorbs;
16 local IsInGroup, IsInRaid = IsInGroup, IsInRaid;
17 local CTimerAfter = C_Timer.After;
18 local RAID_CLASS_COLORS = RAID_CLASS_COLORS;
20 local Frames = OmaFrames;
21 local Indicators = OmaIndicators;
22 local checkIndicators = Indicators.CheckIndicators;
24 local CFrame = CreateFrame("Frame", "OmaCFrame", UIParent);
29 local width, height = Frames.Width, Frames.Height;
30 local anchorX, anchorY = Frames.AnchorX, Frames.AnchorY;
31 local baseColor = Frames.BaseColor;
32 local overlayColorDispel = Frames.OverlayColorDispel;
33 local overlayColorCharm = Frames.OverlayColorCharm;
34 local overlayColorAlert = Frames.OverlayColorAlert;
35 local powerColors = Frames.PowerColors;
37 local function updateHealth(frame, unit)
38 local current, max = UnitHealth(unit), frame.health.max;
39 local healthLost = max - current;
40 -- sanity check, occasionally UnitHealthMax gives zero
42 frame.health:SetWidth(current/frame.health.max*width);
44 frame.health:SetWidth(width);
49 if UnitIsDeadOrGhost(unit) then
50 frame.health:SetWidth(1);
51 if UnitHasIncomingResurrection(unit) then
52 frame.text:SetText("Rez");
54 frame.text:SetText("Dead");
56 elseif not UnitIsConnected(unit) then
57 frame.health:SetWidth(1);
58 frame.text:SetText("DC");
59 elseif healthLost > 0 then
60 if healthLost > 1200000000 then -- 1.2B
61 frame.text:SetFormattedText("-%.1fB", healthLost / 1000000000);
62 elseif healthLost > 1200000 then -- 1.2M
63 frame.text:SetFormattedText("-%.1fM", healthLost / 1000000);
64 elseif healthLost > 1000 then -- 1K
65 frame.text:SetFormattedText("-%dK", healthLost / 1000);
67 frame.text:SetFormattedText("-%d", healthLost)
75 local function updateMaxHealth(frame, unit)
76 frame.health.max = UnitHealthMax(unit);
77 updateHealth(frame, unit);
80 local function updatePower(frame, unit)
81 local max = frame.mana.max;
82 -- sanity check, occasionally UnitPowerMax gives zero
84 frame.mana:SetWidth(UnitPower(unit)/max*width);
86 frame.mana:SetWidth(width);
90 local function updateMaxPower(frame, unit)
91 frame.mana.max = UnitPowerMax(unit);
92 updatePower(frame, unit);
95 local function updatePowerColor(frame, unit)
96 frame.mana:SetColorTexture(unpack(powerColors[UnitPowerType(unit)]));
99 local function updateName(frame, unit)
100 local name = UnitName(unit);
101 if not name then return end
102 frame.name:SetText(ssub(name, 1, 6));
104 local _, class = UnitClass(unit);
105 local color = RAID_CLASS_COLORS[class];
106 if color then frame.name:SetVertexColor(color.r, color.g, color.b) end
109 local function updateHealPred(frame, unit)
110 local incoming = UnitGetIncomingHeals(unit) or 0;
112 local max = frame.health.max;
113 local space = width - frame.health:GetWidth() + 1;
114 local pred = (incoming / max) * width;
115 frame.healpred:SetWidth(min(space, pred));
116 frame.healpred:Show();
118 frame.healpred:Hide();
122 local function updateShield(frame, unit)
123 local shield = UnitGetTotalAbsorbs(unit) or 0;
125 local max = frame.health.max;
126 local space = width - frame.health:GetWidth();
127 shield = (shield / max) * width;
128 if space < shield then
129 frame.shield:SetWidth(space);
130 frame.shieldhl:Show();
132 frame.shield:SetWidth(shield);
133 frame.shieldhl:Hide();
138 frame.shieldhl:Hide();
142 local function updateHealAbsorb(frame, unit)
143 local absorb = UnitGetTotalHealAbsorbs(unit) or 0;
145 local max = frame.health.max;
146 local space = frame.health:GetWidth();
147 absorb = (absorb / max) * width;
148 frame.healabsorb:SetWidth(min(space, absorb));
149 frame.healabsorb:Show();
151 frame.healabsorb:Hide();
155 local function updateAuras(frame, unit)
156 checkIndicators(frame, unit);
157 if UnitDebuff(unit, 1, "RAID") ~= nil then
158 -- something dispellable
159 if frame.overlay.color ~= overlayColorDispel then
160 frame.overlay:SetColorTexture(unpack(overlayColorDispel));
161 frame.overlay:Show();
162 frame.overlay.color = overlayColorDispel;
164 elseif UnitIsCharmed(unit) then
165 if frame.overlay.color ~= overlayColorCharm then
166 frame.overlay:SetColorTexture(unpack(overlayColorCharm));
167 frame.overlay:Show();
168 frame.overlay.color = overlayColorCharm;
171 if frame.overlay.color ~= nil then
172 frame.overlay:Hide();
173 frame.overlay.color = nil;
178 local function updateAggro(frame, unit)
179 local status = UnitThreatSituation(unit);
180 if status and status > 0 then
181 frame.base:SetColorTexture(GetThreatStatusColor(status));
183 frame.base:SetColorTexture(unpack(baseColor));
188 ["UNIT_HEALTH"] = function(frame, unit)
189 updateHealth(frame, unit);
190 updateShield(frame, unit);
191 updateHealAbsorb(frame, unit);
192 -- no heal prediction update, that doesn't overflow too much
194 ["UNIT_POWER"] = function(frame, unit)
195 updatePower(frame, unit);
197 ["UNIT_AURA"] = function(frame, unit)
198 updateAuras(frame, unit);
200 ["UNIT_HEAL_PREDICTION"] = function(frame, unit)
201 updateHealPred(frame, unit);
203 ["UNIT_ABSORB_AMOUNT_CHANGED"] = function(frame, unit)
204 updateShield(frame, unit);
206 ["UNIT_HEAL_ABSORB_AMOUNT_CHANGED"] = function(frame, unit)
207 updateHealAbsorb(frame, unit);
209 ["UNIT_THREAT_SITUATION_UPDATE"] = function(frame, unit)
210 updateAggro(frame, unit);
212 ["UNIT_MAXHEALTH"] = function(frame, unit)
213 updateMaxHealth(frame, unit);
215 ["UNIT_MAXPOWER"] = function(frame, unit)
216 updateMaxPower(frame, unit);
218 ["UNIT_DISPLAYPOWER"] = function(frame, unit)
219 updatePowerColor(frame, unit);
221 ["UNIT_NAME_UPDATE"] = function(frame, unit)
222 updateName(frame, unit);
224 ["UNIT_CONNECTION"] = function(frame, unit)
225 updateHealth(frame, unit);
227 ["INCOMING_RESURRECT_CHANGED"] = function(frame, unit)
229 updateHealth(frame, unit);
231 ["PARTY_MEMBER_ENABLE"] = function(frame)
232 -- new power info possibly (FrameXML/CompactUnitFrame.lua)
233 updateMaxPower(frame, frame.unit);
234 updatePowerColor(frame, frame.unit);
236 ["UPDATE_ALL_BARS"] = function(frame, unit)
237 updateMaxHealth(frame, unit);
238 updateMaxPower(frame, unit);
239 --updateHealth(frame, unit); -- MaxHealth covers this
240 --updatePower(frame, unit); -- MaxPower covers this
241 updateAuras(frame, unit);
242 updateShield(frame, unit);
243 updateHealPred(frame, unit);
244 updateHealAbsorb(frame, unit);
245 updatePowerColor(frame, unit);
246 updateAggro(frame, unit);
247 updateName(frame, unit);
250 eventFuncs["UNIT_HEALTH_FREQUENT"] = eventFuncs["UNIT_HEALTH"];
251 eventFuncs["PARTY_MEMBER_DISABLE"] = eventFuncs["PARTY_MEMBER_ENABLE"];
252 local function unitEvent(self, event, ...)
253 local arg1, arg2, arg3, arg4 = ...;
254 eventFuncs[event](self, arg1);
257 local function unitUpdate(self, elapsed)
258 -- there's no in/out of range event, have to check each frame
259 -- from FrameXML/CompactUnitFrame.lua
260 local inRange, checked = UnitInRange(self.unit);
261 if checked and not inRange then
268 local function registerEvents(frame, unit)
269 -- events are taken from FrameXML/CompactUnitFrame.lua
270 -- TODO vehicle support, ready check support, raid marker support,
271 -- player flags support (/afk, /dnd)
272 -- TODO only update for vehicle events here
273 frame:RegisterEvent("PARTY_MEMBER_ENABLE");
274 frame:RegisterEvent("PARTY_MEMBER_DISABLE");
275 frame:RegisterUnitEvent("UNIT_HEALTH", unit);
276 frame:RegisterUnitEvent("UNIT_HEALTH_FREQUENT", unit);
277 frame:RegisterUnitEvent("UNIT_MAXHEALTH", unit);
278 frame:RegisterUnitEvent("UNIT_POWER", unit);
279 frame:RegisterUnitEvent("UNIT_MAXPOWER", unit);
280 frame:RegisterUnitEvent("UNIT_DISPLAYPOWER", unit);
281 frame:RegisterUnitEvent("UNIT_NAME_UPDATE", unit);
282 frame:RegisterUnitEvent("UNIT_AURA", unit);
283 frame:RegisterUnitEvent("UNIT_HEAL_PREDICTION", unit);
284 frame:RegisterUnitEvent("UNIT_ABSORB_AMOUNT_CHANGED", unit);
285 frame:RegisterUnitEvent("UNIT_HEAL_ABSORB_AMOUNT_CHANGED", unit);
286 frame:RegisterUnitEvent("UNIT_THREAT_SITUATION_UPDATE", unit);
287 frame:RegisterUnitEvent("UNIT_CONNECTION", unit);
288 frame:RegisterUnitEvent("INCOMING_RESURRECT_CHANGED", unit);
291 local function vis(frame, vis)
294 frame:SetScript("OnUpdate", unitUpdate);
295 --frame:UnregisterAllEvents();
296 --registerEvents(frame, frame.unit);
297 -- wait one frame to update data
298 -- create function if needed to pass arguments to unitEvent
299 local func = updaters[frame];
301 func = function() unitEvent(frame, "UPDATE_ALL_BARS", frame.unit) end;
302 updaters[frame] = func;
304 CTimerAfter(0.01, func);
307 frame:SetScript("OnUpdate", nil);
308 --frame:UnregisterAllEvents();
312 local function updateGroup()
316 for _, val in ipairs(raid) do
317 if UnitInRaid(val.frame.unit) then
318 vis(val.frame, true);
319 elseif val.frame:IsShown() then
320 vis(val.frame, false);
323 -- hide player + party (use pairs, not ipairs)
324 for _, val in pairs(party) do
325 if val.frame:IsShown() then vis(val.frame, false) end
328 -- show player + party
329 for _, val in pairs(party) do
330 if UnitInParty(val.frame.unit) then
331 vis(val.frame, true);
332 elseif val.frame:IsShown() then
333 vis(val.frame, false);
337 for _, val in ipairs(raid) do
338 if val.frame:IsShown() then vis(val.frame, false) end
343 vis(party[0].frame, true);
344 -- hide all other frames
345 for _, val in ipairs(party) do
346 if val.frame:IsShown() then vis(val.frame, false) end
348 for _, val in ipairs(raid) do
349 if val.frame:IsShown() then vis(val.frame, false) end
354 local function initialize()
355 CFrame:SetPoint("CENTER", nil, "CENTER", anchorX, anchorY);
356 CFrame:SetHeight((height+2)*8);
357 CFrame:SetWidth((width+2)*5+1); -- extra pixel for shield overflow
358 Frames.InitializeParty(CFrame, party, unitEvent);
359 Frames.InitializeRaid(CFrame, raid, unitEvent);
362 CFrame:RegisterEvent("ADDON_LOADED");
363 CFrame:RegisterEvent("PLAYER_LOGIN");
364 CFrame:RegisterEvent("PLAYER_ENTERING_WORLD");
365 CFrame:RegisterEvent("GROUP_ROSTER_UPDATE");
366 CFrame:RegisterEvent("PLAYER_REGEN_ENABLED");
367 CFrame:SetScript("OnEvent", function(self, event, ...)
368 if event == "GROUP_ROSTER_UPDATE" or event == "PLAYER_REGEN_ENABLED" or
369 event == "PLAYER_ENTERING_WORLD" then
371 elseif event == "PLAYER_LOGIN" then
373 elseif event == "ADDON_LOADED" then