mirror of
https://github.com/Bluewhale1337/ElvUIModernized.git
synced 2026-07-27 08:24:44 +00:00
502 lines
14 KiB
Lua
502 lines
14 KiB
Lua
local E, L, V, P, G = unpack(ElvUI); --Import: Engine, Locales, PrivateDB, ProfileDB, GlobalDB
|
|
local A = E:NewModule("Auras", "AceEvent-3.0");
|
|
local LSM = LibStub("LibSharedMedia-3.0");
|
|
|
|
--Cache global variables
|
|
--Lua functions
|
|
local GetTime = GetTime
|
|
local _G = _G
|
|
local unpack, select, pairs, ipairs = unpack, select, pairs, ipairs
|
|
local floor, min, max, huge = math.floor, math.min, math.max, math.huge
|
|
local format = string.format
|
|
local wipe, tinsert, tsort, tremove = table.wipe, table.insert, table.sort, table.remove
|
|
--WoW API / Variables
|
|
local CreateFrame = CreateFrame
|
|
local UnitAura = UnitAura
|
|
local CancelItemTempEnchantment = CancelItemTempEnchantment
|
|
local CancelUnitBuff = CancelUnitBuff
|
|
local GetInventoryItemQuality = GetInventoryItemQuality
|
|
local GetItemQualityColor = GetItemQualityColor
|
|
local GetWeaponEnchantInfo = GetWeaponEnchantInfo
|
|
local GetInventoryItemTexture = GetInventoryItemTexture
|
|
|
|
local DIRECTION_TO_POINT = {
|
|
DOWN_RIGHT = "TOPLEFT",
|
|
DOWN_LEFT = "TOPRIGHT",
|
|
UP_RIGHT = "BOTTOMLEFT",
|
|
UP_LEFT = "BOTTOMRIGHT",
|
|
RIGHT_DOWN = "TOPLEFT",
|
|
RIGHT_UP = "BOTTOMLEFT",
|
|
LEFT_DOWN = "TOPRIGHT",
|
|
LEFT_UP = "BOTTOMRIGHT"
|
|
}
|
|
|
|
local DIRECTION_TO_HORIZONTAL_SPACING_MULTIPLIER = {
|
|
DOWN_RIGHT = 1,
|
|
DOWN_LEFT = -1,
|
|
UP_RIGHT = 1,
|
|
UP_LEFT = -1,
|
|
RIGHT_DOWN = 1,
|
|
RIGHT_UP = 1,
|
|
LEFT_DOWN = -1,
|
|
LEFT_UP = -1
|
|
}
|
|
|
|
local DIRECTION_TO_VERTICAL_SPACING_MULTIPLIER = {
|
|
DOWN_RIGHT = -1,
|
|
DOWN_LEFT = -1,
|
|
UP_RIGHT = 1,
|
|
UP_LEFT = 1,
|
|
RIGHT_DOWN = -1,
|
|
RIGHT_UP = 1,
|
|
LEFT_DOWN = -1,
|
|
LEFT_UP = 1
|
|
}
|
|
|
|
local IS_HORIZONTAL_GROWTH = {
|
|
RIGHT_DOWN = true,
|
|
RIGHT_UP = true,
|
|
LEFT_DOWN = true,
|
|
LEFT_UP = true
|
|
}
|
|
|
|
function A:UpdateTime(elapsed)
|
|
if self.offset then
|
|
local expiration = select(self.offset, GetWeaponEnchantInfo())
|
|
if expiration then
|
|
self.timeLeft = expiration / 1e3
|
|
else
|
|
self.timeLeft = 0
|
|
end
|
|
else
|
|
self.timeLeft = GetPlayerBuffTimeLeft(self.index)
|
|
end
|
|
|
|
if self.nextUpdate > 0 then
|
|
self.nextUpdate = not self.offset and self.nextUpdate - elapsed or 1
|
|
return
|
|
end
|
|
|
|
local timerValue, formatID
|
|
timerValue, formatID, self.nextUpdate = E:GetTimeInfo(self.timeLeft, A.db.fadeThreshold)
|
|
self.time:SetText(format("%s%s|r", E.TimeColors[formatID], format(E.TimeFormats[formatID][2], timerValue)))
|
|
|
|
if self.timeLeft > E.db.auras.fadeThreshold then
|
|
-- E:StopFlash(self)
|
|
else
|
|
-- E:Flash(self, 1)
|
|
end
|
|
end
|
|
|
|
local function UpdateTooltip()
|
|
if this.offset then
|
|
GameTooltip:SetInventoryItem("player", this.offset == 2 and 16 or 17)
|
|
else
|
|
GameTooltip:SetPlayerBuff(this.index)
|
|
end
|
|
end
|
|
|
|
local function OnEnter()
|
|
if not this:IsVisible() then return end
|
|
|
|
GameTooltip:SetOwner(this, "ANCHOR_BOTTOMLEFT", -5, -5)
|
|
this:UpdateTooltip()
|
|
end
|
|
|
|
local function OnLeave()
|
|
GameTooltip:Hide()
|
|
end
|
|
|
|
local function OnClick()
|
|
if this.index and this.index > 0 then
|
|
CancelPlayerBuff(this.index)
|
|
end
|
|
end
|
|
|
|
function A:CreateIcon(button)
|
|
local font = LSM:Fetch("font", self.db.font)
|
|
button:RegisterForClicks("RightButtonUp")
|
|
|
|
button.texture = button:CreateTexture(nil, "BORDER")
|
|
E:SetInside(button.texture)
|
|
button.texture:SetTexCoord(unpack(E.TexCoords))
|
|
|
|
button.count = button:CreateFontString(nil, "ARTWORK")
|
|
button.count:SetPoint("BOTTOMRIGHT", -1 + self.db.countXOffset, 1 + self.db.countYOffset)
|
|
E:FontTemplate(button.count, font, self.db.fontSize, self.db.fontOutline)
|
|
|
|
button.time = button:CreateFontString(nil, "ARTWORK")
|
|
button.time:SetPoint("TOP", button, "BOTTOM", 1 + self.db.timeXOffset, 0 + self.db.timeYOffset)
|
|
E:FontTemplate(button.time, font, self.db.fontSize, self.db.fontOutline)
|
|
|
|
button.highlight = button:CreateTexture(nil, "HIGHLIGHT")
|
|
button.highlight:SetTexture(1, 1, 1, 0.45)
|
|
E:SetInside(button.highlight)
|
|
|
|
button.UpdateTooltip = UpdateTooltip
|
|
button:SetScript("OnEnter", OnEnter)
|
|
button:SetScript("OnLeave", OnLeave)
|
|
button:SetScript("OnClick", OnClick)
|
|
|
|
E:SetTemplate(button, "Default")
|
|
end
|
|
|
|
local enchantableSlots = {
|
|
[1] = 16,
|
|
[2] = 17
|
|
}
|
|
|
|
local buttons = {}
|
|
function A:ConfigureAuras(header, auraTable, weaponPosition)
|
|
local headerName = header:GetName()
|
|
|
|
local db = self.db.debuffs
|
|
if header.filter == "HELPFUL" then
|
|
db = self.db.buffs
|
|
end
|
|
|
|
local size = db.size
|
|
local point = DIRECTION_TO_POINT[db.growthDirection]
|
|
local xOffset = 0
|
|
local yOffset = 0
|
|
local wrapXOffset = 0
|
|
local wrapYOffset = 0
|
|
local wrapAfter = db.wrapAfter
|
|
local maxWraps = db.maxWraps
|
|
local minWidth = 0
|
|
local minHeight = 0
|
|
|
|
if IS_HORIZONTAL_GROWTH[db.growthDirection] then
|
|
minWidth = ((wrapAfter == 1 and 0 or db.horizontalSpacing) + size) * wrapAfter
|
|
minHeight = (db.verticalSpacing + size) * maxWraps
|
|
xOffset = DIRECTION_TO_HORIZONTAL_SPACING_MULTIPLIER[db.growthDirection] * (db.horizontalSpacing + size)
|
|
yOffset = 0
|
|
wrapXOffset = 0
|
|
wrapYOffset = DIRECTION_TO_VERTICAL_SPACING_MULTIPLIER[db.growthDirection] * (db.verticalSpacing + size)
|
|
else
|
|
minWidth = (db.horizontalSpacing + size) * maxWraps
|
|
minHeight = ((wrapAfter == 1 and 0 or db.verticalSpacing) + size) * wrapAfter
|
|
xOffset = 0
|
|
yOffset = DIRECTION_TO_VERTICAL_SPACING_MULTIPLIER[db.growthDirection] * (db.verticalSpacing + size)
|
|
wrapXOffset = DIRECTION_TO_HORIZONTAL_SPACING_MULTIPLIER[db.growthDirection] * (db.horizontalSpacing + size)
|
|
wrapYOffset = 0
|
|
end
|
|
|
|
wipe(buttons)
|
|
local button
|
|
local numWeapon = 0
|
|
if weaponPosition then
|
|
local hasMainHandEnchant, mainHandExpiration, _, hasOffHandEnchant, offHandExpiration = GetWeaponEnchantInfo()
|
|
for weapon = 2, 1, -1 do
|
|
button = _G["ElvUIPlayerBuffsTempEnchant"..weapon]
|
|
if select(weapon, hasMainHandEnchant, hasOffHandEnchant) then
|
|
numWeapon = numWeapon + 1
|
|
if not button then
|
|
button = CreateFrame("Button", "$parentTempEnchant"..weapon, header)
|
|
self:CreateIcon(button)
|
|
end
|
|
if button then
|
|
if button:IsShown() then button:Hide() end
|
|
|
|
local index = enchantableSlots[weapon]
|
|
local quality = GetInventoryItemQuality("player", index)
|
|
button.texture:SetTexture(GetInventoryItemTexture("player", index))
|
|
|
|
if quality then
|
|
button:SetBackdropBorderColor(GetItemQualityColor(quality))
|
|
end
|
|
|
|
local expirationTime = select(weapon, mainHandExpiration, offHandExpiration)
|
|
if expirationTime then
|
|
button.offset = select(weapon, 2, 5)
|
|
button:SetScript("OnUpdate", function() self.UpdateTime(this, arg1) end)
|
|
button.nextUpdate = -1
|
|
A.UpdateTime(button, 0)
|
|
else
|
|
button.timeLeft = nil
|
|
button.offset = nil
|
|
button:SetScript("OnUpdate", nil)
|
|
button.time:SetText("")
|
|
end
|
|
buttons[weapon] = button
|
|
end
|
|
else
|
|
if button and type(button.Hide) == "function" then
|
|
button.offset = nil
|
|
button:Hide()
|
|
end
|
|
end
|
|
end
|
|
end
|
|
|
|
for i = 1, getn(auraTable) do
|
|
button = _G[headerName.."AuraButton"..i]
|
|
if button then
|
|
if button:IsShown() then button:Hide() end
|
|
else
|
|
button = CreateFrame("Button", "$parentAuraButton"..i, header)
|
|
self:CreateIcon(button)
|
|
end
|
|
local buffInfo = auraTable[i]
|
|
button.index = buffInfo.index
|
|
|
|
if buffInfo.expires and buffInfo.expires > 0 then
|
|
local timeLeft = buffInfo.expires
|
|
if not button.timeLeft then
|
|
button.timeLeft = timeLeft
|
|
button:SetScript("OnUpdate", function() self.UpdateTime(this, arg1) end)
|
|
else
|
|
button.timeLeft = timeLeft
|
|
end
|
|
|
|
button.nextUpdate = -1
|
|
self.UpdateTime(button, 0)
|
|
else
|
|
button.timeLeft = nil
|
|
button.time:SetText("")
|
|
button:SetScript("OnUpdate", nil)
|
|
end
|
|
|
|
if buffInfo.count > 1 then
|
|
button.count:SetText(buffInfo.count)
|
|
else
|
|
button.count:SetText("")
|
|
end
|
|
|
|
if buffInfo.filter == "HARMFUL" then
|
|
local color = DebuffTypeColor[buffInfo.dispelType or ""] or DebuffTypeColor.none
|
|
button:SetBackdropBorderColor(color.r, color.g, color.b)
|
|
else
|
|
button:SetBackdropBorderColor(unpack(E.media.bordercolor))
|
|
end
|
|
|
|
button.texture:SetTexture(buffInfo.icon)
|
|
|
|
buttons[i+numWeapon] = button
|
|
end
|
|
|
|
local display = getn(buttons)
|
|
if wrapAfter and maxWraps then
|
|
display = min(display, wrapAfter * maxWraps)
|
|
end
|
|
|
|
local left, right, top, bottom = huge, -huge, -huge, huge
|
|
for index = 1, display do
|
|
button = buttons[index]
|
|
local tick, cycle = floor(mod((index - 1), wrapAfter)), floor((index - 1) / wrapAfter)
|
|
button:ClearAllPoints()
|
|
button:SetPoint(point, header, cycle * wrapXOffset + tick * xOffset, cycle * wrapYOffset + tick * yOffset)
|
|
|
|
button:SetWidth(size)
|
|
button:SetHeight(size)
|
|
|
|
if button.time then
|
|
local font = LSM:Fetch("font", self.db.font)
|
|
button.time:ClearAllPoints()
|
|
button.time:SetPoint("TOP", button, "BOTTOM", 1 + self.db.timeXOffset, 0 + self.db.timeYOffset)
|
|
E:FontTemplate(button.time, font, self.db.fontSize, self.db.fontOutline)
|
|
|
|
button.count:ClearAllPoints()
|
|
button.count:SetPoint("BOTTOMRIGHT", -1 + self.db.countXOffset, 0 + self.db.countYOffset)
|
|
E:FontTemplate(button.count, font, self.db.fontSize, self.db.fontOutline)
|
|
end
|
|
|
|
button:Show()
|
|
left = min(left, button:GetLeft() or huge)
|
|
right = max(right, button:GetRight() or -huge)
|
|
top = max(top, button:GetTop() or -huge)
|
|
bottom = min(bottom, button:GetBottom() or huge)
|
|
end
|
|
local deadIndex = (getn(auraTable) + numWeapon) + 1
|
|
button = _G[headerName.."AuraButton"..deadIndex]
|
|
while button do
|
|
if button:IsShown() then button:Hide() end
|
|
deadIndex = deadIndex + 1
|
|
button = _G[headerName.."AuraButton"..deadIndex]
|
|
end
|
|
|
|
if display >= 1 then
|
|
header:SetWidth(max(right - left, minWidth))
|
|
header:SetHeight(max(top - bottom, minHeight))
|
|
else
|
|
header:SetWidth(minWidth)
|
|
header:SetHeight(minHeight)
|
|
end
|
|
end
|
|
|
|
local freshTable
|
|
local releaseTable
|
|
do
|
|
local tableReserve = {}
|
|
freshTable = function ()
|
|
local t = next(tableReserve) or {}
|
|
tableReserve[t] = nil
|
|
return t
|
|
end
|
|
releaseTable = function (t)
|
|
tableReserve[t] = wipe(t)
|
|
end
|
|
end
|
|
|
|
local function sortFactory(key, separateOwn, reverse)
|
|
if separateOwn ~= 0 then
|
|
if reverse then
|
|
return function(a, b)
|
|
if a.filter == b.filter then
|
|
local ownA, ownB = a.caster == "player", b.caster == "player"
|
|
if ownA ~= ownB then
|
|
return ownA == (separateOwn > 0)
|
|
end
|
|
return a[key] > b[key]
|
|
else
|
|
return a.filter < b.filter
|
|
end
|
|
end;
|
|
else
|
|
return function(a, b)
|
|
if a.filter == b.filter then
|
|
local ownA, ownB = a.caster == "player", b.caster == "player"
|
|
if ownA ~= ownB then
|
|
return ownA == (separateOwn > 0)
|
|
end
|
|
return a[key] < b[key]
|
|
else
|
|
return a.filter < b.filter
|
|
end
|
|
end;
|
|
end
|
|
else
|
|
if reverse then
|
|
return function(a, b)
|
|
if a.filter == b.filter then
|
|
return a[key] > b[key]
|
|
else
|
|
return a.filter < b.filter
|
|
end
|
|
end;
|
|
else
|
|
return function(a, b)
|
|
if a.filter == b.filter then
|
|
return a[key] < b[key]
|
|
else
|
|
return a.filter < b.filter
|
|
end
|
|
end;
|
|
end
|
|
end
|
|
end
|
|
|
|
local sorters = {}
|
|
for _, key in ipairs{"index", "expires"} do
|
|
local label = string.upper(key)
|
|
sorters[label] = {}
|
|
for bool in pairs{[true] = true, [false] = false} do
|
|
sorters[label][bool] = {}
|
|
for sep = -1, 1 do
|
|
sorters[label][bool][sep] = sortFactory(key, sep, bool)
|
|
end
|
|
end
|
|
end
|
|
sorters.TIME = sorters.EXPIRES
|
|
|
|
local sortingTable = {}
|
|
function A:UpdateHeader(header)
|
|
local filter = header.filter
|
|
local db = self.db.debuffs
|
|
|
|
wipe(sortingTable)
|
|
|
|
local weaponPosition
|
|
if filter == "HELPFUL" then
|
|
db = self.db.buffs
|
|
weaponPosition = 1
|
|
end
|
|
|
|
for i = 0, 23 do
|
|
local aura, _ = freshTable()
|
|
aura.index, aura.untilCancelled = GetPlayerBuff(i, filter)
|
|
if aura.index < 0 then
|
|
releaseTable(aura)
|
|
else
|
|
aura.icon, aura.count, aura.dispelType, aura.expires = GetPlayerBuffTexture(aura.index), GetPlayerBuffApplications(aura.index), GetPlayerBuffDispelType(aura.index), GetPlayerBuffTimeLeft(aura.index)
|
|
aura.filter = filter
|
|
sortingTable[i+1] = aura
|
|
end
|
|
end
|
|
|
|
local sortMethod = (sorters[db.sortMethod] or sorters["INDEX"])[db.sortDir == "-"][db.seperateOwn]
|
|
tsort(sortingTable, sortMethod)
|
|
|
|
self:ConfigureAuras(header, sortingTable, weaponPosition)
|
|
while sortingTable[1] do
|
|
releaseTable(wipe(sortingTable))
|
|
end
|
|
end
|
|
|
|
function A:CreateAuraHeader(filter)
|
|
local name = "ElvUIPlayerDebuffs"
|
|
if filter == "HELPFUL" then
|
|
name = "ElvUIPlayerBuffs"
|
|
end
|
|
|
|
local header = CreateFrame("Frame", name, UIParent)
|
|
header:SetClampedToScreen(true)
|
|
header.filter = filter
|
|
|
|
header:RegisterEvent("PLAYER_AURAS_CHANGED")
|
|
header:SetScript("OnEvent", function()
|
|
A:UpdateHeader(this)
|
|
end)
|
|
|
|
self:UpdateHeader(header)
|
|
|
|
return header
|
|
end
|
|
|
|
function A:Initialize()
|
|
if self.db then return end
|
|
|
|
if E.private.auras.disableBlizzard then
|
|
E:Kill(BuffFrame)
|
|
E:Kill(TemporaryEnchantFrame)
|
|
end
|
|
|
|
if not E.private.auras.enable then return end
|
|
|
|
self.db = E.db.auras
|
|
|
|
self.BuffFrame = self:CreateAuraHeader("HELPFUL")
|
|
self.BuffFrame:SetPoint("TOPRIGHT", MMHolder, "TOPLEFT", -(6 + E.Border), -E.Border - E.Spacing)
|
|
E:CreateMover(self.BuffFrame, "BuffsMover", L["Player Buffs"])
|
|
|
|
self.BuffFrame.GetUpdateWeaponEnchant = function(self)
|
|
local hasMainHandEnchant, _, _, hasOffHandEnchant = GetWeaponEnchantInfo()
|
|
if hasMainHandEnchant and not self.hasMainHandEnchant then
|
|
self.hasMainHandEnchant = true
|
|
return true
|
|
elseif hasOffHandEnchant and not self.hasOffHandEnchant then
|
|
self.hasOffHandEnchant = true
|
|
return true
|
|
elseif self.hasMainHandEnchant and not hasMainHandEnchant then
|
|
self.hasMainHandEnchant = false
|
|
return true
|
|
elseif self.hasOffHandEnchant and not hasOffHandEnchant then
|
|
self.hasOffHandEnchant = false
|
|
return true
|
|
end
|
|
end
|
|
|
|
self.BuffFrame:SetScript("OnUpdate", function()
|
|
if this:GetUpdateWeaponEnchant() then A:UpdateHeader(this) end
|
|
end)
|
|
|
|
self.DebuffFrame = self:CreateAuraHeader("HARMFUL")
|
|
self.DebuffFrame:SetPoint("BOTTOMRIGHT", MMHolder, "BOTTOMLEFT", -(6 + E.Border), E.Border + E.Spacing)
|
|
E:CreateMover(self.DebuffFrame, "DebuffsMover", L["Player Debuffs"])
|
|
end
|
|
|
|
local function InitializeCallback()
|
|
A:Initialize()
|
|
end
|
|
|
|
E:RegisterModule(A:GetName(), InitializeCallback) |