# HG changeset patch
# User Nenue
# Date 1459319096 14400
# Node ID 3dbcad2b387d57810e3e2daedce78d591d51abe7
initial push
diff -r 000000000000 -r 3dbcad2b387d BuffAnchors.lua
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/BuffAnchors.lua Wed Mar 30 02:24:56 2016 -0400
@@ -0,0 +1,302 @@
+--- ${PACKAGE_NAME}
+-- @file-author@
+-- @project-revision@ @project-hash@
+-- @file-revision@ @file-hash@
+-- Created: 3/22/2016 3:10 AM
+
+local MODULE = 'BuffFrame'
+local _, A = ...
+local B, _G = A.frame, _G
+local M = B:RegisterModule(MODULE)
+local type, unpack, select, pairs, ipairs, wipe = type, unpack, select, pairs, ipairs, table.wipe
+local min, ceil, mod, tonumber, tostring = min, ceil, mod, tonumber, tostring
+local CreateFrame = CreateFrame
+local print = B.print('Anchor')
+local fprint = B.fprint
+local bprint = B.print('AnchorFrame')
+
+local GetAnchorFrame = function(name)
+ local c = B.displays[name].conf
+ local anchorFrom, anchorParent, anchorTo, offsetX, offsetY = unpack(c.Anchor)
+ local print = bprint
+ if B.anchor[name] then
+ print('get', B.anchor[name]:GetName())
+ return B.anchor[name], anchorFrom, anchorParent, anchorTo, offsetX, offsetY
+ end
+ print('new frame', name)
+ local frame = CreateFrame('Frame', name..'Anchor', UIParent, B.displays[name].anchorTemplate)
+ frame.conf = c
+
+ local x, dx, y, dy
+ local Anchor_OnMouseDown = function()
+ if c['Parent'] then
+ return
+ end
+
+ x = frame:GetLeft()
+ y = frame:GetTop()
+ frame:StartMoving()
+ frame.isMoving = true
+ end
+
+ local Anchor_OnMouseUp = function()
+ if c['Parent'] then
+ return
+ end
+
+ frame:StopMovingOrSizing()
+ dx = frame:GetLeft() - x
+ dy = frame:GetTop() - y
+ -- update config
+ print('|cFFFFFF00**changing', name, 'anchor by', dx, dy)
+ offsetX = offsetX + dx
+ offsetY = offsetY + dy
+ B.Conf[name .. 'Anchor'] = {anchorFrom, anchorParent, anchorTo, offsetX, offsetY }
+ frame:SetPoint(anchorFrom, _G[anchorParent], anchorTo, offsetX, offsetY)
+ frame.isMoving = nil
+ end
+
+ local AnchorButton_OnClick = function(self, anchor)
+ local point, parent, relative = anchor:GetPoint(1)
+ print('resetting anchors', point, parent:GetName(), relative)
+ B.Conf[name..'Point'] = {point, relative}
+ B.Conf[name..'RelativeX'] = (point:match('RIGHT')) and -1 or 1
+ B.Conf[name..'RelativeY'] = (point:match('TOP')) and -1 or 1
+ wipe(B.drawn[name])
+ B.UpdateBuffs(name)
+ end
+
+ frame.OnUpdate = function(self, elapsed)
+ print(self:GetName(), elapsed)
+ if self:IsMouseOver() then
+ for i, anchorButton in ipairs(frame.anchorButton) do
+ anchorButton:Show()
+ end
+ else
+ for i, anchorButton in ipairs(frame.anchorButton) do
+ anchorButton:Hide()
+ end
+ end
+ end
+
+ frame:SetScript('OnMouseDown', Anchor_OnMouseDown)
+ frame:SetScript("OnMouseUp", Anchor_OnMouseUp)
+ -- table addition
+ for i, anchorButton in ipairs(frame.anchorButton) do
+ anchorButton:SetScript('OnClick', AnchorButton_OnClick)
+ end
+
+ B.displays[name].anchor = frame
+ print(B.displays[name].anchor:GetName())
+ print(B.anchor[name]:GetName())
+ return frame, anchorFrom, anchorParent, anchorTo, offsetX, offsetY
+end
+
+--- Handles the preliminary positioning calculation for buff guide anchors
+M.UpdateAnchorFrames = function(name)
+ local print = fprint(name)
+ local c = B.displays[name].conf
+ local frame, anchorFrom, anchorParent, anchorTo, offsetX, offsetY = GetAnchorFrame(name)
+ print('got', frame:GetName())
+ frame.buffs = B.guides[name]
+ frame.heading:SetText(name)
+ B.SetConfigLayers(frame)
+
+ local buffMax = c['Max'] or 3
+ local perRow = c['PerRow'] or 2
+ local buffSpacing = c['Spacing']
+ local buffSize = c['Size']
+ local buffDurationSize = c['DurationSize']
+
+ if not frame.isMoving then
+ if not B.Conf[name .. 'Parent'] then
+ frame:SetPoint(anchorFrom, _G[anchorParent], anchorTo, offsetX, offsetY)
+ end
+ end
+
+ if frame.contains then buffMax = buffMax + 1 end
+ local cols, rows = min(perRow, buffMax), ceil(buffMax/perRow)
+ local spaces, breaks = (cols - 1), (rows - 1)
+ frame.columns = cols
+ frame.rows = rows
+ frame.spaces = cols - 1
+ frame.breaks = rows - 1
+
+ local width = cols*buffSize + spaces*buffSpacing
+ local height = rows * (buffSize + buffDurationSize) + (breaks * (buffSpacing))
+
+ frame:SetSize(width, height)
+ frame:Show()
+ print(frame:GetName(), frame:GetSize())
+ print(frame:GetPoint(1))
+end
+
+--- Handles placement of anchors embedded within anchors (consolidated buffs, maybe temp enchant)
+M.UpdateAnchorAnchors = function()
+ local print = fprint()
+ for buttonName, d in pairs(B.displays) do
+ local c = B.displays[buttonName].conf
+ local frame = B.anchor[buttonName]
+ local parent, child = c.Parent, c.Position
+
+ frame.parent = nil
+ if B.Conf[buttonName .. 'Parent'] and _G[B.Conf[buttonName .. 'Parent']..'Anchor'] then
+
+ local anchorAnchor = _G[B.Conf[buttonName .. 'Parent']..'Anchor']
+ local anchorTarget = B.guides[parent][child]
+ if anchorTarget then
+ print('link', buttonName, 'to', parent, child)
+ print(parent, child, B.displays[parent].guides[child])
+ local ac = B.displays[parent].conf
+ local anchorFrom, anchorTo = unpack(ac.Point)
+ frame:ClearAllPoints()
+ frame:SetPoint(anchorFrom, anchorTarget, anchorTo)
+ frame.parent = anchorTarget
+ anchorTarget.contains = frame
+ anchorAnchor.contains = frame
+ anchorAnchor.containPosition = child
+ else
+ frame.parent = anchorAnchor
+ anchorAnchor.contains = frame
+ anchorAnchor.containPosition = nil
+ end
+ else
+ frame.parent = nil
+ end
+
+ end
+end
+
+-- if facing key direction, anchor point [1] to parent's point [2]
+local childFacing = {
+ ['TOP'] = {'TOP', 'BOTTOM'},
+ ['BOTTOM'] = {'BOTTOM', 'TOP'},
+ ['RIGHT'] = {'LEFT', 'RIGHT'},
+ ['LEFT'] = {'RIGHT', 'LEFT'},
+}
+-- if align in key position, concatenate value with facing point
+local childAlign = {
+ ['TOP'] = 'TOP%s',
+ ['BOTTOM'] = 'BOTTOM%s',
+ ['MIDDLE'] = '%s',
+ ['LEFT'] = '%sLEFT',
+ ['RIGHT'] = '%sRIGHT',
+ ['CENTER'] = '%s',
+}
+
+--- dep handlers
+B.UpdateAnchorChild = function (frame, child, c)
+ if frame.attached ~= child then
+ B.SetAnchorChild(frame, child, c)
+ end
+
+ print('positioning|cFFFF0088', child, '|r of |cFF00FF00', frame, '|r')
+
+ local frameAnchor = unpack(B.Conf[c.Parent.. 'Anchor'])
+ local childAnchor, childPoint = 'BOTTOMRIGHT', 'TOPRIGHT'
+ local direction, position = unpack(c.Anchor)
+ if direction and position then
+ childAnchor = childAlign[position]:format(childFacing[direction][2])
+ childPoint = childAlign[position]:format(childFacing[direction][1])
+ print('align toward', position,'on', direction, 'edge')
+ end
+
+ print(frameAnchor, direction, position)
+ local lX, lY, cX, cY = frame.outer_X, frame.outer_Y, frame.cutout_X, frame.cutout_Y
+ local mX, mY = 0, 0 -- alignment modifiers
+ local pX, pY = 0, 0 -- position value
+ print('|cFFFF0088PUSHOUTS|r:', lX, lY, '|cFFFF8800PULL-IN|r:', cX, cY)
+
+ -- if attachment is on a moving edge
+ if not frameAnchor:match(direction) then
+ print(' child anchors to a growing edge |cFFFF8800', direction,'|r')
+ if direction == 'BOTTOM' then
+ -- horizontal edge
+
+ else
+ -- vertical edge
+ pX = lX
+ end
+
+ if frameAnchor:match(position) then
+
+ print('close alignment', lX, cX)
+ if position == 'RIGHT' then
+ -- and far X val
+ pX = 0
+ lX = -lX
+ cX = -cX
+ pY = lY
+ else
+ end
+ else
+ print('far alignment', position)
+ end
+ else
+ print(' child anchors to a static edge |cFF0088FF', direction,'|r')
+ -- use no Y offset, position doesn't interfere
+ if direction == 'BOTTOM' or direction == 'TOP' then
+ pY = 0
+ else
+ pX = 0
+ end
+ end
+
+ local frameWidth = frame:GetWidth()
+ local frameHeight = frame:GetHeight()
+
+ local overlapY, overlapX
+
+ -- right and bottom anchors offsets need to be inverted
+ if direction == 'BOTTOM' then
+ print('inverting Y values for anchor on BOTTOM edge, options:', cY, lY, 'actual:', pY)
+ pY = frameHeight - pY
+ cY = frameHeight - cY
+ lY = frameHeight - lY
+ print(' new values:', cY, lY, pY)
+ elseif direction == 'RIGHT' then
+ pX = frameWidth -pX
+ cX = frameWidth-cX
+ lX = frameWidth-lX
+ end
+
+
+ print(child, '|cFFFFFF00', childAnchor, '|r', frame, '|cFFFF0088', childPoint, '|r', pX, pY)
+ child:ClearAllPoints()
+ child:SetPoint(childAnchor, frame, childPoint, pX, pY)
+ frame.attachPoint = {childAnchor, childPoint }
+
+ if Devian and Devian.InWorkspace() then
+ frame.alignedJoint:ClearAllPoints()
+ frame.poppingJointX:ClearAllPoints()
+ frame.poppingJointY:ClearAllPoints()
+ frame.cuttingJointX:ClearAllPoints()
+ frame.cuttingJointY:ClearAllPoints()
+ frame.childSpace:ClearAllPoints()
+
+ frame.alignedJoint:SetPoint(childAnchor, frame, childPoint, pX, pY)
+ frame.poppingJointY:SetPoint(childAnchor, frame, childPoint, lX, lY) -- should really only differ when rows exceed 1
+ frame.poppingJointX:SetPoint(childAnchor, frame, childPoint, lX, lY)
+ frame.cuttingJointY:SetPoint(childAnchor, frame, childPoint, cX, cY) -- should really only differ when rows exceed 1
+ frame.cuttingJointX:SetPoint(childAnchor, frame, childPoint, cX, cY)
+ frame.childSpace:SetAllPoints(child)
+
+ frame.alignedJoint:Show()
+ frame.poppingJointX:Show()
+ frame.poppingJointY:Show()
+ frame.cuttingJointX:Show()
+ frame.cuttingJointY:Show()
+ frame.childSpace:Show()
+
+ print('|cFFFF0000MIN |r', childAnchor, childPoint, pX, pY)
+ print('|cFF00FFFFFAR |r', childAnchor, childPoint, cX, cY)
+ print('|cFFFFFF00CLOSE|r', childAnchor, childPoint, lX, lY)
+
+ end
+end
+
+B.SetAnchorChild = function(frame, child, c)
+ print('linking', child)
+ frame.attached = child
+ frame.attachmentConf = c
+end
\ No newline at end of file
diff -r 000000000000 -r 3dbcad2b387d BuffButton.lua
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/BuffButton.lua Wed Mar 30 02:24:56 2016 -0400
@@ -0,0 +1,440 @@
+--- Actual BlizzUI modifications are applied here
+-- @file-author@
+-- @project-revision@ @project-hash@
+-- @file-revision@ @file-hash@
+-- Created: 3/12/2016 12:47 AM
+local MODULE = 'BuffFrame'
+local _, A = ...
+local B, _G = A.frame, _G
+local type, unpack, select, pairs, ipairs = _G.type, _G.unpack, _G.select, _G.pairs, _G.ipairs
+local min, ceil, mod, tonumber, tostring = _G.min, _G.ceil, _G.mod, _G.tonumber, _G.tostring
+local floor, wipe, max = _G.math.floor, _G.table.wipe, _G.math.max
+local CreateFrame, IsInGroup, GetCVarBool = _G.CreateFrame, _G.IsInGroup, _G.GetCVarBool
+local BuffFrame, ConsolidatedBuffs = _G.BuffFrame, _G.ConsolidatedBuffs
+local print, gprint, aprint, fprint = B.print('Buff'), B.print('SetGuides'), B.print('SetAnchors'), B.fprint
+local displays, anchors, guides, decors, positioned, drawn, zoom = B.displays, {}, {}, {}, {}, {}, {}
+local UnitAura, UnitName, RegisterStateDriver = _G.UnitAura, _G.UnitName, _G.RegisterStateDriver
+
+local M = B:RegisterModule(MODULE)
+
+M.GetBuffZoom = function(buffName)
+ local zoom = tonumber(B.displays[buffName].conf['Zoom']) / 100 / 2
+ local zoomL, zoomU, zoomR, zoomD = zoom, zoom, 1-zoom, 1-zoom
+ print(buffName, zoom)
+ return function(self, ...)
+ if select('#',...) == 4 then
+ zoomL, zoomR, zoomU, zoomD = ...
+ end
+ self:SetTexCoord(zoomL, zoomR, zoomU, zoomD)
+ return zoomL, zoomR, zoomU, zoomD
+ end
+end
+
+
+
+M.UpdateButtonAlpha = function(self)
+ if not self.parent.timeLeft or not self:IsVisible() then
+ self:SetScript('OnUpdate', nil)
+ return
+ end
+
+ if self.parent.timeLeft < _G.BUFF_WARNING_TIME then
+ self:SetAlpha(BuffFrame.BuffAlphaValue)
+ else
+ self:SetAlpha(1)
+ end
+end
+
+--- Called infrequently to align stencil frames
+local refreshCount = 0
+M.UpdateGuideFrames = function(buffName)
+ refreshCount = refreshCount + 1
+ local print = fprint()
+
+
+ local anchor = anchors[buffName]
+ local c, g, d = displays[buffName].conf, guides[buffName], decors[buffName]
+ local perRow = c['PerRow']
+ local buffSpacing, buffSize, buffBorder, buffDurationSize, buffCountSize, relativeX, relativeY = c['Spacing'], c['Size'], c['Border'], c['DurationSize'], c['CountSize'], c['RelativeX'], c['RelativeY']
+ local consolidated = (anchors[buffName].contains and IsInGroup())
+ local consolidatedPosition = (consolidated and anchors[buffName].containPosition or 0)
+
+
+ print('|cFF00FF00Setting Guides ('..refreshCount..'):|r', buffName, 'user max:',c['Max'], 'hard max:', displays[buffName].maxIcons)
+
+ local buffMax = min(c['Max'], displays[buffName].maxIcons)
+ local anchorFrom, anchorTo = c.Point[1], c.Point[2]
+ anchor.Zoom = M.GetBuffZoom(buffName)
+
+
+
+ if consolidated then
+ buffMax = buffMax + 1
+ end
+
+ local legend = {}
+ legend.r, legend.g, legend.b, legend.a = unpack(displays[buffName].legendColor)
+ local horizFrom = (relativeX < 0) and 'RIGHT' or 'LEFT'
+ local horizTo = (relativeX < 0) and 'LEFT' or 'RIGHT'
+ local vertFrom = (relativeY < 0) and 'TOP' or 'BOTTOM'
+ local vertTo = (relativeY < 0) and 'BOTTOM' or 'TOP'
+ local previous, up
+ local bottom_extent = 0
+ for i = 1, buffMax do
+ print('update idx', i)
+ if not g[i] then
+ g[i] = CreateFrame('Frame', buffName..'Guide'..i, anchor, displays[buffName].template or 'VeneerGuideTemplate')
+ RegisterStateDriver(g[i], "visibility", "[petbattle] [vehicleui] hide; show")
+ end
+
+ local guide = g[i]
+
+ local row = ceil(i / perRow)
+ local col = mod(i, perRow)
+ if col == 0 then
+ col = perRow
+ end
+
+ guide.previous = previous
+ guide.up = up
+ local x, y, parent = 0, 0, anchor
+ if i == 1 then
+ parent = anchor
+ up = guide
+ elseif col == 1 then
+ parent = g[i-perRow]
+ y = (buffSpacing + bottom_extent) * relativeY
+ up = guide
+ anchorFrom = vertFrom .. horizFrom
+ anchorTo = vertFrom .. horizFrom
+ bottom_extent = 0
+ else
+ parent = g[i-1]
+ x = buffSpacing * relativeX
+ anchorFrom = vertFrom .. horizFrom
+ anchorTo = vertFrom .. horizTo
+ end
+ previous = guide
+ guide.parent = parent
+
+ ---------------------------------
+ -- Positioning layer
+ if i ~= consolidatedPosition or not consolidated then
+ guide:SetSize(buffSize, buffSize + buffDurationSize)
+ -- RaidBuffTray will fix the sizing
+ end
+ bottom_extent = max(bottom_extent, guide:GetHeight())
+
+ guide.info = {} -- UnitAura cache
+
+ if i == consolidatedPosition then
+ guide.legend:SetTexture(1,1,0,0.5)
+ else
+ guide.legend:SetTexture(legend.r, legend.g, legend.b, legend.a)
+ end
+
+ guide.idText:SetText(i) -- needs to reflect the current position
+
+ guide:ClearAllPoints()
+ guide:SetPoint(anchorFrom, parent, anchorTo, x, y)
+ print(anchorFrom, parent, anchorTo, x, y)
+
+ guide.icon:SetSize(buffSize - buffBorder * 2, buffSize - buffBorder * 2)
+ guide.icon:ClearAllPoints()
+ guide.icon:SetPoint('TOPLEFT', guide, 'TOPLEFT', buffBorder, -buffBorder )
+
+ local anchorTo, anchorFrom, x, y = unpack(c.DurationPoint)
+ guide.duration:ClearAllPoints()
+ guide.duration:SetPoint(anchorTo, guide, anchorFrom, x, y)
+ --guide.duration:SetSize(buffSize, buffDurationSize)
+ print(' duration ->', anchorFrom, anchorTo, x, y)
+
+ local anchorTo, anchorFrom, x, y = unpack(c.CountPoint)
+ guide.count:ClearAllPoints()
+ guide.count:SetPoint(anchorTo, guide.icon, anchorFrom, x, y)
+ --guide.count:SetSize(buffSize, c.CountSize)
+ print(' count ->', anchorFrom, anchorTo, x, y)
+
+ -----------------------------------
+ -- Background decorations layer
+ if not d[i] then
+ d[i] = CreateFrame('Frame', buffName..i..'Decor', _G.UIParent, 'VeneerDecorTemplate')
+ RegisterStateDriver(d[i], "visibility", "[petbattle] [vehicleui] hide")
+ end
+
+ d[i]:SetPoint('BOTTOMLEFT', guide.icon, 'BOTTOMLEFT', -buffBorder, -buffBorder)
+ d[i]:SetPoint('TOPRIGHT', guide.icon, 'TOPRIGHT', buffBorder, buffBorder)
+
+
+ guide:Show()
+ B.SetConfigLayers(guide)
+ end
+
+
+ if #guides[buffName] > buffMax then
+ local lim = #guides[buffName]
+ for i = buffMax+1, lim do
+
+ local g = guides[buffName][i]
+ if g:IsVisible() then
+ print('cleaning up #', i, buffName)
+ g:Hide()
+ B.RemoveConfigLayers(g)
+ end
+
+ end
+ end
+
+ anchor.last = previous
+ anchor.up = up
+
+ print(anchor:GetName(), anchor:GetSize())
+end
+
+M.UpdateButtonPositions = function(buffName, auraType)
+ local print = fprint()
+ local c = auraType.conf
+ local numBuffs = 0
+ local actualIcons = auraType.actualIcons()
+ local maxIcons = auraType.maxIcons
+ local anchor = anchors[buffName]
+ local buffMax = c['Max']
+ local consolidated = (anchor.contains and IsInGroup())
+ local consolidatedPosition = (consolidated and anchor.containPosition or 0)
+
+ for k,v in pairs(decors[buffName]) do
+ print(v)
+ end
+
+ if consolidated then
+ decors[buffName][1]:Hide()
+ numBuffs = numBuffs + 1
+ buffMax = buffMax + 1
+ end
+
+ print(' ', 'frame count:', auraType.actualIcons(), 'hardmax:', maxIcons)
+ if auraType.actualIcons() > 0 then
+ for i = 1, actualIcons do
+
+
+ local buff = _G[buffName .. i]
+ local buffIcon = _G[buffName .. i .. 'Icon']
+ local buffBorder = c['Border']
+ local buffDuration = _G[buffName .. i .. 'Duration']
+ local buffCount = _G[buffName .. i .. 'Count']
+ local buffDurationSize = c['DurationSize']
+ local debuffBorder = _G[buffName .. i .. 'Border']
+
+
+ if buff and not buff.consolidated then
+ numBuffs = numBuffs + 1
+ local guide = guides[buffName][numBuffs]
+ local deco = decors[buffName][numBuffs]
+ if numBuffs > buffMax then
+ -- if a limit is reached, start hiding
+ if guide then
+ guide.info = nil
+ end
+ if deco then
+ deco:Hide()
+ end
+ buff:Hide()
+ else
+ local buffData = guide.info
+ buffData.name, buffData.rank, buffData.icon, buffData.count, buffData.dispelType, buffData.duration, buffData.expires, buffData.caster, buffData.isStealable, buffData.shouldConsolidate, buffData.spellID, buffData.canApplyAura, buffData.isBossDebuff, buffData.value1, buffData.value2, buffData.value3
+ = UnitAura(buff.unit, buff:GetID(), nil, buff.filters)
+
+ if guide.caster and buffData.caster then
+ if (buffData.caster ~= 'player' or c.ShowSelfCast) then
+ guide.caster:SetText(UnitName(buffData.caster))
+ else
+ guide.caster:SetText(nil)
+ end
+ end
+
+
+ print(numBuffs, i, buff:GetName(), buff:GetID(), decors[buffName][numBuffs]:GetName())
+
+ buff:SetAllPoints(guide)
+ buffIcon:ClearAllPoints()
+ buffIcon:SetPoint('TOPLEFT', guide.icon, 'TOPLEFT', 0, 0)
+ buffIcon:SetPoint('BOTTOMRIGHT', guide.icon, 'BOTTOMRIGHT', 0, 0)
+
+ deco.parent = buff
+ -- make sure so they aren't re-shown in pet battle
+ if not C_PetBattles.IsInBattle() then
+ deco:Show()
+ deco:SetAlpha(1)
+ end
+
+ if debuffBorder then
+ deco.background:SetTexture(debuffBorder:GetVertexColor())
+ debuffBorder:Hide()
+ else
+ if guide.info.caster == 'player' then
+ print(guide.info.caster)
+ deco.background:SetTexture(unpack(c.PlayerColor))
+ elseif buffData.isBossDebuff then
+ print(guide.info.isBossDebuff)
+ deco.background:SetTexture(unpack(c.BossColor))
+ else
+ print(guide.info.caster)
+ deco.background:SetTexture(unpack(c.Color))
+ end
+ end
+
+
+ buffDuration:ClearAllPoints()
+ local from, to = unpack(c.DurationPoint)
+ buffDuration:SetPoint(from, guide.duration, to)
+ buffDuration:SetText('WHAT')
+
+ if buff.timeLeft and c.WarningFade then
+ deco:SetScript('OnUpdate', M.UpdateButtonAlpha)
+ else
+ deco:SetScript('OnUpdate', nil)
+ deco:SetAlpha(1.0)
+ end
+
+ buffCount:ClearAllPoints()
+ local from, to = unpack(c.CountPoint)
+ buffCount:SetPoint(from, guide.count, to)
+
+ if not drawn[buffName][numBuffs] then
+ anchors[buffName].Zoom(buffIcon)
+
+ if buffDuration then
+ local font = buffDuration:GetFont()
+ buffDuration:SetFont(font, c.DurationSize, 'OUTLINE')
+
+ end
+
+ if buffCount then
+ local font = buffCount:GetFont()
+ buffCount:SetFont(font, c.CountSize, 'OUTLINE')
+ end
+ drawn[buffName][numBuffs] = true
+ end
+ end
+ end
+
+ end
+ end
+ -- clear any outliers
+ for i = numBuffs+1, buffMax do
+ if guides[buffName][i].caster then
+ guides[buffName][i].caster:SetText(nil)
+ end
+ --if not decors[buffName][i].parent or
+
+ decors[buffName][i].parent = nil
+ decors[buffName][i]:SetAlpha(1.0)
+ decors[buffName][i]:SetScript('OnUpdate', nil)
+ decors[buffName][i]:Hide()
+ end
+
+ -- parametric occlusion data for compacted anchor points
+ if numBuffs == 0 then
+ anchor.cutout_X = 0
+ anchor.cutout_Y = 0
+ anchor.outer_X = 0
+ anchor.outer_Y = 0
+ elseif numBuffs <= buffMax then
+ local sX, sY = guides[buffName][numBuffs]:GetWidth(), guides[buffName][numBuffs]:GetHeight()
+ local p = c.PerRow
+ local lX = mod(numBuffs, p)
+ local lY = floor(numBuffs / p)
+ local oX = min(numBuffs, c.PerRow)
+ local oY = ceil(numBuffs / p)
+ anchor.cutout_X = lX * sX + lX * c.Spacing -- max clearance to fit alongside the row
+ anchor.cutout_Y = lY * sY + lY * c.Spacing
+ anchor.outer_Y = oY * sY + oY * c.Spacing -- distance of farthest row
+ anchor.outer_X = oX * sX + oX * c.Spacing
+
+
+ print('|cFF0088FF', 'inner corner', lX, lY, 'outer corners', oX, oY)
+ print('cutout delta =', anchor.cutout_X, anchor.cutout_Y, 'out of', floor(anchor:GetWidth()), floor(anchor:GetHeight()))
+ print('extent delta =', anchor.outer_X, anchor.outer_Y)
+ else
+ anchor.cutout_X = 0
+ anchor.cutout_Y = 0
+ anchor.outer_X = 0
+ anchor.outer_Y = 0
+ end
+
+ if anchor.attached then
+ M.UpdateAnchorChild(anchor, anchor.attached, anchor.attachmentConf)
+ end
+
+end
+
+M.PostBuffAnchors = function()
+ local print = fprint()
+ if M.ShowConsolidatedBuffs then
+ M.UpdateRaidBuffs()
+ end
+ for buttonName, auraType in pairs(displays) do
+ print('sending', buttonName, auraType)
+ -- if waiting for anchors
+ if not anchors[buttonName] then
+ return
+ end
+
+ --if positioned[buttonName] == 0 then
+ print('possibly reloaded UI, check positions')
+ M.UpdateGuideFrames(buttonName)
+ --end
+
+ M.UpdateButtonPositions(buttonName, auraType)
+ end
+end
+
+M.UpdateBuffs = function(buttonName, forced)
+ local print = B.fprint(buttonName)
+ local c = displays[buttonName].conf
+ if drawn[buttonName] then
+ wipe(drawn[buttonName])
+ else
+ drawn[buttonName] = {}
+ end
+
+ M.UpdateAnchorFrames(buttonName)
+ M.UpdateGuideFrames(buttonName)
+ M.UpdateButtonPositions(buttonName, displays[buttonName])
+end
+
+--- should only be called from user input
+print('init def')
+function M:OnInitialize ()
+ drawn = B.Abstract(B.displays, 'drawn')
+ -- Lesser extent of guide frames that have been positioned
+ positioned = B.Abstract(B.displays, 'positioned', positioned)
+ -- Backdrop style frame
+ decors = B.Abstract(B.displays, 'decorator', decors)
+ -- Static positioning frames
+ guides = B.Abstract(B.displays, 'guides', guides)
+ -- Anchor points for guides
+ anchors = B.Abstract(B.displays, 'anchor')
+ -- Stored functions for doing icon texture adjustments
+ zoom = B.Abstract(B.displays, 'zoom', zoom)
+
+ B:RegisterUnitEvent("UNIT_AURA", "player", "vehicle")
+ B:RegisterEvent("GROUP_ROSTER_UPDATE")
+ B:RegisterEvent("PLAYER_SPECIALIZATION_CHANGED")
+ hooksecurefunc("BuffFrame_UpdateAllBuffAnchors", M.PostBuffAnchors)
+ hooksecurefunc("RaidBuffTray_Update", M.UpdateRaidBuffs)
+end
+print('update def')
+function M:OnUpdate ()
+ M.ShowConsolidated = (IsInGroup() and GetCVarBool("consolidateBuffs"))
+ M.ShowMissingBuffs = (IsInGroup() and B.Conf.RaidShowMissing)
+
+ for name, auraType in pairs(displays) do
+ print(name, auraType)
+ M.UpdateBuffs(auraType.buffName, true)
+ end
+
+ M.UpdateAnchorAnchors()
+ M.UpdateRaidBuffs()
+ M.UpdateBuffsTodo()
+end
\ No newline at end of file
diff -r 000000000000 -r 3dbcad2b387d BuffFrame.xml
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/BuffFrame.xml Wed Mar 30 02:24:56 2016 -0400
@@ -0,0 +1,9 @@
+
+
+
+
+
+
\ No newline at end of file
diff -r 000000000000 -r 3dbcad2b387d Config.lua
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/Config.lua Wed Mar 30 02:24:56 2016 -0400
@@ -0,0 +1,388 @@
+--- All the control GUI stuff, including chat command functions
+-- @file-author@
+-- @project-revision@ @project-hash@
+-- @file-revision@ @file-hash@
+-- Created: 3/12/2016 12:49 AM
+local B, _G = select(2,...).frame, _G
+local M = B:RegisterModule("Options")
+local tostring, tonumber, floor, format = tostring, tonumber, floor, string.format
+local unpack, select, pairs, ipairs, type, wipe = unpack, select, pairs, ipairs, type, table.wipe
+local CreateFrame, IsControlKeyDown = _G.CreateFrame, _G.IsControlKeyDown
+local max = math.max
+local OpacitySliderFrame, ColorPickerFrame = _G.OpacitySliderFrame, _G.ColorPickerFrame
+local print = B.print('Cfgl')
+local function round(number, decimals)
+ if floor(number) == number then
+ return ('%d'):format(number)
+ end
+
+ return (("%%.%df"):format(decimals)):format(number)
+end
+
+--- STATE VARIABLES
+local configInit
+--- Dummies for addon table upvalues
+local configFrames = {} -- actual frame objects
+local displays = B.displays -- anchor objects dummy
+
+
+--- Returns a value retreival function and the current value stored in config
+-- @paramsig value, previousValue = configInteger(key)
+-- @param key Name of the config field being represented.
+local defaultGroup = 'BuffButton'
+local configInteger = function(group, key)
+ return function(self ,display)
+ return floor(tonumber(self:GetValue()) + 0.5)
+ end, (B.Conf[group ..key] or B.Conf[defaultGroup..key])
+end
+local configPercent = function(group, key)
+ return function(self, display)
+ local value = self:GetValue()
+ if display then
+ return tostring(floor(value*100+0.5))..' %'
+ else
+ return floor((value*100+0.5))/100
+ end
+ end, (B.Conf[group ..key] or B.Conf[defaultGroup..key])
+end
+local configColor = function(group, key)
+ -- table for config, color value list for text
+ return function(self, display)
+ if display then
+ return "|cFFFF4444" .. round(self.rgba[1], 1) .. "|r, |cFF44FF44" .. round(self.rgba[2], 1) .. "|r, |cFF4488FF" ..
+ round(self.rgba[3], 1) .. "|r, " .. round(self.rgba[4], 1)
+ else
+ return self.rgba
+ end
+ end, (B.Conf[group ..key] or B.Conf[defaultGroup..key])
+end
+local configCheck = function(group, key)
+ return function(self) return self:GetChecked() end, B.Conf[group ..key] or B.Conf[defaultGroup..key]
+end
+-- initializes the corresponding type of config field
+local frameTypeConv = {
+ Color = 'Button',
+ Font = 'Frame',
+}
+local configTypeParams = {
+ Slider = function(frame, optionInfo)
+ frame:SetMinMaxValues(optionInfo[5], optionInfo[6])
+ frame:SetValueStep(optionInfo[7])
+ frame:SetStepsPerPage(optionInfo[8])
+ print(frame.OptName, '\n {', optionInfo[5], optionInfo[6], optionInfo[7], optionInfo[8], '}')
+ end,
+ CheckButton = function(frame, optionInfo)
+ frame.SetValue = function(self, ...)
+ self:SetChecked(...)
+ B.Conf[self.OptName] = self:GetChecked()
+ print(self.OptTab)
+ B.UpdateAll()
+ end
+ frame:SetScript("OnClick",function(self)
+ B.Conf[self.OptName] = self:GetChecked()
+ print(B.Conf[self.OptName], self:GetChecked())
+ B.UpdateAll()
+ end)
+ end,
+ Color = function(frame, optionInfo)
+ frame.rgba = { frame.current:GetVertexColor() }
+ local colorPickerCallback = function(restore)
+ local newR, newG, newB, newA
+ if restore then
+ newR, newG, newB, newA = unpack(restore)
+ else
+ newA, newR, newG, newB = OpacitySliderFrame:GetValue(), ColorPickerFrame:GetColorRGB()
+ print('not cancel', newA, newR, newB, newG)
+ end
+ frame:SetValue({newR, newG, newB, newA})
+ B.UpdateBuffs(frame.OptTab)
+ end
+ frame:SetScript("OnClick", function(self)
+ print('got a click')
+ local r, g, b, a = frame.current:GetVertexColor()
+ ColorPickerFrame:SetColorRGB(r, g, b)
+ ColorPickerFrame.hasOpacity = (a ~= nil)
+ ColorPickerFrame.opacity = a
+ ColorPickerFrame.previousValues = {r,g,b,a}
+ ColorPickerFrame.func, ColorPickerFrame.opacityFunc, ColorPickerFrame.cancelFunc =
+ colorPickerCallback, colorPickerCallback,colorPickerCallback
+ ColorPickerFrame:Hide()
+ ColorPickerFrame:Show()
+ end)
+ frame.SetValue = function(self, rgba)
+ print(rgba)
+ frame.rgba = rgba
+ B.Conf[self.OptName] = rgba
+ frame.current:SetVertexColor(unpack(rgba))
+ frame.fieldvalue:SetText(frame.OptValue(frame, true))
+ end
+ end
+}
+--- configDialog
+-- @usage tinsert(configDialog, {prefix, row, [...] })
+-- Each top level member defines a group of config value handlers, structured as an iterative table where the
+-- first member is a key prefix, the second member is an integer row value, and all following members are treated
+-- as a widget resource, defined initially as a complete sub-table, which can be re-used further down by passing
+-- the string literal widget suffix.
+-- widget table: ... {'suffix', 'description', valueCallback, 'template', [widget parameters]}
+-- widget copy: ... 'suffix', ...
+local configDialog = {
+ {'BuffButton', 1,
+
+ {'Max', 'Max', configInteger, 'Slider',
+ 1, _G.BUFF_MAX_DISPLAY, 1, 1}, -- valueMin, valueMax, valueStep, stepsPerPage
+ {'PerRow', 'Per Row', configInteger, 'Slider',
+ 1, _G.BUFF_MAX_DISPLAY, 1, 1}, -- valueMin, valueMax, valueStep, stepsPerPage,
+ {'Size', 'Icon Size', configInteger, 'Slider',
+ 1, 256, 1, 1},
+ {'Spacing', 'Icon Spacing', configInteger, 'Slider',
+ 1, 50, 1, 1},
+ {'DurationSize', 'Duration Text Height', configInteger, 'Slider',
+ 1, 72, 1, 1},
+ {'Zoom', 'Icon Zoom', configInteger, 'Slider',
+ 0, 100, 1, 1},
+ {'Border', 'Border', configInteger, 'Slider',
+ 1, 16, 1, 1},
+ {'Color', 'Default Border', configColor, 'Color'},
+ {'RaidColor', 'RaidBuff Border', configColor, 'Color'},
+ {'PlayerColor', 'Player Buffs', configColor, 'Color'},
+ {'BossColor', 'Encounter Buffs', configColor, 'Color'},
+ {'ShowSelfCast', 'Show name for self-casts', configCheck, 'CheckButton'}
+ },
+ { 'DebuffButton', 1,
+ {'Max', 'Max', configInteger, 'Slider',
+ 1, _G.DEBUFF_MAX_DISPLAY, 1, 1 }
+ ,
+ {'PerRow', 'Per Row', configInteger, 'Slider',
+ 1, _G.DEBUFF_MAX_DISPLAY, 1, 1 },
+ 'Size', 'Spacing', 'DurationSize', 'Zoom', 'Border',
+ 'Color', 'RaidColor', 'PlayerColor', 'BossColor',
+ },
+ { 'TempEnchant', 1,
+ {'Max', 'Max', configInteger, 'Slider',
+ 1, _G.NUM_TEMP_ENCHANT_FRAMES, 1, 1 },
+ {'PerRow', 'Per Row', configInteger, 'Slider',
+ 1, _G.NUM_TEMP_ENCHANT_FRAMES, 1, 1},
+ 'Size', 'Spacing', 'DurationSize', 'Zoom', 'Border',
+ 'Color', 'RaidColor', 'PlayerColor', 'BossColor',
+ },
+ { 'ConsolidatedBuff', 2,
+ {'Position', 'Slot Position', configInteger, 'Slider',
+ 1, _G.BUFF_MAX_DISPLAY, 1, 1 }
+
+ },
+ { 'ConsolidatedBuff', 2,
+ 'Size'
+ },
+ { 'Raid', 3,
+ {'ShowMissing', 'Verbose missing raid buffs', configCheck, 'CheckButton'}
+ }
+}
+
+
+
+
+local configFrame
+local optionTemplates = {}
+local configPadding, configSpacing = 3, 3
+
+--- Walks the structure table to generate a pretty config panel
+local InitConfig = function()
+ configInit = true
+ local configWidth = B:GetWidth()
+ local optionWidth = (configWidth - configPadding) / 3 - configSpacing
+ local configHeight = 0
+ local bottom_extent = 0
+ local clusterHeight = 0
+ local clusterOffset = 0
+ local lastCluster
+ local cluster = 1
+ local col = 0
+ for t, taboptions in ipairs(configDialog) do
+ local group = taboptions[1]
+ cluster = taboptions[2]
+ col = col + 1
+
+
+ if not configFrames[t] then
+ configFrames[t] = {}
+ end
+
+
+ if cluster ~= lastCluster then
+ configHeight = configHeight + clusterHeight
+ print('|cFFFF8800## new cluster|r, advancing offset from', clusterOffset, 'to', clusterOffset + clusterHeight)
+ clusterOffset = clusterOffset + clusterHeight
+ col = 1
+ clusterHeight = 0
+ lastCluster = cluster
+ end
+
+ print('processing tab', group)
+ local row = 0
+ for i = 3, #taboptions do
+ row = row + 1
+ local optionInfo = taboptions[i]
+ if type(optionInfo) == 'string' then
+ optionInfo = optionTemplates[optionInfo]
+ end
+ local key, fieldname, valueFuncGenerator, configType = unpack(optionInfo)
+
+ if not optionTemplates[key] then
+ optionTemplates[key] = optionInfo
+ end
+
+ local fullkey = group .. key
+ print(fullkey, fieldname)
+
+ if not configFrames[t][row] then
+ print('building frame', t, group, row)
+ local frameTemplate = 'VeneerConfig'..configType
+ local frameType = frameTypeConv[configType] or configType
+ configFrames[t][row] = CreateFrame(frameType, fullkey, B, frameTemplate)
+ local f = configFrames[t][row]
+ f.OptKey = key
+ f.OptTab = group
+ f.OptName = fullkey
+ local valueFunc, initialValue = valueFuncGenerator(group, key)
+ print(' value getter', fullkey,'->', valueFunc,initialValue)
+ configTypeParams[configType](f, optionInfo)
+ f.OptValue = valueFunc
+
+ --- Enclosing these to
+ -- a) make the panel easy to bring up externally
+ -- b) limit gameplay risk from config frame errors
+ -- c) milk the iterator scope for all its worth
+ f.OnChange = function(self)
+
+ -- holding control; mirror this setting in other categories
+ if IsControlKeyDown() and not (configInit) then
+ configInit = true
+ for optTab, opts in pairs(configFrames) do
+ for _, opt in ipairs(opts) do
+ if opt.OptKey == key then
+ if optTab ~= group then
+ print('mapping to', optTab, opt.OptKey)
+ opt:SetValue(self:GetValue())
+ end
+
+ end
+ end
+ end
+ configInit = nil
+ end
+ local newValue = valueFunc(self)
+ if newValue ~= B.Conf[fullkey] then
+ print(newValue, fullkey)
+ f.fieldvalue:SetText(valueFunc(self, true))
+ B.Conf[fullkey] = valueFunc(self)
+ -- prepare to update
+ wipe(B.drawn[f.OptTab])
+ B.UpdateBuffs(self.OptTab)
+ B.UpdateConfigLayers()
+ end
+
+ end
+
+ f:SetValue(initialValue)
+ local yBuffer = configPadding
+ if f.fieldname then
+ f.fieldname:SetText(fieldname)
+ yBuffer = yBuffer + f.fieldname:GetHeight()
+ end
+ if f.fieldvalue then
+ f.fieldvalue:SetText(f:OptValue(true))
+ end
+
+ local point, relative, x, y = 'TOPLEFT', 'BOTTOMLEFT', 0, -3
+
+ local base
+ if (row == 1) then
+ bottom_extent = 0
+ base = B.header
+ x = (col-1) * (optionWidth+configSpacing)
+ y = -configPadding
+ else
+ base = configFrames[t][row-1]
+ end
+
+ print('|cFFFF0088'..cluster..'|r |cFF00FF00'.. row..'|r', col, base:GetName(), x, y - clusterOffset)
+
+ if frameType ~= 'CheckButton' then
+ f:SetWidth(optionWidth)
+ end
+
+ f:SetPoint(point, base, relative, x, y-yBuffer-clusterOffset)
+ --print('creating', frameType, fieldname)
+ f:Show()
+
+ bottom_extent = bottom_extent + f:GetHeight() + yBuffer + configSpacing
+
+
+
+ clusterHeight = max(clusterHeight, bottom_extent)
+ --print('y', floor(yBuffer+0.5), 'f:H', floor(f:GetHeight()+0.5), 'hTally', floor(bottom_extent+0.5), 'hMax', floor(configHeight+0.5))
+ end
+ end
+ end
+
+ -- grab the last cluster
+ if lastCluster == cluster then
+ print('|cFF00FF00##scooping up last cluster info')
+ configHeight = configHeight + clusterHeight
+ end
+
+ if not B.configFramesCreated then
+ B.configFramesCreated = true
+ B:SetHeight(B.header:GetStringHeight() + configSpacing*3 + configHeight)
+ end
+ if configInit then configInit = nil end
+end
+
+M.Command = function(enable, editbox)
+ displays = B.displays
+ if type(enable) == 'boolean' then
+ B.Conf.ConfigMode = enable
+ else
+ B.Conf.ConfigMode = (B.Conf.ConfigMode == false) and true or false
+ end
+
+ print('/BUFF', B.Conf.ConfigMode, type(B.Conf.ConfigMode))
+ if B.Conf.ConfigMode then
+ if not B.configFramesCreated then
+ InitConfig()
+ end
+ print('Veneer config')
+ B:Show()
+ else
+ B:Hide()
+ end
+ B.UpdateAll()
+ B.UpdateConfigLayers()
+end
+
+B.Close = function ()
+ M.Command()
+end
+
+B.ToggleGuides = function(_, self)
+ B.Conf.GuidesMode = (not B.Conf.GuidesMode)
+ if B.Conf.GuidesMode then
+ self:GetNormalTexture():SetTexture(0.94, 0.21, 0.21, 1)
+ else
+ self:GetNormalTexture():SetTexture(0, 0, 0, 1)
+ end
+
+ B.UpdateConfigLayers()
+end
+
+M.OnEnable = function()
+ M.Command(B.Conf.ConfigMode)
+end
+
+M.OnInitialize = function()
+ DEFAULT_CHAT_FRAME:AddMessage("|cFF22D822Veneer|r")
+ SLASH_BUFFALO1, SLASH_BUFFALO2 = "/buffalo", "/buff"
+ SlashCmdList.BUFFALO = M.Command
+
+end
\ No newline at end of file
diff -r 000000000000 -r 3dbcad2b387d Constants.lua
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/Constants.lua Wed Mar 30 02:24:56 2016 -0400
@@ -0,0 +1,347 @@
+--- ${PACKAGE_NAME}
+-- @file-author@
+-- @project-revision@ @project-hash@
+-- @file-revision@ @file-hash@
+-- Created: 3/22/2016 3:14 PM
+local _, A = ...
+local B = A.frame
+
+-----------------------
+-- Buff frames metadata
+-----------------------
+local legendAlpha = 0.5
+B.displays.BuffButton = {
+ legendColor = {0, 1, 0, legendAlpha},
+ maxIcons = BUFF_MAX_DISPLAY,
+ actualIcons = function () return _G.BUFF_ACTUAL_DISPLAY end,
+ buffName = 'BuffButton',
+ drawCount = {},
+ filters = 'HELPFUL',
+ anchorTemplate = 'VeneerAnchorTemplate',
+}
+B.displays.DebuffButton = {
+ legendColor = {1, 0, 0, legendAlpha},
+ maxIcons = DEBUFF_MAX_DISPLAY,
+ actualIcons = function () return _G.DEBUFF_ACTUAL_DISPLAY end,
+ buffName = 'DebuffButton',
+ drawCount = {},
+ filters = 'HARMFUL',
+ anchorTemplate = 'VeneerAnchorTemplate',
+}
+B.displays.TempEnchant = {
+ legendColor = {1, 0, 0.5, legendAlpha},
+ maxIcons = NUM_TEMP_ENCHANT_FRAMES,
+ actualIcons = function () return BuffFrame.numEnchants end,
+ buffName = 'TempEnchant',
+ drawCount = {},
+ anchorTemplate = 'VeneerAnchorTemplate',
+}
+B.displays.ConsolidatedBuff = {
+ legendColor = {0.5, 0.5, 0.5, legendAlpha},
+ maxIcons = 9,
+ actualIcons = function() return select(2, GetRaidBuffInfo()) end,
+ buffName = 'ConsolidatedBuff',
+ anchorTemplate = 'VeneerConsolidatedBuffsAnchor',
+ buffTemplate = 'VeneerRaidBuffTemplate',
+ drawCount = {},
+ filters = 'HELPFUL',
+}
+
+-----------------------
+-- RaidBuff visual args
+-----------------------
+B.BuffStyles = {
+ ["active"] = {
+ SetDesaturated = false,
+ Color = {1, 1, 1, 1},
+ SetBlendMode = 'BLEND',
+ TextColor = {1,1,1,1},
+ },
+ ["missing"] = {
+ SetDesaturated = false,
+ Color = {1, 0, 0, 0.5},
+ SetBlendMode = 'ADD',
+ TextColor = {1,0,0,1},
+ },
+ ["available"] = {
+ SetDesaturated = true,
+ Color = {0.35, 1, 0.35, 0.5},
+ SetBlendMode = 'ADD',
+ TextColor = {1, 1, 0, 1},
+ },
+}
+
+--- RaidBuff availability criteria
+-- @field spellID - UnitAura() == true
+-- @field spec - test for spec choice
+-- @field auraType - UnitAura() == true, and no other tests of the same value have returned true prior
+-- @field talent - test for talent selection
+-- @field petFamily - test pet family
+-- @field [true] - passive group aura
+B.ClassRaidBuffs = {
+ -- stats
+ [1] = {
+ ['HUNTER'] = {
+ {talent = {155228}, spellID = 160206, spellName = 'Lone Wolf: Power of the Primates', auraType = 'lonewolf'},
+ {petFamily = 'Dog'}, -- active pet family
+ {petFamily = 'Gorilla'},
+ {petFamily = 'Shale Spider'},
+ {petFamily = 'Worm'},
+ },
+ ['DRUID'] = {
+ {spellID = 1126, spellName = 'Mark of the Wild'},
+ },
+ ['MONK'] = {
+ {spellID = 115921, spellName = 'Legacy of the Emperor'},
+ {spellID = 116781, spellName = 'Legacy of the White Tiger'} -- windwalker, replaces emperor internally
+ },
+ ['PALADIN'] = {spellID = 20217, spellName = 'Blessing of Kings', auraType = 'blessing'},
+ },
+
+ -- stamina
+ [2] = {
+ ['HUNTER'] = {
+ {talent = {155228}, spellID = 160199, spellName = 'Lone Wolf: Fortitude of the Bear', auraType = 'lonewolf'},
+ {petFamily = 'Bear'}, -- active pet family
+ {petFamily = 'Goat'},
+ {petFamily = 'Rylak'},
+ {petFamily = 'Silithid'},
+ },
+ ['PRIEST'] = {
+ {spellID = 21562, 'Power Word: Fortitude'}
+ },
+ ['WARRIOR'] = {
+ {spellID = 469, spellName = 'Commanding Shout', auraType = 'shout'}
+ },
+ ['WARLOCK'] = {
+ {true}
+ }
+ },
+
+ -- attack power
+ [3] = {
+ ['HUNTER'] = {
+ {true},
+ },
+ ['DEATHKNIGHT'] = {
+ {spec = 2},
+ {spec = 3},
+ },
+ ['WARRIOR'] = {
+ {spellName = 'Battle Shout', auraType = 'shout'}
+ }
+ },
+
+ -- HASTE
+ [4] = {
+ ['HUNTER'] = {
+ {talent = {155228}, spellID = 160203, spellName = 'Lone Wolf: Haste of the Hyena', auraType = 'lonewolf'},
+ {petFamily = 'Hyena'}, -- active pet family
+ {petFamily = 'Sporebat'},
+ {petFamily = 'Rylak'},
+ {petFamily = 'Wasp'},
+ },
+ ['DEATHKNIGHT'] = {
+ {spec = 2}, -- unholy aura
+ {spec = 3},
+ },
+ ['PRIEST'] = {
+ {spec = 3}, -- mind quickening
+ },
+ ['ROGUE'] = {
+ true -- swiftblade's
+ },
+ ['SHAMAN'] = {
+ true -- grace of air
+ },
+ },
+
+ -- SPELL POWER
+ [5] = {
+ ['HUNTER'] = {
+ {talent = {155228}, spellID = 160205, spellName = 'Lone Wolf: Wisdom of the Serpent', auraType = 'lonewolf'},
+ {petFamily = 'Waterstrider'}, -- active pet family
+ {petFamily = 'Serpent'},
+ {petFamily = 'Silithid'},
+ },
+ ['MAGE'] = {
+ {spellID = 1459, spellName = 'Arcane Brilliance'}, -- arcane brilliance
+ {spellID = 61316, spellName = 'Dalaran Brilliance'}, -- dalaran brilliance
+ },
+ ['WARLOCK'] = {
+ {spellID = 109773,spellName = 'Dark Intent' }
+ },
+ },
+
+ -- CRITICAL STRIKE
+ [6] = {
+ ['HUNTER'] = {
+ {talent = {155228}, spellID = 160200, spellName = 'Lone Wolf: Ferocity of the Raptor', auraType = 'lonewolf'},
+ {petFamily = 'Devilsaur'}, -- active pet family
+ {petFamily = 'Quilen'},
+ {petFamily = 'Raptor'},
+ {petFamily = 'Shale Spider'},
+ {petFamily = 'Waterstrider'},
+ {petFamily = 'Wolf'},
+ },
+ ['DRUID'] = {
+ {spec = 2, spellID = 17007, auraType = 'druidform'}
+ },
+ ['MAGE'] = {
+ {spellID = 1459, spellName = 'Arcane Brilliance'}, -- arcane brilliance
+ {spellID = 61316, spellName = 'Dalaran Brilliance'}, -- dalaran brilliance
+ },
+ ['MONK'] = {
+ {spellID = 116781, spellName = 'Legacy of the White Tiger', spec = 2} -- windwalker
+ }
+ },
+
+ -- MASTERY
+ [7] = {
+ ['HUNTER'] = {
+ {talent = {155228}, spellID = 160198, spellName = 'Lone Wolf: Grace of the Cat', auraType = 'lonewolf'},
+ {petFamily = 'Cat'}, -- active pet family
+ {petFamily = 'Hydra'},
+ {petFamily = 'Spirit Beast'},
+ {petFamily = 'Tallstrider'},
+ },
+ ['DEATHKNIGHT'] = {
+ {spec = 1}
+ },
+ ['DRUID'] = {
+ {spec = 1, spellID = 24907, auraType = 'druidform'},
+ },
+ ['PALADIN'] = {
+ {spec = 1, spellID = 19740, spellName = 'Blessing of Might', auraType = 'blessing'}
+ },
+ ['SHAMAN'] = {true},
+ },
+
+ -- MULTISTRIKE
+ [8] = {
+ ['HUNTER'] = {
+ {talent = {155228}, spellID = 172968, spellName = 'Lone Wolf: Quickness of the Dragonhawk', auraType = 'lonewolf'},
+ {petFamily = 'Bat'}, -- active pet family
+ {petFamily = 'Clefthoof'},
+ {petFamily = 'Corehound'},
+ {petFamily = 'Dragonhawk'},
+ {petFamily = 'Wind Serpent'},
+ },
+ ['MONK'] = {
+ {spec = 2 }
+ }, -- Windflurry,
+ ['PRIEST'] = {
+ {spec = 3 }
+ }, -- quickening,
+ ['ROGUE'] = {true}, -- swiftblade's
+ ['WARLOCK'] = {
+ {spellID = 109773,spellName = 'Dark Intent' }
+ },
+ },
+
+ -- VERSATILITY
+ [9] = {
+ ['HUNTER'] = {
+ {talent = {155228}, spellID = 172967, spellName = 'Lone Wolf: Versatility of the Ravager', auraType = 'lonewolf'},
+ {petFamily = 'Ravager'}, -- active pet family
+ {petFamily = 'Boar'},
+ {petFamily = 'Porcupine'},
+ {petFamily = 'Clefthoof'},
+ {petFamily = 'Stag'},
+ {petFamily = 'Worm'},
+ {petFamily = 'Bird of Prey'},
+ },
+ ['DEATH KNIGHT'] = {
+ {spec = 2}, -- unholy aura
+ {spec = 3},
+ },
+ ['DRUID'] = {
+ {spellID = 1126, spellName = 'Mark of the Wild'},
+ },
+ ['PALADIN'] = {
+ {spec = 2}, -- retribution
+ },
+ ['WARRIOR'] = {
+ {spec = 2}, -- arms or fury
+ {spec = 3},
+ },
+ }
+}
+
+-------------------------
+-- Default config values
+-------------------------
+B.ConfDefaults = {
+ -- defaulted to on for first-time setup
+ ConfigMode = true,
+ GuidesMode = true,
+
+ BuffButtonAnchor = {'TOPRIGHT', 'UIParent', 'TOPRIGHT', -200, -5},
+ BuffButtonMax = 24,
+ BuffButtonPerRow = 10,
+ BuffButtonSize = 50,
+ BuffButtonSpacing = 4,
+ BuffButtonZoom = 15,
+ BuffButtonVertexColor = {},
+ BuffButtonPoint = {'TOPRIGHT', 'TOPRIGHT'},
+ BuffButtonDurationSize = 16,
+ BuffButtonDurationPoint = {'BOTTOM', 'BOTTOM', 0, -1},
+ BuffButtonCountSize = 18,
+ BuffButtonCountPoint = {'TOPRIGHT', 'TOPRIGHT', -3, -3},
+ BuffButtonRelativeX = -1,
+ BuffButtonRelativeY = -1,
+
+ BuffButtonColor = {1, 1, 1, 1},
+ BuffButtonPlayerColor = {1,1,1,1},
+ BuffButtonRaidColor = {0.25,1,0.25,1},
+ BuffButtonBossColor = {1,0.5,0,1},
+ BuffButtonBorder = 1,
+
+ BuffButtonWarningFade = true,
+ BuffButtonShowSelfCast = true,
+
+ DebuffButtonAnchor = {'TOPRIGHT', 'UIParent', 'TOPRIGHT', -200, -200},
+ DebuffButtonMax = 12,
+ DebuffButtonPerRow = 10,
+ DebuffButtonSize = 50,
+ DebuffButtonSpacing = 4,
+ DebuffButtonDurationSize = 16,
+ DebuffButtonZoom = 15,
+ DebuffButtonVertexColor = {},
+ DebuffButtonPoint = {'TOPRIGHT','TOPRIGHT'},
+ DebuffButtonRelativeX = -1,
+ DebuffButtonRelativeY = -1,
+
+
+ TempEnchantAnchor = {'TOPRIGHT', 'UIParent', 'TOPRIGHT', -200, -300},
+ TempEnchantMax = 2,
+ TempEnchantPerRow = 10,
+ TempEnchantSize = 50,
+ TempEnchantSpacing = 4,
+ TempEnchantDurationSize = 16,
+ TempEnchantZoom = 15,
+ TempEnchantVertexColor = {},
+ TempEnchantPoint = {'TOPRIGHT', 'TOPRIGHT'},
+ TempEnchantRelativeX = -1,
+ TempEnchantRelativeY = -1,
+ TempEnchantColor = {1,0,0.5,1},
+
+ ConsolidatedBuffAnchor = {'TOPRIGHT', 'UIParent', 'TOPRIGHT', 0, 0},
+ ConsolidatedBuffIcon = false,
+ ConsolidatedBuffMax = 9,
+ ConsolidatedBuffSize = 16,
+ ConsolidatedBuffParent = 'BuffButton',
+ ConsolidatedBuffPosition = 1,
+ ConsolidatedBuffSpacing = 1,
+ ConsolidatedBuffBorder = 0,
+ ConsolidatedBuffPerRow = 3,
+ ConsolidatedBuffPoint = {'TOPRIGHT', 'TOPRIGHT'},
+ ConsolidatedBuffRelativeX = -1,
+ ConsolidatedBuffRelativeY = -1,
+ ConsolidatedBuffDurationSize = 0,
+ ConsolidatedBuffDurationPoint = {'BOTTOM', 'BOTTOM', 0, 0},
+ ConsolidatedBuffCountPoint = {'BOTTOM', 'BOTTOM', 0, 0},
+
+ RaidShowMissing = true,
+
+}
\ No newline at end of file
diff -r 000000000000 -r 3dbcad2b387d Core.xml
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/Core.xml Wed Mar 30 02:24:56 2016 -0400
@@ -0,0 +1,477 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ self.mouseover = self:IsMouseOver()
+
+
+ if self:IsMouseOver() and not self.contains then
+ self.caster:Show()
+ else
+ self.caster:Hide()
+ end
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ self:OnChange()
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ self:OnChange()
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ self:RegisterForDrag('LeftButton')
+
+
+ self:StartMoving()
+
+
+ self:StopMovingOrSizing()
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff -r 000000000000 -r 3dbcad2b387d Init.lua
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/Init.lua Wed Mar 30 02:24:56 2016 -0400
@@ -0,0 +1,371 @@
+--- Modulizer framework
+-- OnInitialize
+-- OnUpdate
+-- OnEnable -- run when GetSpecialization() returns true
+
+local ADDON, A = ...
+Veneer = Veneer or CreateFrame('Frame', 'Veneer', UIParent)
+local B = Veneer
+local wipe, min, max, random, tinsert = table.wipe, math.min, math.max, math.random, table.insert
+local pairs, ipairs, select, unpack, _G = pairs, ipairs, select, unpack, _G
+local type, tostring, format = type, tostring, string.format
+A.frame = B
+
+--- Cache tables
+local initOnced
+local modules = {}
+local queuedModules = {}
+local moduleStack = {
+}
+
+--- Various region categories
+B.displays = {}
+B.configLayers = {}
+B.configLayersRef = {}
+
+--@debug@
+--- Generates a print handler pointing to a static channel signature
+-- @usage func = B.print(sig)
+-- @param sig channel name or number
+local printfuncs = {}
+B.print = function(pref, ...)
+ if Devian and Devian.InWorkspace() then
+ printfuncs[pref] = printfuncs[pref] or function(...) print(pref, ...) end
+
+ return printfuncs[pref]
+ else
+ return function () end
+ end
+end
+
+local rgb = {}
+local getcolor = function()
+ local n, p = 0, 4
+ for i = 1, 3 do
+ rgb[i] = min(random(n,p) * 64, 255)
+ if rgb[i] == 255 then
+ p = 4
+ elseif rgb[i] > 0 then
+ n = 2
+ end
+ end
+ return unpack(rgb)
+end
+
+local color = {}
+local fprints = {}
+B.fprint = function()
+ if not (Devian and Devian.InWorkspace()) then
+ return function() end
+ end
+
+
+ local sig = debugstack(2,1)
+ if fprints[sig] then
+ return fprints[sig]
+ end
+
+ local func = sig:match("%`(%a+)%'")
+ if not func then
+ func = sig:match("<(.-)>")
+ end
+ func = func:gsub('(%l+)(%u)', function(a, b) return a:sub(0,2) .. b end, 1)
+ func = func:gsub('^.+%\\', '')
+ if not func then
+ func = 'noname'
+ end
+
+ local r, g, b = getcolor()
+ color[sig] = color[sig] or format('|cFF%02X%02X%02X%s|r', r, g, b, func)
+
+ --print(color[func] .. ' ( ' .. table.concat(args, ', ')..' )' )
+ func = B.print(func)
+ fprints[sig] = func
+ return func
+end
+
+--@end-debug@
+--[=[@non-debug@
+B.print = function() end
+--@end-non-debug@]=]
+
+-- for the Mikk script
+-- GLOBALS: NUM_LE_RAID_BUFF_TYPES
+-- GLOBALS: BUFF_FLASH_TIME_ON, BUFF_FLASH_TIME_OFF, BUFF_MIN_ALPHA, BUFF_WARNING_TIME, BUFF_DURATION_WARNING_TIME
+-- GLOBALS: BUFFS_PER_ROW, BUFF_MAX_DISPLAY, BUFF_ACTUAL_DISPLAY, DEBUFF_MAX_DISPLAY, DEBUFF_ACTUAL_DISPLAY, BUFF_ROW_SPACING
+-- GLOBALS: CONSOLIDATED_BUFFS_PER_ROW, CONSOLIDATED_BUFF_ROW_HEIGHT, NUM_TEMP_ENCHANT_FRAMES
+-- GLOBALS: BUFF_BUTTON_HEIGHT, BUFF_FRAME_BASE_EXTENT, BUFF_HORIZ_SPACING
+
+local print = B.print('Bfl')
+
+--- Template for making perpendicular traversals of the displays structure; also makes sure the table is there
+B.Abstract = function(dest, key, table)
+ if table then
+ for _, v in pairs(dest) do
+ v[key] = {}
+ end
+ end
+ B[key] = setmetatable({}, {
+ __index = function(t, k)
+ return dest[k][key]
+ end,
+ __newindex = function(_, k, v)
+ print('abstract write ('..key..'):', k)
+ dest[k][key] = v
+ end,
+ __tostring = function() return 'Abstract:'..key..'' end
+ })
+
+
+ return B[key]
+end
+
+
+--- localize for speed
+local layers, refs, displays = B.configLayers, B.configLayersRef, B.displays
+
+local ModulesCall = function(func)
+
+ local n = 0
+ for i = 1, #moduleStack do
+ print('calling level '..i)
+ local stackset = moduleStack[i]
+
+ for name, module in pairs(stackset) do
+ n = n + 1
+ print(n..' '..name..'.'..func..'()')
+
+
+ if module[func] then
+ module[func](module)
+ end
+ end
+ end
+end
+
+
+local Enable = function()
+end
+
+--- The things that happen repeatedly
+local Init = function ()
+end
+
+
+--- Things that happen immediately upon entering world
+local InitOnce = function()
+ print('entering world first time')
+ local defaults = B.ConfDefaults
+ print('|cFFFFFF00Veneer|r')
+ if not VeneerData then
+ VeneerData = {}
+ for k,v in pairs(defaults) do
+ VeneerData[k] = v
+ end
+ print('Veneer defaults being used.')
+ end
+
+ B.Conf = setmetatable(VeneerData, {__index = function(_, k) return defaults[k] end})
+
+ -- suffix tables
+ for name, display in pairs(displays) do
+ display.conf = setmetatable({}, {
+ __index = function(_, k)
+ --print('config check '.. name .. k)
+ return B.Conf[name .. k] or B.Conf['BuffButton' .. k]
+ end,
+ __newindex = function(_, k , v)
+ B.Conf[name..k] = v
+ end,
+ })
+ end
+
+ -- To ensure that modules are run in controlled order, walk the dependency list; if the dep shows up
+ -- in the loaded manifest, remove the value. If the dep list isn't empty, move that module to the next
+ -- layer.
+ local loaded = {}
+ local stackLevels = #moduleStack
+ local i = 1
+ moduleStack[1] = modules
+ repeat
+ print('setting init level '.. i)
+ local queue = moduleStack[i]
+ for name, module in pairs(queue) do
+
+ if queuedModules[name] and #queuedModules[name] > 0 then
+ local p = #queuedModules[name]
+ for j = 1, p do
+ local dep = queuedModules[name][j]
+
+ if loaded[dep] then
+ print( ' ' .. dep .. ' OK')
+ queuedModules[name][j] = nil
+ for k = j, p do
+ print(' shift ' .. (k+1) .. ' ('..tostring(queuedModules[name][k+1])..') to ' .. k ..'')
+ queuedModules[name][k] = queuedModules[name][k+1]
+ end
+ end
+ end
+
+ if #queuedModules[name] == 0 then
+ queuedModules[name] = nil
+ print(' |cFF00FFFF'.. name ..'|r deps OK')
+ loaded[name] = true
+ else
+
+ print(' |cFFFF8800' .. name ..'|r pending')
+ local next = i+1
+ if not moduleStack[next] then
+ moduleStack[next] = {}
+ end
+ stackLevels = next
+ moduleStack[next][name] = module
+ queue[name] = nil
+ end
+
+ else
+ print(' |cFF00FF00'.. name ..'|r no deps')
+ loaded[name] = true
+ end
+ end
+ i = i + 1
+ until i > stackLevels
+
+
+ for level, batch in ipairs(moduleStack) do
+ print('config level', level)
+ for name, module in pairs(batch) do
+ print('integrity check', name)
+
+ --[===[@non-debug@
+ if module.defaults and not VeneerData[name] then
+ --@end-non-debug@]===]
+ print('Adding defaults from module ', name)
+ VeneerData[name] = module.default
+ --[===[@non-debug@
+ end
+ --@end-non-debug@]===]
+ end
+ end
+ -- remove from existing
+end
+
+--- Fires an update to all modules
+local lastUpdate
+function B.UpdateAll(...)
+ lastUpdate = GetTime()
+ ModulesCall('OnUpdate', lastUpdate)
+end
+
+B:RegisterEvent('PLAYER_ENTERING_WORLD')
+B:SetScript('OnEvent', function(self, event)
+ if event == 'PLAYER_ENTERING_WORLD' then
+ if not initOnced then
+ InitOnce()
+ ModulesCall('OnInitialize')
+ initOnced = true
+ C_Timer.After(1, function()
+ if GetSpecialization() then
+ print(GetSpecialization(), 'enabling')
+ ModulesCall('OnEnable')
+ B:SetScript('OnUpdate', nil)
+ end
+
+ end)
+ end
+
+ end
+
+ B.UpdateAll()
+end)
+
+--- Modulizer method
+--
+function B:RegisterModule (name, module, ...)
+ if modules[name] then
+ print('pulling modules[|cFFFF8800'.. tostring(name) ..'|r]')
+ return modules[name]
+ end
+
+ print('new module |cFF00BBFF'.. tostring(name) ..'|r')
+ if module then
+ if modules[name] then
+ error("Module table for '"..tostring(name).."' already exists.")
+ end
+ else
+ module = CreateFrame('Frame', 'Veneer' .. tostring(name) .. 'Handler', B, 'VeneerHandlerTemplate')
+ end
+ modules[name] = module
+ if select('#', ...) >= 1 then
+ local numDeps = select('#', ...)
+ print(' '..numDeps..' deps detected')
+ for i = 1, numDeps do
+ local dep = select(i, ...)
+ -- means that init/enable funcs are ordered to run after deps do their things
+ queuedModules[name] = queuedModules[name] or {}
+ tinsert(queuedModules[name], dep)
+ print(' needs '..dep)
+ end
+ end
+ return module
+end
+
+
+B.SetConfigLayers = function(frame)
+ local print = B.fprint()
+ if not frame.config then
+ print(frame:GetName(), 'has no config layers')
+ return
+ end
+ print('Registering config layers from', frame:GetName())
+
+ for i, subframe in ipairs(frame.config) do
+ -- make sure there are no duplicates
+ if not refs[subframe] then
+ local key = #layers+1
+ layers[key] = subframe
+ refs[subframe] = key
+ end
+ print(' ', i, subframe:GetName())
+ end
+end
+
+B.RemoveConfigLayers = function(frame)
+ local print = B.fprint()
+ print('|cFFFF0000RemoveConfigLayers', frame:GetName())
+ for i, subframe in pairs(layers) do
+ if subframe:GetParent() == frame then
+ print('|cFFFF8800 ', subframe:GetParent():GetName(), '|cFFFFFF00', subframe:GetName())
+ layers[i]:Hide()
+ layers[i] = nil
+ refs[subframe] = nil
+ end
+ end
+end
+
+B.UpdateConfigLayers = function()
+ local print = B.fprint()
+ local func = B.Conf.GuidesMode and 'Show' or 'Hide'
+ local numAnchors = 0
+ for name, display in pairs(displays) do
+ numAnchors = numAnchors + 1
+ display.anchor:EnableMouse(B.Conf.GuidesMode)
+ if B.Conf.GuidesMode then
+ display.anchor:SetScript('OnUpdate', display.anchor.OnUpdate)
+ else
+ display.anchor:SetScript('OnUpdate', nil)
+
+ for i, anchorButton in ipairs(display.anchor.anchorButton) do
+ anchorButton:Hide()
+ end
+
+ end
+
+ end
+ for id, region in pairs(layers) do
+ print(id, region:GetName(), func)
+ region[func](region)
+ end
+
+ print('['..func..'] updated', #layers, 'regions,', numAnchors, 'frames')
+end
\ No newline at end of file
diff -r 000000000000 -r 3dbcad2b387d ObjectiveInfo.lua
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/ObjectiveInfo.lua Wed Mar 30 02:24:56 2016 -0400
@@ -0,0 +1,135 @@
+local B = select(2,...).frame
+local wipe, pairs, ipairs, min, max, unpack = table.wipe, pairs, ipairs, min, max, unpack
+local GetNumQuestLeaderBoards, GetAchievementNumCriteria, GetQuestLogLeaderBoard, GetAchievementCriteriaInfo = GetNumQuestLeaderBoards, GetAchievementNumCriteria, GetQuestLogLeaderBoard, GetAchievementCriteriaInfo
+local GetQuestLogIndexByID, GetSuperTrackedQuestID, SetSuperTrackedQuestID, GetQuestWatchInfo = GetQuestLogIndexByID, GetSuperTrackedQuestID, SetSuperTrackedQuestID, GetQuestWatchInfo
+local mod = B:RegisterModule("ObjectiveTracker", _G.VeneerObjectiveWrapper, 'BuffFrame')
+local print = B.print('Objectives')
+
+local Tracker, AutoQuest, Quest, Cheevs = mod.Tracker, mod.AutoQuest, mod.Quest, mod.Cheevs
+--------------------------------------------------------------------
+--- Tracker-specific data retrieval functions
+--------------------------------------------------------------------
+
+Quest.GetNumWatched = function()
+ return GetNumQuestWatches ()
+end
+Quest.GetInfo = function (self, watchIndex)
+ print('|cFF00DDFFQuest|r.|cFF0088FFGetInfo(|r'.. tostring(watchIndex)..'|r)')
+ local questID, title, questLogIndex, numObjectives, requiredMoney, isComplete,
+ startEvent, isAutoComplete, failureTime, timeElapsed, questType, isTask, isStory, isOnMap, hasLocalPOI = GetQuestWatchInfo(watchIndex)
+print(GetQuestWatchInfo(watchIndex))
+ if not questID then
+ return
+ end
+ print(self.Info)
+ self.Info[questID] = self.Info[questID] or {}
+
+ local q = self.Info[questID]
+ q.watchIndex = watchIndex
+ q.type = 'Quest'
+ q.questID = questID
+ q.title = title
+ q.questLogIndex = questLogIndex
+ q.numObjectives = numObjectives
+ q.requiredMoney = requiredMoney
+ q.isComplete = isComplete
+ q.startEvent = startEvent
+ q.isAutoComplete = isAutoComplete
+ q.failureTime = failureTime
+ q.timeElapsed = timeElapsed
+ q.questType = questType
+ q.isTask = isTask
+ q.isStory = isStory
+ q.isOnMap = isOnMap
+ q.hasLocalPOI = hasLocalPOI
+
+ --- Start QuestLogEntry calls
+ -----------------------------------------
+ SelectQuestLogEntry(questLogIndex)
+ q.greenRange = GetQuestGreenRange()
+ q.isDaily = QuestIsDaily()
+ q.isWeekly = QuestIsWeekly()
+ -----------------------------------------
+
+ --- End QuestLogEntry calls
+ print(' |cFF0088FF', q.isDaily, q.isWeekly)
+
+ q.isComplete = IsQuestComplete(questID)
+ q.isBreadCrumb = IsBreadcrumbQuest(questID)
+ q.isStoryQuest = IsStoryQuest(questID)
+ q.completionText= GetQuestLogCompletionText(questLogIndex)
+ q.trackingID = questID
+ q.superTracked = (questID == GetSuperTrackedQuestID()) -- call directly so artifact data doesn't become an issue
+ q.numObjectives = GetNumQuestLeaderBoards(questLogIndex)
+ q.objectives = {}
+ for i = 1, q.numObjectives do
+ local text, type, finished = GetQuestLogLeaderBoard(i, questLogIndex)
+ q.objectives[i] = {
+ type = type,
+ text = text,
+ finished = finished
+ }
+ if type == 'event' then
+ elseif type == 'monster' then
+ elseif type == 'object' then
+ elseif type == 'reputation' then
+ elseif type == 'item' then
+ end
+ end
+
+ local link, icon, charges = GetQuestLogSpecialItemInfo(questLogIndex)
+ local start, duration, enable = GetQuestLogSpecialItemCooldown(questLogIndex)
+ if link or icon or charges then
+ q.specialItem = {
+ link = link,
+ charges = charges,
+ icon = icon,
+ start = start,
+ duration = duration,
+ enable = enable,
+ }
+ end
+
+ self.LogInfo[questLogIndex] = q
+ print('|cFF0088FFGetQuestInfo('..questID..')|r', questLogIndex, title)
+ return q
+end
+
+Cheevs.GetNumWatched = function(self)
+ Cheevs.trackedCheevs = {GetTrackedAchievements()}
+ return GetNumTrackedAchievements()
+end
+Cheevs.GetInfo = function(self, index)
+ local cheevID = Cheevs.trackedCheevs[index]
+ local id, name, points, completed, month, day, year, description, flags, icon, rewardText, isGuildAch, wasEarnedByMe, earnedBy = GetAchievementInfo(cheevID)
+
+ print('|cFF00FF00', GetAchievementNumCriteria(cheevID))
+ self.Info[cheevID] = {}
+ local c = self.Info[cheevID]
+ c.type = 'Cheevs'
+ c.watchIndex = index
+ c.cheevID = cheevID
+ c.title = name
+ c.points, c.completed, c.month, c.day, c.year, c.description, c.flags, c.icon, c.rewardText, c.isGuildAch, c.wasEarnedByMe, c.earnedBy =
+ points, completed, month, day, year, description, flags, icon, rewardText, isGuildAch, wasEarnedByMe, earnedBy
+ c.numObjectives = GetAchievementNumCriteria(cheevID)
+ c.objectives = {}
+ for i = 1, c.numObjectives do
+ local description, type, completed, quantity, requiredQuantity, characterName, flags, assetID, quantityString, criteriaID = GetAchievementCriteriaInfo(cheevID, i)
+ c.objectives[i] = {
+ text = description,
+ type = type,
+ finished = completed,
+ quantity = quantity,
+ requiredQuantity = requiredQuantity,
+ characterName = characterName,
+ flags = flags,
+ assetID = assetID,
+ quantityString = quantityString,
+ criteriaID = criteriaID,
+ }
+ end
+
+ self.WatchInfo[index] = c
+ return self.Info[cheevID]
+end
diff -r 000000000000 -r 3dbcad2b387d ObjectiveTracker.lua
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/ObjectiveTracker.lua Wed Mar 30 02:24:56 2016 -0400
@@ -0,0 +1,249 @@
+--- ${PACKAGE_NAME}
+-- @file-author@
+-- @project-revision@ @project-hash@
+-- @file-revision@ @file-hash@
+-- Created: 3/26/2016 1:51 AM
+local B = select(2,...).frame
+local wipe, pairs, ipairs, min, max, unpack = table.wipe, pairs, ipairs, min, max, unpack
+local setmetatable, type = setmetatable, type
+local GetNumQuestLeaderBoards, GetAchievementNumCriteria, GetQuestLogLeaderBoard, GetAchievementCriteriaInfo = GetNumQuestLeaderBoards, GetAchievementNumCriteria, GetQuestLogLeaderBoard, GetAchievementCriteriaInfo
+local GetQuestLogIndexByID, GetSuperTrackedQuestID, SetSuperTrackedQuestID, GetQuestWatchInfo = GetQuestLogIndexByID, GetSuperTrackedQuestID, SetSuperTrackedQuestID, GetQuestWatchInfo
+local mod = B:RegisterModule("ObjectiveTracker", _G.VeneerObjectiveWrapper, 'BuffFrame')
+local print = B.print('Objectives')
+local ObjectiveTrackerFrame = ObjectiveTrackerFrame
+
+--[[
+ Full quest info is available if:
+ - It's in the player quest log, or is available from the Gossip interface
+ - It's being shared from another player and is acceptible
+ - It's an auto-quest that is available in the current location
+ Partial quest info is availabe if:
+ - It's already completed (i.e. it appears in CompletedQuestInfo()).
+ - It's an scheduled interval quest (daily, weekly, etc.)
+ - It's contained in a quest link received from chat
+ Under any other circumstances, only minimal info can be pulled:
+ - Its availability to the player
+ - Its relation with the currently engaged NPC
+ - Its binary completion status
+
+]]
+--- Global Frames
+local Wrapper = _G.VeneerObjectiveWrapper
+local Scroller = Wrapper.scrollArea
+local Scroll = _G.VeneerObjectiveScroll
+
+--- list used to make things happen
+mod.orderedNames = {[1] = 'AutoQuest', [2] = 'Quest', [3] = 'Cheevs'}
+
+--- ipairs() list of handlers for wrapper update
+mod.orderedHandlers = {}
+mod.orderedTrackers = {}
+mod.indexedTrackers = {}
+--- pairs() list of handler frames for tracker updates
+mod.namedTrackers = {}
+
+--- Handler stubs
+mod.AutoQuest = {
+ name = "AutoQuest"
+}
+mod.Quest = {
+ name = "Quest"
+}
+mod.Cheevs = {
+ name = "Cheevs"
+}
+
+
+--- Temp values set during updates
+local wrapperWidth, wrapperHeight
+local scrollWidth, scrollHeight
+local previousBlock
+local currentBlock
+
+local frame_guide_init = function(self)
+ self.testU = self.testU or self:CreateTexture('TestU', 'OVERLAY', 'VnTestLine')
+ self.testB = self.testB or self:CreateTexture('TestB', 'OVERLAY', 'VnTestLine')
+ self.testL = self.testL or self:CreateTexture('TestL', 'OVERLAY', 'VnTestLine')
+ self.testR = self.testR or self:CreateTexture('TestR', 'OVERLAY', 'VnTestLine')
+end
+local frame_guide = function(self, target)
+ if not target then return end
+ if target:IsDragging() then return end
+ local thickness = 1
+ local midX, midY = target:GetCenter()
+ local width, height = target:GetWidth() * 1.5, target:GetHeight() * 1.5
+ --print('frame', target:GetLeft(), target:GetTop(), target:GetRight(), target:GetBottom())
+ self.testB:ClearAllPoints()
+ self.testB:SetPoint('TOP', UIParent, 'BOTTOMLEFT', midX, target:GetBottom())
+ self.testB:SetSize(width,thickness)
+
+ self.testU:ClearAllPoints()
+ self.testU:SetPoint('BOTTOM', UIParent, 'BOTTOMLEFT', midX, target:GetTop())
+ self.testU:SetSize(width,thickness)
+
+ self.testL:ClearAllPoints()
+ self.testL:SetPoint('RIGHT', UIParent, 'BOTTOMLEFT', target:GetLeft(), midY)
+ self.testL:SetSize(thickness,height)
+
+ self.testR:ClearAllPoints()
+ self.testR:SetPoint('LEFT', UIParent, 'BOTTOMLEFT', target:GetRight(), midY)
+ self.testR:SetSize(thickness,height)
+end
+
+--- Handler template
+local CreateHandler = function (self, name, index)
+ print(self, name)
+ local handler = setmetatable({}, {
+ __tostring = function() return name end,
+ __call = function (self) mod.UpdateTracker(self) end
+ })
+ if type(mod.orderedHandlers[index]) == 'table' then
+ return mod.orderedHandlers[index]
+ end
+
+ print('take up locals first')
+ local preset = {}
+ for k,v in pairs(mod[name]) do
+ preset[k] = true
+ if type(v) == 'table' then
+ handler[k] = {}
+ else
+ handler[k] = v
+ end
+ end
+
+ print('resulting handler contents')
+ for k, v in pairs(self) do
+ if not handler[k] then
+ if type(v) == 'table' then
+ -- assume all tables to be local data; don't inherit or ref
+ handler[k] = {}
+ else
+ handler[k] = mod.Tracker[k]
+ end
+ else
+ print(name, 'has its own', k)
+ end
+ end
+ print('|cFFFF4400'..tostring(name)..'|r:')
+ for k, v in pairs(handler) do
+ print(string.format("%24s %8s %s", (preset[k] and '|cFFFFFFFF' or '|cFFFFFF00') .. k .. '|r', type(v), tostring(v)))
+ end
+ mod[name] = handler
+ mod.orderedHandlers[index] = handler
+ return true
+end
+
+mod.Tracker = setmetatable({}, {
+ __call = CreateHandler,
+ __tostring = function() return 'DEFAULT_TRACKING_HANDLER' end
+})
+local Tracker = mod.Tracker
+Tracker.numWatched = 0 --- number of entries being handled
+Tracker.numBlocks = 0 --- number of blocks created
+Tracker.actualBlocks = 0 --- number of blocks in use
+
+Tracker.freeBlocks = {} --- block heap
+Tracker.usedBlocks = {}
+
+Tracker.Watched = {} -- find by watchIndex
+Tracker.Info = {} -- find by data ID
+Tracker.BlockInfo = {} -- find by block ID
+Tracker.LogInfo = {} -- find by log ID (quest log mainly)
+Tracker.WatchBlock = {}
+Tracker.LogBlock = {}
+
+
+
+Tracker.GetBlock = function(handler, blockIndex)
+ local block = handler.usedBlocks[blockIndex]
+ if not handler.usedBlocks[blockIndex] then
+ if #handler.freeBlocks >= 1 then
+ block = handler.freeBlocks[#handler.freeBlocks]
+ handler.freeBlocks[#handler.freeBlocks] = nil
+ else
+ block = CreateFrame('Frame', 'Veneer'..tostring(handler)..'Block'..blockIndex, Scroll, 'VeneerTrackerBlock')
+ block.SetStyle = mod.SetBlockStyle
+ block:ClearAllPoints() -- making sure the anchors are clear in case they get added for some other template usage
+ end
+
+ handler.usedBlocks[blockIndex] = block
+ end
+ return handler.usedBlocks[blockIndex]
+end
+local SmallEvents = {
+ QUEST_ACCEPTED = 'OnQuestAccepted'
+}
+
+local HandlerEvents = {
+ QUEST_ACCEPTED = mod.Quest,
+ QUEST_WATCH_LIST_CHANGED = mod.Quest,
+ SUPER_TRACKED_QUEST_CHANGED = mod.Quest,
+ QUEST_LOG_UPDATE = mod.Quest,
+ TRACKED_ACHIEVEMENT_LIST_CHANGED = mod.Cheevs,
+ TRACKED_ACHIEVEMENT_UPDATE = mod.Cheevs
+}
+
+function mod:OnEvent (event, ...)
+ local isHandled
+ if SmallEvents[event] then
+ print('|cFF00FF00'..SmallEvents[event]..'(' ..event..'|r', ...)
+ mod[SmallEvents[event]](event, ...)
+ isHandled = true
+ end
+ if HandlerEvents[event] then
+ print('|cFF0088FF'..event..'|r wrapper update')
+ mod.UpdateWrapper()
+ isHandled = true
+ end
+ if not isHandled then
+ print('|cFFFF4400'..event..'|r', ...)
+ end
+ --@debug@
+ if Devian and Devian.InWorkspace() then
+ frame_guide_init(Scroller)
+ frame_guide(Scroller, Scroller)
+ end
+end
+
+function mod:OnInitialize()
+
+ self.InitializeTrackers()
+ for event, _ in pairs(SmallEvents) do
+ self:RegisterEvent(event)
+ end
+ for event, _ in pairs(HandlerEvents) do
+ self:RegisterEvent(event)
+ end
+ self:SetScript('OnEvent', mod.OnEvent)
+
+ ObjectiveTrackerFrame:UnregisterAllEvents()
+ ObjectiveTrackerFrame:Hide()
+end
+
+--[[
+QUESTLINE_UPDATE This event is not yet documented
+QUESTTASK_UPDATE This event is not yet documented
+QUEST_ACCEPTED Fires when a new quest is added to the player's quest log (which is what happens after a player accepts a quest).
+QUEST_ACCEPT_CONFIRM Fires when certain kinds of quests (e.g. NPC escort quests) are started by another member of the player's group
+QUEST_AUTOCOMPLETE Fires when a quest is automatically completed (remote handin available)
+QUEST_BOSS_EMOTE This event is not yet documented
+QUEST_CHOICE_CLOSE This event is not yet documented
+QUEST_CHOICE_UPDATE This event is not yet documented
+QUEST_COMPLETE Fires when the player is looking at the "Complete" page for a quest, at a questgiver.
+QUEST_DETAIL Fires when details of an available quest are presented by a questgiver
+QUEST_FINISHED Fires when the player ends interaction with a questgiver or ends a stage of the questgiver dialog
+QUEST_GREETING Fires when a questgiver presents a greeting along with a list of active or available quests
+QUEST_ITEM_UPDATE Fires when information about items in a questgiver dialog is updated
+QUEST_LOG_UPDATE Fires when the game client receives updates relating to the player's quest log (this event is not just related to the quests inside it)
+QUEST_POI_UPDATE This event is not yet documented
+QUEST_PROGRESS Fires when interacting with a questgiver about an active quest
+QUEST_REMOVED This event is not yet documented
+QUEST_TURNED_IN Fired when a quest is turned in
+QUEST_WATCH_LIST_CHANGED This event is not yet documented
+QUEST_WATCH_OBJECTIVES_CHANGED This event is not yet documented
+QUEST_WATCH_UPDATE Fires when the player's status regarding a quest's objectives changes, for instance picking up a required object or killing a mob for that quest. All forms of (quest objective) progress changes will trigger this event.]
+
+TRACKED_ACHIEVEMENT_LIST_CHANGED This event is not yet documented
+TRACKED_ACHIEVEMENT_UPDATE Fires when the player's progress changes on an achievement marked for watching in the objectives tracker
+ ]]
\ No newline at end of file
diff -r 000000000000 -r 3dbcad2b387d ObjectiveTracker.xml
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/ObjectiveTracker.xml Wed Mar 30 02:24:56 2016 -0400
@@ -0,0 +1,237 @@
+
+
+
+
+
+
+
+
+
+
+ self.toggle = true
+ self:RegisterForDrag('LeftButton')
+
+
+
+
+ self:StartMoving()
+
+
+ self:StopMovingOrSizing()
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff -r 000000000000 -r 3dbcad2b387d ObjectiveUI.lua
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/ObjectiveUI.lua Wed Mar 30 02:24:56 2016 -0400
@@ -0,0 +1,64 @@
+--- ${PACKAGE_NAME}
+-- @file-author@
+-- @project-revision@ @project-hash@
+-- @file-revision@ @file-hash@
+-- Created: 3/29/2016 7:07 PM
+local B = select(2,...).frame
+local mod = B:RegisterModule("ObjectiveTracker", _G.VeneerObjectiveWrapper, 'BuffFrame')
+local print = B.print('Objectives')
+local Tracker, AutoQuest, Quest, Cheevs = mod.Tracker, mod.AutoQuest, mod.Quest, mod.Cheevs
+
+--------------------------------------------------------------------
+--- Tracker-specific widget functions
+--------------------------------------------------------------------
+
+Tracker.Select = function(self) end
+Tracker.Open = function(self) end
+Tracker.Remove = function(self) end
+Tracker.Report = function(self)
+ print('Stats:', self.numWatched,'items tracked,', self.numBlocks,'blocks assigned.')
+end
+
+Tracker.OnMouseUp = function(self, button)
+ if button == 'LeftButton' then
+ self:Select()
+ mod.UpdateWrapper()
+ elseif button == 'RightButton' then
+ self:Open()
+ end
+ print('|cFFFF8800'..tostring(self:GetName())..':MouseUp()|r ->',self.info.trackingID)
+end
+
+Tracker.OnMouseDown = function(self, button)
+ if button == 'LeftButton' then
+ self:SetStyle('Active')
+ end
+ print(self.info.title)
+end
+
+-----------------------------
+--- AUTO_QUEST
+AutoQuest.name = "Remote Quests"
+AutoQuest.GetNumWatched = GetNumAutoQuestPopUps
+
+-----------------------------
+--- QUEST
+Quest.name = "Quests"
+Quest.Select = function(self)
+ SetSuperTrackedQuestID(self.info.questID)
+end
+Quest.Open = function(self)
+ print('something something quest log')
+ QuestMapFrame_ShowQuestDetails(self.info.questID)
+ ToggleQuestLog()
+end
+
+
+-----------------------------
+--- CHEEVS
+Cheevs.Select = function(self)
+end
+
+Cheevs.Open = function(self)
+end
+
diff -r 000000000000 -r 3dbcad2b387d RaidBuffTray.lua
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/RaidBuffTray.lua Wed Mar 30 02:24:56 2016 -0400
@@ -0,0 +1,354 @@
+--- ${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
\ No newline at end of file
diff -r 000000000000 -r 3dbcad2b387d Veneer.toc
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/Veneer.toc Wed Mar 30 02:24:56 2016 -0400
@@ -0,0 +1,13 @@
+## Interface: 60200
+## Title: Veneer
+## Notes: Buff button management
+## Author: Krakyn
+## Version: 1.0-@project-revision@
+## SavedVariables: VeneerData
+## X-Category: Interface Enhancements
+## DefaultState: Enabled
+## LoadOnDemand: 0
+## OptionalDeps: Devian
+Core.xml
+BuffFrame.xml
+ObjectiveTracker.xml
\ No newline at end of file