Init
This commit is contained in:
@@ -0,0 +1,610 @@
|
||||
local Auras = {}
|
||||
local stealableColor = {r = 1, g = 1, b = 1}
|
||||
local playerUnits = {player = true, vehicle = true, pet = true}
|
||||
local mainHand, offHand = {time = 0}, {time = 0}
|
||||
local tempEnchantScan
|
||||
ShadowUF:RegisterModule(Auras, "auras", ShadowUF.L["Auras"])
|
||||
|
||||
function Auras:OnEnable(frame)
|
||||
frame.auras = frame.auras or {}
|
||||
|
||||
frame:RegisterNormalEvent("PLAYER_ENTERING_WORLD", self, "Update")
|
||||
frame:RegisterUnitEvent("UNIT_AURA", self, "Update")
|
||||
frame:RegisterUpdateFunc(self, "Update")
|
||||
|
||||
self:UpdateFilter(frame)
|
||||
end
|
||||
|
||||
function Auras:OnDisable(frame)
|
||||
frame:UnregisterAll(self)
|
||||
end
|
||||
|
||||
-- Aura positioning code
|
||||
-- Definitely some of the more unusual code I've done, not sure I really like this method
|
||||
-- but it does allow more flexibility with how things are anchored without me having to hardcode the 10 different growth methods
|
||||
local function load(text)
|
||||
local result, err = loadstring(text)
|
||||
if( err ) then
|
||||
error(err, 3)
|
||||
return nil
|
||||
end
|
||||
|
||||
return result()
|
||||
end
|
||||
|
||||
local positionData = setmetatable({}, {
|
||||
__index = function(tbl, index)
|
||||
local data = {}
|
||||
local columnGrowth = ShadowUF.Layout:GetColumnGrowth(index)
|
||||
local auraGrowth = ShadowUF.Layout:GetAuraGrowth(index)
|
||||
data.xMod = (columnGrowth == "RIGHT" or auraGrowth == "RIGHT") and 1 or -1
|
||||
data.yMod = (columnGrowth ~= "TOP" and auraGrowth ~= "TOP") and -1 or 1
|
||||
|
||||
local auraX, colX, auraY, colY, xOffset, yOffset, initialXOffset, initialYOffset = 0, 0, 0, 0, "", "", "", ""
|
||||
if( columnGrowth == "LEFT" or columnGrowth == "RIGHT" ) then
|
||||
colX = 1
|
||||
xOffset = " + offset"
|
||||
initialXOffset = string.format(" + (%d * offset)", data.xMod)
|
||||
auraY = 3
|
||||
data.isSideGrowth = true
|
||||
elseif( columnGrowth == "TOP" or columnGrowth == "BOTTOM" ) then
|
||||
colY = 2
|
||||
yOffset = " + offset"
|
||||
initialYOffset = string.format(" + (%d * offset)", data.yMod)
|
||||
auraX = 2
|
||||
end
|
||||
|
||||
data.initialAnchor = load(string.format([[return function(button, offset)
|
||||
button:ClearAllPoints()
|
||||
button:SetPoint(button.point, button.anchorTo, button.relativePoint, button.xOffset%s, button.yOffset%s)
|
||||
end]], initialXOffset, initialYOffset))
|
||||
data.column = load(string.format([[return function(button, positionTo, offset)
|
||||
button:ClearAllPoints()
|
||||
button:SetPoint("%s", positionTo, "%s", %d * (%d%s), %d * (%d%s)) end
|
||||
]], ShadowUF.Layout:ReverseDirection(columnGrowth), columnGrowth, data.xMod, colX, xOffset, data.yMod, colY, yOffset))
|
||||
data.aura = load(string.format([[return function(button, positionTo)
|
||||
button:ClearAllPoints()
|
||||
button:SetPoint("%s", positionTo, "%s", %d, %d) end
|
||||
]], ShadowUF.Layout:ReverseDirection(auraGrowth), auraGrowth, data.xMod * auraX, data.yMod * auraY))
|
||||
|
||||
tbl[index] = data
|
||||
return tbl[index]
|
||||
end,
|
||||
})
|
||||
|
||||
local function positionButton(id, group, config)
|
||||
local position = positionData[group.forcedAnchorPoint or config.anchorPoint]
|
||||
local button = group.buttons[id]
|
||||
button.isAuraAnchor = nil
|
||||
|
||||
-- Alright, in order to find out where an aura group is going to be anchored to certain buttons need
|
||||
-- to be flagged as suitable anchors visually, this speeds it up bcause this data is cached and doesn't
|
||||
-- have to be recalculated unless auras are specifically changed
|
||||
if( id > 1 ) then
|
||||
if( position.isSideGrowth and id <= config.perRow ) then
|
||||
button.isAuraAnchor = true
|
||||
end
|
||||
|
||||
if( id % config.perRow == 1 or config.perRow == 1 ) then
|
||||
position.column(button, group.buttons[id - config.perRow], 0)
|
||||
|
||||
if( not position.isSideGrowth ) then
|
||||
button.isAuraAnchor = true
|
||||
end
|
||||
else
|
||||
position.aura(button, group.buttons[id - 1])
|
||||
end
|
||||
else
|
||||
button.isAuraAnchor = true
|
||||
button.point = ShadowUF.Layout:GetPoint(config.anchorPoint)
|
||||
button.relativePoint = ShadowUF.Layout:GetRelative(config.anchorPoint)
|
||||
button.xOffset = config.x + (position.xMod * ShadowUF.db.profile.backdrop.inset)
|
||||
button.yOffset = config.y + (position.yMod * ShadowUF.db.profile.backdrop.inset)
|
||||
button.anchorTo = group.anchorTo
|
||||
|
||||
position.initialAnchor(button, 0)
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
local columnsHaveScale = {}
|
||||
local function positionAllButtons(group, config)
|
||||
local position = positionData[group.forcedAnchorPoint or config.anchorPoint]
|
||||
|
||||
-- Figure out which columns have scaling so we can work out positioning
|
||||
local columnID = 0
|
||||
for id, button in pairs(group.buttons) do
|
||||
if( id % config.perRow == 1 or config.perRow == 1 ) then
|
||||
columnID = columnID + 1
|
||||
columnsHaveScale[columnID] = nil
|
||||
end
|
||||
|
||||
if( not columnsHaveScale[columnID] and button.isSelfScaled ) then
|
||||
local size = math.ceil(button:GetSize() * button:GetScale())
|
||||
columnsHaveScale[columnID] = columnsHaveScale[columnID] and math.max(size, columnsHaveScale[columnID]) or size
|
||||
end
|
||||
end
|
||||
|
||||
local columnID = 1
|
||||
for id, button in pairs(group.buttons) do
|
||||
if( id > 1 ) then
|
||||
if( id % config.perRow == 1 or config.perRow == 1 ) then
|
||||
columnID = columnID + 1
|
||||
|
||||
local anchorButton = group.buttons[id - config.perRow]
|
||||
local previousScale, currentScale = columnsHaveScale[columnID - 1], columnsHaveScale[columnID]
|
||||
local offset = 0
|
||||
-- Previous column has a scaled aura, and the button we are anchoring to is not scaled
|
||||
if( previousScale and not anchorButton.isSelfScaled ) then
|
||||
offset = (previousScale / 4)
|
||||
end
|
||||
|
||||
-- Current column has a scaled aura, and the button isn't scaled
|
||||
if( currentScale and not button.isSelfScaled ) then
|
||||
offset = offset + (currentScale / 4)
|
||||
end
|
||||
|
||||
-- Current anchor is scaled, previous is not
|
||||
if( button.isSelfScaled and not anchorButton.isSelfScaled ) then
|
||||
offset = offset - (currentScale / 6)
|
||||
end
|
||||
|
||||
-- At least one of them is scaled
|
||||
if( ( not button.isSelfScaled or not anchorButton.isSelfScaled ) and offset > 0 ) then
|
||||
offset = offset + 1
|
||||
end
|
||||
|
||||
--print(columnID, math.ceil(offset))
|
||||
position.column(button, anchorButton, math.ceil(offset))
|
||||
else
|
||||
position.aura(button, group.buttons[id - 1])
|
||||
end
|
||||
-- If the initial column is self scaled, but the initial anchor isn't, will have to reposition it
|
||||
elseif( columnsHaveScale[columnID] ) then
|
||||
local offset = math.ceil(columnsHaveScale[columnID] / 8)
|
||||
if( button.isSelfScaled ) then
|
||||
offset = -(offset / 2)
|
||||
else
|
||||
offset = offset + 2
|
||||
end
|
||||
|
||||
--print(1, offset)
|
||||
position.initialAnchor(button, offset)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
-- Aura button functions
|
||||
-- Updates the X seconds left on aura tooltip while it's shown
|
||||
local function updateTooltip(self)
|
||||
if( GameTooltip:IsOwned(self) ) then
|
||||
GameTooltip:SetUnitAura(self.unit, self.auraID, self.filter)
|
||||
end
|
||||
end
|
||||
|
||||
local function showTooltip(self)
|
||||
if( not ShadowUF.db.profile.locked ) then return end
|
||||
|
||||
GameTooltip:SetOwner(self, "ANCHOR_BOTTOMLEFT")
|
||||
if( self.filter == "TEMP" ) then
|
||||
GameTooltip:SetInventoryItem("player", self.auraID)
|
||||
self:SetScript("OnUpdate", nil)
|
||||
else
|
||||
GameTooltip:SetUnitAura(self.unit, self.auraID, self.filter)
|
||||
self:SetScript("OnUpdate", updateTooltip)
|
||||
end
|
||||
end
|
||||
|
||||
local function hideTooltip(self)
|
||||
self:SetScript("OnUpdate", nil)
|
||||
GameTooltip:Hide()
|
||||
end
|
||||
|
||||
local function cancelBuff(self)
|
||||
if( not ShadowUF.db.profile.locked ) then return end
|
||||
|
||||
if( self.filter == "TEMP" ) then
|
||||
CancelItemTempEnchantment(self.auraID - 15)
|
||||
else
|
||||
CancelUnitBuff(self.unit, self.auraID, self.filter)
|
||||
end
|
||||
end
|
||||
|
||||
local function updateButton(id, group, config)
|
||||
local button = group.buttons[id]
|
||||
if( not button ) then
|
||||
group.buttons[id] = CreateFrame("Button", nil, group)
|
||||
|
||||
button = group.buttons[id]
|
||||
button:SetScript("OnEnter", showTooltip)
|
||||
button:SetScript("OnLeave", hideTooltip)
|
||||
button:SetScript("OnClick", cancelBuff)
|
||||
button:RegisterForClicks("RightButtonUp")
|
||||
|
||||
button.cooldown = CreateFrame("Cooldown", nil, button)
|
||||
button.cooldown:SetAllPoints(button)
|
||||
button.cooldown:SetReverse(true)
|
||||
button.cooldown:SetFrameLevel(7)
|
||||
button.cooldown:Hide()
|
||||
|
||||
button.stack = button:CreateFontString(nil, "OVERLAY")
|
||||
button.stack:SetFont("Interface\\AddOns\\ShadowedUnitFrames\\media\\fonts\\Myriad Condensed Web.ttf", 10, "OUTLINE")
|
||||
button.stack:SetShadowColor(0, 0, 0, 1.0)
|
||||
button.stack:SetShadowOffset(0.50, -0.50)
|
||||
button.stack:SetHeight(1)
|
||||
button.stack:SetWidth(1)
|
||||
button.stack:SetAllPoints(button)
|
||||
button.stack:SetJustifyV("BOTTOM")
|
||||
button.stack:SetJustifyH("RIGHT")
|
||||
|
||||
button.border = button:CreateTexture(nil, "OVERLAY")
|
||||
button.border:SetPoint("CENTER", button)
|
||||
|
||||
button.icon = button:CreateTexture(nil, "BACKGROUND")
|
||||
button.icon:SetAllPoints(button)
|
||||
button.icon:SetTexCoord(0.07, 0.93, 0.07, 0.93)
|
||||
end
|
||||
|
||||
if( ShadowUF.db.profile.auras.borderType == "" ) then
|
||||
button.border:Hide()
|
||||
elseif( ShadowUF.db.profile.auras.borderType == "blizzard" ) then
|
||||
button.border:SetTexture("Interface\\Buttons\\UI-Debuff-Overlays")
|
||||
button.border:SetTexCoord(0.296875, 0.5703125, 0, 0.515625)
|
||||
button.border:Show()
|
||||
else
|
||||
button.border:SetTexture("Interface\\AddOns\\ShadowedUnitFrames\\media\\textures\\border-" .. ShadowUF.db.profile.auras.borderType)
|
||||
button.border:SetTexCoord(0, 1, 0, 1)
|
||||
button.border:Show()
|
||||
end
|
||||
|
||||
-- Set the button sizing
|
||||
button.cooldown.noCooldownCount = ShadowUF.db.profile.omnicc
|
||||
button:SetHeight(config.size)
|
||||
button:SetWidth(config.size)
|
||||
button.border:SetHeight(config.size + 1)
|
||||
button.border:SetWidth(config.size + 1)
|
||||
button:ClearAllPoints()
|
||||
button:Hide()
|
||||
|
||||
-- Position the button quickly
|
||||
positionButton(id, group, config)
|
||||
end
|
||||
|
||||
-- Let the mover access this for creating aura things
|
||||
Auras.updateButton = updateButton
|
||||
|
||||
-- Create an aura anchor as well as the buttons to contain it
|
||||
local function updateGroup(self, type, config, reverseConfig)
|
||||
self.auras[type] = self.auras[type] or CreateFrame("Frame", nil, self.highFrame)
|
||||
|
||||
local group = self.auras[type]
|
||||
group.buttons = group.buttons or {}
|
||||
|
||||
group.maxAuras = config.perRow * config.maxRows
|
||||
group.totalAuras = 0
|
||||
group.temporaryEnchants = 0
|
||||
group.type = type
|
||||
group.parent = self
|
||||
group.anchorTo = self
|
||||
group:SetFrameLevel(5)
|
||||
group:Show()
|
||||
|
||||
-- If debuffs are anchored to buffs, debuffs need to grow however buffs do
|
||||
if( config.anchorOn and reverseConfig.enabled ) then
|
||||
group.forcedAnchorPoint = reverseConfig.anchorPoint
|
||||
end
|
||||
|
||||
if( self.unit == "player" ) then
|
||||
mainHand.time = 0
|
||||
offHand.time = 0
|
||||
|
||||
group:SetScript("OnUpdate", config.temporary and tempEnchantScan or nil)
|
||||
else
|
||||
group:SetScript("OnUpdate", nil)
|
||||
end
|
||||
|
||||
-- Update filters used for the anchor
|
||||
group.filter = group.type == "buffs" and "HELPFUL" or group.type == "debuffs" and "HARMFUL" or ""
|
||||
|
||||
-- This is a bit of an odd filter, when used with a HELPFUL filter, it will only return buffs you can cast on group members
|
||||
-- When used with HARMFUL it will only return debuffs you can cure
|
||||
if( config.raid ) then
|
||||
group.filter = group.filter .. "|RAID"
|
||||
end
|
||||
|
||||
for id, button in pairs(group.buttons) do
|
||||
updateButton(id, group, config)
|
||||
end
|
||||
end
|
||||
|
||||
-- Update aura positions based off of configuration
|
||||
function Auras:OnLayoutApplied(frame, config)
|
||||
if( frame.auras ) then
|
||||
if( frame.auras.buffs ) then
|
||||
for _, button in pairs(frame.auras.buffs.buttons) do
|
||||
button:Hide()
|
||||
end
|
||||
end
|
||||
if( frame.auras.debuffs ) then
|
||||
for _, button in pairs(frame.auras.debuffs.buttons) do
|
||||
button:Hide()
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
if( not frame.visibility.auras ) then return end
|
||||
|
||||
if( config.auras.buffs.enabled ) then
|
||||
updateGroup(frame, "buffs", config.auras.buffs, config.auras.debuffs)
|
||||
end
|
||||
|
||||
if( config.auras.debuffs.enabled ) then
|
||||
updateGroup(frame, "debuffs", config.auras.debuffs, config.auras.buffs)
|
||||
end
|
||||
|
||||
-- Anchor an aura group to another aura group
|
||||
frame.auras.anchorAurasOn = nil
|
||||
if( config.auras.buffs.enabled and config.auras.debuffs.enabled ) then
|
||||
if( config.auras.buffs.anchorOn ) then
|
||||
frame.auras.anchorAurasOn = frame.auras.debuffs
|
||||
frame.auras.anchorAurasChild = frame.auras.buffs
|
||||
elseif( config.auras.debuffs.anchorOn ) then
|
||||
frame.auras.anchorAurasOn = frame.auras.buffs
|
||||
frame.auras.anchorAurasChild = frame.auras.debuffs
|
||||
end
|
||||
end
|
||||
|
||||
-- Check if either auras are anchored to each other
|
||||
if( config.auras.buffs.anchorPoint == config.auras.debuffs.anchorPoint and config.auras.buffs.enabled and config.auras.debuffs.enabled and not config.auras.buffs.anchorOn and not config.auras.debuffs.anchorOn ) then
|
||||
frame.auras.anchor = frame.auras[config.auras.buffs.prioritize and "buffs" or "debuffs"]
|
||||
frame.auras.primary = config.auras.buffs.prioritize and "buffs" or "debuffs"
|
||||
frame.auras.secondary = frame.auras.primary == "buffs" and "debuffs" or "buffs"
|
||||
else
|
||||
frame.auras.anchor = nil
|
||||
end
|
||||
|
||||
self:UpdateFilter(frame)
|
||||
end
|
||||
|
||||
-- Temporary enchant support
|
||||
local timeElapsed = 0
|
||||
local function updateTemporaryEnchant(frame, slot, tempData, hasEnchant, timeLeft, charges)
|
||||
-- If there's less than a 750 millisecond differences in the times, we don't need to bother updating.
|
||||
-- Any sort of enchant takes more than 0.750 seconds to cast so it's impossible for the user to have two
|
||||
-- temporary enchants with that little difference, as totems don't really give pulsing auras anymore.
|
||||
if( tempData.has and ( timeLeft < tempData.time and ( tempData.time - timeLeft ) < 750 ) and charges == tempData.charges ) then return false end
|
||||
|
||||
-- Some trickys magic, we can't get the start time of temporary enchants easily.
|
||||
-- So will save the first time we find when a new enchant is added
|
||||
if( timeLeft > tempData.time or not tempData.has ) then
|
||||
tempData.startTime = GetTime()
|
||||
end
|
||||
|
||||
tempData.has = hasEnchant
|
||||
tempData.time = timeLeft
|
||||
tempData.charges = charges
|
||||
|
||||
local config = ShadowUF.db.profile.units[frame.parent.unitType].auras[frame.type]
|
||||
|
||||
-- Create any buttons we need
|
||||
if( #(frame.buttons) < frame.temporaryEnchants ) then
|
||||
updateButton(frame.temporaryEnchants, frame, config)
|
||||
end
|
||||
|
||||
local button = frame.buttons[frame.temporaryEnchants]
|
||||
|
||||
-- Purple border
|
||||
button.border:SetVertexColor(0.50, 0, 0.50)
|
||||
|
||||
-- Show the cooldown ring
|
||||
if( not ShadowUF.db.profile.auras.disableCooldown ) then
|
||||
button.cooldown:SetCooldown(tempData.startTime, timeLeft / 1000)
|
||||
button.cooldown:Show()
|
||||
end
|
||||
|
||||
-- Enlarge our own auras
|
||||
if( config.enlargeSelf and caster == ShadowUF.playerUnit ) then
|
||||
button.isSelfScaled = true
|
||||
button:SetScale(config.selfScale)
|
||||
else
|
||||
button.isSelfScaled = nil
|
||||
button:SetScale(1)
|
||||
end
|
||||
|
||||
-- Size it
|
||||
button:SetHeight(config.size)
|
||||
button:SetWidth(config.size)
|
||||
button.border:SetHeight(config.size + 1)
|
||||
button.border:SetWidth(config.size + 1)
|
||||
|
||||
-- Stack + icon + show! Never understood why, auras sometimes return 1 for stack even if they don't stack
|
||||
button.auraID = slot
|
||||
button.filter = "TEMP"
|
||||
button.unit = nil
|
||||
button.columnHasScaled = nil
|
||||
button.previousHasScale = nil
|
||||
button.icon:SetTexture(GetInventoryItemTexture("player", slot))
|
||||
button.stack:SetText(charges > 1 and charges or "")
|
||||
button:Show()
|
||||
end
|
||||
|
||||
-- Unfortunately, temporary enchants have basically no support beyond hacks. So we will hack!
|
||||
tempEnchantScan = function(self, elapsed)
|
||||
timeElapsed = timeElapsed + elapsed
|
||||
if( timeElapsed < 0.50 ) then return end
|
||||
timeElapsed = timeElapsed - 0.50
|
||||
|
||||
local hasMain, mainTimeLeft, mainCharges, hasOff, offTimeLeft, offCharges = GetWeaponEnchantInfo()
|
||||
self.temporaryEnchants = 0
|
||||
|
||||
if( hasMain ) then
|
||||
self.temporaryEnchants = self.temporaryEnchants + 1
|
||||
updateTemporaryEnchant(self, 16, mainHand, hasMain, mainTimeLeft or 0, mainCharges)
|
||||
mainHand.time = mainTimeLeft or 0
|
||||
end
|
||||
|
||||
mainHand.has = hasMain
|
||||
|
||||
if( hasOff and self.temporaryEnchants < self.maxAuras ) then
|
||||
self.temporaryEnchants = self.temporaryEnchants + 1
|
||||
updateTemporaryEnchant(self, 17, offHand, hasOff, offTimeLeft or 0, offCharges)
|
||||
offHand.time = offTimeLeft or 0
|
||||
end
|
||||
|
||||
offHand.has = hasOff
|
||||
|
||||
-- Update if totals changed
|
||||
if( self.lastTemporary ~= self.temporaryEnchants ) then
|
||||
self.lastTemporary = self.temporaryEnchants
|
||||
Auras:Update(self.parent)
|
||||
end
|
||||
end
|
||||
|
||||
-- Nice and simple, don't need to do a full update because either this is called in an OnEnable or
|
||||
-- the zone monitor will handle it all cleanly. The fun part of this code is aura filtering itself takes 10 seconds
|
||||
-- but making the configuration clean takes two weeks and another 2-3 days of implementing
|
||||
-- This isn't actually filled with data, it's just to stop any errors from triggering if no filter is added
|
||||
local filterDefault = {}
|
||||
function Auras:UpdateFilter(frame)
|
||||
local zone = select(2, IsInInstance())
|
||||
local id = zone .. frame.unitType
|
||||
|
||||
local white = ShadowUF.db.profile.filters.zonewhite[zone .. frame.unitType]
|
||||
local black = ShadowUF.db.profile.filters.zoneblack[zone .. frame.unitType]
|
||||
frame.auras.whitelist = white and ShadowUF.db.profile.filters.whitelists[white] or filterDefault
|
||||
frame.auras.blacklist = black and ShadowUF.db.profile.filters.blacklists[black] or filterDefault
|
||||
end
|
||||
|
||||
-- Scan for auras
|
||||
local function scan(parent, frame, type, config, filter)
|
||||
if( frame.totalAuras >= frame.maxAuras or not config.enabled ) then return end
|
||||
|
||||
local isFriendly = UnitIsFriend(frame.parent.unit, "player")
|
||||
local index = 0
|
||||
while( true ) do
|
||||
index = index + 1
|
||||
local name, rank, texture, count, auraType, duration, endTime, caster, isStealable = UnitAura(frame.parent.unit, index, filter)
|
||||
if( not name ) then break end
|
||||
|
||||
if( ( not config.player or playerUnits[caster] ) and ( not parent.whitelist[type] and not parent.blacklist[type] or parent.whitelist[type] and parent.whitelist[name] or parent.blacklist[type] and not parent.blacklist[name] ) ) then
|
||||
-- Create any buttons we need
|
||||
frame.totalAuras = frame.totalAuras + 1
|
||||
if( #(frame.buttons) < frame.totalAuras ) then
|
||||
updateButton(frame.totalAuras, frame, ShadowUF.db.profile.units[frame.parent.unitType].auras[frame.type])
|
||||
end
|
||||
|
||||
-- Show debuff border, or a special colored border if it's stealable
|
||||
local button = frame.buttons[frame.totalAuras]
|
||||
if( isStealable and not isFriendly and not ShadowUF.db.profile.auras.disableColor ) then
|
||||
button.border:SetVertexColor(stealableColor.r, stealableColor.g, stealableColor.b)
|
||||
elseif( ( not isFriendly or type == "debuffs" ) and not ShadowUF.db.profile.auras.disableColor ) then
|
||||
local color = auraType and DebuffTypeColor[auraType] or DebuffTypeColor.none
|
||||
button.border:SetVertexColor(color.r, color.g, color.b)
|
||||
else
|
||||
button.border:SetVertexColor(0.60, 0.60, 0.60)
|
||||
end
|
||||
|
||||
-- Show the cooldown ring
|
||||
if( not ShadowUF.db.profile.auras.disableCooldown and duration > 0 and endTime > 0 and ( not config.selfTimers or ( config.selfTimers and playerUnits[caster] ) ) ) then
|
||||
button.cooldown:SetCooldown(endTime - duration, duration)
|
||||
button.cooldown:Show()
|
||||
else
|
||||
button.cooldown:Hide()
|
||||
end
|
||||
|
||||
-- Enlarge our own auras
|
||||
if( config.enlargeSelf and playerUnits[caster] ) then
|
||||
button.isSelfScaled = true
|
||||
button:SetScale(config.selfScale)
|
||||
else
|
||||
button.isSelfScaled = nil
|
||||
button:SetScale(1)
|
||||
end
|
||||
|
||||
-- Size it
|
||||
button:SetHeight(config.size)
|
||||
button:SetWidth(config.size)
|
||||
button.border:SetHeight(config.size + 1)
|
||||
button.border:SetWidth(config.size + 1)
|
||||
|
||||
-- Stack + icon + show! Never understood why, auras sometimes return 1 for stack even if they don't stack
|
||||
button.auraID = index
|
||||
button.filter = filter
|
||||
button.unit = frame.parent.unit
|
||||
button.columnHasScaled = nil
|
||||
button.previousHasScale = nil
|
||||
button.icon:SetTexture(texture)
|
||||
button.stack:SetText(count > 1 and count or "")
|
||||
button:Show()
|
||||
|
||||
-- Too many auras shown break out
|
||||
-- Get down
|
||||
if( frame.totalAuras >= frame.maxAuras ) then break end
|
||||
end
|
||||
end
|
||||
|
||||
for i=frame.totalAuras + 1, #(frame.buttons) do frame.buttons[i]:Hide() end
|
||||
|
||||
-- The default 1.30 scale doesn't need special handling, after that it does
|
||||
if( config.enlargeSelf ) then
|
||||
positionAllButtons(frame, config)
|
||||
end
|
||||
end
|
||||
|
||||
Auras.scan = scan
|
||||
|
||||
local function anchorGroupToGroup(frame, config, group, childConfig, childGroup)
|
||||
-- Child group has nothing in it yet, so don't care
|
||||
if( not childGroup.buttons[1] ) then return end
|
||||
|
||||
-- Group we want to anchor to has nothing in it, takeover the postion
|
||||
if( group.totalAuras == 0 ) then
|
||||
local position = positionData[config.anchorPoint]
|
||||
childGroup.buttons[1]:ClearAllPoints()
|
||||
childGroup.buttons[1]:SetPoint(ShadowUF.Layout:GetPoint(config.anchorPoint), group.anchorTo, ShadowUF.Layout:GetRelative(config.anchorPoint), config.x + (position.xMod * ShadowUF.db.profile.backdrop.inset), config.y + (position.yMod * -ShadowUF.db.profile.backdrop.inset))
|
||||
return
|
||||
end
|
||||
|
||||
local anchorTo
|
||||
for i=#(group.buttons), 1, -1 do
|
||||
local button = group.buttons[i]
|
||||
if( button.isAuraAnchor and button:IsVisible() ) then
|
||||
anchorTo = button
|
||||
break
|
||||
end
|
||||
end
|
||||
|
||||
local position = positionData[childGroup.forcedAnchorPoint or childConfig.anchorPoint]
|
||||
if( position.isSideGrowth ) then
|
||||
position.aura(childGroup.buttons[1], anchorTo)
|
||||
else
|
||||
position.column(childGroup.buttons[1], anchorTo, 2)
|
||||
end
|
||||
end
|
||||
|
||||
Auras.anchorGroupToGroup = anchorGroupToGroup
|
||||
|
||||
-- Do an update and figure out what we need to scan
|
||||
function Auras:Update(frame)
|
||||
local config = ShadowUF.db.profile.units[frame.unitType].auras
|
||||
if( frame.auras.anchor ) then
|
||||
frame.auras.anchor.totalAuras = frame.auras.anchor.temporaryEnchants
|
||||
|
||||
scan(frame.auras, frame.auras.anchor, frame.auras.primary, config[frame.auras.primary], frame.auras[frame.auras.primary].filter)
|
||||
scan(frame.auras, frame.auras.anchor, frame.auras.secondary, config[frame.auras.secondary], frame.auras[frame.auras.secondary].filter)
|
||||
else
|
||||
if( config.buffs.enabled ) then
|
||||
frame.auras.buffs.totalAuras = frame.auras.buffs.temporaryEnchants
|
||||
scan(frame.auras, frame.auras.buffs, "buffs", config.buffs, frame.auras.buffs.filter)
|
||||
end
|
||||
|
||||
if( config.debuffs.enabled ) then
|
||||
frame.auras.debuffs.totalAuras = 0
|
||||
scan(frame.auras, frame.auras.debuffs, "debuffs", config.debuffs, frame.auras.debuffs.filter)
|
||||
end
|
||||
|
||||
if( frame.auras.anchorAurasOn ) then
|
||||
anchorGroupToGroup(frame, config[frame.auras.anchorAurasOn.type], frame.auras.anchorAurasOn, config[frame.auras.anchorAurasChild.type], frame.auras.anchorAurasChild)
|
||||
end
|
||||
end
|
||||
end
|
||||
@@ -0,0 +1,464 @@
|
||||
local Cast = {}
|
||||
local L = ShadowUF.L
|
||||
local FADE_TIME = 0.30
|
||||
local FAKE_UPDATE_TIME = 0.10
|
||||
|
||||
ShadowUF:RegisterModule(Cast, "castBar", L["Cast bar"], true)
|
||||
|
||||
-- I'm not really thrilled with this method of detecting fake unit casts, mostly because it's inefficient and ugly
|
||||
local function monitorFakeCast(self, elapsed)
|
||||
self.timeElapsed = self.timeElapsed + elapsed
|
||||
if( self.timeElapsed <= FAKE_UPDATE_TIME ) then return end
|
||||
self.timeElapsed = self.timeElapsed - FAKE_UPDATE_TIME
|
||||
|
||||
local spell, rank, displayName, icon, startTime, endTime, isTradeSkill, castID, notInterruptible = UnitCastingInfo(self.parent.unit)
|
||||
local isChannelled
|
||||
if( not spell ) then
|
||||
spell, rank, displayName, icon, startTime, endTime, isTradeSkill, castID, notInterruptible = UnitChannelInfo(self.parent.unit)
|
||||
isChannelled = true
|
||||
end
|
||||
|
||||
-- Cast started
|
||||
if( not self.endTime and endTime ) then
|
||||
self.endTime = endTime
|
||||
self.notInterruptible = notInterruptible
|
||||
self.spellName = spell
|
||||
Cast:UpdateCast(self.parent, self.parent.unit, isChannelled, spell, rank, displayName, icon, startTime, endTime, isTradeSkill, castID, notInterruptible)
|
||||
-- Cast stopped
|
||||
elseif( self.endTime and not endTime ) then
|
||||
if( GetTime() <= (self.endTime / 1000) ) then
|
||||
Cast:EventInterruptCast(self.parent, nil, self.parent.unit, self.spellName)
|
||||
end
|
||||
|
||||
self.notInterruptible = nil
|
||||
self.spellName = nil
|
||||
self.endTime = nil
|
||||
return
|
||||
end
|
||||
|
||||
-- Cast delayed
|
||||
if( self.endTime and endTime ~= self.endTime ) then
|
||||
self.endTime = endTime
|
||||
Cast:UpdateDelay(self.parent, spell, rank, displayName, icon, startTime, endTime)
|
||||
end
|
||||
|
||||
-- Cast interruptible status changed
|
||||
if( self.spellName and self.notInterruptible ~= notInterruptible ) then
|
||||
self.notInterruptible = notInterruptible
|
||||
if( notInterruptible ) then
|
||||
Cast:EventUninterruptible(self.parent)
|
||||
else
|
||||
Cast:EventInterruptible(self.parent)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
local function updateFakeUnitCast(self)
|
||||
self.endTime = nil
|
||||
self.notInterruptible = nil
|
||||
self.spellName = nil
|
||||
|
||||
monitorFakeCast(self, FAKE_UPDATE_TIME)
|
||||
end
|
||||
|
||||
function Cast:OnEnable(frame)
|
||||
if( not frame.castBar ) then
|
||||
frame.castBar = CreateFrame("Frame", nil, frame)
|
||||
frame.castBar.bar = ShadowUF.Units:CreateBar(frame)
|
||||
frame.castBar.background = frame.castBar.bar.background
|
||||
frame.castBar.bar.parent = frame
|
||||
|
||||
frame.castBar.icon = frame.castBar.bar:CreateTexture(nil, "ARTWORK")
|
||||
frame.castBar.bar.name = frame.castBar.bar:CreateFontString(nil, "ARTWORK")
|
||||
frame.castBar.bar.time = frame.castBar.bar:CreateFontString(nil, "ARTWORK")
|
||||
end
|
||||
|
||||
if( ShadowUF.fakeUnits[frame.unitType] ) then
|
||||
frame.castBar.monitor = frame.castBar.monitor or CreateFrame("Frame", nil, frame)
|
||||
frame.castBar.monitor.timeElapsed = 0
|
||||
frame.castBar.monitor.parent = frame
|
||||
frame.castBar.monitor:SetScript("OnUpdate", monitorFakeCast)
|
||||
frame.castBar.monitor:SetScript("OnShow", updateFakeUnitCast)
|
||||
frame.castBar.monitor:Show()
|
||||
return
|
||||
end
|
||||
|
||||
frame:RegisterUnitEvent("UNIT_SPELLCAST_START", self, "EventUpdateCast")
|
||||
frame:RegisterUnitEvent("UNIT_SPELLCAST_STOP", self, "EventStopCast")
|
||||
frame:RegisterUnitEvent("UNIT_SPELLCAST_FAILED", self, "EventStopCast")
|
||||
frame:RegisterUnitEvent("UNIT_SPELLCAST_INTERRUPTED", self, "EventInterruptCast")
|
||||
frame:RegisterUnitEvent("UNIT_SPELLCAST_DELAYED", self, "EventDelayCast")
|
||||
frame:RegisterUnitEvent("UNIT_SPELLCAST_SUCCEEDED", self, "EventCastSucceeded")
|
||||
|
||||
frame:RegisterUnitEvent("UNIT_SPELLCAST_CHANNEL_START", self, "EventUpdateChannel")
|
||||
frame:RegisterUnitEvent("UNIT_SPELLCAST_CHANNEL_STOP", self, "EventStopCast")
|
||||
frame:RegisterUnitEvent("UNIT_SPELLCAST_CHANNEL_INTERRUPTED", self, "EventInterruptCast")
|
||||
frame:RegisterUnitEvent("UNIT_SPELLCAST_CHANNEL_UPDATE", self, "EventDelayChannel")
|
||||
|
||||
frame:RegisterUnitEvent("UNIT_SPELLCAST_INTERRUPTIBLE", self, "EventInterruptible")
|
||||
frame:RegisterUnitEvent("UNIT_SPELLCAST_NOT_INTERRUPTIBLE", self, "EventUninterruptible")
|
||||
|
||||
frame:RegisterUpdateFunc(self, "UpdateCurrentCast")
|
||||
end
|
||||
|
||||
function Cast:OnLayoutApplied(frame, config)
|
||||
if( not frame.visibility.castBar ) then return end
|
||||
|
||||
-- Set textures
|
||||
frame.castBar.bar:SetStatusBarTexture(ShadowUF.Layout.mediaPath.statusbar)
|
||||
frame.castBar.bar:SetStatusBarColor(0, 0, 0, 0)
|
||||
frame.castBar.bar:GetStatusBarTexture():SetHorizTile(false)
|
||||
frame.castBar.background:SetVertexColor(0, 0, 0, 0)
|
||||
frame.castBar.background:SetHorizTile(false)
|
||||
|
||||
-- Setup the main bar + icon
|
||||
frame.castBar.bar:ClearAllPoints()
|
||||
frame.castBar.bar:SetHeight(frame.castBar:GetHeight())
|
||||
frame.castBar.bar:SetValue(0)
|
||||
frame.castBar.bar:SetMinMaxValues(0, 1)
|
||||
|
||||
-- Use the entire bars width and show the icon
|
||||
if( config.castBar.icon == "HIDE" ) then
|
||||
frame.castBar.bar:SetWidth(frame.castBar:GetWidth())
|
||||
frame.castBar.bar:SetAllPoints(frame.castBar)
|
||||
frame.castBar.icon:Hide()
|
||||
-- Shift the bar to the side and show an icon
|
||||
else
|
||||
frame.castBar.bar:SetWidth(frame.castBar:GetWidth() - frame.castBar:GetHeight())
|
||||
frame.castBar.icon:ClearAllPoints()
|
||||
frame.castBar.icon:SetWidth(frame.castBar:GetHeight())
|
||||
frame.castBar.icon:SetHeight(frame.castBar:GetHeight())
|
||||
frame.castBar.icon:Show()
|
||||
|
||||
if( config.castBar.icon == "LEFT" ) then
|
||||
frame.castBar.bar:SetPoint("TOPLEFT", frame.castBar, "TOPLEFT", frame.castBar:GetHeight() + 1, 0)
|
||||
frame.castBar.icon:SetPoint("TOPRIGHT", frame.castBar.bar, "TOPLEFT", -1, 0)
|
||||
else
|
||||
frame.castBar.bar:SetPoint("TOPLEFT", frame.castBar, "TOPLEFT", 1, 0)
|
||||
frame.castBar.icon:SetPoint("TOPLEFT", frame.castBar.bar, "TOPRIGHT", 0, 0)
|
||||
end
|
||||
end
|
||||
|
||||
-- Set the font at the very least, so it doesn't error when we set text on it even if it isn't being shown
|
||||
ShadowUF.Layout:ToggleVisibility(frame.castBar.bar.name, config.castBar.name.enabled)
|
||||
if( config.castBar.name.enabled ) then
|
||||
frame.castBar.bar.name:SetParent(frame.highFrame)
|
||||
frame.castBar.bar.name:SetWidth(frame.castBar.bar:GetWidth() * 0.75)
|
||||
frame.castBar.bar.name:SetHeight(ShadowUF.db.profile.font.size + 1)
|
||||
frame.castBar.bar.name:SetJustifyH(ShadowUF.Layout:GetJustify(config.castBar.name))
|
||||
|
||||
ShadowUF.Layout:AnchorFrame(frame.castBar.bar, frame.castBar.bar.name, config.castBar.name)
|
||||
ShadowUF.Layout:SetupFontString(frame.castBar.bar.name, config.castBar.name.size)
|
||||
end
|
||||
|
||||
ShadowUF.Layout:ToggleVisibility(frame.castBar.bar.time, config.castBar.time.enabled)
|
||||
if( config.castBar.time.enabled ) then
|
||||
frame.castBar.bar.time:SetParent(frame.highFrame)
|
||||
frame.castBar.bar.time:SetWidth(frame.castBar.bar:GetWidth() * 0.25)
|
||||
frame.castBar.bar.time:SetHeight(ShadowUF.db.profile.font.size + 1)
|
||||
frame.castBar.bar.time:SetJustifyH(ShadowUF.Layout:GetJustify(config.castBar.time))
|
||||
|
||||
ShadowUF.Layout:AnchorFrame(frame.castBar.bar, frame.castBar.bar.time, config.castBar.time)
|
||||
ShadowUF.Layout:SetupFontString(frame.castBar.bar.time, config.castBar.time.size)
|
||||
end
|
||||
|
||||
-- So we don't have to check the entire thing in an OnUpdate
|
||||
frame.castBar.bar.time.enabled = config.castBar.time.enabled
|
||||
|
||||
if( config.castBar.autoHide and not UnitCastingInfo(frame.unit) and not UnitChannelInfo(frame.unit) ) then
|
||||
ShadowUF.Layout:SetBarVisibility(frame, "castBar", false)
|
||||
end
|
||||
end
|
||||
|
||||
function Cast:OnDisable(frame, unit)
|
||||
frame:UnregisterAll(self)
|
||||
|
||||
if( frame.castBar ) then
|
||||
if( frame.castBar.monitor ) then frame.castBar.monitor:Hide() end
|
||||
frame.castBar.bar.name:Hide()
|
||||
frame.castBar.bar.time:Hide()
|
||||
frame.castBar.bar:Hide()
|
||||
end
|
||||
end
|
||||
|
||||
-- Easy coloring
|
||||
local function setBarColor(self, r, g, b)
|
||||
self:SetStatusBarColor(r, g, b, ShadowUF.db.profile.bars.alpha)
|
||||
|
||||
if( not self.background.overrideColor ) then
|
||||
self.background:SetVertexColor(r, g, b, ShadowUF.db.profile.bars.backgroundAlpha)
|
||||
end
|
||||
end
|
||||
|
||||
-- Cast OnUpdates
|
||||
local function fadeOnUpdate(self, elapsed)
|
||||
self.fadeElapsed = self.fadeElapsed - elapsed
|
||||
|
||||
if( self.fadeElapsed <= 0 ) then
|
||||
self.fadeElapsed = nil
|
||||
self.name:Hide()
|
||||
self.time:Hide()
|
||||
self:Hide()
|
||||
|
||||
local frame = self:GetParent()
|
||||
if( ShadowUF.db.profile.units[frame.unitType].castBar.autoHide ) then
|
||||
ShadowUF.Layout:SetBarVisibility(frame, "castBar", false)
|
||||
end
|
||||
else
|
||||
local alpha = self.fadeElapsed / self.fadeStart
|
||||
self:SetAlpha(alpha)
|
||||
self.time:SetAlpha(alpha)
|
||||
self.name:SetAlpha(alpha)
|
||||
end
|
||||
end
|
||||
|
||||
local function castOnUpdate(self, elapsed)
|
||||
local time = GetTime()
|
||||
self.elapsed = self.elapsed + (time - self.lastUpdate)
|
||||
self.lastUpdate = time
|
||||
self:SetValue(self.elapsed)
|
||||
|
||||
if( self.elapsed <= 0 ) then
|
||||
self.elapsed = 0
|
||||
end
|
||||
|
||||
if( self.time.enabled ) then
|
||||
local timeLeft = self.endSeconds - self.elapsed
|
||||
if( timeLeft <= 0 ) then
|
||||
self.time:SetText("0.0")
|
||||
elseif( self.pushback == 0 ) then
|
||||
self.time:SetFormattedText("%.1f", timeLeft)
|
||||
else
|
||||
self.time:SetFormattedText("|cffff0000%.1f|r %.1f", self.pushback, timeLeft)
|
||||
end
|
||||
end
|
||||
|
||||
-- Cast finished, do a quick fade
|
||||
if( self.elapsed >= self.endSeconds ) then
|
||||
setBarColor(self, ShadowUF.db.profile.castColors.finished.r, ShadowUF.db.profile.castColors.finished.g, ShadowUF.db.profile.castColors.finished.b)
|
||||
|
||||
self.spellName = nil
|
||||
self.fadeElapsed = FADE_TIME
|
||||
self.fadeStart = FADE_TIME
|
||||
self:SetScript("OnUpdate", fadeOnUpdate)
|
||||
end
|
||||
end
|
||||
|
||||
local function channelOnUpdate(self, elapsed)
|
||||
local time = GetTime()
|
||||
self.elapsed = self.elapsed - (time - self.lastUpdate)
|
||||
self.lastUpdate = time
|
||||
self:SetValue(self.elapsed)
|
||||
|
||||
if( self.elapsed <= 0 ) then
|
||||
self.elapsed = 0
|
||||
end
|
||||
|
||||
if( self.time.enabled ) then
|
||||
if( self.elapsed <= 0 ) then
|
||||
self.time:SetText("0.0")
|
||||
elseif( self.pushback == 0 ) then
|
||||
self.time:SetFormattedText("%.1f", self.elapsed)
|
||||
else
|
||||
self.time:SetFormattedText("|cffff0000%.1f|r %.1f", self.pushback, self.elapsed)
|
||||
end
|
||||
end
|
||||
|
||||
-- Channel finished, do a quick fade
|
||||
if( self.elapsed <= 0 ) then
|
||||
setBarColor(self, ShadowUF.db.profile.castColors.finished.r, ShadowUF.db.profile.castColors.finished.g, ShadowUF.db.profile.castColors.finished.b)
|
||||
|
||||
self.spellName = nil
|
||||
self.fadeElapsed = FADE_TIME
|
||||
self.fadeStart = FADE_TIME
|
||||
self:SetScript("OnUpdate", fadeOnUpdate)
|
||||
end
|
||||
end
|
||||
|
||||
function Cast:UpdateCurrentCast(frame)
|
||||
if( UnitCastingInfo(frame.unit) ) then
|
||||
self:UpdateCast(frame, frame.unit, false, UnitCastingInfo(frame.unit))
|
||||
elseif( UnitChannelInfo(frame.unit) ) then
|
||||
self:UpdateCast(frame, frame.unit, true, UnitChannelInfo(frame.unit))
|
||||
else
|
||||
if( ShadowUF.db.profile.units[frame.unitType].castBar.autoHide ) then
|
||||
ShadowUF.Layout:SetBarVisibility(frame, "castBar", false)
|
||||
end
|
||||
|
||||
setBarColor(frame.castBar.bar, 0, 0, 0)
|
||||
|
||||
frame.castBar.bar.spellName = nil
|
||||
frame.castBar.bar.name:Hide()
|
||||
frame.castBar.bar.time:Hide()
|
||||
frame.castBar.bar:Hide()
|
||||
end
|
||||
end
|
||||
|
||||
-- Cast updated/changed
|
||||
function Cast:EventUpdateCast(frame)
|
||||
self:UpdateCast(frame, frame.unit, false, UnitCastingInfo(frame.unit))
|
||||
end
|
||||
|
||||
function Cast:EventDelayCast(frame)
|
||||
self:UpdateDelay(frame, UnitCastingInfo(frame.unit))
|
||||
end
|
||||
|
||||
-- Channel updated/changed
|
||||
function Cast:EventUpdateChannel(frame)
|
||||
self:UpdateCast(frame, frame.unit, true, UnitChannelInfo(frame.unit))
|
||||
end
|
||||
|
||||
function Cast:EventDelayChannel(frame)
|
||||
self:UpdateDelay(frame, UnitChannelInfo(frame.unit))
|
||||
end
|
||||
|
||||
-- Cast finished
|
||||
function Cast:EventStopCast(frame, event, unit, spell)
|
||||
local cast = frame.castBar.bar
|
||||
if( cast.spellName ~= spell or ( event == "UNIT_SPELLCAST_FAILED" and cast.isChannelled ) ) then return end
|
||||
if( cast.time.enabled ) then
|
||||
cast.time:SetText("0.0")
|
||||
end
|
||||
|
||||
setBarColor(cast, ShadowUF.db.profile.castColors.interrupted.r, ShadowUF.db.profile.castColors.interrupted.g, ShadowUF.db.profile.castColors.interrupted.b)
|
||||
if( ShadowUF.db.profile.units[frame.unitType].castBar.autoHide ) then
|
||||
ShadowUF.Layout:SetBarVisibility(frame, "castBar", true)
|
||||
end
|
||||
|
||||
cast.spellName = nil
|
||||
cast.fadeElapsed = FADE_TIME
|
||||
cast.fadeStart = FADE_TIME
|
||||
cast:SetScript("OnUpdate", fadeOnUpdate)
|
||||
cast:SetMinMaxValues(0, 1)
|
||||
cast:SetValue(1)
|
||||
cast:Show()
|
||||
end
|
||||
|
||||
-- Cast interrupted
|
||||
function Cast:EventInterruptCast(frame, event, unit, spell)
|
||||
local cast = frame.castBar.bar
|
||||
if( cast.spellName ~= spell ) then return end
|
||||
|
||||
setBarColor(cast, ShadowUF.db.profile.castColors.interrupted.r, ShadowUF.db.profile.castColors.interrupted.g, ShadowUF.db.profile.castColors.interrupted.b)
|
||||
if( ShadowUF.db.profile.units[frame.unitType].castBar.autoHide ) then
|
||||
ShadowUF.Layout:SetBarVisibility(frame, "castBar", true)
|
||||
end
|
||||
|
||||
if( ShadowUF.db.profile.units[frame.unitType].castBar.name.enabled ) then
|
||||
cast.name:SetText(L["Interrupted"])
|
||||
end
|
||||
|
||||
cast.spellName = nil
|
||||
cast.fadeElapsed = FADE_TIME + 0.20
|
||||
cast.fadeStart = cast.fadeElapsed
|
||||
cast:SetScript("OnUpdate", fadeOnUpdate)
|
||||
cast:SetMinMaxValues(0, 1)
|
||||
cast:SetValue(1)
|
||||
cast:Show()
|
||||
end
|
||||
|
||||
-- Cast succeeded
|
||||
function Cast:EventCastSucceeded(frame, unit, spell)
|
||||
local cast = frame.castBar.bar
|
||||
if( not cast.isChannelled and cast.spellName == spell ) then
|
||||
setBarColor(cast, ShadowUF.db.profile.castColors.finished.r, ShadowUF.db.profile.castColors.finished.g, ShadowUF.db.profile.castColors.finished.b)
|
||||
end
|
||||
end
|
||||
|
||||
-- Interruptible status changed
|
||||
function Cast:EventInterruptible(frame)
|
||||
local cast = frame.castBar.bar
|
||||
if( cast.isChannelled ) then
|
||||
setBarColor(cast, ShadowUF.db.profile.castColors.channel.r, ShadowUF.db.profile.castColors.channel.g, ShadowUF.db.profile.castColors.channel.b)
|
||||
else
|
||||
setBarColor(cast, ShadowUF.db.profile.castColors.cast.r, ShadowUF.db.profile.castColors.cast.g, ShadowUF.db.profile.castColors.cast.b)
|
||||
end
|
||||
end
|
||||
|
||||
function Cast:EventUninterruptible(frame)
|
||||
setBarColor(frame.castBar.bar, ShadowUF.db.profile.castColors.uninterruptible.r, ShadowUF.db.profile.castColors.uninterruptible.g, ShadowUF.db.profile.castColors.uninterruptible.b)
|
||||
end
|
||||
|
||||
function Cast:UpdateDelay(frame, spell, rank, displayName, icon, startTime, endTime)
|
||||
if( not spell or not frame.castBar.bar.startTime ) then return end
|
||||
local cast = frame.castBar.bar
|
||||
startTime = startTime / 1000
|
||||
endTime = endTime / 1000
|
||||
|
||||
-- For a channel, delay is a negative value so using plus is fine here
|
||||
local delay = startTime - cast.startTime
|
||||
if( not cast.isChannelled ) then
|
||||
cast.endSeconds = cast.endSeconds + delay
|
||||
cast:SetMinMaxValues(0, cast.endSeconds)
|
||||
else
|
||||
cast.elapsed = cast.elapsed + delay
|
||||
end
|
||||
|
||||
cast.pushback = cast.pushback + delay
|
||||
cast.lastUpdate = GetTime()
|
||||
cast.startTime = startTime
|
||||
cast.endTime = endTime
|
||||
end
|
||||
|
||||
-- Update the actual bar
|
||||
function Cast:UpdateCast(frame, unit, channelled, spell, rank, displayName, icon, startTime, endTime, isTradeSkill, castID, notInterruptible)
|
||||
if( not spell ) then return end
|
||||
local cast = frame.castBar.bar
|
||||
if( ShadowUF.db.profile.units[frame.unitType].castBar.autoHide ) then
|
||||
ShadowUF.Layout:SetBarVisibility(frame, "castBar", true)
|
||||
end
|
||||
|
||||
-- Set casted spell
|
||||
if( ShadowUF.db.profile.units[frame.unitType].castBar.name.enabled ) then
|
||||
if( ShadowUF.db.profile.units[frame.unitType].castBar.name.rank and rank and rank ~= "" ) then
|
||||
cast.name:SetFormattedText("%s (%s)", spell, rank)
|
||||
cast.name:SetAlpha(ShadowUF.db.profile.bars.alpha)
|
||||
cast.name:Show()
|
||||
else
|
||||
cast.name:SetText(spell)
|
||||
cast.name:SetAlpha(ShadowUF.db.profile.bars.alpha)
|
||||
cast.name:Show()
|
||||
end
|
||||
end
|
||||
|
||||
-- Show cast time
|
||||
if( cast.time.enabled ) then
|
||||
cast.time:SetAlpha(1)
|
||||
cast.time:Show()
|
||||
end
|
||||
|
||||
-- Set spell icon
|
||||
if( ShadowUF.db.profile.units[frame.unitType].castBar.icon ~= "HIDE" ) then
|
||||
frame.castBar.icon:SetTexture(icon)
|
||||
frame.castBar.icon:Show()
|
||||
end
|
||||
|
||||
-- Setup cast info
|
||||
cast.isChannelled = channelled
|
||||
cast.startTime = startTime / 1000
|
||||
cast.endTime = endTime / 1000
|
||||
cast.endSeconds = cast.endTime - cast.startTime
|
||||
cast.elapsed = cast.isChannelled and cast.endSeconds or 0
|
||||
cast.spellName = spell
|
||||
cast.spellRank = rank
|
||||
cast.pushback = 0
|
||||
cast.lastUpdate = cast.startTime
|
||||
cast:SetMinMaxValues(0, cast.endSeconds)
|
||||
cast:SetValue(cast.elapsed)
|
||||
cast:SetAlpha(ShadowUF.db.profile.bars.alpha)
|
||||
cast:Show()
|
||||
|
||||
if( cast.isChannelled ) then
|
||||
cast:SetScript("OnUpdate", channelOnUpdate)
|
||||
else
|
||||
cast:SetScript("OnUpdate", castOnUpdate)
|
||||
end
|
||||
|
||||
if( notInterruptible ) then
|
||||
setBarColor(cast, ShadowUF.db.profile.castColors.uninterruptible.r, ShadowUF.db.profile.castColors.uninterruptible.g, ShadowUF.db.profile.castColors.uninterruptible.b)
|
||||
elseif( cast.isChannelled ) then
|
||||
setBarColor(cast, ShadowUF.db.profile.castColors.channel.r, ShadowUF.db.profile.castColors.channel.g, ShadowUF.db.profile.castColors.channel.b)
|
||||
else
|
||||
setBarColor(cast, ShadowUF.db.profile.castColors.cast.r, ShadowUF.db.profile.castColors.cast.g, ShadowUF.db.profile.castColors.cast.b)
|
||||
end
|
||||
end
|
||||
@@ -0,0 +1,46 @@
|
||||
local Combat = {}
|
||||
ShadowUF:RegisterModule(Combat, "combatText", ShadowUF.L["Combat text"])
|
||||
|
||||
function Combat:OnEnable(frame)
|
||||
if( not frame.combatText ) then
|
||||
frame.combatText = CreateFrame("Frame", nil, frame.highFrame)
|
||||
frame.combatText:SetFrameStrata("HIGH")
|
||||
frame.combatText.feedbackText = frame.combatText:CreateFontString(nil, "ARTWORK")
|
||||
frame.combatText.feedbackText:SetPoint("CENTER", frame.combatText, "CENTER", 0, 0)
|
||||
frame.combatText:SetFrameLevel(frame.topFrameLevel)
|
||||
|
||||
frame.combatText.feedbackStartTime = 0
|
||||
frame.combatText:SetScript("OnUpdate", CombatFeedback_OnUpdate)
|
||||
frame.combatText:SetHeight(1)
|
||||
frame.combatText:SetWidth(1)
|
||||
end
|
||||
|
||||
frame:RegisterUnitEvent("UNIT_COMBAT", self, "Update")
|
||||
end
|
||||
|
||||
function Combat:OnLayoutApplied(frame, config)
|
||||
-- Update feedback text
|
||||
ShadowUF.Layout:ToggleVisibility(frame.combatText, frame.visibility.combatText)
|
||||
if( frame.visibility.combatText ) then
|
||||
frame.combatText.feedbackFontHeight = ShadowUF.db.profile.font.size + 1
|
||||
frame.combatText.fontPath = ShadowUF.Layout.mediaPath.font
|
||||
|
||||
ShadowUF.Layout:SetupFontString(frame.combatText.feedbackText, 1)
|
||||
ShadowUF.Layout:AnchorFrame(frame, frame.combatText, config.combatText)
|
||||
end
|
||||
end
|
||||
|
||||
function Combat:OnDisable(frame)
|
||||
frame:UnregisterAll(self)
|
||||
end
|
||||
|
||||
function Combat:Update(frame, event, unit, type, ...)
|
||||
CombatFeedback_OnCombatEvent(frame.combatText, type, ...)
|
||||
if( type == "IMMUNE" ) then
|
||||
frame.combatText.feedbackText:SetTextHeight(frame.combatText.feedbackFontHeight * 0.75)
|
||||
end
|
||||
|
||||
-- Increasing the font size will make the text look pixelated, however scaling it up will make it look smooth and awesome
|
||||
frame.combatText:SetScale(frame.combatText.feedbackText:GetStringHeight() / ShadowUF.db.profile.font.size)
|
||||
frame.combatText.feedbackText:SetFont(frame.combatText.fontPath, ShadowUF.db.profile.font.size, "OUTLINE")
|
||||
end
|
||||
@@ -0,0 +1,128 @@
|
||||
local Combo = {}
|
||||
ShadowUF:RegisterModule(Combo, "comboPoints", ShadowUF.L["Combo points"])
|
||||
|
||||
function Combo:OnEnable(frame)
|
||||
frame.comboPoints = frame.comboPoints or CreateFrame("Frame", nil, frame)
|
||||
frame:RegisterNormalEvent("UNIT_COMBO_POINTS", self, "Update")
|
||||
frame:RegisterUpdateFunc(self, "Update")
|
||||
end
|
||||
|
||||
function Combo:OnLayoutApplied(frame, config)
|
||||
-- Not a bar so set the containers frame configuration
|
||||
if( config.comboPoints and not config.comboPoints.isBar ) then
|
||||
ShadowUF.Layout:ToggleVisibility(frame.comboPoints, frame.visibility.comboPoints)
|
||||
end
|
||||
|
||||
if( not frame.visibility.comboPoints ) then return end
|
||||
|
||||
-- Hide the active combo points
|
||||
if( frame.comboPoints.points ) then
|
||||
for _, texture in pairs(frame.comboPoints.points) do
|
||||
texture:Hide()
|
||||
end
|
||||
end
|
||||
|
||||
-- Setup for bar display!
|
||||
if( config.comboPoints.isBar ) then
|
||||
frame.comboPoints.blocks = frame.comboPoints.blocks or {}
|
||||
frame.comboPoints.points = frame.comboPoints.blocks
|
||||
|
||||
-- Position bars, the 5 accounts for borders
|
||||
local blockWidth = (frame.comboPoints:GetWidth() - 4 ) / MAX_COMBO_POINTS
|
||||
for id=1, MAX_COMBO_POINTS do
|
||||
frame.comboPoints.blocks[id] = frame.comboPoints.blocks[id] or frame.comboPoints:CreateTexture(nil, "OVERLAY")
|
||||
local texture = frame.comboPoints.blocks[id]
|
||||
texture:SetVertexColor(1, 0.80, 0)
|
||||
texture:SetHorizTile(false)
|
||||
texture:SetTexture(ShadowUF.Layout.mediaPath.statusbar)
|
||||
texture:SetHeight(frame.comboPoints:GetHeight())
|
||||
texture:SetWidth(blockWidth)
|
||||
texture:ClearAllPoints()
|
||||
|
||||
if( config.comboPoints.growth == "LEFT" ) then
|
||||
if( id > 1 ) then
|
||||
texture:SetPoint("TOPRIGHT", frame.comboPoints.blocks[id - 1], "TOPLEFT", -1, 0)
|
||||
else
|
||||
texture:SetPoint("TOPRIGHT", frame.comboPoints, "TOPRIGHT", 0, 0)
|
||||
end
|
||||
else
|
||||
if( id > 1 ) then
|
||||
texture:SetPoint("TOPLEFT", frame.comboPoints.blocks[id - 1], "TOPRIGHT", 1, 0)
|
||||
else
|
||||
texture:SetPoint("TOPLEFT", frame.comboPoints, "TOPLEFT", 0, 0)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
-- guess not, will have to do icons :(
|
||||
else
|
||||
local point, relativePoint
|
||||
local x, y = 0, 0
|
||||
|
||||
if( config.comboPoints.growth == "LEFT" ) then
|
||||
point, relativePoint = "BOTTOMRIGHT", "BOTTOMLEFT"
|
||||
x = config.comboPoints.spacing
|
||||
elseif( config.comboPoints.growth == "RIGHT" ) then
|
||||
point, relativePoint = "BOTTOMLEFT", "BOTTOMRIGHT"
|
||||
x = config.comboPoints.spacing
|
||||
elseif( config.comboPoints.growth == "UP" ) then
|
||||
point, relativePoint = "BOTTOMLEFT", "TOPLEFT"
|
||||
y = config.comboPoints.spacing
|
||||
elseif( config.comboPoints.growth == "DOWN" ) then
|
||||
point, relativePoint = "TOPLEFT", "BOTTOMLEFT"
|
||||
y = config.comboPoints.spacing
|
||||
end
|
||||
|
||||
|
||||
frame.comboPoints.icons = frame.comboPoints.icons or {}
|
||||
frame.comboPoints.points = frame.comboPoints.icons
|
||||
|
||||
for id=1, MAX_COMBO_POINTS do
|
||||
frame.comboPoints.icons[id] = frame.comboPoints.icons[id] or frame.comboPoints:CreateTexture(nil, "OVERLAY")
|
||||
local texture = frame.comboPoints.icons[id]
|
||||
texture:SetTexture("Interface\\AddOns\\ShadowedUnitFrames\\media\\textures\\combo")
|
||||
texture:SetHeight(config.comboPoints.size)
|
||||
texture:SetWidth(config.comboPoints.size)
|
||||
|
||||
if( id > 1 ) then
|
||||
texture:ClearAllPoints()
|
||||
texture:SetPoint(point, frame.comboPoints.icons[id - 1], relativePoint, x, y)
|
||||
else
|
||||
texture:ClearAllPoints()
|
||||
texture:SetPoint("CENTER", frame.comboPoints, "CENTER", 0, 0)
|
||||
end
|
||||
end
|
||||
|
||||
-- Position the main frame
|
||||
frame.comboPoints:SetHeight(0.1)
|
||||
frame.comboPoints:SetWidth(0.1)
|
||||
|
||||
ShadowUF.Layout:AnchorFrame(frame, frame.comboPoints, config.comboPoints)
|
||||
end
|
||||
end
|
||||
|
||||
function Combo:OnDisable(frame)
|
||||
frame:UnregisterAll(self)
|
||||
end
|
||||
|
||||
function Combo:Update(frame)
|
||||
-- For Malygos dragons, they also self cast their CP on themselves, which is why we check CP on ourself!
|
||||
local playerUnit = UnitHasVehicleUI("player") and "vehicle" or "player"
|
||||
local points = GetComboPoints(playerUnit)
|
||||
if( points == 0 ) then
|
||||
points = GetComboPoints(playerUnit, playerUnit)
|
||||
end
|
||||
|
||||
-- Bar display, hide it if we don't have any combo points
|
||||
if( ShadowUF.db.profile.units[frame.unitType].comboPoints.isBar ) then
|
||||
ShadowUF.Layout:SetBarVisibility(frame, "comboPoints", points > 0)
|
||||
end
|
||||
|
||||
for id, pointTexture in pairs(frame.comboPoints.points) do
|
||||
if( id <= points ) then
|
||||
pointTexture:Show()
|
||||
else
|
||||
pointTexture:Hide()
|
||||
end
|
||||
end
|
||||
end
|
||||
Reference in New Issue
Block a user