view RaidBuffTray.lua @ 37:e84d645c8ab8

- revised the tracker update function to build its complete data list up front and use the values as points of comparison for determining possible out of place blocks, which will be iterated over afterward to remove what wasn't re-used - also entailed revising the exact role of global event handlers and function hooks, limiting their directions of communication so one doesn't end up calling the other multiple or inifinity times - schema handling polish
author Nenue
date Mon, 18 Apr 2016 07:56:23 -0400
parents 3dbcad2b387d
children
line wrap: on
line source
--- ${PACKAGE_NAME}
-- @file-author@
-- @project-revision@ @project-hash@
-- @file-revision@ @file-hash@
-- Created: 3/20/2016 10:00 PM

local _, A = ...
local B = A.frame
local MODULE = 'BuffFrame'
local M = B:RegisterModule(MODULE)
local displays = B.displays

local parentAnchor, parentFrame, raidbuffsFrame
local band, lshift, CreateFrame = bit.band, bit.lshift, CreateFrame
local raidBuffs = {}
local raidBuffSymbols = {'St', 'HP', 'AP', 'Ha', 'SP', 'Cr', 'Ma', 'MS', 'V' }
local missingBuffs = {}
local playerBuffing, playerCurrentBuff
local playerBuffs = {}
local c, ac, frameSize, frameSpacing, framePosition
local fprint = B.fprint
local NUM_LE_MISSING_RAID_BUFFS = 0
local missingBuffsAnchor


--- Takes a given icon texture and calls the pre-defined function set
M.UpdateBuffStyle = function(buff, style, path)
  local print = fprint()
  local icon = buff.icon
  local symbol = buff.symbol
  path = path or icon.iconPath
  --print(style,  icon.iconStyle)

  if style ~= buff.iconStyle or path ~= buff.iconPath then
    print('|cFF0088FFUpdateBuffStyle(|r',  icon:GetName(), style, path)
    icon.iconStyle = style
    icon.iconPath = path
  else
    --print('|cFF00FF88UpdateBuffStyle(|r',  icon:GetName(), style, path, ') same values, ignore')
    return
  end
  local styleset = B.BuffStyles[style]
  if not path or path == '' then
    print('path is nil/empty')
    icon:SetTexture(1, 1, 1, 1)
    icon:SetVertexColor(unpack(styleset.Color))
  else
    icon:SetTexture(path or icon:GetTexture())
    icon:SetVertexColor(unpack(styleset.Color))
  end

  if symbol and symbol.GetText then
    symbol:SetTextColor(unpack(styleset.TextColor))
    symbol:SetText(buff.symbolName or 'NaW')
  end

  icon:SetBlendMode(styleset.SetBlendMode)
  icon:SetDesaturated(styleset.SetDesaturated)
end

--- Populates a list of targets needing a buff, fired by a handler
local PlayerBuffTodo ={}
M.UpdateBuffStatus = function(aura, filters)
  if not PlayerBuffStatus[aura] then
    PlayerBuffStatus[aura] = {}
  end


  print(UnitClass('player'))
  if IsInGroup() then
    local numBuffed = 0
    local partySize = GetNumGroupMembers()
    local missing = {}
    for i = 1, partySize do
      local unit = 'raid'..i
      if UnitAura(unit, aura, nil, filters) then
        numBuffed = numBuffed + 1
      else
        tinsert(missing, unit)
      end
    end

    PlayerBuffTodo[aura] = missing

  end
end

--- Evaluates buff availability criteria
-- Uses hard returns to avoid over-iterating conditionals, particularly pet family
local function IsBuffAvailable(criteria)
  local available, active = false, false
  local result
  for _, test in ipairs(criteria) do
    if test == true then
      -- it's a passive effect that is always on
      return true, true
    else
      if c.spec then
        if not (result and c.spec == B.PlayerSpec) then
          return false
        end
      end

      if c.talent then
        local talentID, name, texture, selected, available = GetTalentInfoByID(c.talent, GetActiveSpecGroup())
        if not (result and selected) then
          return false
        end
      end

      if c.petFamily then
        local lim = min(5, NUM_PET_STABLE_SLOTS) -- to avoid volatile loop condition
        for p = 1, lim do
          local hasPet = false
          local icon, name, level, family, talent = GetStablePetInfo(p)
          if family == c.petFamily then
            hasPet = true
          end
          if not (result and hasPet) then
            return false
          end
        end
      end

    end
  end
  return true, false
