463 lines
13 KiB
Lua
463 lines
13 KiB
Lua
local E, L, V, P, G = unpack(select(2, ...)); --Import: Engine, Locales, PrivateDB, ProfileDB, GlobalDB
|
|
local NP = E:GetModule("NamePlates")
|
|
local LSM = E.Libs.LSM
|
|
local LAI = E.Libs.LAI
|
|
|
|
--Lua functions
|
|
local select, unpack, pairs = select, unpack, pairs
|
|
local band = bit.band
|
|
local tinsert = table.insert
|
|
local floor = math.floor
|
|
local split = string.split
|
|
--WoW API / Variables
|
|
local CreateFrame = CreateFrame
|
|
local GetSpellInfo = GetSpellInfo
|
|
local GetTime = GetTime
|
|
|
|
local CREATED, VISIBLE, HIDDEN = 2, 1, 0
|
|
|
|
local positionValues = {
|
|
BOTTOMLEFT = "TOP",
|
|
BOTTOMRIGHT = "TOP",
|
|
LEFT = "RIGHT",
|
|
RIGHT = "LEFT",
|
|
TOPLEFT = "BOTTOM",
|
|
TOPRIGHT = "BOTTOM"
|
|
}
|
|
|
|
local positionValues2 = {
|
|
BOTTOMLEFT = "BOTTOM",
|
|
BOTTOMRIGHT = "BOTTOM",
|
|
LEFT = "LEFT",
|
|
RIGHT = "RIGHT",
|
|
TOPLEFT = "TOP",
|
|
TOPRIGHT = "TOP"
|
|
}
|
|
|
|
|
|
local RaidIconBit = {
|
|
["STAR"] = 0x00100000,
|
|
["CIRCLE"] = 0x00200000,
|
|
["DIAMOND"] = 0x00400000,
|
|
["TRIANGLE"] = 0x00800000,
|
|
["MOON"] = 0x01000000,
|
|
["SQUARE"] = 0x02000000,
|
|
["CROSS"] = 0x04000000,
|
|
["SKULL"] = 0x08000000
|
|
}
|
|
|
|
local ByRaidIcon = {}
|
|
|
|
function NP:LibAuraInfo_AURA_APPLIED(event, destGUID)
|
|
self:UpdateElement_AurasByGUID(destGUID, event)
|
|
end
|
|
|
|
function NP:LibAuraInfo_AURA_REMOVED(event, destGUID)
|
|
self:UpdateElement_AurasByGUID(destGUID, event)
|
|
end
|
|
|
|
function NP:LibAuraInfo_AURA_REFRESH(event, destGUID)
|
|
self:LibAuraInfo_AURA_APPLIED(event, destGUID)
|
|
end
|
|
|
|
function NP:LibAuraInfo_AURA_APPLIED_DOSE(event, destGUID)
|
|
self:LibAuraInfo_AURA_APPLIED(event, destGUID)
|
|
end
|
|
|
|
function NP:LibAuraInfo_AURA_CLEAR(event, destGUID)
|
|
self:UpdateElement_AurasByGUID(destGUID, event)
|
|
end
|
|
|
|
function NP:LibAuraInfo_UNIT_AURA(event, destGUID)
|
|
self:UpdateElement_AurasByGUID(destGUID, event)
|
|
end
|
|
|
|
function NP:UpdateTime(elapsed)
|
|
self.timeLeft = self.timeLeft - elapsed
|
|
self:SetValue(self.timeLeft)
|
|
|
|
if self.nextUpdate > 0 then
|
|
self.nextUpdate = self.nextUpdate - elapsed
|
|
return
|
|
end
|
|
|
|
if self.timeLeft < 0 then
|
|
self:SetScript("OnUpdate", nil)
|
|
self:Hide()
|
|
return
|
|
end
|
|
|
|
local value, id, nextUpdate, remainder = E:GetTimeInfo(self.timeLeft, self.threshold, self.hhmmThreshold, self.mmssThreshold)
|
|
self.nextUpdate = nextUpdate
|
|
|
|
local style = E.TimeFormats[id]
|
|
if style then
|
|
local which = (self.textColors and 2 or 1) + (self.showSeconds and 0 or 2)
|
|
if self.textColors then
|
|
self.text:SetFormattedText(style[which], value, self.textColors[id], remainder)
|
|
else
|
|
self.text:SetFormattedText(style[which], value, remainder)
|
|
end
|
|
end
|
|
|
|
local color = self.timeColors[id]
|
|
if color then
|
|
self.text:SetTextColor(color.r, color.g, color.b)
|
|
end
|
|
end
|
|
|
|
local unstableAffliction = GetSpellInfo(30108)
|
|
local vampiricTouch = GetSpellInfo(34914)
|
|
function NP:SetAura(frame, guid, index, filter, isDebuff, visible)
|
|
local isAura, name, texture, count, debuffType, duration, expiration, caster, spellID, _ = LAI:GUIDAura(guid, index, filter)
|
|
|
|
if frame.forceShow or frame.forceCreate then
|
|
spellID = 47540
|
|
name, _, texture = GetSpellInfo(spellID)
|
|
if frame.forceShow then
|
|
isAura, count, debuffType, duration, expiration = true, 5, "Magic", 0, 0
|
|
end
|
|
end
|
|
|
|
if isAura then
|
|
local position = visible + 1
|
|
local button = frame[position] or NP:Construct_AuraIcon(frame, position)
|
|
|
|
button.caster = caster
|
|
button.filter = filter
|
|
button.isDebuff = isDebuff
|
|
|
|
local filterCheck = not frame.forceCreate
|
|
if not (frame.forceShow or frame.forceCreate) then
|
|
filterCheck = NP:AuraFilter(guid, button, name, texture, count, debuffType, duration, expiration, caster, spellID)
|
|
end
|
|
|
|
if filterCheck then
|
|
if button.icon then button.icon:SetTexture(texture) end
|
|
if button.count then button.count:SetText(count > 1 and count) end
|
|
|
|
if duration > 0 and expiration ~= 0 then
|
|
local timeLeft = expiration - GetTime()
|
|
if timeLeft > 0 then
|
|
button.timeLeft = timeLeft
|
|
button.nextUpdate = 0
|
|
|
|
button:SetMinMaxValues(0, duration)
|
|
button:SetValue(timeLeft)
|
|
|
|
button:SetScript("OnUpdate", NP.UpdateTime)
|
|
-- else
|
|
-- return HIDDEN
|
|
end
|
|
else
|
|
button.timeLeft = nil
|
|
button.text:SetText("")
|
|
button:SetScript("OnUpdate", nil)
|
|
button:SetMinMaxValues(0, 1)
|
|
button:SetValue(0)
|
|
end
|
|
|
|
button:SetID(index)
|
|
button:Show()
|
|
|
|
if isDebuff then
|
|
local color = (debuffType and DebuffTypeColor[debuffType]) or DebuffTypeColor.none
|
|
if button.name and (button.name == unstableAffliction or button.name == vampiricTouch) then
|
|
self:StyleFrameColor(button, 0.05, 0.85, 0.94)
|
|
else
|
|
self:StyleFrameColor(button, color.r * 0.6, color.g * 0.6, color.b * 0.6)
|
|
end
|
|
end
|
|
|
|
return VISIBLE
|
|
elseif frame.forceCreate then
|
|
button:Hide()
|
|
|
|
return CREATED
|
|
else
|
|
return HIDDEN
|
|
end
|
|
end
|
|
end
|
|
|
|
function NP:Update_AurasPosition(frame, db)
|
|
local size = db.size + db.spacing
|
|
local anchor = E.InversePoints[db.anchorPoint]
|
|
local growthx = (db.growthX == "LEFT" and -1) or 1
|
|
local growthy = (db.growthY == "DOWN" and -1) or 1
|
|
local cols = db.perrow
|
|
|
|
for i = frame.anchoredIcons + 1, #frame do
|
|
local button = frame[i]
|
|
if not button then break end
|
|
|
|
local col = (i - 1) % cols
|
|
local row = floor((i - 1) / cols)
|
|
|
|
button:SetSize(db.size, db.size)
|
|
button:ClearAllPoints()
|
|
button:SetPoint(anchor, frame, anchor, col * size * growthx, row * size * growthy)
|
|
|
|
button.count:FontTemplate(LSM:Fetch("font", db.countFont), db.countFontSize, db.countFontOutline)
|
|
button.count:ClearAllPoints()
|
|
button.count:SetPoint(db.countPosition, db.countXOffset, db.countYOffset)
|
|
|
|
button.text:FontTemplate(LSM:Fetch("font", db.durationFont), db.durationFontSize, db.durationFontOutline)
|
|
button.text:ClearAllPoints()
|
|
button.text:SetPoint(db.durationPosition, db.durationXOffset, db.durationYOffset)
|
|
|
|
button:SetOrientation(db.cooldownOrientation)
|
|
|
|
button.bg:ClearAllPoints()
|
|
if db.cooldownOrientation == "VERTICAL" then
|
|
button.bg:SetPoint("TOPLEFT", button)
|
|
button.bg:SetPoint("BOTTOMRIGHT", button:GetStatusBarTexture(), "TOPRIGHT")
|
|
else
|
|
button.bg:SetPoint("TOPRIGHT", button)
|
|
button.bg:SetPoint("BOTTOMLEFT", button:GetStatusBarTexture(), "BOTTOMRIGHT")
|
|
end
|
|
|
|
if db.reverseCooldown then
|
|
button:SetStatusBarColor(0, 0, 0, 0.5)
|
|
button.bg:SetTexture(0, 0, 0, 0)
|
|
else
|
|
button:SetStatusBarColor(0, 0, 0, 0)
|
|
button.bg:SetTexture(0, 0, 0, 0.5)
|
|
end
|
|
end
|
|
end
|
|
|
|
function NP:UpdateElement_AuraIcons(frame, guid, filter, limit, isDebuff)
|
|
local index, visible, hidden, created = 1, 0, 0, 0
|
|
|
|
while visible < limit do
|
|
local result = NP:SetAura(frame, guid, index, filter, isDebuff, visible)
|
|
if not result then
|
|
break
|
|
elseif result == HIDDEN then
|
|
hidden = hidden + 1
|
|
elseif result == VISIBLE then
|
|
visible = visible + 1
|
|
elseif result == CREATED then
|
|
visible = visible + 1
|
|
created = created + 1
|
|
end
|
|
index = index + 1
|
|
end
|
|
|
|
visible = visible - created
|
|
|
|
for i = visible + 1, #frame do
|
|
frame[i].timeLeft = nil
|
|
frame[i]:SetScript("OnUpdate", nil)
|
|
frame[i]:Hide()
|
|
end
|
|
return visible
|
|
end
|
|
|
|
function NP:UpdateElement_Auras(frame)
|
|
if not frame.Health:IsShown() then return end
|
|
|
|
local guid = frame.guid
|
|
|
|
if not guid then
|
|
if frame.UnitClass == "HERO" then
|
|
local name = frame.UnitName
|
|
guid = self.GUIDByName[name]
|
|
elseif frame.RaidIcon:IsShown() then
|
|
guid = ByRaidIcon[frame.RaidIconType]
|
|
end
|
|
|
|
if guid then
|
|
frame.guid = guid
|
|
elseif not frame.Buffs.forceShow and not frame.Debuffs.forceShow then
|
|
return
|
|
end
|
|
end
|
|
|
|
local db = NP.db.units[frame.UnitType].buffs
|
|
if db.enable then
|
|
local buffs = frame.Buffs
|
|
buffs.visibleBuffs = NP:UpdateElement_AuraIcons(buffs, guid, buffs.filter or "HELPFUL", db.perrow * db.numrows)
|
|
|
|
if #buffs > buffs.anchoredIcons then
|
|
self:Update_AurasPosition(buffs, db)
|
|
|
|
buffs.anchoredIcons = #buffs
|
|
end
|
|
end
|
|
|
|
db = NP.db.units[frame.UnitType].debuffs
|
|
if db.enable then
|
|
local debuffs = frame.Debuffs
|
|
debuffs.visibleDebuffs = NP:UpdateElement_AuraIcons(debuffs, guid, debuffs.filter or "HARMFUL", db.perrow * db.numrows, true)
|
|
|
|
if #debuffs > debuffs.anchoredIcons then
|
|
self:Update_AurasPosition(debuffs, db)
|
|
|
|
debuffs.anchoredIcons = #debuffs
|
|
end
|
|
end
|
|
|
|
self:StyleFilterUpdate(frame, "UNIT_AURA")
|
|
end
|
|
|
|
function NP:UpdateElement_AurasByGUID(guid, event)
|
|
local destName, destFlags = LAI:GetGUIDInfo(guid)
|
|
|
|
if destName then
|
|
destName = split("-", destName)
|
|
end
|
|
|
|
local raidIcon
|
|
if destFlags then
|
|
for iconName, bitmask in pairs(RaidIconBit) do
|
|
if band(destFlags, bitmask) > 0 then
|
|
ByRaidIcon[iconName] = guid
|
|
raidIcon = iconName
|
|
break
|
|
end
|
|
end
|
|
end
|
|
|
|
local frame = self:SearchForFrame(guid, raidIcon, destName)
|
|
if frame then
|
|
frame.guid = guid
|
|
self.GUIDByName[destName] = guid
|
|
self:UpdateElement_Auras(frame)
|
|
end
|
|
end
|
|
|
|
function NP:Construct_AuraIcon(parent, index)
|
|
local db = NP.db.units[parent:GetParent().UnitType][parent.type]
|
|
|
|
local button = CreateFrame("StatusBar", "$parentButton"..index, parent)
|
|
NP:StyleFrame(button, true)
|
|
|
|
button:SetStatusBarTexture(E.media.blankTex)
|
|
button:SetStatusBarColor(0, 0, 0, 0)
|
|
button:SetOrientation("VERTICAL")
|
|
|
|
button.bg = button:CreateTexture()
|
|
button.bg:SetTexture(0, 0, 0, 0.5)
|
|
|
|
button.bg:SetPoint("TOPLEFT", button)
|
|
button.bg:SetPoint("BOTTOMRIGHT", button:GetStatusBarTexture(), "TOPRIGHT")
|
|
|
|
button.icon = button:CreateTexture(nil, "BORDER")
|
|
button.icon:SetTexCoord(unpack(E.TexCoords))
|
|
button.icon:SetAllPoints()
|
|
|
|
button.count = button:CreateFontString(nil, "OVERLAY")
|
|
button.count:SetJustifyH("RIGHT")
|
|
button.count:FontTemplate(LSM:Fetch("font", db.countFont), db.countFontSize, db.countFontOutline)
|
|
|
|
button.text = button:CreateFontString(nil, "OVERLAY")
|
|
|
|
-- support cooldown override
|
|
if not button.isRegisteredCooldown then
|
|
button.CooldownOverride = "nameplates"
|
|
button.isRegisteredCooldown = true
|
|
button.forceEnabled = true
|
|
|
|
if not E.RegisteredCooldowns.nameplates then E.RegisteredCooldowns.nameplates = {} end
|
|
tinsert(E.RegisteredCooldowns.nameplates, button)
|
|
end
|
|
|
|
button.text:FontTemplate(LSM:Fetch("font", db.durationFont), db.durationFontSize, db.durationFontOutline)
|
|
|
|
NP:Update_CooldownOptions(button)
|
|
|
|
tinsert(parent, button)
|
|
|
|
return button
|
|
end
|
|
|
|
function NP:Update_CooldownOptions(button)
|
|
E:Cooldown_Options(button, self.db.cooldown, button)
|
|
end
|
|
|
|
function NP:Configure_Auras(frame, auraType)
|
|
local auras = frame[auraType]
|
|
local db = self.db.units[frame.UnitType][auras.type]
|
|
|
|
auras:SetWidth(db.perrow * db.size + ((db.perrow - 1) * db.spacing))
|
|
auras:SetHeight(db.numrows * db.size + ((db.numrows - 1) * db.spacing))
|
|
auras:ClearAllPoints()
|
|
auras:SetPoint(positionValues[db.anchorPoint], db.attachTo == "BUFFS" and frame.Buffs or frame.Health, positionValues2[db.anchorPoint], db.xOffset, db.yOffset)
|
|
end
|
|
|
|
function NP:ConstructElement_Auras(frame, auraType)
|
|
local auras = CreateFrame("Frame", "$parent"..auraType, frame)
|
|
auras:Show()
|
|
auras:SetSize(150, 27)
|
|
auras:SetPoint("TOP", 0, 22)
|
|
auras.anchoredIcons = 0
|
|
auras.type = string.lower(auraType)
|
|
|
|
return auras
|
|
end
|
|
|
|
function NP:CheckFilter(name, spellID, isPlayer, allowDuration, noDuration, ...)
|
|
for i = 1, select("#", ...) do
|
|
local filterName = select(i, ...)
|
|
if not filterName then return true end
|
|
if G.nameplates.specialFilters[filterName] or E.global.unitframe.aurafilters[filterName] then
|
|
local filter = E.global.unitframe.aurafilters[filterName]
|
|
if filter then
|
|
local filterType = filter.type
|
|
local spellList = filter.spells
|
|
local spell = spellList and (spellList[spellID] or spellList[name])
|
|
|
|
if filterType and (filterType == "Whitelist") and (spell and spell.enable) and allowDuration then
|
|
return true
|
|
elseif filterType and (filterType == "Blacklist") and (spell and spell.enable) then
|
|
return false
|
|
end
|
|
elseif filterName == "Personal" and isPlayer and allowDuration then
|
|
return true
|
|
elseif filterName == "nonPersonal" and (not isPlayer) and allowDuration then
|
|
return true
|
|
elseif filterName == "blockNoDuration" and noDuration then
|
|
return false
|
|
elseif filterName == "blockNonPersonal" and (not isPlayer) then
|
|
return false
|
|
end
|
|
end
|
|
end
|
|
end
|
|
|
|
function NP:AuraFilter(guid, button, name, texture, count, debuffType, duration, expiration, caster, spellID)
|
|
local parent = button:GetParent()
|
|
local parentType = parent.type
|
|
local db = NP.db.units[parent:GetParent().UnitType][parentType]
|
|
if not db then return true end
|
|
|
|
local isPlayer = caster == E.myguid
|
|
|
|
-- keep these same as in `UF:AuraFilter`
|
|
button.isPlayer = isPlayer
|
|
button.dtype = debuffType
|
|
button.duration = duration
|
|
button.expiration = expiration
|
|
button.stackCount = count
|
|
button.name = name
|
|
button.spellID = spellID
|
|
button.spell = name
|
|
button.priority = 0
|
|
|
|
if not db.filters then return true end
|
|
|
|
local priority = db.filters.priority
|
|
local noDuration = (not duration or duration == 0)
|
|
local allowDuration = noDuration or (duration and (duration > 0) and db.filters.maxDuration == 0 or duration <= db.filters.maxDuration) and (db.filters.minDuration == 0 or duration >= db.filters.minDuration)
|
|
local filterCheck
|
|
|
|
if priority ~= "" then
|
|
filterCheck = NP:CheckFilter(name, spellID, isPlayer, allowDuration, noDuration, split(",", priority))
|
|
else
|
|
filterCheck = allowDuration and true -- Allow all auras to be shown when the filter list is empty, while obeying duration sliders
|
|
end
|
|
|
|
return filterCheck
|
|
end |