-- Events.lua local _; local unpack = unpack; local ssub = string.sub; local min = math.min; local ceil = math.ceil; local UnitName, UnitClass, UnitExists = UnitName, UnitClass, UnitExists; local UnitPower, UnitPowerMax, UnitPowerType = UnitPower, UnitPowerMax, UnitPowerType; local UnitHealth, UnitHealthMax = UnitHealth, UnitHealthMax; local UnitGetIncomingHeals, UnitGetTotalAbsorbs = UnitGetIncomingHeals, UnitGetTotalAbsorbs; local UnitThreatSituation, GetThreatStatusColor = UnitThreatSituation, GetThreatStatusColor; local UnitIsDeadOrGhost, UnitIsConnected = UnitIsDeadOrGhost, UnitIsConnected; local UnitGetTotalHealAbsorbs = UnitGetTotalHealAbsorbs; local UnitHasVehicleUI, UnitTargetsVehicleInRaidUI = UnitHasVehicleUI, UnitTargetsVehicleInRaidUI; local UnitLevel, UnitClassification = UnitLevel, UnitClassification; local UnitAffectingCombat, IsResting = UnitAffectingCombat, IsResting; local UnitIsPVPFreeForAll, UnitIsPVP = UnitIsPVPFreeForAll, UnitIsPVP; local UnitFactionGroup, UnitIsMercenary = UnitFactionGroup, UnitIsMercenary; local UnitIsGroupLeader, UnitIsGroupAssistant = UnitIsGroupLeader, UnitIsGroupAssistant; local HasLFGRestrictions = HasLFGRestrictions; local UnitPlayerControlled, UnitIsPlayer = UnitPlayerControlled, UnitIsPlayer; local UnitIsTapDenied, UnitSelectionColor = UnitIsTapDenied, UnitSelectionColor; local GetRaidTargetIndex, SetRaidTargetIconTexture = GetRaidTargetIndex, SetRaidTargetIconTexture; local RAID_CLASS_COLORS = RAID_CLASS_COLORS; local updateAuraFrames = OmaUFAuras.UpdateAuras; local Settings = OmaUFSettings; local baseColor = Settings.BaseColor; local healthColor = Settings.HealthColor; local powerColors = Settings.PowerColors; local M = {}; OmaUFEvents = M; function M.RegisterUnitEvents(frame) -- events are taken from FrameXML/CompactUnitFrame.lua and FrameXML/TargetFrame.lua -- TODO player flags support (/afk, /dnd) frame:RegisterEvent("RAID_TARGET_UPDATE"); -- have to register all and just check local displayed = frame.unit ~= frame.displayed and frame.displayed or nil; frame:RegisterUnitEvent("UNIT_HEALTH", frame.unit, displayed); frame:RegisterUnitEvent("UNIT_HEALTH_FREQUENT", frame.unit, displayed); frame:RegisterUnitEvent("UNIT_MAXHEALTH", frame.unit, displayed); if frame.mana then frame:RegisterUnitEvent("UNIT_POWER", frame.unit, displayed); frame:RegisterUnitEvent("UNIT_MAXPOWER", frame.unit, displayed); frame:RegisterUnitEvent("UNIT_DISPLAYPOWER", frame.unit, displayed); frame:RegisterUnitEvent("UNIT_POWER_BAR_SHOW", frame.unit, displayed); frame:RegisterUnitEvent("UNIT_POWER_BAR_HIDE", frame.unit, displayed); end if frame.shield then frame:RegisterUnitEvent("UNIT_ABSORB_AMOUNT_CHANGED", frame.unit, displayed); end if frame.healabsorb then frame:RegisterUnitEvent("UNIT_HEAL_ABSORB_AMOUNT_CHANGED", frame.unit, displayed); end if frame.auras then frame:RegisterUnitEvent("UNIT_AURA", frame.unit, displayed); end frame:RegisterUnitEvent("UNIT_NAME_UPDATE", frame.unit, displayed); frame:RegisterUnitEvent("UNIT_THREAT_SITUATION_UPDATE", frame.unit, displayed); frame:RegisterUnitEvent("UNIT_CONNECTION", frame.unit, displayed); frame:RegisterUnitEvent("UNIT_FACTION", frame.unit, displayed); end local registerUnitEvents = M.RegisterUnitEvents; local function updateMaxHealth(frame, unit) frame.health.max = UnitHealthMax(unit); end local function updateHealth(frame, unit) local current, max = UnitHealth(unit), frame.health.max; if current > max or max <= 0 then -- somehow current health has gone over the maximum (missed maxhealth event) frame.health:SetWidth(frame.width); updateMaxHealth(frame, unit); frame.health:Show(); elseif current <= 0 or UnitIsDeadOrGhost(unit) then frame.health:Hide(); else frame.health:SetWidth(current/max*frame.width); frame.health:Show(); end end local function updateHealthText(frame, unit) if UnitIsDeadOrGhost(unit) then frame.healthText:SetText("Dead"); elseif not UnitIsConnected(unit) then frame.healthText:SetText("DC"); elseif frame.healthText.percent then frame.healthText:SetFormattedText("%.1f", UnitHealth(unit)/frame.health.max*100); else local current = UnitHealth(unit); if current > 1000000000 then -- 1.0B frame.healthText:SetFormattedText("%.2fB", current / 1000000000); elseif current > 1000000 then -- 1.0M frame.healthText:SetFormattedText("%.2fM", current / 1000000); elseif current > 1000 then -- 1K frame.healthText:SetFormattedText("%.1fK", current / 1000); else frame.healthText:SetFormattedText("%d", current) end end end local function updateMaxPower(frame, unit) frame.mana.max = UnitPowerMax(unit); end local function updatePower(frame, unit) local current, max = UnitPower(unit), frame.mana.max; if current <= 0 then frame.mana:Hide(); elseif current > max or max <= 0 then frame.mana:SetWidth(frame.width); updateMaxPower(frame, unit); frame.mana:Show(); else frame.mana:SetWidth(current/max*frame.width); frame.mana:Show(); end end local function updatePowerText(frame, unit) local current, max = UnitPower(unit), frame.mana.max; if UnitIsDeadOrGhost(unit) or not UnitIsConnected(unit) then frame.manaText:Hide(); elseif max > 0 and current > 0 and current < max then frame.manaText:SetText(ceil(current/max*100)); frame.manaText:Show(); else frame.manaText:Hide(); end end local function updatePowerColor(frame, unit) frame.mana:SetVertexColor(unpack(powerColors[UnitPowerType(unit)])); end local function updateName(frame, unit) local name = UnitName(unit); if not name then return end frame.name:SetText(ssub(name, 1, frame.name.count)); end local function updateShield(frame, unit) local shield = UnitGetTotalAbsorbs(unit) or 0; if shield > 0 then local space = frame.width - frame.health:GetWidth(); shield = (shield / frame.health.max) * frame.width; if space == 0 then frame.shield:Hide(); frame.shieldhl:Show(); elseif space < shield then frame.shield:SetWidth(space); frame.shield:Show(); frame.shieldhl:Show(); else frame.shield:SetWidth(shield); frame.shield:Show(); frame.shieldhl:Hide(); end else frame.shield:Hide(); frame.shieldhl:Hide(); end end local function updateHealAbsorb(frame, unit) local absorb = UnitGetTotalHealAbsorbs(unit) or 0; if absorb > 0 then local space = frame.health:GetWidth(); absorb = (absorb / frame.health.max) * frame.width; frame.healabsorb:SetWidth(min(space, absorb)); frame.healabsorb:Show(); else frame.healabsorb:Hide(); end end local function updateAuras(frame, unit) if frame.auras then updateAuraFrames(frame, unit) end end local function updateAggro(frame, unit) local status = UnitThreatSituation(unit); if status and status > 0 then frame.base:SetVertexColor(GetThreatStatusColor(status)); else frame.base:SetVertexColor(unpack(baseColor)); end end -- only works for player frame local function updateVehicle(frame) local shouldTargetVehicle = UnitHasVehicleUI("player") and UnitTargetsVehicleInRaidUI("player") and UnitExists("vehicle"); if shouldTargetVehicle then if not frame.inVehicle then frame.inVehicle = true; frame.displayed = frame.vehicle; registerUnitEvents(frame); end elseif frame.inVehicle then frame.inVehicle = false; frame.displayed = frame.unit; registerUnitEvents(frame); end end local function updateLevelText(frame, unit, levelup) if levelup then -- PLAYER_LEVEL_UP frame.level:SetText(levelup); else local level = UnitLevel(unit); local class = UnitClassification(unit); local leveltext, classtext; if level < 0 then if class == "worldboss" then leveltext = "Boss"; else leveltext = "??"; end else leveltext = level; end if class == "rareelite" then classtext = " Rare Elite"; elseif class == "elite" then classtext = " Elite"; elseif class == "rare" then classtext = " Rare"; else classtext = ""; end frame.level:SetFormattedText("%s%s", leveltext, classtext); end end local function updateStatus(frame, unit) -- coords from FrameXML/PlayerFrame.lua if frame.inCombat or UnitAffectingCombat(unit) then frame.status:SetTexCoord(0.5, 1, 0, 0.484375); frame.status:Show(); elseif unit == "player" and IsResting() then frame.status:SetTexCoord(0, 0.5, 0, 0.421875); frame.status:Show(); else frame.status:Hide(); end end local pvpIcons = { Alliance = "Interface\\TARGETINGFRAME\\UI-PVP-Alliance", Horde = "Interface\\TARGETINGFRAME\\UI-PVP-Horde" }; local function updatePVP(frame, unit) if UnitIsPVPFreeForAll(unit) then frame.pvp:SetTexture("Interface\\TARGETINGFRAME\\UI-PVP-FFA"); frame.pvp:Show(); elseif UnitIsPVP(unit) then local faction = UnitFactionGroup(unit); if faction and faction ~= "Neutral" then -- from FrameXML/PlayerFrame.lua, mercenary checks if UnitIsMercenary(unit) then if faction == "Horde" then faction = "Alliance"; elseif faction == "Alliance" then faction = "Horde"; end end frame.pvp:SetTexture(pvpIcons[faction]); frame.pvp:Show(); else frame.pvp:Hide(); end else frame.pvp:Hide(); end end local function updateLeaderIcon(frame, unit) if UnitIsGroupLeader(frame.unit) then if HasLFGRestrictions() then frame.leader:SetTexture("Interface\\LFGFrame\\UI-LFG-ICON-PORTRAITROLES"); frame.leader:SetTexCoord(0, 0.296875, 0.015625, 0.3125); else frame.leader:SetTexture("Interface\\GROUPFRAME\\UI-Group-LeaderIcon"); frame.leader:SetTexCoord(0, 1, 0, 1); end frame.leader:Show(); elseif UnitIsGroupAssistant(frame.unit) then frame.leader:SetTexture("Interface\\GROUPFRAME\\UI-Group-AssistantIcon"); frame.leader:SetTexCoord(0, 1, 0, 1); frame.leader:Show(); else frame.leader:Hide(); end end local function updateHealthColor(frame, unit) if not UnitPlayerControlled(unit) and UnitIsTapDenied(unit) then frame.health:SetVertexColor(0.5, 0.5, 0.5); elseif UnitIsPlayer(unit) then local _, class = UnitClass(unit); local color = RAID_CLASS_COLORS[class]; if color then frame.health:SetVertexColor(color.r, color.g, color.b) else frame.health:SetVertexColor(unpack(healthColor)) end elseif UnitPlayerControlled(unit) then frame.health:SetVertexColor(0, 1, 0); else frame.health:SetVertexColor(UnitSelectionColor(unit)); end end local function updateRaidMarker(frame, unit) local index = GetRaidTargetIndex(unit); if index then SetRaidTargetIconTexture(frame.targeticon, index); frame.targeticon:Show(); else frame.targeticon:Hide(); end end local eventFuncs = { ["UNIT_HEALTH"] = function(frame) updateHealth(frame, frame.displayed); updateHealthText(frame, frame.displayed); if frame.shield then updateShield(frame, frame.displayed) end if frame.healabsorb then updateHealAbsorb(frame, frame.displayed) end end, ["UNIT_POWER"] = function(frame) updatePower(frame, frame.displayed); updatePowerText(frame, frame.displayed); end, ["UNIT_AURA"] = function(frame) updateAuras(frame, frame.displayed); end, ["UNIT_ABSORB_AMOUNT_CHANGED"] = function(frame) updateShield(frame, frame.displayed); end, ["UNIT_HEAL_ABSORB_AMOUNT_CHANGED"] = function(frame) updateHealAbsorb(frame, frame.displayed); end, ["UNIT_THREAT_SITUATION_UPDATE"] = function(frame) updateAggro(frame, frame.displayed); end, ["UNIT_MAXHEALTH"] = function(frame) updateMaxHealth(frame, frame.displayed); updateHealth(frame, frame.displayed); updateHealthText(frame, frame.displayed); if frame.shield then updateShield(frame, frame.displayed) end if frame.healabsorb then updateHealAbsorb(frame, frame.displayed) end end, ["UNIT_MAXPOWER"] = function(frame) updateMaxPower(frame, frame.displayed); updatePower(frame, frame.displayed); updatePowerText(frame, frame.displayed); end, ["UNIT_DISPLAYPOWER"] = function(frame) updatePowerColor(frame, frame.displayed); updateMaxPower(frame, frame.displayed); updatePower(frame, frame.displayed); updatePowerText(frame, frame.displayed); end, ["UNIT_NAME_UPDATE"] = function(frame) if frame.name then updateName(frame, frame.displayed) end updateHealthColor(frame, frame.displayed); end, ["UNIT_CONNECTION"] = function(frame) updateHealthText(frame, frame.displayed); updatePowerText(frame, frame.displayed); end, ["UNIT_LEVEL"] = function(frame) -- if this is registered, frame has frame.level updateLevelText(frame, frame.unit); end, ["PLAYER_LEVEL_UP"] = function(frame, arg1) updateLevelText(frame, frame.unit, arg1); end, ["PLAYER_UPDATE_RESTING"] = function(frame) -- player frame has frame.status updateStatus(frame, frame.unit); end, ["PLAYER_REGEN_DISABLED"] = function(frame) frame.inCombat = true; if frame.status then updateStatus(frame, frame.unit) end end, ["PLAYER_REGEN_ENABLED"] = function(frame) frame.inCombat = false; if frame.status then updateStatus(frame, frame.unit) end end, ["UNIT_FACTION"] = function(frame) if frame.pvp then updatePVP(frame, frame.unit) end updateHealthColor(frame, frame.displayed); end, ["PARTY_LEADER_CHANGED"] = function(frame) updateLeaderIcon(frame, frame.unit); end, ["RAID_TARGET_UPDATE"] = function(frame) updateRaidMarker(frame, frame.displayed); end, ["UPDATE_ALL_BARS"] = function(frame) if frame.vehicle then updateVehicle(frame) end updateMaxHealth(frame, frame.displayed); updateHealth(frame, frame.displayed); updateHealthText(frame, frame.displayed); updateHealthColor(frame, frame.displayed); updateAggro(frame, frame.displayed); updateRaidMarker(frame, frame.displayed); if frame.mana then updateMaxPower(frame, frame.displayed); updatePower(frame, frame.displayed); updatePowerText(frame, frame.displayed); updatePowerColor(frame, frame.displayed); end if frame.auras then updateAuras(frame, frame.displayed) end if frame.shield then updateShield(frame, frame.displayed) end if frame.healabsorb then updateHealAbsorb(frame, frame.displayed) end if frame.name then updateName(frame, frame.displayed) end if frame.level then updateLevelText(frame, frame.unit) end if frame.status then updateStatus(frame, frame.unit) end if frame.pvp then updatePVP(frame, frame.unit) end if frame.leader then updateLeaderIcon(frame, frame.unit) end end, }; eventFuncs["UNIT_HEALTH_FREQUENT"] = eventFuncs["UNIT_HEALTH"]; eventFuncs["UNIT_POWER_BAR_SHOW"] = eventFuncs["UNIT_DISPLAYPOWER"]; eventFuncs["UNIT_POWER_BAR_HIDE"] = eventFuncs["UNIT_DISPLAYPOWER"]; eventFuncs["UNIT_ENTERED_VEHICLE"] = eventFuncs["UPDATE_ALL_BARS"]; eventFuncs["UNIT_EXITED_VEHICLE"] = eventFuncs["UPDATE_ALL_BARS"]; eventFuncs["UNIT_PET"] = eventFuncs["UPDATE_ALL_BARS"]; eventFuncs["GROUP_ROSTER_UPDATE"] = eventFuncs["UPDATE_ALL_BARS"]; eventFuncs["PLAYER_ENTERING_WORLD"] = eventFuncs["UPDATE_ALL_BARS"]; eventFuncs["PLAYER_TARGET_CHANGED"] = eventFuncs["UPDATE_ALL_BARS"]; eventFuncs["INSTANCE_ENCOUNTER_ENGAGE_UNIT"] = eventFuncs["UPDATE_ALL_BARS"]; eventFuncs["UNIT_TARGETABLE_CHANGED"] = eventFuncs["UPDATE_ALL_BARS"]; function M.UnitEvent(self, event, arg1) eventFuncs[event](self, arg1); end