end

--- events: PLAYER_SPECIALIZATION_CHANGED
function M:UpdateBuffsTodo (unit)
  -- buffs vs. auras
  if unit ~= 'player' then
    -- look for changes in the GIST manifest and sort them out
    return
  end

  local class = UnitClass('player')
  local spec = GetSpecialization()
  if not class or
      not spec or
      not IsInGroup() or
      not B.PlayerBuffStatus[class] then
    -- if just logging in, info won't be available for several seconds
    -- if not grouped, don't calc
    -- hide frame
      B.PlayerBuffsActive = function() return false end
    return
  end

  -- verify change
  if B.PlayerCurrentSpec == spec or B.PlayerClass == class then
    return
  end
  B.PlayerCurrentSpec = spec
  B.PlayerClass = class

  local test = B.ClassRaidBuffs
  local buffTypes = {}
  local auraTypes = {}
  for i = 1, NUM_LE_RAID_BUFF_TYPES do
    local name, filters
    if test[i] and test[i][class] then
      playerBuffs[i], name, filters = IsBuffAvailable(test[i][class])
    else
      playerBuffs[i] = nil
    end

    if name then
      B.UpdateBuffStatus(name, filters)
    end
  end
end

-- Called once to setup the ConsolidatedBuffs stencil
local consolidatedBuffsLoaded
M.SetConsolidatedBuffs = function()
  local print = fprint()
  c = displays.ConsolidatedBuff.conf
  parentFrame = B.guides[c.Parent][c.Position]
  raidbuffsFrame = B.anchor.ConsolidatedBuff

  B.SetConfigLayers(raidbuffsFrame)
  consolidatedBuffsLoaded = true
  ConsolidatedBuffs:ClearAllPoints()
  ConsolidatedBuffs:SetAllPoints(parentFrame.icon)
  if c.Icon then
    ConsolidatedBuffsIcon:SetAllPoints(parentFrame.icon)
    ConsolidatedBuffsIcon:SetTexCoord(0.609,0.89,0.215,0.78)
  else
    ConsolidatedBuffsIcon:Hide()
  end

  ConsolidatedBuffsCount:Hide()
end

