-- updater.lua -- 2019 Aleksi Blinnikka -- -- Main update function for all frames. Gets around issues with events. local _, addon = ...; local unpack = unpack; local min = math.min; local format = string.format; local UnitDebuff, UnitIsCharmed = UnitDebuff, UnitIsCharmed; local UnitHealth, UnitHealthMax = UnitHealth, UnitHealthMax; local UnitPower, UnitPowerMax = UnitPower, UnitPowerMax; local UnitIsAFK, UnitIsDND = UnitIsAFK, UnitIsDND; local UnitGetIncomingHeals, UnitGetTotalAbsorbs = UnitGetIncomingHeals, UnitGetTotalAbsorbs; local UnitIsDeadOrGhost, UnitIsConnected = UnitIsDeadOrGhost, UnitIsConnected; local UnitGetTotalHealAbsorbs = UnitGetTotalHealAbsorbs; local InCombatLockdown, IsResting = InCombatLockdown, IsResting; local dispelcolor = addon.Colors.OverlayColorDispel; local charmcolor = addon.Colors.OverlayColorCharm; local majorcolor = addon.Colors.OverlayColorAlert; local healcolor = addon.Colors.OverlayColorHeal; local ignoredAuras = { [315176] = true, -- Grasping Tendrils }; local powerColors = { [Enum.PowerType.Mana] = {0.1, 0.5, 0.9}, [Enum.PowerType.Rage] = {1, 0, 0}, [Enum.PowerType.Pain] = {1, 0, 0}, [Enum.PowerType.Focus] = {1, 0.5, 0}, [Enum.PowerType.Energy] = {1, 0.8, 0}, [Enum.PowerType.Fury] = {0.8, 0.3, 0.9}, [Enum.PowerType.RunicPower] = {0.8, 0, 0.2}, [Enum.PowerType.LunarPower] = {0.3, 0.5, 0.9}, [Enum.PowerType.Maelstrom] = {0, 0.5, 1}, [Enum.PowerType.Insanity] = {0.4, 0, 0.8}, }; function addon.FrameUpdate(frame) assert(type(frame) == "table", "FrameUpdate received invalid frame parameter!"); local unit = frame.displayed; local width = frame.barwidth; -- range check (doesn't have an event) frames can be marked constantly visible if not frame.constant then local inrange, checked = UnitInRange(unit); if checked and not inrange then frame:SetAlpha(0.55); else frame:SetAlpha(1); end end -- states if UnitIsDeadOrGhost(unit) then frame.text:SetText("Dead"); if not frame.text:IsShown() then frame.text:Show() end if frame.health:IsShown() then frame.health:Hide() end if frame.shield:IsShown() then frame.shield:Hide() end if frame.shieldhl:IsShown() then frame.shieldhl:Hide() end if frame.healpred:IsShown() then frame.healpred:Hide() end if frame.healabsorb:IsShown() then frame.healabsorb:Hide() end frame.prev.health = nil; frame.prev.hmax = nil; elseif not UnitIsConnected(unit) then frame.text:SetText("DC"); if not frame.text:IsShown() then frame.text:Show() end if frame.health:IsShown() then frame.health:Hide() end if frame.shield:IsShown() then frame.shield:Hide() end if frame.shieldhl:IsShown() then frame.shieldhl:Hide() end if frame.healpred:IsShown() then frame.healpred:Hide() end if frame.healabsorb:IsShown() then frame.healabsorb:Hide() end frame.prev.health = nil; frame.prev.hmax = nil; else if UnitIsAFK(unit) then frame.text.status = true; frame.prev.htext = nil; frame.text:SetText("afk"); if not frame.text:IsShown() then frame.text:Show() end elseif UnitIsDND(unit) then frame.text.status = true; frame.prev.htext = nil; frame.text:SetText("dnd"); if not frame.text:IsShown() then frame.text:Show() end else frame.text.status = false; if frame.raid and frame.text:IsShown() then frame.text:Hide(); end end if not frame.raid and frame.unit == "player" then if InCombatLockdown() then frame.status:SetTexCoord(0.5, 1, 0, 0.484375); frame.status:Show(); elseif IsResting() then frame.status:SetTexCoord(0, 0.5, 0, 0.421875); frame.status:Show(); elseif frame.status:IsShown() then frame.status:Hide(); end end -- health local current, hmax = UnitHealth(unit), UnitHealthMax(unit); if frame.prev.health ~= current or frame.prev.hmax ~= hmax then frame.prev.health = current; frame.prev.hmax = hmax; if hmax < current or hmax <= 1 then frame.health:SetWidth(width); frame.health.width = width; if not frame.health:IsShown() then frame.health:Show() end elseif current <= 0 then if frame.health:IsShown() then frame.health:Hide() end else local w = current/hmax*width; frame.health:SetWidth(w); frame.health.width = w; if not frame.health:IsShown() then frame.health:Show() end end end -- health text if not frame.raid and not frame.text.status and frame.prev.htext ~= current then frame.prev.htext = current; if frame.boss then if hmax < current or hmax <= 1 then frame.text:SetText("100"); if not frame.text:IsShown() then frame.text:Show() end elseif current <= 0 then if frame.text:IsShown() then frame.text:Hide() end else frame.text:SetFormattedText("%.1f", current/hmax*100); if not frame.text:IsShown() then frame.text:Show() end end else if current > 1000000000 then -- 1.0B frame.text:SetFormattedText("%.2fB", current / 1000000000); elseif current > 1000000 then -- 1.0M frame.text:SetFormattedText("%.2fM", current / 1000000); elseif current > 1000 then -- 1.0K frame.text:SetFormattedText("%.1fK", current / 1000); end if not frame.text:IsShown() then frame.text:Show() end end end -- shield local hwidth = frame.health.width; current = UnitGetTotalAbsorbs(unit) or 0; if current > 0 then local space = width - hwidth; current = (current / hmax) * width; if space == 0 then if frame.shield:IsShown() then frame.shield:Hide() end if not frame.shieldhl:IsShown() then frame.shieldhl:Show() end elseif space < current then frame.shield:SetWidth(space); if not frame.shield:IsShown() then frame.shield:Show() end if not frame.shieldhl:IsShown() then frame.shieldhl:Show() end else frame.shield:SetWidth(current); if not frame.shield:IsShown() then frame.shield:Show() end if frame.shieldhl:IsShown() then frame.shieldhl:Hide() end end else if frame.shield:IsShown() then frame.shield:Hide() end if frame.shieldhl:IsShown() then frame.shieldhl:Hide() end end -- heal absorb current = UnitGetTotalHealAbsorbs(unit) or 0; if current > 0 then current = (current / hmax) * width; frame.healabsorb:SetWidth(min(hwidth, current)); if not frame.healabsorb:IsShown() then frame.healabsorb:Show() end elseif frame.healabsorb:IsShown() then frame.healabsorb:Hide(); end -- heal prediction current = UnitGetIncomingHeals(unit) or 0; if current > 0 then current = (current / hmax) * width; -- at least 1 pixel prediction shown frame.healpred:SetWidth(min(width - hwidth + 1, current)); if not frame.healpred:IsShown() then frame.healpred:Show() end elseif frame.healpred:IsShown() then frame.healpred:Hide(); end -- mana, if present if frame.mana ~= nil then local current, max = UnitPower(unit), UnitPowerMax(unit); local ptype = UnitPowerType(unit); if frame.mana.ptype ~= ptype then frame.mana.ptype = ptype; frame.mana:SetVertexColor(unpack(powerColors[ptype])); end if frame.prev.mana ~= current or frame.prev.mmax ~= max then frame.prev.mana = current; frame.prev.mmax = max; if max < 1 then if frame.mana:IsShown() then frame.mana:Hide() end if frame.manatext:IsShown() then frame.manatext:Hide() end elseif max < current then frame.mana:SetWidth(width); frame.manatext:SetText("100"); if not frame.mana:IsShown() then frame.mana:Show() end if not frame.manatext:IsShown() then frame.manatext:Show() end elseif current <= 0 then if frame.mana:IsShown() then frame.mana:Hide() end if frame.manatext:IsShown() then frame.manatext:Hide() end else local percent = current/max; frame.mana:SetWidth(percent*width); frame.manatext:SetText(format("%d", percent*100+0.5)); if not frame.mana:IsShown() then frame.mana:Show() end if not frame.manatext:IsShown() then frame.manatext:Show() end end end end -- forced aura updates if frame.rounds ~= nil then frame.rounds = frame.rounds + 1; if (frame.rounds > 7) then frame.tankcd = {}; frame.alert = {}; frame.stacks = {}; frame.heal = {}; frame.buff1 = {}; addon.SetAuras(frame.unit, frame.guid); frame.rounds = 0; end end if frame.raid then -- tank CD marker if next(frame.tankcd) then if not frame.defensive:IsShown() then frame.defensive:Show() end elseif frame.defensive:IsShown() then frame.defensive:Hide(); end -- aura stacks if next(frame.stacks) then local _, amount = next(frame.stacks); frame.stack:SetText(amount); if not frame.stack:IsShown() then frame.stack:Show() end elseif frame.stack:IsShown() then frame.stack:Hide(); end -- custom buff indicator 1 if next(frame.buff1) then if not frame.buffind1:IsShown() then frame.buffind1:Show() end elseif frame.buffind1:IsShown() then frame.buffind1:Hide(); end -- custom buff indicator 2 if next(frame.buff2) then if not frame.buffind2:IsShown() then frame.buffind2:Show() end elseif frame.buffind2:IsShown() then frame.buffind2:Hide(); end -- incoming ability if next(frame.incoming) then if not frame.glow:IsShown() then frame.glow:Show() end elseif frame.glow:IsShown() then frame.glow:Hide(); end -- overlays if next(frame.alert) then -- major if frame.overlay.color ~= majorcolor then frame.overlay:SetVertexColor(unpack(majorcolor)); frame.overlay.color = majorcolor; if not frame.overlay:IsShown() then frame.overlay:Show() end end else local _, _, _, _, _, _, _, _, _, spellid = UnitDebuff(unit, 1, "RAID"); if UnitIsCharmed(unit) and frame.unit == frame.displayed then -- charmed if frame.overlay.color ~= charmcolor then frame.overlay:SetVertexColor(unpack(charmcolor)); frame.overlay.color = charmcolor; if not frame.overlay:IsShown() then frame.overlay:Show() end end elseif spellid ~= nil and not ignoredAuras[spellid] then -- dispellable if frame.overlay.color ~= dispelcolor then frame.overlay:SetVertexColor(unpack(dispelcolor)); frame.overlay.color = dispelcolor; if not frame.overlay:IsShown() then frame.overlay:Show() end end elseif next(frame.heal) then -- major heals needed if frame.overlay.color ~= healcolor then frame.overlay:SetVertexColor(unpack(healcolor)); frame.overlay.color = healcolor; if not frame.overlay:IsShown() then frame.overlay:Show() end end else if frame.overlay.color ~= nil then frame.overlay.color = nil; if frame.overlay:IsShown() then frame.overlay:Hide() end end end end end end end