Nenue@0: --- ${PACKAGE_NAME} Nenue@0: -- @file-author@ Nenue@0: -- @project-revision@ @project-hash@ Nenue@0: -- @file-revision@ @file-hash@ Nenue@0: -- Created: 3/20/2016 10:00 PM Nenue@0: Nenue@0: local _, A = ... Nenue@49: local vn = A.frame Nenue@0: local MODULE = 'BuffFrame' Nenue@49: local Aura = vn:RegisterModule(MODULE) Nenue@0: local parentAnchor, parentFrame, raidbuffsFrame Nenue@49: local unpack, band, lshift, CreateFrame = unpack,bit.band, bit.lshift, CreateFrame Nenue@0: local raidBuffs = {} Nenue@0: local raidBuffSymbols = {'St', 'HP', 'AP', 'Ha', 'SP', 'Cr', 'Ma', 'MS', 'V' } Nenue@0: local missingBuffs = {} Nenue@0: local playerBuffing, playerCurrentBuff Nenue@0: local playerBuffs = {} Nenue@0: local c, ac, frameSize, frameSpacing, framePosition Nenue@49: local fprint = vn.fprint Nenue@49: local xprint = vn.print('XML') Nenue@0: local NUM_LE_MISSING_RAID_BUFFS = 0 Nenue@0: local missingBuffsAnchor Nenue@0: Nenue@0: Nenue@0: --- Takes a given icon texture and calls the pre-defined function set Nenue@49: Aura.UpdateBuffStyle = function(buff, style, path) Nenue@0: local print = fprint() Nenue@0: local icon = buff.icon Nenue@0: local symbol = buff.symbol Nenue@0: path = path or icon.iconPath Nenue@0: --print(style, icon.iconStyle) Nenue@0: Nenue@0: if style ~= buff.iconStyle or path ~= buff.iconPath then Nenue@0: print('|cFF0088FFUpdateBuffStyle(|r', icon:GetName(), style, path) Nenue@0: icon.iconStyle = style Nenue@0: icon.iconPath = path Nenue@0: else Nenue@0: --print('|cFF00FF88UpdateBuffStyle(|r', icon:GetName(), style, path, ') same values, ignore') Nenue@0: return Nenue@0: end Nenue@49: local styleset = Aura.BuffStyles[style] Nenue@0: if not path or path == '' then Nenue@0: print('path is nil/empty') Nenue@0: icon:SetTexture(1, 1, 1, 1) Nenue@0: icon:SetVertexColor(unpack(styleset.Color)) Nenue@0: else Nenue@0: icon:SetTexture(path or icon:GetTexture()) Nenue@0: icon:SetVertexColor(unpack(styleset.Color)) Nenue@0: end Nenue@0: Nenue@0: if symbol and symbol.GetText then Nenue@0: symbol:SetTextColor(unpack(styleset.TextColor)) Nenue@0: symbol:SetText(buff.symbolName or 'NaW') Nenue@0: end Nenue@0: Nenue@0: icon:SetBlendMode(styleset.SetBlendMode) Nenue@0: icon:SetDesaturated(styleset.SetDesaturated) Nenue@0: end Nenue@0: Nenue@0: --- Populates a list of targets needing a buff, fired by a handler Nenue@0: local PlayerBuffTodo ={} Nenue@48: local PlayerBuffStatus = {} Nenue@48: local UnitClass, IsInGroup, GetNumGroupMembers, UnitAura = UnitClass, IsInGroup, GetNumGroupMembers, UnitAura Nenue@48: local GetTalentInfoByID, GetActiveSpecGroup, GetStablePetInfo, GetSpecialization = GetTalentInfoByID, GetActiveSpecGroup, GetStablePetInfo, GetSpecialization Nenue@49: Aura.UpdateBuffStatus = function(aura, filters) Nenue@49: local print = xprint Nenue@0: if not PlayerBuffStatus[aura] then Nenue@0: PlayerBuffStatus[aura] = {} Nenue@0: end Nenue@0: print(UnitClass('player')) Nenue@0: if IsInGroup() then Nenue@0: local numBuffed = 0 Nenue@0: local partySize = GetNumGroupMembers() Nenue@0: local missing = {} Nenue@0: for i = 1, partySize do Nenue@0: local unit = 'raid'..i Nenue@0: if UnitAura(unit, aura, nil, filters) then Nenue@0: numBuffed = numBuffed + 1 Nenue@0: else Nenue@0: tinsert(missing, unit) Nenue@0: end Nenue@0: end Nenue@0: Nenue@0: PlayerBuffTodo[aura] = missing Nenue@0: Nenue@0: end Nenue@0: end Nenue@0: Nenue@0: --- Evaluates buff availability criteria Nenue@0: -- Uses hard returns to avoid over-iterating conditionals, particularly pet family Nenue@0: local function IsBuffAvailable(criteria) Nenue@0: local available, active = false, false Nenue@0: local result Nenue@0: for _, test in ipairs(criteria) do Nenue@0: if test == true then Nenue@0: -- it's a passive effect that is always on Nenue@0: return true, true Nenue@0: else Nenue@0: if c.spec then Nenue@49: if not (result and c.spec == vn.PlayerSpec) then Nenue@0: return false Nenue@0: end Nenue@0: end Nenue@0: Nenue@0: if c.talent then Nenue@0: local talentID, name, texture, selected, available = GetTalentInfoByID(c.talent, GetActiveSpecGroup()) Nenue@0: if not (result and selected) then Nenue@0: return false Nenue@0: end Nenue@0: end Nenue@0: Nenue@0: if c.petFamily then Nenue@0: local lim = min(5, NUM_PET_STABLE_SLOTS) -- to avoid volatile loop condition Nenue@0: for p = 1, lim do Nenue@0: local hasPet = false Nenue@0: local icon, name, level, family, talent = GetStablePetInfo(p) Nenue@0: if family == c.petFamily then Nenue@0: hasPet = true Nenue@0: end Nenue@0: if not (result and hasPet) then Nenue@0: return false Nenue@0: end Nenue@0: end Nenue@0: end Nenue@0: Nenue@0: end Nenue@0: end Nenue@0: return true, false Nenue@0: end Nenue@0: Nenue@0: --- events: PLAYER_SPECIALIZATION_CHANGED Nenue@49: function Aura:UpdateBuffsTodo (unit) Nenue@0: -- buffs vs. auras Nenue@0: if unit ~= 'player' then Nenue@0: -- look for changes in the GIST manifest and sort them out Nenue@0: return Nenue@0: end Nenue@0: Nenue@0: local class = UnitClass('player') Nenue@0: local spec = GetSpecialization() Nenue@0: if not class or Nenue@0: not spec or Nenue@0: not IsInGroup() or Nenue@49: not Aura.PlayerBuffStatus[class] then Nenue@0: -- if just logging in, info won't be available for several seconds Nenue@0: -- if not grouped, don't calc Nenue@0: -- hide frame Nenue@49: Aura.PlayerBuffsActive = function() return false end Nenue@0: return Nenue@0: end Nenue@0: Nenue@0: -- verify change Nenue@49: if vn.PlayerCurrentSpec == spec or vn.PlayerClass == class then Nenue@0: return Nenue@0: end Nenue@49: vn.PlayerCurrentSpec = spec Nenue@49: vn.PlayerClass = class Nenue@0: Nenue@49: local test = vn.ClassRaidBuffs Nenue@0: local buffTypes = {} Nenue@0: local auraTypes = {} Nenue@0: for i = 1, NUM_LE_RAID_BUFF_TYPES do Nenue@0: local name, filters Nenue@0: if test[i] and test[i][class] then Nenue@0: playerBuffs[i], name, filters = IsBuffAvailable(test[i][class]) Nenue@0: else Nenue@0: playerBuffs[i] = nil Nenue@0: end Nenue@0: Nenue@0: if name then Nenue@49: vn.UpdateBuffStatus(name, filters) Nenue@0: end Nenue@0: end Nenue@0: end Nenue@0: Nenue@0: -- Called once to setup the ConsolidatedBuffs stencil Nenue@49: local consolidatedBuffsLoaded, displays Nenue@49: Aura.SetConsolidatedBuffs = function() Nenue@0: local print = fprint() Nenue@49: displays = Aura.displays Nenue@0: c = displays.ConsolidatedBuff.conf Nenue@49: parentFrame = Aura.guides[c.Parent][c.Position] Nenue@49: raidbuffsFrame = Aura.anchors.ConsolidatedBuff Nenue@0: Nenue@49: vn.SetConfigLayers(raidbuffsFrame) Nenue@0: consolidatedBuffsLoaded = true Nenue@0: ConsolidatedBuffs:ClearAllPoints() Nenue@0: ConsolidatedBuffs:SetAllPoints(parentFrame.icon) Nenue@0: if c.Icon then Nenue@0: ConsolidatedBuffsIcon:SetAllPoints(parentFrame.icon) Nenue@0: ConsolidatedBuffsIcon:SetTexCoord(0.609,0.89,0.215,0.78) Nenue@0: else Nenue@0: ConsolidatedBuffsIcon:Hide() Nenue@0: end Nenue@0: Nenue@0: ConsolidatedBuffsCount:Hide() Nenue@0: end Nenue@0: Nenue@49: local CanShowConsolidated = function() Nenue@49: return IsInGroup() and GetCVarBool("consolidateBuffs") Nenue@49: end Nenue@49: Nenue@0: local missingTypes = {} Nenue@0: local raidBuffsInitialized Nenue@49: Aura.UpdateRaidBuffs = function() Nenue@49: local print = xprint Nenue@0: if not consolidatedBuffsLoaded then Nenue@49: Aura.SetConsolidatedBuffs() Nenue@0: end Nenue@0: Nenue@49: if not CanShowConsolidated() then Nenue@49: Nenue@49: if parentFrame.contains then Nenue@49: print((CanShowConsolidated() and '|cFF88FF88' or '|cFF444444')..'showConsolidated|r', (parentFrame.contains and '|cFF88FF88' or '|cFF444444') .. 'parent.contains|r') Nenue@49: if raidBuffsInitialized then Nenue@49: for i = 1, 9 do Nenue@49: if raidBuffs[i] then Nenue@49: raidBuffs[i]:Hide() Nenue@49: end Nenue@0: end Nenue@49: raidBuffsInitialized = nil Nenue@0: end Nenue@49: if parentFrame then Nenue@49: print(c.Parent, c.Position) Nenue@49: print('de-flagging parent') Nenue@49: parentFrame.contains = nil Nenue@49: end Nenue@49: raidbuffsFrame:Hide() Nenue@0: end Nenue@49: Nenue@0: return Nenue@49: --- ENDS HERE IF NOT SHOWING CONSOLIDATED FRAME Nenue@0: end Nenue@0: Nenue@49: local c = Aura.displays.ConsolidatedBuff.conf Nenue@52: if CanShowConsolidated() then Nenue@52: Nenue@52: if not parentFrame.contains then Nenue@52: raidBuffsInitialized = true Nenue@52: print('re-flagging parent', parentFrame:GetName()) Nenue@52: parentFrame.contains = parentFrame Nenue@52: Aura.decors[c.Parent][c.Position]:Hide() Nenue@52: Nenue@52: -- make sure parent icon is updated Nenue@52: local w = c.Size*c.PerRow+c.Spacing*(c.PerRow-1)+c.Border*2 Nenue@52: parentFrame:SetSize(w, w) Nenue@52: parentFrame.icon:SetSize(w - c.Border*2, w - c.Border*2) Nenue@52: parentFrame.contains = raidbuffsFrame Nenue@52: end Nenue@52: Nenue@49: raidbuffsFrame:SetPoint('TOPRIGHT', parentFrame, 'TOPRIGHT') Nenue@0: raidbuffsFrame:Show() Nenue@0: Nenue@49: Aura.UpdateBuffs(c.Parent) Nenue@0: end Nenue@0: Nenue@0: -- have to loop again due to tainting restrictions Nenue@0: -- could compare the tooltip font object pointers, but that may change Nenue@0: local buffStack = GetRaidBuffInfo() Nenue@0: print(GetRaidBuffInfo()) Nenue@49: local guides = vn.guides.ConsolidatedBuff Nenue@0: local numBuffs = 0 Nenue@0: local numAvailable = 0 Nenue@0: local mask = 1 Nenue@0: if buffStack == nil then Nenue@0: return -- discard Nenue@0: end Nenue@0: Nenue@0: Nenue@0: for i = 1, NUM_LE_RAID_BUFF_TYPES do Nenue@0: local available = (band(buffStack, mask) > 0) Nenue@0: local name, _, icon, start, duration, spellID, slot = GetRaidBuffTrayAuraInfo(i) Nenue@0: print(i, name, icon, available) Nenue@0: Nenue@0: raidBuffs[i] = raidBuffs[i] or CreateFrame('Frame', 'VeneerRaidBuff' .. i, raidbuffsFrame, 'VeneerRaidBuffTemplate') Nenue@0: local buff = raidBuffs[i] Nenue@0: if not raidBuffs[i].stylized then Nenue@0: print(' setting style', i) Nenue@0: buff.stylized = true Nenue@0: buff.symbol:SetText(raidBuffSymbols[i]) Nenue@0: buff.symbol:SetFont("Fonts\\FRIZQT__.TTF", 10, 'OUTLINE') Nenue@0: buff:SetSize(parentFrame.icon:GetWidth()/c.PerRow,parentFrame.icon:GetWidth()/c.PerRow) Nenue@0: buff.symbolName = raidBuffSymbols[i] Nenue@0: Nenue@0: buff.icon:SetAllPoints(guides[i].icon) Nenue@0: buff:SetAllPoints(guides[i]) Nenue@0: raidbuffsFrame.Zoom(buff.icon) Nenue@0: end Nenue@0: Nenue@0: buff:Show() Nenue@0: local buffStyle = 'missing' Nenue@0: if name then Nenue@0: buff:Show() Nenue@0: buff.symbol:Hide() Nenue@0: missingTypes[i] = nil Nenue@0: numBuffs = numBuffs + 1 Nenue@0: numAvailable = numAvailable + 1 Nenue@0: buffStyle = 'active' Nenue@0: else Nenue@0: buff.symbol:Show() Nenue@0: if band(buffStack, mask) > 0 then Nenue@0: buffStyle = 'available' Nenue@0: numAvailable = numAvailable + 1 Nenue@0: else Nenue@0: buffStyle = 'missing' Nenue@0: icon = '' Nenue@0: end Nenue@0: end Nenue@0: mask = lshift(mask, 1) Nenue@0: Nenue@49: Aura.UpdateBuffStyle(buff, buffStyle, icon) Nenue@0: end Nenue@0: Nenue@0: -- todo: filter by castable and suppress for non-overlapping auras Nenue@0: Nenue@0: raidbuffsFrame.label:SetText(numBuffs..'/'..numAvailable) Nenue@0: print(parentFrame:GetName(), parentFrame:GetSize()) Nenue@0: Nenue@49: if vn.ShowMissingBuffs then Nenue@49: vn.UpdateMissingBuffs() Nenue@0: elseif missingBuffsAnchor and missingBuffsAnchor:IsVisible() then Nenue@0: for i = 1, NUM_LE_MISSING_RAID_BUFFS do Nenue@0: missingBuffs[i]:Hide() Nenue@0: end Nenue@0: end Nenue@0: end Nenue@0: Nenue@49: vn.UpdateMissingBuffs = function() Nenue@49: local print = vn.fprint() Nenue@0: local numMissing = 0 Nenue@0: Nenue@0: local firstMissing, lastMissing Nenue@0: for i = 1, NUM_LE_RAID_BUFF_TYPES do Nenue@0: local name, _, icon, start, duration, spellID, slot = GetRaidBuffTrayAuraInfo(i) Nenue@0: Nenue@0: if not name then Nenue@0: numMissing = numMissing + 1 Nenue@0: Nenue@0: print('missing buff', i, numMissing) Nenue@49: vn.UpdateBuffStyle(raidBuffs[i].icon, 'missing', "") Nenue@0: Nenue@0: missingBuffs[numMissing] = missingBuffs[numMissing] or CreateFrame('Button', 'VeneerMissingBuff' .. numMissing, raidbuffsFrame, 'VeneerMissingBuffTemplate') Nenue@0: Nenue@0: local missing = missingBuffs[numMissing] Nenue@0: Nenue@0: missing:Show() Nenue@0: missing:SetSize(c.Size*c.PerRow, c.Size) Nenue@0: if numMissing == 1 then Nenue@0: firstMissing = missing Nenue@0: else Nenue@0: missing:SetPoint('TOP', lastMissing, 'BOTTOM', 0, -c.Spacing) Nenue@0: end Nenue@0: Nenue@0: missing.label:SetText(_G['RAID_BUFF_'.. i]) Nenue@0: lastMissing = missing Nenue@0: Nenue@0: end Nenue@0: end Nenue@0: Nenue@0: if firstMissing then Nenue@0: print(firstMissing:GetName(), raidbuffsFrame) Nenue@0: firstMissing:SetPoint('TOPRIGHT', raidbuffsFrame.label, 'BOTTOMRIGHT', 0, c.Spacing) Nenue@0: missingBuffsAnchor = firstMissing Nenue@0: end Nenue@0: Nenue@0: for i = numMissing +1, NUM_LE_MISSING_RAID_BUFFS do Nenue@0: missingBuffs[i]:Hide() Nenue@0: end Nenue@0: NUM_LE_MISSING_RAID_BUFFS = numMissing Nenue@0: end