local missingTypes = {}
local raidBuffsInitialized
M.UpdateRaidBuffs = function()
  local print = fprint()
  if not consolidatedBuffsLoaded then
    M.SetConsolidatedBuffs()
  end

  if not M.ShowConsolidated or not parentFrame.contains then
    print('  hiding raid buffs square')
    if raidBuffsInitialized then
      for i = 1, 9 do
        if raidBuffs[i] then
          raidBuffs[i]:Hide()
        end
      end
      raidBuffsInitialized = nil
    end
    if parentFrame then
      print(c.Parent, c.Position)
      print('de-flagging parent')
      parentFrame.contains = nil
    end
    raidbuffsFrame:Hide()
    return
  end

  local c = B.displays.ConsolidatedBuff.conf
  if parentFrame and not parentFrame.contains then
    raidBuffsInitialized = true
    print('re-flagging parent', parentFrame:GetName())
    parentFrame.contains = parentFrame
    B.decors[c.Parent][c.Position]:Hide()
    raidbuffsFrame:Show()

    -- make sure parent icon is updated
    local w = c.Size*c.PerRow+c.Spacing*(c.PerRow-1)+c.Border*2
    parentFrame:SetSize(w, w)
    parentFrame.icon:SetSize(w - c.Border*2, w - c.Border*2)
    parentFrame.contains = raidbuffsFrame

    M.UpdateBuffs(c.Parent)
  end

  -- have to loop again due to tainting restrictions
  -- could compare the tooltip font object pointers, but that may change
  local buffStack = GetRaidBuffInfo()
  print(GetRaidBuffInfo())
  local guides = B.guides.ConsolidatedBuff
  local numBuffs = 0
  local numAvailable = 0
  local mask = 1
  if buffStack == nil then
    return -- discard
  end


  for i = 1, NUM_LE_RAID_BUFF_TYPES do
    local available = (band(buffStack, mask) > 0)
    local name, _, icon, start, duration, spellID, slot = GetRaidBuffTrayAuraInfo(i)
    print(i, name, icon, available)

    raidBuffs[i] = raidBuffs[i] or CreateFrame('Frame', 'VeneerRaidBuff' .. i, raidbuffsFrame, 'VeneerRaidBuffTemplate')
    local buff = raidBuffs[i]
    if not raidBuffs[i].stylized then
      print('  setting style', i)
      buff.stylized = true
      buff.symbol:SetText(raidBuffSymbols[i])
      buff.symbol:SetFont("Fonts\\FRIZQT__.TTF", 10, 'OUTLINE')
      buff:SetSize(parentFrame.icon:GetWidth()/c.PerRow,parentFrame.icon:GetWidth()/c.PerRow)
      buff.symbolName = raidBuffSymbols[i]

      buff.icon:SetAllPoints(guides[i].icon)
      buff:SetAllPoints(guides[i])
      raidbuffsFrame.Zoom(buff.icon)
    end

    buff:Show()
    local buffStyle = 'missing'
    if name then
      buff:Show()
      buff.symbol:Hide()
      missingTypes[i] = nil
      numBuffs = numBuffs + 1
      numAvailable = numAvailable + 1
      buffStyle = 'active'
    else
      buff.symbol:Show()
      if band(buffStack, mask) > 0 then
        buffStyle = 'available'
        numAvailable = numAvailable + 1
      else
        buffStyle = 'missing'
        icon = ''
      end
    end
    mask = lshift(mask, 1)

    M.UpdateBuffStyle(buff, buffStyle, icon)
  end

  -- todo: filter by castable and suppress for non-overlapping auras

  raidbuffsFrame.label:SetText(numBuffs..'/'..numAvailable)
  print(parentFrame:GetName(), parentFrame:GetSize())

  if B.ShowMissingBuffs then
      B.UpdateMissingBuffs()
  elseif missingBuffsAnchor and missingBuffsAnchor:IsVisible() then
    for i = 1, NUM_LE_MISSING_RAID_BUFFS do
      missingBuffs[i]:Hide()
    end
  end
end

B.UpdateMissingBuffs = function()
  local print = B.fprint()
  local numMissing = 0

  local firstMissing, lastMissing
  for i = 1, NUM_LE_RAID_BUFF_TYPES do
    local name, _, icon, start, duration, spellID, slot = GetRaidBuffTrayAuraInfo(i)

    if not name then
      numMissing = numMissing + 1

      print('missing buff', i, numMissing)
      B.UpdateBuffStyle(raidBuffs[i].icon, 'missing', "")

      missingBuffs[numMissing] = missingBuffs[numMissing] or CreateFrame('Button', 'VeneerMissingBuff' .. numMissing, raidbuffsFrame, 'VeneerMissingBuffTemplate')

      local missing = missingBuffs[numMissing]

      missing:Show()
      missing:SetSize(c.Size*c.PerRow, c.Size)
      if numMissing == 1 then
        firstMissing = missing
      else
        missing:SetPoint('TOP', lastMissing, 'BOTTOM', 0, -c.Spacing)
      end

      missing.label:SetText(_G['RAID_BUFF_'.. i])
      lastMissing = missing

    end
  end

  if firstMissing then
    print(firstMissing:GetName(), raidbuffsFrame)
    firstMissing:SetPoint('TOPRIGHT', raidbuffsFrame.label, 'BOTTOMRIGHT', 0, c.Spacing)
    missingBuffsAnchor = firstMissing
  end

  for i = numMissing +1, NUM_LE_MISSING_RAID_BUFFS do
    missingBuffs[i]:Hide()
  end
  NUM_LE_MISSING_RAID_BUFFS = numMissing
end