Nameplate Overhaul (#38)

* ElvUI/NamePlates: initial nameplate conversions

* More nameplate work

* Modules/Cooldowns: various CD fixes, nameplates cant show 'swipe' texture

* ElvUI/NamePlates: final nameplate polish

* Modules/Misc: add space before interrupted announcement
This commit is contained in:
Andrew
2023-05-22 19:18:59 -07:00
committed by GitHub
parent 5d51f92ed3
commit 8edf2d7f8a
75 changed files with 8870 additions and 8088 deletions
+1 -2
View File
@@ -539,7 +539,6 @@ function AB:StyleButton(button, noBackdrop, useMasque)
if macroText then
macroText:ClearAllPoints()
macroText:SetWidth(self.db.fontWidth)
macroText:Point("BOTTOM", 0, 1)
macroText:FontTemplate(LSM:Fetch("font", self.db.font), self.db.fontSize, self.db.fontOutline)
macroText:SetTextColor(color.r, color.g, color.b)
@@ -995,4 +994,4 @@ local function InitializeCallback()
AB:Initialize()
end
E:RegisterModule(AB:GetName(), InitializeCallback)
E:RegisterModule(AB:GetName(), InitializeCallback)
+1
View File
@@ -17,6 +17,7 @@ local MICRO_BUTTONS = {
"SocialsMicroButton",
"PVPMicroButton",
"LFDMicroButton",
"ChallengesMicroButton",
"MainMenuMicroButton",
"HelpMicroButton"
}
+1 -1
View File
@@ -63,7 +63,7 @@ do
end
do
local interruptMsg = INTERRUPTED.." %s's \124cff71d5ff\124Hspell:%d\124h[%s]\124h\124r!"
local interruptMsg = " "..INTERRUPTED.." %s's \124cff71d5ff\124Hspell:%d\124h[%s]\124h\124r!"
function M:ToggleInterruptAnnounce()
if E.db.general.interruptAnnounce == "NONE" then
+150 -425
View File
@@ -1,463 +1,188 @@
local E, L, V, P, G = unpack(select(2, ...)); --Import: Engine, Locales, PrivateDB, ProfileDB, GlobalDB
local NP = E:GetModule("NamePlates")
local E, L, V, P, G = unpack(ElvUI)
local NP = E:GetModule('NamePlates')
local UF = E:GetModule('UnitFrames')
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 _G = _G
local wipe = wipe
local unpack = unpack
local CreateFrame = CreateFrame
local GetSpellInfo = GetSpellInfo
local GetTime = GetTime
local CREATED, VISIBLE, HIDDEN = 2, 1, 0
function NP:Construct_Auras(nameplate)
local frameName = nameplate:GetName()
local positionValues = {
BOTTOMLEFT = "TOP",
BOTTOMRIGHT = "TOP",
LEFT = "RIGHT",
RIGHT = "LEFT",
TOPLEFT = "BOTTOM",
TOPRIGHT = "BOTTOM"
}
local Buffs = CreateFrame('Frame', frameName..'Buffs', nameplate)
Buffs:Size(1, 1)
Buffs.size = 27
Buffs.num = 4
Buffs.spacing = E.Border * 2
Buffs.onlyShowPlayer = false
Buffs.disableMouse = true
Buffs.isNamePlate = nameplate
local positionValues2 = {
BOTTOMLEFT = "BOTTOM",
BOTTOMRIGHT = "BOTTOM",
LEFT = "LEFT",
RIGHT = "RIGHT",
TOPLEFT = "TOP",
TOPRIGHT = "TOP"
}
Buffs.initialAnchor = 'BOTTOMLEFT'
Buffs.growthX = 'RIGHT'
Buffs.growthY = 'UP'
Buffs.type = 'buffs'
Buffs.forceShow = nameplate == _G.ElvNP_Test
Buffs.tickers = {} -- StyleFilters
Buffs.stacks = {}
Buffs.rows = {}
local Debuffs = CreateFrame('Frame', frameName..'Debuffs', nameplate)
Debuffs:Size(1, 1)
Debuffs.size = 27
Debuffs.num = 4
Debuffs.spacing = E.Border * 2
Debuffs.onlyShowPlayer = false
Debuffs.disableMouse = true
Debuffs.isNamePlate = nameplate
Debuffs.initialAnchor = 'BOTTOMLEFT'
Debuffs.growthX = 'RIGHT'
Debuffs.growthY = 'UP'
Debuffs.type = 'debuffs'
Debuffs.forceShow = nameplate == _G.ElvNP_Test
Debuffs.tickers = {} -- StyleFilters
Debuffs.stacks = {}
Debuffs.rows = {}
local RaidIconBit = {
["STAR"] = 0x00100000,
["CIRCLE"] = 0x00200000,
["DIAMOND"] = 0x00400000,
["TRIANGLE"] = 0x00800000,
["MOON"] = 0x01000000,
["SQUARE"] = 0x02000000,
["CROSS"] = 0x04000000,
["SKULL"] = 0x08000000
}
Buffs.PreUpdate = UF.PreUpdateAura
Buffs.PreSetPosition = UF.SortAuras
Buffs.SetPosition = UF.SetPosition
Buffs.PostCreateIcon = NP.Construct_AuraIcon
Buffs.PostUpdateIcon = UF.PostUpdateAura
Buffs.CustomFilter = UF.AuraFilter
local ByRaidIcon = {}
Debuffs.PreUpdate = UF.PreUpdateAura
Debuffs.PreSetPosition = UF.SortAuras
Debuffs.SetPosition = UF.SetPosition
Debuffs.PostCreateIcon = NP.Construct_AuraIcon
Debuffs.PostUpdateIcon = UF.PostUpdateAura
Debuffs.CustomFilter = UF.AuraFilter
function NP:LibAuraInfo_AURA_APPLIED(event, destGUID)
self:UpdateElement_AurasByGUID(destGUID, event)
nameplate.Buffs_, nameplate.Debuffs_ = Buffs, Debuffs
nameplate.Buffs, nameplate.Debuffs = Buffs, Debuffs
end
function NP:LibAuraInfo_AURA_REMOVED(event, destGUID)
self:UpdateElement_AurasByGUID(destGUID, event)
end
function NP:Construct_AuraIcon(button)
if not button then return end
function NP:LibAuraInfo_AURA_REFRESH(event, destGUID)
self:LibAuraInfo_AURA_APPLIED(event, destGUID)
end
button:SetTemplate(nil, nil, nil, nil, nil, true, true)
function NP:LibAuraInfo_AURA_APPLIED_DOSE(event, destGUID)
self:LibAuraInfo_AURA_APPLIED(event, destGUID)
end
button.cd:SetReverse(true)
button.cd:SetInside(button)
function NP:LibAuraInfo_AURA_CLEAR(event, destGUID)
self:UpdateElement_AurasByGUID(destGUID, event)
end
button.icon:SetDrawLayer('ARTWORK')
button.icon:SetInside()
function NP:LibAuraInfo_UNIT_AURA(event, destGUID)
self:UpdateElement_AurasByGUID(destGUID, event)
end
button.count:ClearAllPoints()
button.count:Point('BOTTOMRIGHT', 1, 1)
button.count:SetJustifyH('RIGHT')
function NP:UpdateTime(elapsed)
self.timeLeft = self.timeLeft - elapsed
self:SetValue(self.timeLeft)
button.overlay:SetTexture()
button.stealable:SetTexture()
button.isNamePlate = true
if self.nextUpdate > 0 then
self.nextUpdate = self.nextUpdate - elapsed
return
E:RegisterCooldown(button.cd, 'nameplates')
local auras = button:GetParent()
if auras and auras.type then
local db = NP:PlateDB(auras.__owner)
button.db = db[auras.type]
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
NP:UpdateAuraSettings(button)
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)
function NP:Configure_Auras(nameplate, auras, db)
auras.size = db.size
auras.height = not db.keepSizeRatio and db.height
auras.numAuras = db.numAuras
auras.numRows = db.numRows
auras.onlyShowPlayer = false
auras.spacing = db.spacing
auras.growthY = UF.MatchGrowthY[db.anchorPoint] or db.growthY
auras.growthX = UF.MatchGrowthX[db.anchorPoint] or db.growthX
auras.xOffset = db.xOffset
auras.yOffset = db.yOffset
auras.anchorPoint = db.anchorPoint
auras.auraSort = UF.SortAuraFuncs[db.sortMethod]
auras.initialAnchor = E.InversePoints[db.anchorPoint]
auras.filterList = UF:ConvertFilters(auras, db.priority)
auras.smartPosition, auras.smartFluid = UF:SetSmartPosition(nameplate)
auras.attachTo = UF:GetAuraAnchorFrame(nameplate, db.attachTo) -- keep below SetSmartPosition
auras.num = db.numAuras * db.numRows
auras.db = db -- for auraSort
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)
local index = 1
while auras[index] do
local button = auras[index]
if button then
button.db = db
NP:UpdateAuraSettings(button)
button:SetBackdropBorderColor(unpack(E.media.bordercolor))
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)
auras:Point(auras.initialAnchor, auras.attachTo, auras.anchorPoint, auras.xOffset, auras.yOffset)
auras:Size(db.numAuras * db.size + ((db.numAuras - 1) * db.spacing), 1)
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)
function NP:Update_Auras(nameplate)
local db = NP:PlateDB(nameplate)
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
if db.debuffs.enable or db.buffs.enable then
if not nameplate:IsElementEnabled('Auras') then
nameplate:EnableElement('Auras')
end
nameplate.Buffs_:ClearAllPoints()
nameplate.Debuffs_:ClearAllPoints()
if db.debuffs.enable then
nameplate.Debuffs = nameplate.Debuffs_
NP:Configure_Auras(nameplate, nameplate.Debuffs, db.debuffs)
nameplate.Debuffs:Show()
nameplate.Debuffs:ForceUpdate()
elseif nameplate.Debuffs then
nameplate.Debuffs:Hide()
nameplate.Debuffs = nil
end
if db.buffs.enable then
nameplate.Buffs = nameplate.Buffs_
NP:Configure_Auras(nameplate, nameplate.Buffs, db.buffs)
nameplate.Buffs:Show()
nameplate.Buffs:ForceUpdate()
elseif nameplate.Buffs then
nameplate.Buffs:Hide()
nameplate.Buffs = nil
end
elseif nameplate:IsElementEnabled('Auras') then
nameplate:DisableElement('Auras')
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
function NP:UpdateAuraSettings(button)
local db = button.db
if db then
local point = db.countPosition or 'CENTER'
button.count:ClearAllPoints()
button.count:SetJustifyH(point:find('RIGHT') and 'RIGHT' or 'LEFT')
button.count:Point(point, db.countXOffset, db.countYOffset)
button.count:FontTemplate(LSM:Fetch('font', db.countFont), db.countFontSize, db.countFontOutline)
end
return filterCheck
end
if button.auraInfo then
wipe(button.auraInfo)
else
button.auraInfo = {}
end
button.needsButtonTrim = true
button.needsUpdateCooldownPosition = true
end
@@ -0,0 +1,299 @@
local E, L, V, P, G = unpack(ElvUI)
local NP = E:GetModule('NamePlates')
local UF = E:GetModule('UnitFrames')
local AB = E:GetModule('ActionBars')
local _G = _G
local wipe = wipe
local next = next
local pairs = pairs
local unpack = unpack
local GetTime = GetTime
local UnitGUID = UnitGUID
local CreateFrame = CreateFrame
NP.BossMods_ActiveUnitGUID = {}
NP.BossMods_TextureCache = {}
local allowHostile = false
function NP:BossMods_CreateIcon(element)
element.index = not element.index and 1 or (element.index + 1)
local button = CreateFrame('Button', element:GetName()..'Button'..element.index, element)
button:EnableMouse(false)
button:SetTemplate(nil, nil, nil, nil, nil, true, true)
local cooldown = CreateFrame('Cooldown', '$parentCooldown', button, 'CooldownFrameTemplate')
cooldown:SetReverse(true)
cooldown:SetInside(button)
E:RegisterCooldown(cooldown, 'nameplates')
local icon = button:CreateTexture(nil, 'ARTWORK')
icon:SetTexCoord(unpack(E.TexCoords))
icon:SetInside()
button.icon = icon
button.cd = cooldown
button.db = element.db
return button
end
function NP:BossMods_GetIcon(plate, texture)
local element, unused, avaiableIcon = plate.BossMods
local activeButton = element.activeIcons[texture]
if not activeButton then
unused, avaiableIcon = next(element.unusedIcons)
if unused then element.unusedIcons[unused] = nil end
end
local button = activeButton or avaiableIcon or NP:BossMods_CreateIcon(element)
if not activeButton then
element.activeIcons[texture] = button
end
return button
end
function NP:BossMods_PositionIcons(element)
if not next(element.activeIcons) then return end
local index = 1
local anchor, inversed, growthX, growthY, width, height, cols, point, middle = UF:GetAuraPosition(element)
element.currentRow = nil -- clear this for a new update
for _, button in pairs(element.activeIcons) do
UF:SetAuraPosition(element, button, index, anchor, inversed, growthX, growthY, width, height, cols, point, middle)
button:Size(width, height)
button:Show()
AB:TrimIcon(button)
index = index + 1
end
end
function NP:BossMods_TrackIcons(track, unitGUID, texture, duration, desaturate, startTime)
if track then
NP.BossMods_TextureCache[texture] = true -- use this to easily populate boss mod style filters
if not NP.BossMods_ActiveUnitGUID[unitGUID] then
NP.BossMods_ActiveUnitGUID[unitGUID] = {}
end
local active = NP.BossMods_ActiveUnitGUID[unitGUID]
if not active[texture] then
active[texture] = {}
end
local activeTexture = active[texture]
activeTexture.duration = duration
activeTexture.desaturate = desaturate
activeTexture.startTime = startTime
else
local active = NP.BossMods_ActiveUnitGUID[unitGUID]
if active then
if active[texture] then
active[texture] = nil
end
if not next(active) then
NP.BossMods_ActiveUnitGUID[unitGUID] = nil
end
end
end
end
function NP:BossMods_ClearIcons()
if not next(NP.BossMods_ActiveUnitGUID) then return end
for unitGUID, textures in pairs(NP.BossMods_ActiveUnitGUID) do
for texture in pairs(textures) do
local plate = NP.PlateGUID[unitGUID]
if plate then
NP:BossMods_ClearIcon(plate, texture)
NP:StyleFilterUpdate(plate, 'FAKE_BossModAuras')
end
end
end
wipe(NP.BossMods_ActiveUnitGUID)
end
function NP:BossMods_AddIcon(unitGUID, texture, duration, desaturate, skip)
local active = NP.BossMods_ActiveUnitGUID[unitGUID]
local activeTexture = active and active[texture]
local pastTime = activeTexture and activeTexture.startTime
local pastDuration = activeTexture and activeTexture.duration
if pastTime and pastDuration and pastDuration ~= duration then
pastTime = nil -- reset the cooldown timer if a new duration is given
end
local startTime = duration and (pastTime or GetTime()) or nil
NP:BossMods_TrackIcons(true, unitGUID, texture, duration, desaturate, startTime)
local plate = NP.PlateGUID[unitGUID]
if not plate then return end
local button = NP:BossMods_GetIcon(plate, texture)
button.icon:SetDesaturated(desaturate)
button.icon:SetTexture(texture)
if duration then
button.cd:SetCooldown(startTime, duration)
button.cd:Show()
else
button.cd:Hide()
end
if desaturate then
button:SetBackdropBorderColor(unpack(E.media.bordercolor))
else
local color = _G.DebuffTypeColor.none
button:SetBackdropBorderColor(color.r * 0.6, color.g * 0.6, color.b * 0.6)
end
NP:BossMods_PositionIcons(plate.BossMods)
if not skip then -- this will happen already during PostUpdateAllElements
NP:StyleFilterUpdate(plate, 'FAKE_BossModAuras')
end
end
function NP:BossMods_RemoveIcon(unitGUID, texture)
NP:BossMods_TrackIcons(false, unitGUID, texture)
local plate = NP.PlateGUID[unitGUID]
if plate then
NP:BossMods_ClearIcon(plate, texture)
NP:BossMods_PositionIcons(plate.BossMods)
NP:StyleFilterUpdate(plate, 'FAKE_BossModAuras')
end
end
function NP:BossMods_ClearIcon(plate, texture)
local element = plate.BossMods
local button = element.activeIcons[texture]
if not button then return end
button:Hide()
element.activeIcons[texture] = nil
element.unusedIcons[texture] = button
end
function NP:BossMods_UpdateIcon(plate, removed)
local unitGUID = plate.unitGUID
local active = NP.BossMods_ActiveUnitGUID[unitGUID]
if not active then
local element = plate.BossMods
if element and next(element.activeIcons) then
for texture in pairs(element.activeIcons) do
NP:BossMods_ClearIcon(plate, texture)
end
end
return
end
local enabled = allowHostile and NP.db.bossMods.enable
for texture, info in pairs(active) do
if removed or not enabled then
NP:BossMods_ClearIcon(plate, texture)
elseif enabled then
NP:BossMods_AddIcon(unitGUID, texture, info.duration, info.desaturate, true)
end
end
end
function NP:BossMods_AddIcon_DBM(isGUID, unit, texture, duration, desaturate)
if not (allowHostile and NP.db.bossMods.enable) then return end
local unitGUID = (isGUID and unit) or UnitGUID(unit)
NP:BossMods_AddIcon(unitGUID, texture, duration, desaturate)
end
function NP:BossMods_RemoveIcon_DBM(isGUID, unit, texture)
local unitGUID = (isGUID and unit) or UnitGUID(unit)
NP:BossMods_RemoveIcon(unitGUID, texture)
end
function NP:BossMods_AddIcon_BW(_, unitGUID, texture, duration, desaturate)
if not (allowHostile and NP.db.bossMods.enable) then return end
NP:BossMods_AddIcon(unitGUID, texture, duration, desaturate)
end
function NP:BossMods_RemoveIcon_BW(_, unitGUID, texture)
NP:BossMods_RemoveIcon(unitGUID, texture)
end
function NP:BossMods_DisableHostile()
NP:BossMods_ClearIcons()
allowHostile = false
end
function NP:BossMods_EnableHostile()
allowHostile = true
end
function NP:DBM_SupportedNPMod()
return _G.DBM.Options.UseNameplateHandoff
end
function NP:BossMods_RegisterCallbacks()
local DBM = _G.DBM
if DBM and DBM.RegisterCallback and DBM.Nameplate then
DBM.Nameplate.SupportedNPMod = NP.DBM_SupportedNPMod
DBM:RegisterCallback('BossMod_ShowNameplateAura',NP.BossMods_AddIcon_DBM)
DBM:RegisterCallback('BossMod_HideNameplateAura',NP.BossMods_RemoveIcon_DBM)
DBM:RegisterCallback('BossMod_EnableHostileNameplates',NP.BossMods_EnableHostile)
DBM:RegisterCallback('BossMod_DisableHostileNameplates',NP.BossMods_DisableHostile)
end
local BWL = _G.BigWigsLoader
if BWL and BWL.RegisterMessage then
BWL.RegisterMessage(NP,'BigWigs_AddNameplateIcon',NP.BossMods_AddIcon_BW)
BWL.RegisterMessage(NP,'BigWigs_RemoveNameplateIcon',NP.BossMods_RemoveIcon_BW)
BWL.RegisterMessage(NP,'BigWigs_EnableHostileNameplates',NP.BossMods_EnableHostile)
BWL.RegisterMessage(NP,'BigWigs_DisableHostileNameplates',NP.BossMods_DisableHostile)
end
end
function NP:Update_BossMods(plate)
local db = NP.db.bossMods
if not db.enable then return end
local anchor = db.anchorPoint
local inverse = E.InversePoints[anchor]
local element = plate.BossMods
element:ClearAllPoints()
element:SetPoint(inverse or 'TOPRIGHT', plate, anchor or 'TOPRIGHT', db.xOffset, db.yOffset)
element:SetSize(plate.width or 150, db.size)
element.db = db
element.spacing = db.spacing
element.initialAnchor = inverse
element.growthY = UF.MatchGrowthY[anchor] or db.growthY
element.growthX = UF.MatchGrowthX[anchor] or db.growthX
element.size = db.size + (db.spacing or 0)
element.height = not db.keepSizeRatio and db.height
element.rows = {}
end
function NP:Construct_BossMods(nameplate)
local element = CreateFrame('Frame', '$parentBossMods', nameplate)
element.activeIcons = {}
element.unusedIcons = {}
return element
end
+220 -324
View File
@@ -1,358 +1,254 @@
local E, L, V, P, G = unpack(select(2, ...)); --Import: Engine, Locales, PrivateDB, ProfileDB, GlobalDB
local NP = E:GetModule("NamePlates")
local E, L, V, P, G = unpack(ElvUI)
local NP = E:GetModule('NamePlates')
local UF = E:GetModule('UnitFrames')
local CH = E:GetModule('Chat')
local LSM = E.Libs.LSM
--Lua functions
local _G = _G
local abs = abs
local next = next
local unpack = unpack
local abs = math.abs
--WoW API / Variables
local strjoin = strjoin
local strmatch = strmatch
local CreateFrame = CreateFrame
local GetTime = GetTime
local UnitCastingInfo = UnitCastingInfo
local UnitChannelInfo = UnitChannelInfo
local FAILED = FAILED
local UnitCanAttack = UnitCanAttack
local UnitName = UnitName
local INTERRUPTED = INTERRUPTED
local function resetAttributes(self)
self.casting = nil
self.channeling = nil
self.notInterruptible = nil
self.spellName = nil
function NP:Castbar_CheckInterrupt(unit)
if unit == 'vehicle' then
unit = 'player'
end
if self.notInterruptible and UnitCanAttack('player', unit) then
self:SetStatusBarColor(NP.db.colors.castNoInterruptColor.r, NP.db.colors.castNoInterruptColor.g, NP.db.colors.castNoInterruptColor.b)
if self.Icon and NP.db.colors.castbarDesaturate then
self.Icon:SetDesaturated(true)
end
else
self:SetStatusBarColor(NP.db.colors.castColor.r, NP.db.colors.castColor.g, NP.db.colors.castColor.b)
if self.Icon then
self.Icon:SetDesaturated(false)
end
end
end
function NP:Update_CastBarOnUpdate(elapsed)
if self.casting or self.channeling then
local isCasting = self.casting
if isCasting then
self.value = self.value + elapsed
if self.value >= self.max then
resetAttributes(self)
self:Hide()
NP:StyleFilterUpdate(self:GetParent(), "FAKE_Casting")
return
end
else
self.value = self.value - elapsed
if self.value <= 0 then
resetAttributes(self)
self:Hide()
NP:StyleFilterUpdate(self:GetParent(), "FAKE_Casting")
return
end
function NP:Castbar_CustomDelayText(duration)
if self.channeling then
if self.channelTimeFormat == 'CURRENT' then
self.Time:SetFormattedText('%.1f |cffaf5050%.1f|r', abs(duration - self.max), self.delay)
elseif self.channelTimeFormat == 'CURRENTMAX' then
self.Time:SetFormattedText('%.1f / %.1f |cffaf5050%.1f|r', duration, self.max, self.delay)
elseif self.channelTimeFormat == 'REMAINING' then
self.Time:SetFormattedText('%.1f |cffaf5050%.1f|r', duration, self.delay)
elseif self.channelTimeFormat == 'REMAININGMAX' then
self.Time:SetFormattedText('%.1f / %.1f |cffaf5050%.1f|r', abs(duration - self.max), self.max, self.delay)
end
else
if self.castTimeFormat == 'CURRENT' then
self.Time:SetFormattedText('%.1f |cffaf5050%s %.1f|r', duration, '+', self.delay)
elseif self.castTimeFormat == 'CURRENTMAX' then
self.Time:SetFormattedText('%.1f / %.1f |cffaf5050%s %.1f|r', duration, self.max, '+', self.delay)
elseif self.castTimeFormat == 'REMAINING' then
self.Time:SetFormattedText('%.1f |cffaf5050%s %.1f|r', abs(duration - self.max), '+', self.delay)
elseif self.castTimeFormat == 'REMAININGMAX' then
self.Time:SetFormattedText('%.1f / %.1f |cffaf5050%s %.1f|r', abs(duration - self.max), self.max, '+', self.delay)
end
end
end
if self.delay ~= 0 then
if self.channeling then
if self.channelTimeFormat == "CURRENT" then
self.Time:SetFormattedText("%.1f |cffaf5050%.2f|r", abs(self.value - self.max), self.delay)
elseif self.channelTimeFormat == "CURRENTMAX" then
self.Time:SetFormattedText("%.1f / %.2f |cffaf5050%.2f|r", abs(self.value - self.max), self.max, self.delay)
elseif self.channelTimeFormat == "REMAINING" then
self.Time:SetFormattedText("%.1f |cffaf5050%.2f|r", self.value, self.delay)
elseif self.channelTimeFormat == "REMAININGMAX" then
self.Time:SetFormattedText("%.1f / %.2f |cffaf5050%.2f|r", self.value, self.max, self.max, self.delay)
function NP:Castbar_CustomTimeText(duration)
if self.channeling then
if self.channelTimeFormat == 'CURRENT' then
self.Time:SetFormattedText('%.1f', abs(duration - self.max))
elseif self.channelTimeFormat == 'CURRENTMAX' then
self.Time:SetFormattedText('%.1f / %.1f', abs(duration - self.max), self.max)
elseif self.channelTimeFormat == 'REMAINING' then
self.Time:SetFormattedText('%.1f', duration)
elseif self.channelTimeFormat == 'REMAININGMAX' then
self.Time:SetFormattedText('%.1f / %.1f', duration, self.max)
end
else
if self.castTimeFormat == 'CURRENT' then
self.Time:SetFormattedText('%.1f', duration)
elseif self.castTimeFormat == 'CURRENTMAX' then
self.Time:SetFormattedText('%.1f / %.1f', duration, self.max)
elseif self.castTimeFormat == 'REMAINING' then
self.Time:SetFormattedText('%.1f', abs(duration - self.max))
elseif self.castTimeFormat == 'REMAININGMAX' then
self.Time:SetFormattedText('%.1f / %.1f', abs(duration - self.max), self.max)
end
end
end
function NP:Castbar_PostCastStart(unit)
self:CheckInterrupt(unit)
-- player or NPCs; if used on other players: the cast target doesn't match their target, can be misleading if they mouseover cast
local plate = self.__owner
local db = NP:PlateDB(plate)
if db.castbar and db.castbar.enable then
if db.castbar.displayTarget then
local frameType = plate.frameType
if frameType == 'PLAYER' then
if self.curTarget then
self.Text:SetText(self.spellName..' > '..self.curTarget)
end
else
if self.castTimeFormat == "CURRENT" then
self.Time:SetFormattedText("%.1f |cffaf5050%s %.2f|r", self.value, "+", self.delay)
elseif self.castTimeFormat == "CURRENTMAX" then
self.Time:SetFormattedText("%.1f / %.2f |cffaf5050%s %.2f|r", self.value, self.max, "+", self.delay)
elseif self.castTimeFormat == "REMAINING" then
self.Time:SetFormattedText("%.1f |cffaf5050%s %.2f|r", abs(self.value - self.max), "+", self.delay)
elseif self.castTimeFormat == "REMAININGMAX" then
self.Time:SetFormattedText("%.1f / %.2f |cffaf5050%s %.2f|r", abs(self.value - self.max), self.max, "+", self.delay)
end
end
else
if self.channeling then
if self.channelTimeFormat == "CURRENT" then
self.Time:SetFormattedText("%.1f", abs(self.value - self.max))
elseif self.channelTimeFormat == "CURRENTMAX" then
self.Time:SetFormattedText("%.1f / %.2f", abs(self.value - self.max), self.max)
elseif self.channelTimeFormat == "REMAINING" then
self.Time:SetFormattedText("%.1f", self.value)
elseif self.channelTimeFormat == "REMAININGMAX" then
self.Time:SetFormattedText("%.1f / %.2f", self.value, self.max)
end
else
if self.castTimeFormat == "CURRENT" then
self.Time:SetFormattedText("%.1f", self.value)
elseif self.castTimeFormat == "CURRENTMAX" then
self.Time:SetFormattedText("%.1f / %.2f", self.value, self.max)
elseif self.castTimeFormat == "REMAINING" then
self.Time:SetFormattedText("%.1f", abs(self.value - self.max))
elseif self.castTimeFormat == "REMAININGMAX" then
self.Time:SetFormattedText("%.1f / %.2f", abs(self.value - self.max), self.max)
elseif frameType == 'ENEMY_NPC' or frameType == 'FRIENDLY_NPC' then
local target = self.curTarget or UnitName(unit..'target')
if target and target ~= '' and target ~= plate.unitName then
self.Text:SetText(self.spellName..' > '..target)
end
end
end
self:SetValue(self.value)
elseif self.holdTime > 0 then
self.holdTime = self.holdTime - elapsed
else
resetAttributes(self)
self:Hide()
NP:StyleFilterUpdate(self:GetParent(), "FAKE_Casting")
NP:StyleFilterUpdate(plate, 'FAKE_Cast')
end
end
function NP:Update_CastBar(frame, event, unit)
local castBar = frame.CastBar
if unit then
if not event then
if UnitChannelInfo(unit) then
event = "UNIT_SPELLCAST_CHANNEL_START"
elseif UnitCastingInfo(unit) then
event = "UNIT_SPELLCAST_START"
end
end
elseif castBar:IsShown() then
resetAttributes(castBar)
castBar:Hide()
function NP:Castbar_PostCastFail()
NP:StyleFilterUpdate(self.__owner, 'FAKE_Cast')
self:SetStatusBarColor(NP.db.colors.castInterruptedColor.r, NP.db.colors.castInterruptedColor.g, NP.db.colors.castInterruptedColor.b)
end
function NP:Castbar_PostCastInterruptible(unit)
self:CheckInterrupt(unit)
end
function NP:Castbar_PostCastStop()
NP:StyleFilterUpdate(self.__owner, 'FAKE_Cast')
end
function NP:Construct_Castbar(nameplate)
local castbar = CreateFrame('StatusBar', nameplate:GetName()..'Castbar', nameplate)
castbar:SetParent(nameplate)
castbar:CreateBackdrop('Transparent', nil, nil, nil, nil, true, true)
castbar:SetStatusBarTexture(LSM:Fetch('statusbar', NP.db.statusbar))
NP.StatusBars[castbar] = true
castbar.ModuleStatusBars = NP.StatusBars -- not oUF
castbar.Button = CreateFrame('Frame', nil, castbar)
castbar.Button:SetTemplate(nil, nil, nil, nil, nil, true, true)
castbar.Icon = castbar.Button:CreateTexture(nil, 'ARTWORK')
castbar.Icon:SetParent(castbar.Button)
castbar.Icon:SetTexCoord(unpack(E.TexCoords))
castbar.Icon:SetInside()
castbar.Time = castbar:CreateFontString(nil, 'OVERLAY')
castbar.Time:FontTemplate(LSM:Fetch('font', NP.db.font), NP.db.fontSize, NP.db.fontOutline)
castbar.Time:Point('RIGHT', castbar, 'RIGHT', -4, 0)
castbar.Time:SetJustifyH('RIGHT')
castbar.Text = castbar:CreateFontString(nil, 'OVERLAY')
castbar.Text:FontTemplate(LSM:Fetch('font', NP.db.font), NP.db.fontSize, NP.db.fontOutline)
castbar.Text:Point('LEFT', castbar, 'LEFT', 4, 0)
castbar.Text:SetJustifyH('LEFT')
castbar.Text:SetWordWrap(false)
castbar.CheckInterrupt = NP.Castbar_CheckInterrupt
castbar.CustomDelayText = NP.Castbar_CustomDelayText
castbar.CustomTimeText = NP.Castbar_CustomTimeText
castbar.PostCastStart = NP.Castbar_PostCastStart
castbar.PostCastFail = NP.Castbar_PostCastFail
castbar.PostCastInterruptible = NP.Castbar_PostCastInterruptible
castbar.PostCastStop = NP.Castbar_PostCastStop
if nameplate == _G.ElvNP_Test then
castbar.Hide = castbar.Show
castbar:Show()
castbar.Text:SetText('Casting')
castbar.Time:SetText('3.1')
castbar.Icon:SetTexture([[Interface\Icons\Achievement_Character_Pandaren_Female]])
castbar:SetStatusBarColor(NP.db.colors.castColor.r, NP.db.colors.castColor.g, NP.db.colors.castColor.b)
end
if self.db.units[frame.UnitType].castbar.enable ~= true then return end
if self.db.units[frame.UnitType].health.enable ~= true and not (frame.isTarget and self.db.alwaysShowTargetHealth) then return end --Bug
return castbar
end
if event == "UNIT_SPELLCAST_START" or event == "UNIT_SPELLCAST_CHANNEL_START" then
local name, _, _, texture, startTime, endTime, _, _, notInterruptible = UnitCastingInfo(unit)
event = "UNIT_SPELLCAST_START"
if not name then
name, _, _, texture, startTime, endTime, _, notInterruptible = UnitChannelInfo(unit)
event = "UNIT_SPELLCAST_CHANNEL_START"
function NP:CASTBAR_COMBAT_LOG_EVENT_UNFILTERED(event, sourceGUID, sourceName, targetGUID)
if (event == 'SPELL_INTERRUPT' or event == 'SPELL_PERIODIC_INTERRUPT') and targetGUID and (sourceName and sourceName ~= '') then
local plate, classColor = NP.PlateGUID[targetGUID]
if plate and plate.Castbar then
local db = NP:PlateDB(plate)
if db.castbar and db.castbar.enable and db.castbar.sourceInterrupt and (db.castbar.timeToHold > 0) then
local name = strmatch(sourceName, '([^%-]+).*')
if db.castbar.sourceInterruptClassColor then
local data = CH:GetPlayerInfoByGUID(sourceGUID)
if data and data.classColor then
classColor = data.classColor.colorStr
end
plate.Castbar.Text:SetFormattedText('%s > %s', INTERRUPTED, classColor and strjoin('', '|c', classColor, name) or name)
else
plate.Castbar.Text:SetFormattedText('%s > %s', INTERRUPTED, name)
end
end
end
end
end
function NP:Update_Castbar(nameplate)
local frameDB = NP:PlateDB(nameplate)
local db = frameDB.castbar
local castbar = nameplate.Castbar
if nameplate == _G.ElvNP_Test then
castbar:SetAlpha((not frameDB.nameOnly and db.enable) and 1 or 0)
end
if db.enable then
if not nameplate:IsElementEnabled('Castbar') then
nameplate:EnableElement('Castbar')
end
if not name then
resetAttributes(castBar)
castBar:Hide()
return
end
castbar.timeToHold = db.timeToHold
castbar.castTimeFormat = db.castTimeFormat
castbar.channelTimeFormat = db.channelTimeFormat
endTime = endTime / 1000
startTime = startTime / 1000
castbar:Size(db.width, db.height)
castbar:Point('CENTER', nameplate, 'CENTER', db.xOffset, db.yOffset)
castBar.max = endTime - startTime
castBar.startTime = startTime
castBar.delay = 0
castBar.casting = event == "UNIT_SPELLCAST_START"
castBar.channeling = event == "UNIT_SPELLCAST_CHANNEL_START"
castBar.notInterruptible = notInterruptible
castBar.holdTime = 0
castBar.interrupted = nil
castBar.spellName = name
if castBar.casting then
castBar.value = GetTime() - startTime
if db.showIcon then
castbar.Button:ClearAllPoints()
castbar.Button:Point(db.iconPosition == 'RIGHT' and 'BOTTOMLEFT' or 'BOTTOMRIGHT', castbar, db.iconPosition == 'RIGHT' and 'BOTTOMRIGHT' or 'BOTTOMLEFT', db.iconOffsetX, db.iconOffsetY)
castbar.Button:Size(db.iconSize, db.iconSize)
castbar.Button:Show()
else
castBar.value = endTime - GetTime()
castbar.Button:Hide()
end
castBar:SetMinMaxValues(0, castBar.max)
castBar:SetValue(castBar.value)
castbar.Time:ClearAllPoints()
castbar.Text:ClearAllPoints()
castBar.Icon.texture:SetTexture(texture)
castBar.Spark:Show()
castBar.Name:SetText(name)
castBar.Time:SetText()
castBar:Show()
elseif event == "UNIT_SPELLCAST_STOP" or event == "UNIT_SPELLCAST_CHANNEL_STOP" then
if castBar:IsShown() then
resetAttributes(castBar)
end
elseif event == "UNIT_SPELLCAST_FAILED" or event == "UNIT_SPELLCAST_INTERRUPTED" then
if castBar:IsShown() then
castBar.Spark:Hide()
castBar.Name:SetText(event == "UNIT_SPELLCAST_FAILED" and FAILED or INTERRUPTED)
castBar.holdTime = self.db.units[frame.UnitType].castbar.timeToHold --How long the castbar should stay visible after being interrupted, in seconds
castBar.interrupted = true
resetAttributes(castBar)
castBar:SetValue(castBar.max)
end
elseif event == "UNIT_SPELLCAST_DELAYED" or event == "UNIT_SPELLCAST_CHANNEL_UPDATE" then
if frame:IsShown() then
local name, startTime, endTime, _
if event == "UNIT_SPELLCAST_DELAYED" then
name, _, _, _, startTime, endTime = UnitCastingInfo(unit)
else
name, _, _, _, startTime, endTime = UnitChannelInfo(unit)
end
if not name then
resetAttributes(castBar)
castBar:Hide()
return
end
endTime = endTime / 1000
startTime = startTime / 1000
local delta
if castBar.casting then
delta = startTime - castBar.startTime
castBar.value = GetTime() - startTime
else
delta = castBar.startTime - startTime
castBar.value = endTime - GetTime()
end
if delta < 0 then
delta = 0
end
castBar.Name:SetText(name)
castBar.max = endTime - startTime
castBar.startTime = startTime
castBar.delay = castBar.delay + delta
castBar:SetMinMaxValues(0, castBar.max)
castBar:SetValue(castBar.value)
end
elseif event == "UNIT_SPELLCAST_INTERRUPTIBLE" or event == "UNIT_SPELLCAST_NOT_INTERRUPTIBLE" then
castBar.notInterruptible = event == "UNIT_SPELLCAST_NOT_INTERRUPTIBLE"
end
if not castBar.notInterruptible then
if castBar.interrupted then
castBar:SetStatusBarColor(self.db.colors.castInterruptedColor.r, self.db.colors.castInterruptedColor.g, self.db.colors.castInterruptedColor.b)
if db.textPosition == 'BELOW' then
castbar.Time:Point('TOPRIGHT', castbar, 'BOTTOMRIGHT', db.timeXOffset, db.timeYOffset)
castbar.Text:Point('TOPLEFT', castbar, 'BOTTOMLEFT', db.textXOffset, db.textYOffset)
elseif db.textPosition == 'ABOVE' then
castbar.Time:Point('BOTTOMRIGHT', castbar, 'TOPRIGHT', db.timeXOffset, db.timeYOffset)
castbar.Text:Point('BOTTOMLEFT', castbar, 'TOPLEFT', db.textXOffset, db.textYOffset)
else
castBar:SetStatusBarColor(self.db.colors.castColor.r, self.db.colors.castColor.g, self.db.colors.castColor.b)
end
castBar.Icon.texture:SetDesaturated(false)
else
castBar:SetStatusBarColor(self.db.colors.castNoInterruptColor.r, self.db.colors.castNoInterruptColor.g, self.db.colors.castNoInterruptColor.b)
if self.db.colors.castbarDesaturate then
castBar.Icon.texture:SetDesaturated(true)
end
end
self:StyleFilterUpdate(frame, "FAKE_Casting")
end
function NP:Configure_CastBarScale(frame, scale, noPlayAnimation)
if frame.currentScale == scale then return end
local db = self.db.units[frame.UnitType].castbar
if not db.enable then return end
local castBar = frame.CastBar
if noPlayAnimation then
castBar:SetSize(db.width * scale, db.height * scale)
castBar.Icon:SetSize(db.iconSize * scale, db.iconSize * scale)
else
if castBar.scale:IsPlaying() or castBar.Icon.scale:IsPlaying() then
castBar.scale:Stop()
castBar.Icon.scale:Stop()
castbar.Time:Point('RIGHT', castbar, 'RIGHT', db.timeXOffset, db.timeYOffset)
castbar.Text:Point('LEFT', castbar, 'LEFT', db.textXOffset, db.textYOffset)
end
castBar.scale.width:SetChange(db.width * scale)
castBar.scale.height:SetChange(db.height * scale)
castBar.scale:Play()
if db.hideTime then
castbar.Time:Hide()
else
castbar.Time:FontTemplate(LSM:Fetch('font', db.font), db.fontSize, db.fontOutline)
castbar.Time:Show()
end
castBar.Icon.scale.width:SetChange(db.iconSize * scale)
castBar.Icon.scale.height:SetChange(db.iconSize * scale)
castBar.Icon.scale:Play()
if db.hideSpellName then
castbar.Text:Hide()
else
castbar.Text:FontTemplate(LSM:Fetch('font', db.font), db.fontSize, db.fontOutline)
castbar.Text:Show()
end
elseif nameplate:IsElementEnabled('Castbar') then
nameplate:DisableElement('Castbar')
end
end
function NP:Configure_CastBar(frame, configuring)
local db = self.db.units[frame.UnitType].castbar
local castBar = frame.CastBar
castBar:SetPoint("TOP", frame.Health, "BOTTOM", db.xOffset, db.yOffset)
if db.showIcon then
castBar.Icon:ClearAllPoints()
castBar.Icon:SetPoint(db.iconPosition == "RIGHT" and "BOTTOMLEFT" or "BOTTOMRIGHT", castBar, db.iconPosition == "RIGHT" and "BOTTOMRIGHT" or "BOTTOMLEFT", db.iconOffsetX, db.iconOffsetY)
castBar.Icon:Show()
else
castBar.Icon:Hide()
end
castBar.Time:ClearAllPoints()
castBar.Name:ClearAllPoints()
castBar.Spark:SetPoint("CENTER", castBar:GetStatusBarTexture(), "RIGHT", 0, 0)
castBar.Spark:SetHeight(db.height * 2)
if db.textPosition == "BELOW" then
castBar.Time:SetPoint("TOPRIGHT", castBar, "BOTTOMRIGHT")
castBar.Name:SetPoint("TOPLEFT", castBar, "BOTTOMLEFT")
elseif db.textPosition == "ABOVE" then
castBar.Time:SetPoint("BOTTOMRIGHT", castBar, "TOPRIGHT")
castBar.Name:SetPoint("BOTTOMLEFT", castBar, "TOPLEFT")
else
castBar.Time:SetPoint("RIGHT", castBar, "RIGHT", -4, 0)
castBar.Name:SetPoint("LEFT", castBar, "LEFT", 4, 0)
end
if configuring then
self:Configure_CastBarScale(frame, frame.currentScale or 1, configuring)
end
castBar.Name:FontTemplate(LSM:Fetch("font", db.font), db.fontSize, db.fontOutline)
castBar.Time:FontTemplate(LSM:Fetch("font", db.font), db.fontSize, db.fontOutline)
if db.hideSpellName then
castBar.Name:Hide()
else
castBar.Name:Show()
end
if db.hideTime then
castBar.Time:Hide()
else
castBar.Time:Show()
end
castBar:SetStatusBarTexture(LSM:Fetch("statusbar", self.db.statusbar))
castBar.castTimeFormat = db.castTimeFormat
castBar.channelTimeFormat = db.channelTimeFormat
end
function NP:Construct_CastBar(parent)
local frame = CreateFrame("StatusBar", "$parentCastBar", parent)
NP:StyleFrame(frame)
frame:SetScript("OnUpdate", NP.Update_CastBarOnUpdate)
frame.Icon = CreateFrame("Frame", nil, frame)
frame.Icon.texture = frame.Icon:CreateTexture(nil, "BORDER")
frame.Icon.texture:SetAllPoints()
frame.Icon.texture:SetTexCoord(unpack(E.TexCoords))
NP:StyleFrame(frame.Icon)
frame.Time = frame:CreateFontString(nil, "OVERLAY")
frame.Time:SetJustifyH("RIGHT")
frame.Time:SetWordWrap(false)
frame.Name = frame:CreateFontString(nil, "OVERLAY")
frame.Name:SetJustifyH("LEFT")
frame.Name:SetWordWrap(false)
frame.Spark = frame:CreateTexture(nil, "OVERLAY")
frame.Spark:SetTexture([[Interface\CastingBar\UI-CastingBar-Spark]])
frame.Spark:SetBlendMode("ADD")
frame.Spark:SetSize(15, 15)
frame.holdTime = 0
frame.interrupted = nil
frame.scale = CreateAnimationGroup(frame)
frame.scale.width = frame.scale:CreateAnimation("Width")
frame.scale.width:SetDuration(0.2)
frame.scale.height = frame.scale:CreateAnimation("Height")
frame.scale.height:SetDuration(0.2)
frame.Icon.scale = CreateAnimationGroup(frame.Icon)
frame.Icon.scale.width = frame.Icon.scale:CreateAnimation("Width")
frame.Icon.scale.width:SetDuration(0.2)
frame.Icon.scale.height = frame.Icon.scale:CreateAnimation("Height")
frame.Icon.scale.height:SetDuration(0.2)
frame:Hide()
return frame
end
@@ -0,0 +1,310 @@
local E, L, V, P, G = unpack(ElvUI)
local NP = E:GetModule('NamePlates')
local UF = E:GetModule('UnitFrames')
local LSM = E.Libs.LSM
local _G = _G
local max, next, ipairs = max, next, ipairs
local CreateFrame = CreateFrame
local UnitHasVehicleUI = UnitHasVehicleUI
local MAX_COMBO_POINTS = MAX_COMBO_POINTS
local MAX_POINTS = { -- match to UF.classMaxResourceBar
DEATHKNIGHT = max(6, MAX_COMBO_POINTS),
ROGUE = max(7, MAX_COMBO_POINTS),
HERO = max(5, MAX_COMBO_POINTS),
DRUID = max(5, MAX_COMBO_POINTS)
}
function NP:ClassPower_SetBarColor(bar, r, g, b)
bar:SetStatusBarColor(r, g, b)
if bar.bg then
bar.bg:SetVertexColor(r * NP.multiplier, g * NP.multiplier, b * NP.multiplier)
end
end
function NP:ClassPower_UpdateColor(powerType, rune)
local isRunes = powerType == 'RUNES'
local classPower = self.classColor
local colors = NP.db.colors.classResources
local fallback = NP.db.colors.power[powerType]
if isRunes and NP.db.colors.chargingRunes then
NP:Runes_UpdateCharged(self, rune)
elseif isRunes and rune and not classPower then
local color = colors.DEATHKNIGHT[rune.runeType or 0]
NP:ClassPower_SetBarColor(rune, color.r, color.g, color.b)
else
local classColor = not classPower and ((isRunes and colors.DEATHKNIGHT) or (powerType == 'COMBO_POINTS' and colors.comboPoints) or (powerType == 'ESSENCE' and colors.EVOKER) or (powerType == 'CHI' and colors.MONK))
for i, bar in ipairs(self) do
local color = classPower or (isRunes and classColor[bar.runeType or 0]) or (classColor and classColor[i]) or colors[E.myclass] or fallback
NP:ClassPower_SetBarColor(bar, color.r, color.g, color.b)
end
end
end
function NP:ClassPower_PostUpdate(Cur, _, needUpdate, powerType, chargedPoints)
if Cur and Cur > 0 then
self:Show()
else
self:Hide()
end
if needUpdate then
NP:Update_ClassPower(self.__owner)
end
if powerType == 'COMBO_POINTS' and E.myclass == 'ROGUE' then
NP.ClassPower_UpdateColor(self, powerType)
if chargedPoints then
local color = NP.db.colors.classResources.chargedComboPoint
for _, chargedIndex in next, chargedPoints do
self[chargedIndex]:SetStatusBarColor(color.r, color.g, color.b)
self[chargedIndex].bg:SetVertexColor(color.r * NP.multiplier, color.g * NP.multiplier, color.b * NP.multiplier)
end
end
end
end
function NP:Construct_ClassPower(nameplate)
local frameName = nameplate:GetName()
local ClassPower = CreateFrame('Frame', frameName..'ClassPower', nameplate)
ClassPower:CreateBackdrop('Transparent', nil, nil, nil, nil, true, true)
ClassPower:Hide()
local texture = LSM:Fetch('statusbar', NP.db.statusbar)
local total = MAX_POINTS[E.myclass] or 0
for i = 1, total do
local bar = CreateFrame('StatusBar', frameName..'ClassPower'..i, ClassPower)
bar:SetStatusBarTexture(texture)
NP.StatusBars[bar] = true
bar.bg = ClassPower:CreateTexture(frameName..'ClassPower'..i..'bg', 'BORDER')
bar.bg:SetTexture(texture)
bar.bg:SetAllPoints()
if nameplate == _G.ElvNP_Test then
local combo = NP.db.colors.classResources.comboPoints[i]
bar.bg:SetVertexColor(combo.r, combo.g, combo.b)
end
ClassPower[i] = bar
end
if nameplate == _G.ElvNP_Test then
ClassPower.Hide = ClassPower.Show
ClassPower:Show()
end
ClassPower.UpdateColor = NP.ClassPower_UpdateColor
ClassPower.PostUpdate = NP.ClassPower_PostUpdate
return ClassPower
end
function NP:Update_ClassPower(nameplate)
local db = NP:PlateDB(nameplate)
if nameplate == _G.ElvNP_Test then
if not db.nameOnly and db.classpower and db.classpower.enable then
NP.ClassPower_UpdateColor(nameplate.ClassPower, 'COMBO_POINTS')
nameplate.ClassPower:SetAlpha(1)
else
nameplate.ClassPower:SetAlpha(0)
end
end
local target = nameplate.frameType == 'TARGET'
if (target or nameplate.frameType == 'PLAYER') and db.classpower and db.classpower.enable then
if not nameplate:IsElementEnabled('ClassPower') then
nameplate:EnableElement('ClassPower')
end
local anchor = target and NP:GetClassAnchor()
nameplate.ClassPower:ClearAllPoints()
nameplate.ClassPower:Point('CENTER', anchor or nameplate, 'CENTER', db.classpower.xOffset, db.classpower.yOffset)
nameplate.ClassPower:Size(db.classpower.width, db.classpower.height)
nameplate.ClassPower.classColor = db.classpower.classColor and RAID_CLASS_COLORS[E.myclass]
for i = 1, #nameplate.ClassPower do
nameplate.ClassPower[i]:Hide()
nameplate.ClassPower[i].bg:Hide()
end
local maxButtons = nameplate.ClassPower.__max
if maxButtons > 0 then
local Width = db.classpower.width / maxButtons
for i = 1, maxButtons do
local button = nameplate.ClassPower[i]
button:Show()
button.bg:Show()
button:ClearAllPoints()
if i == 1 then
local width = Width - (maxButtons == 6 and 2 or 0)
button:Point('LEFT', nameplate.ClassPower, 'LEFT', 0, 0)
button:Size(width, db.classpower.height)
else
button:Point('LEFT', nameplate.ClassPower[i - 1], 'RIGHT', 1, 0)
button:Size(Width - 1, db.classpower.height)
if i == maxButtons then
button:Point('RIGHT', nameplate.ClassPower)
end
end
end
end
else
if nameplate:IsElementEnabled('ClassPower') then
nameplate:DisableElement('ClassPower')
end
nameplate.ClassPower:Hide()
end
end
function NP:Runes_UpdateCharged(runes, rune)
local colors = NP.db.colors.classResources.DEATHKNIGHT
local classColor = (runes and runes.classColor) or (rune and rune.__owner and rune.__owner.classColor)
if rune then
NP:ClassPower_SetBarColor(rune, UF:Runes_GetColor(rune, colors, classColor))
elseif runes then
for _, bar in ipairs(runes) do
NP:ClassPower_SetBarColor(bar, UF:Runes_GetColor(bar, colors, classColor))
end
end
end
function NP:Runes_PostUpdate()
self:SetShown(not UnitHasVehicleUI('player'))
if NP.db.colors.chargingRunes then
NP:Runes_UpdateCharged(self)
end
end
function NP:Runes_UpdateChargedColor()
if NP.db.colors.chargingRunes then
NP:Runes_UpdateCharged(nil, self)
end
end
function NP:Runes_PostUpdateColor(r, g, b, color, rune)
NP.ClassPower_UpdateColor(self, 'RUNES', rune)
end
function NP:Construct_Runes(nameplate)
local frameName = nameplate:GetName()
local Runes = CreateFrame('Frame', frameName..'Runes', nameplate)
Runes:SetFrameStrata("BACKGROUND")
Runes:CreateBackdrop('Transparent', nil, nil, nil, nil, true, true)
Runes:Hide()
Runes.PostUpdate = NP.Runes_PostUpdate
Runes.PostUpdateColor = NP.Runes_PostUpdateColor
local texture = LSM:Fetch('statusbar', NP.db.statusbar)
local color = NP.db.colors.classResources.DEATHKNIGHT[0]
for i = 1, 6 do
local rune = CreateFrame('StatusBar', frameName..'Runes'..i, Runes)
rune:SetStatusBarTexture(texture)
rune:SetStatusBarColor(color.r, color.g, color.b)
rune.PostUpdateColor = NP.Runes_UpdateChargedColor
rune.__owner = Runes
NP.StatusBars[rune] = true
rune.bg = rune:CreateTexture(frameName..'Runes'..i..'bg', 'BORDER')
rune.bg:SetVertexColor(color.r * NP.multiplier, color.g * NP.multiplier, color.b * NP.multiplier)
rune.bg:SetTexture(texture)
rune.bg:SetAllPoints()
rune.bg.multiplier = 0.35
Runes[i] = rune
end
return Runes
end
function NP:Update_Runes(nameplate)
local db = NP:PlateDB(nameplate)
local target = nameplate.frameType == 'TARGET'
if (target or nameplate.frameType == 'PLAYER') and db.classpower and db.classpower.enable then
if not nameplate:IsElementEnabled('Runes') then
nameplate:EnableElement('Runes')
end
local anchor = target and NP:GetClassAnchor()
nameplate.Runes:ClearAllPoints()
nameplate.Runes:Point('CENTER', anchor or nameplate, 'CENTER', db.classpower.xOffset, db.classpower.yOffset)
nameplate.Runes:Show()
nameplate.Runes.classColor = db.classpower.classColor and RAID_CLASS_COLORS[E.myclass]
nameplate.Runes.sortOrder = (db.classpower.sortDirection ~= 'NONE') and db.classpower.sortDirection
nameplate.Runes.colorSpec = NP.db.colors.runeBySpec
local width = db.classpower.width / 6
nameplate.Runes:Size(db.classpower.width, db.classpower.height)
for i = 1, 6 do
local rune = nameplate.Runes[i]
if i == 1 then
rune:Size(width, db.classpower.height)
rune:ClearAllPoints()
rune:Point('LEFT', nameplate.Runes, 'LEFT', 0, 0)
else
rune:Size(width - 1, db.classpower.height)
rune:ClearAllPoints()
rune:Point('LEFT', nameplate.Runes[i-1], 'RIGHT', 1, 0)
if i == 6 then
rune:Point('RIGHT', nameplate.Runes)
end
end
end
else
if nameplate:IsElementEnabled('Runes') then
nameplate:DisableElement('Runes')
end
nameplate.Runes:Hide()
end
end
function NP:Construct_Stagger(nameplate)
local Stagger = CreateFrame('StatusBar', nameplate:GetName()..'Stagger', nameplate)
Stagger:SetStatusBarTexture(LSM:Fetch('statusbar', NP.db.statusbar))
Stagger:CreateBackdrop('Transparent', nil, nil, nil, nil, true, true)
Stagger:Hide()
NP.StatusBars[Stagger] = true
return Stagger
end
function NP:Update_Stagger(nameplate)
local db = NP:PlateDB(nameplate)
local target = nameplate.frameType == 'TARGET'
if (target or nameplate.frameType == 'PLAYER') and db.classpower and db.classpower.enable then
if not nameplate:IsElementEnabled('Stagger') then
nameplate:EnableElement('Stagger')
end
local anchor = target and NP:GetClassAnchor()
nameplate.Stagger:ClearAllPoints()
nameplate.Stagger:Point('CENTER', anchor or nameplate, 'CENTER', db.classpower.xOffset, db.classpower.yOffset)
nameplate.Stagger:Size(db.classpower.width, db.classpower.height)
elseif nameplate:IsElementEnabled('Stagger') then
nameplate:DisableElement('Stagger')
end
end
@@ -0,0 +1,302 @@
local E, L, V, P, G = unpack(ElvUI)
local NP = E:GetModule('NamePlates')
local UF = E:GetModule('UnitFrames')
local LSM = E.Libs.LSM
local ipairs = ipairs
local unpack = unpack
local UnitPlayerControlled = UnitPlayerControlled
local UnitClass = UnitClass
local UnitReaction = UnitReaction
local UnitIsConnected = UnitIsConnected
local CreateFrame = CreateFrame
function NP:Health_UpdateColor(_, unit)
if unit and self.isNamePlate and unit:sub(1, 9) ~= "nameplate" then
local isUnit = self.unit and UnitIsUnit(self.unit, unit)
if isUnit then
unit = self.unit
end
end
if not unit or self.unit ~= unit then return end
local element = self.Health
local r, g, b, t
if element.colorDisconnected and not UnitIsConnected(unit) then
t = self.colors.disconnected
elseif (element.colorClass and self.isPlayer) or (element.colorClassNPC and not self.isPlayer) or (element.colorClassPet and UnitPlayerControlled(unit) and not self.isPlayer) then
local _, class = UnitClass(unit)
t = self.colors.class[class]
elseif element.colorReaction and UnitReaction(unit, 'player') then
local reaction = UnitReaction(unit, 'player')
t = NP.db.colors.reactions[reaction == 4 and 'neutral' or reaction <= 3 and 'bad' or 'good']
elseif element.colorSmooth then
r, g, b = self:ColorGradient(element.cur or 1, element.max or 1, unpack(element.smoothGradient or self.colors.smooth))
elseif element.colorHealth then
t = NP.db.colors.health
end
if t then
r, g, b = t.r, t.g, t.b
element.r, element.g, element.b = r, g, b -- save these for the style filter to switch back
end
local sf = NP:StyleFilterChanges(self)
if sf.HealthColor then
r, g, b = sf.HealthColor.r, sf.HealthColor.g, sf.HealthColor.b
end
if b then
element:SetStatusBarColor(r, g, b)
if element.bg then
element.bg:SetVertexColor(r * NP.multiplier, g * NP.multiplier, b * NP.multiplier)
end
end
if element.PostUpdateColor then
element:PostUpdateColor(unit, r, g, b)
end
end
function NP:Construct_Health(nameplate)
local Health = CreateFrame('StatusBar', nameplate:GetName()..'Health', nameplate)
Health:SetParent(nameplate)
Health:CreateBackdrop('Transparent', nil, nil, nil, nil, true, true)
Health:SetStatusBarTexture(LSM:Fetch('statusbar', NP.db.statusbar))
Health.considerSelectionInCombatHostile = true
Health.UpdateColor = NP.Health_UpdateColor
NP.StatusBars[Health] = true
local statusBarTexture = Health:GetStatusBarTexture()
local healthFlashTexture = Health:CreateTexture(nameplate:GetName()..'FlashTexture', 'OVERLAY')
healthFlashTexture:SetTexture(LSM:Fetch('background', 'ElvUI Blank'))
healthFlashTexture:Point('BOTTOMLEFT', statusBarTexture, 'BOTTOMLEFT')
healthFlashTexture:Point('TOPRIGHT', statusBarTexture, 'TOPRIGHT')
healthFlashTexture:Hide()
nameplate.HealthFlashTexture = healthFlashTexture
local clipFrame = CreateFrame("Frame", nil, Health)
clipFrame:SetScript("OnUpdate", UF.HealthClipFrame_OnUpdate)
clipFrame:SetAllPoints()
clipFrame:EnableMouse(false)
clipFrame.__frame = Health
Health.ClipFrame = clipFrame
return Health
end
function NP:Health_SetColors(nameplate, threatColors)
if threatColors then -- managed by ThreatIndicator_PostUpdate
nameplate.Health:SetColorTapping(nil)
nameplate.Health:SetColorSelection(nil)
nameplate.Health.colorReaction = nil
nameplate.Health.colorClass = nil
else
local db = NP:PlateDB(nameplate)
nameplate.Health:SetColorTapping(true)
nameplate.Health:SetColorSelection(true)
nameplate.Health.colorReaction = true
nameplate.Health.colorClass = db.health and db.health.useClassColor
end
end
function NP:Update_Health(nameplate, skipUpdate)
local db = NP:PlateDB(nameplate)
NP:Health_SetColors(nameplate)
if skipUpdate then return end
if db.health.enable then
if not nameplate:IsElementEnabled('Health') then
nameplate:EnableElement('Health')
end
nameplate.Health:Point('CENTER')
nameplate.Health:Point('LEFT')
nameplate.Health:Point('RIGHT')
E:SetSmoothing(nameplate.Health, NP.db.smoothbars)
elseif nameplate:IsElementEnabled('Health') then
nameplate:DisableElement('Health')
end
nameplate.Health.width = db.health.width
nameplate.Health.height = db.health.height
nameplate.Health:Height(db.health.height)
end
function NP:Update_HealComm(nameplate)
local db = NP:PlateDB(nameplate)
if db.health.enable and db.health.healPrediction then
if not nameplate:IsElementEnabled('HealCommBar') then
nameplate:EnableElement('HealCommBar')
end
nameplate.HealCommBar.myBar:SetStatusBarColor(NP.db.colors.healPrediction.personal.r, NP.db.colors.healPrediction.personal.g, NP.db.colors.healPrediction.personal.b)
nameplate.HealCommBar.otherBar:SetStatusBarColor(NP.db.colors.healPrediction.others.r, NP.db.colors.healPrediction.others.g, NP.db.colors.healPrediction.others.b)
elseif nameplate:IsElementEnabled('HealCommBar') then
nameplate:DisableElement('HealCommBar')
end
end
function NP.HealthClipFrame_HealComm(frame)
local pred = frame.HealCommBar
if pred then
NP:SetAlpha_HealComm(pred, true)
NP:SetVisibility_HealComm(pred)
end
end
function NP:SetAlpha_HealComm(obj, show)
obj.myBar:SetAlpha(show and 1 or 0)
obj.otherBar:SetAlpha(show and 1 or 0)
end
function NP:SetVisibility_HealComm(obj)
-- the first update is from `HealthClipFrame_HealComm`
-- we set this variable to allow `Configure_HealComm` to
-- update the elements overflow lock later on by option
if not obj.allowClippingUpdate then
obj.allowClippingUpdate = true
end
if obj.maxOverflow > 1 then
obj.myBar:SetParent(obj.health)
obj.otherBar:SetParent(obj.health)
else
obj.myBar:SetParent(obj.parent)
obj.otherBar:SetParent(obj.parent)
end
end
function NP:Construct_HealComm(frame)
local health = frame.Health
local parent = health.ClipFrame
local myBar = CreateFrame("StatusBar", nil, parent)
local otherBar = CreateFrame("StatusBar", nil, parent)
myBar:SetFrameLevel(health:GetFrameLevel()+1)
otherBar:SetFrameLevel(health:GetFrameLevel()+1)
NP.StatusBars[myBar] = true
NP.StatusBars[otherBar] = true
local healPrediction = {
myBar = myBar,
otherBar = otherBar,
PostUpdate = NP.UpdateHealComm,
maxOverflow = 1,
health = health,
parent = parent,
frame = frame
}
NP:SetAlpha_HealComm(healPrediction)
return healPrediction
end
function NP:Configure_HealComm(frame)
local db = NP:PlateDB(frame)
if db.health.enable and db.health.healPrediction then
if not frame:IsElementEnabled('HealComm4') then
frame:EnableElement('HealComm4')
end
local healPrediction = frame.HealCommBar
local c = db.colors.healPrediction
healPrediction.maxOverflow = 1 + (c.maxOverflow or 0)
if healPrediction.allowClippingUpdate then
NP:SetVisibility_HealComm(healPrediction)
end
local health = frame.Health
local orientation = health:GetOrientation()
local myBar = healPrediction.myBar
local otherBar = healPrediction.otherBar
myBar:SetOrientation(orientation)
otherBar:SetOrientation(orientation)
if orientation == "HORIZONTAL" then
local width = health:GetWidth()
width = (width > 0 and width) or health.WIDTH
local healthTexture = health:GetStatusBarTexture()
myBar:Size(width, 0)
myBar:ClearAllPoints()
myBar:Point("TOP", health, "TOP")
myBar:Point("BOTTOM", health, "BOTTOM")
myBar:Point("LEFT", healthTexture, "RIGHT")
otherBar:Size(width, 0)
otherBar:ClearAllPoints()
otherBar:Point("TOP", health, "TOP")
otherBar:Point("BOTTOM", health, "BOTTOM")
otherBar:Point("LEFT", myBar:GetStatusBarTexture(), "RIGHT")
else
local height = health:GetHeight()
height = (height > 0 and height) or health.HEIGHT
local healthTexture = health:GetStatusBarTexture()
myBar:Size(0, height)
myBar:ClearAllPoints()
myBar:Point("LEFT", health, "LEFT")
myBar:Point("RIGHT", health, "RIGHT")
myBar:Point("BOTTOM", healthTexture, "TOP")
otherBar:Size(0, height)
otherBar:ClearAllPoints()
otherBar:Point("LEFT", health, "LEFT")
otherBar:Point("RIGHT", health, "RIGHT")
otherBar:Point("BOTTOM", myBar:GetStatusBarTexture(), "TOP")
end
frame.HealCommBar.myBar:SetStatusBarColor(NP.db.colors.healPrediction.personal.r, NP.db.colors.healPrediction.personal.g, NP.db.colors.healPrediction.personal.b)
frame.HealCommBar.otherBar:SetStatusBarColor(NP.db.colors.healPrediction.others.r, NP.db.colors.healPrediction.others.g, NP.db.colors.healPrediction.others.b)
elseif frame:IsElementEnabled('HealComm4') then
frame:DisableElement('HealComm4')
end
end
local function UpdateFillBar(frame, previousTexture, bar, amount)
if amount == 0 then
bar:Hide()
return previousTexture
end
local orientation = frame:GetOrientation()
bar:ClearAllPoints()
if orientation == "HORIZONTAL" then
bar:SetPoint("TOPLEFT", previousTexture, "TOPRIGHT")
bar:SetPoint("BOTTOMLEFT", previousTexture, "BOTTOMRIGHT")
else
bar:SetPoint("BOTTOMRIGHT", previousTexture, "TOPRIGHT")
bar:SetPoint("BOTTOMLEFT", previousTexture, "TOPLEFT")
end
local totalWidth, totalHeight = frame:GetSize()
if orientation == "HORIZONTAL" then
bar:Width(totalWidth)
else
bar:Height(totalHeight)
end
return bar:GetStatusBarTexture()
end
function NP:UpdateHealComm(_, myIncomingHeal, allIncomingHeal)
local health = self.health
local previousTexture = health:GetStatusBarTexture()
previousTexture = UpdateFillBar(health, previousTexture, self.myBar, myIncomingHeal)
UpdateFillBar(health, previousTexture, self.otherBar, allIncomingHeal)
end
@@ -0,0 +1,313 @@
local E, L, V, P, G = unpack(ElvUI)
local NP = E:GetModule('NamePlates')
local LSM = E.Libs.LSM
local strfind = strfind
local ipairs, unpack = ipairs, unpack
local CreateFrame = CreateFrame
local targetIndicators = {'Spark', 'TopIndicator', 'LeftIndicator', 'RightIndicator'}
function NP:Construct_QuestIcons(nameplate)
local QuestIcons = CreateFrame('Frame', nameplate:GetName() .. 'QuestIcons', nameplate)
QuestIcons:Size(20)
QuestIcons:Hide()
for _, object in ipairs(NP.QuestIcons.iconTypes) do
local icon = QuestIcons:CreateTexture(nil, 'BORDER', nil, 1)
icon.Text = QuestIcons:CreateFontString(nil, 'OVERLAY')
icon.Text:FontTemplate()
icon:Hide()
QuestIcons[object] = icon
end
QuestIcons.Item:SetTexCoord(unpack(E.TexCoords))
QuestIcons.Chat:SetTexture([[Interface\WorldMap\ChatBubble_64.PNG]])
QuestIcons.Chat:SetTexCoord(0, 0.5, 0.5, 1)
return QuestIcons
end
function NP:Update_QuestIcons(nameplate)
local plateDB = NP:PlateDB(nameplate)
local db = plateDB.questIcon
if db and db.enable and (nameplate.frameType == 'FRIENDLY_NPC' or nameplate.frameType == 'ENEMY_NPC') then
if not nameplate:IsElementEnabled('QuestIcons') then
nameplate:EnableElement('QuestIcons')
end
nameplate.QuestIcons:ClearAllPoints()
nameplate.QuestIcons:Point(E.InversePoints[db.position], nameplate, db.position, db.xOffset, db.yOffset)
for _, object in ipairs(NP.QuestIcons.iconTypes) do
local icon = nameplate.QuestIcons[object]
icon:Size(db.size, db.size)
icon:SetAlpha(db.hideIcon and 0 or 1)
local xoffset = strfind(db.textPosition, 'LEFT') and -2 or 2
local yoffset = strfind(db.textPosition, 'BOTTOM') and 2 or -2
icon.Text:ClearAllPoints()
icon.Text:Point('CENTER', icon, db.textPosition, xoffset, yoffset)
icon.Text:FontTemplate(LSM:Fetch('font', db.font), db.fontSize, db.fontOutline)
icon.Text:SetJustifyH('CENTER')
icon.size, icon.position = db.size, db.position
end
elseif nameplate:IsElementEnabled('QuestIcons') then
nameplate:DisableElement('QuestIcons')
end
end
function NP:Construct_ClassificationIndicator(nameplate)
return nameplate:CreateTexture(nameplate:GetName() .. 'ClassificationIndicator', 'OVERLAY')
end
function NP:Update_ClassificationIndicator(nameplate)
local plateDB = NP:PlateDB(nameplate)
local db = plateDB.eliteIcon
if db and db.enable and (nameplate.frameType == 'FRIENDLY_NPC' or nameplate.frameType == 'ENEMY_NPC') then
if not nameplate:IsElementEnabled('ClassificationIndicator') then
nameplate:EnableElement('ClassificationIndicator')
end
nameplate.ClassificationIndicator:ClearAllPoints()
nameplate.ClassificationIndicator:Size(db.size, db.size)
nameplate.ClassificationIndicator:Point(E.InversePoints[db.position], nameplate, db.position, db.xOffset, db.yOffset)
elseif nameplate:IsElementEnabled('ClassificationIndicator') then
nameplate:DisableElement('ClassificationIndicator')
end
end
function NP:Construct_TargetIndicator(nameplate)
local TargetIndicator = CreateFrame('Frame', nameplate:GetName() .. 'TargetIndicator', nameplate)
TargetIndicator:SetFrameLevel(nameplate:GetFrameLevel()-1)
TargetIndicator.Shadow = CreateFrame('Frame', nil, TargetIndicator)
TargetIndicator.Shadow:Hide()
for _, object in ipairs(targetIndicators) do
local indicator = TargetIndicator:CreateTexture(nil, 'BACKGROUND')
indicator:Hide()
TargetIndicator[object] = indicator
end
return TargetIndicator
end
function NP:Update_TargetIndicator(nameplate)
local enabled = nameplate:IsElementEnabled('TargetIndicator')
if nameplate.frameType == 'PLAYER' then
if enabled then
nameplate:DisableElement('TargetIndicator')
end
return
elseif not enabled then
nameplate:EnableElement('TargetIndicator')
end
local tdb = NP.db.units.TARGET
local indicator = nameplate.TargetIndicator
indicator.arrow = E.Media.Textures[NP.db.units.TARGET.arrow] or E.Media.Textures.TopIndicator
indicator.lowHealthThreshold = NP.db.lowHealthThreshold
indicator.preferGlowColor = NP.db.colors.preferGlowColor
indicator.style = tdb.glowStyle
if indicator.style ~= 'none' then
local style, color, size, spacing = tdb.glowStyle, NP.db.colors.glowColor, tdb.arrowSize, tdb.arrowSpacing
local r, g, b, a = color.r, color.g, color.b, color.a
local db = NP:PlateDB(nameplate)
-- background glow is 2, 6, and 8; 2 is background glow only
if not db.health.enable and (style ~= 'style2' and style ~= 'style6' and style ~= 'style8') then
style = 'style2'
indicator.style = style
end
-- top arrow is 3, 5, 6
if indicator.TopIndicator and (style == 'style3' or style == 'style5' or style == 'style6') then
indicator.TopIndicator:Point('BOTTOM', nameplate.Health, 'TOP', 0, spacing)
indicator.TopIndicator:SetVertexColor(r, g, b, a)
indicator.TopIndicator:SetSize(size, size)
end
-- side arrows are 4, 7, 8
if indicator.LeftIndicator and indicator.RightIndicator and (style == 'style4' or style == 'style7' or style == 'style8') then
indicator.LeftIndicator:Point('LEFT', nameplate.Health, 'RIGHT', spacing, 0)
indicator.RightIndicator:Point('RIGHT', nameplate.Health, 'LEFT', -spacing, 0)
indicator.LeftIndicator:SetVertexColor(r, g, b, a)
indicator.RightIndicator:SetVertexColor(r, g, b, a)
indicator.LeftIndicator:SetSize(size, size)
indicator.RightIndicator:SetSize(size, size)
end
-- border glow is 1, 5, 7
if indicator.Shadow and (style == 'style1' or style == 'style5' or style == 'style7') then
indicator.Shadow:SetOutside(nameplate.Health, E.PixelMode and 6 or 8, E.PixelMode and 6 or 8, nil, true)
indicator.Shadow:SetBackdropBorderColor(r, g, b)
indicator.Shadow:SetAlpha(a)
end
-- background glow is 2, 6, and 8
if indicator.Spark and (style == 'style2' or style == 'style6' or style == 'style8') then
local size
if db.health.enable and not (db.nameOnly or nameOnlySF) then
parent = nameplate.Health
size = E.Border + 14
else
parent = nameplate
size = -(E.Border + 4)
end
indicator.Spark:Point('TOPLEFT', parent, 'TOPLEFT', -(size * 2), size)
indicator.Spark:Point('BOTTOMRIGHT', parent, 'BOTTOMRIGHT', (size * 2), -size)
indicator.Spark:SetVertexColor(r, g, b, a)
end
end
end
function NP:Construct_Highlight(nameplate)
Highlight = nameplate.nameplateAnchor.blizzHighlight
return Highlight
end
function NP:Update_Highlight(nameplate, nameOnlySF)
local db = NP:PlateDB(nameplate)
if NP.db.highlight and db.enable then
if not nameplate:IsElementEnabled('Highlight') then
nameplate:EnableElement('Highlight')
end
local highlight = nameplate.Highlight
if highlight:GetParent() ~= nameplate then
highlight:SetParent(nameplate)
end
if highlight:GetDrawLayer() ~= "OVERLAY" then
Highlight:SetDrawLayer("OVERLAY")
end
highlight:SetTexture(E.Media.Textures.Spark)
highlight:SetAllPoints(nameplate)
if db.health.enable and not (db.nameOnly or nameOnlySF) then
highlight:SetAlpha(0.75)
else
highlight:SetAlpha(0.50)
end
elseif nameplate:IsElementEnabled('Highlight') then
nameplate:DisableElement('Highlight')
end
end
function NP:Construct_PVPRole(nameplate)
local texture = nameplate:CreateTexture(nameplate:GetName() .. 'PVPRole', 'OVERLAY', nil, 1)
texture:Size(40)
texture.HealerTexture = E.Media.Textures.Healer
texture.TankTexture = E.Media.Textures.Tank
texture:SetTexture(texture.HealerTexture)
texture:Hide()
return texture
end
function NP:Update_PVPRole(nameplate)
local db = NP:PlateDB(nameplate)
if (nameplate.frameType == 'FRIENDLY_PLAYER' or nameplate.frameType == 'ENEMY_PLAYER') and (db.markHealers or db.markTanks) then
if not nameplate:IsElementEnabled('PVPRole') then
nameplate:EnableElement('PVPRole')
end
nameplate.PVPRole.ShowHealers = db.markHealers
nameplate.PVPRole.ShowTanks = db.markTanks
nameplate.PVPRole:Point('RIGHT', nameplate.Health, 'LEFT', -6, 0)
elseif nameplate:IsElementEnabled('PVPRole') then
nameplate:DisableElement('PVPRole')
end
end
function NP:Update_Fader(nameplate)
local db = NP:PlateDB(nameplate)
local vis = db.visibility
if not vis or vis.showAlways then
if nameplate:IsElementEnabled('Fader') then
nameplate:DisableElement('Fader')
NP:PlateFade(nameplate, 0.5, nameplate:GetAlpha(), 1)
end
elseif db.enable then
if not nameplate.Fader then
nameplate.Fader = {}
end
if not nameplate:IsElementEnabled('Fader') then
nameplate:EnableElement('Fader')
nameplate.Fader:SetOption('MinAlpha', 0)
nameplate.Fader:SetOption('Smooth', 0.3)
nameplate.Fader:SetOption('Hover', true)
--nameplate.Fader:SetOption('Power', true)
nameplate.Fader:SetOption('Health', true)
nameplate.Fader:SetOption('Casting', true)
end
nameplate.Fader:SetOption('Combat', vis.showInCombat)
nameplate.Fader:SetOption('PlayerTarget', vis.showWithTarget)
nameplate.Fader:SetOption('DelayAlpha', (vis.alphaDelay > 0 and vis.alphaDelay) or nil)
nameplate.Fader:SetOption('Delay', (vis.hideDelay > 0 and vis.hideDelay) or nil)
nameplate.Fader:ForceUpdate()
end
end
function NP:Construct_Cutaway(nameplate)
local frameName = nameplate:GetName()
local Cutaway = {}
Cutaway.Health = nameplate.Health.ClipFrame:CreateTexture(frameName .. 'CutawayHealth')
local healthTexture = nameplate.Health:GetStatusBarTexture()
Cutaway.Health:Point('TOPLEFT', healthTexture, 'TOPRIGHT')
Cutaway.Health:Point('BOTTOMLEFT', healthTexture, 'BOTTOMRIGHT')
-- Cutaway.Power = nameplate.Power.ClipFrame:CreateTexture(frameName .. 'CutawayPower')
-- local powerTexture = nameplate.Power:GetStatusBarTexture()
-- Cutaway.Power:Point('TOPLEFT', powerTexture, 'TOPRIGHT')
-- Cutaway.Power:Point('BOTTOMLEFT', powerTexture, 'BOTTOMRIGHT')
return Cutaway
end
function NP:Update_Cutaway(nameplate)
local eitherEnabled = NP.db.cutaway.health.enabled or NP.db.cutaway.power.enabled
if not eitherEnabled then
if nameplate:IsElementEnabled('Cutaway') then
nameplate:DisableElement('Cutaway')
end
else
if not nameplate:IsElementEnabled('Cutaway') then
nameplate:EnableElement('Cutaway')
end
nameplate.Cutaway:UpdateConfigurationValues(NP.db.cutaway)
if NP.db.cutaway.health.forceBlankTexture then
nameplate.Cutaway.Health:SetTexture(E.media.blankTex)
else
nameplate.Cutaway.Health:SetTexture(LSM:Fetch('statusbar', NP.db.statusbar))
end
-- if NP.db.cutaway.power.forceBlankTexture then
-- nameplate.Cutaway.Power:SetTexture(E.media.blankTex)
-- else
-- nameplate.Cutaway.Power:SetTexture(LSM:Fetch('statusbar', NP.db.statusbar))
-- end
end
end
@@ -0,0 +1,66 @@
local E, L, V, P, G = unpack(ElvUI)
local NP = E:GetModule('NamePlates')
local _G = _G
local unpack = unpack
local hooksecurefunc = hooksecurefunc
function NP:Portrait_PostUpdate()
local nameplate = self.__owner
local db = NP:PlateDB(nameplate)
local sf = NP:StyleFilterChanges(nameplate)
if sf.Portrait or (db.portrait and db.portrait.enable) then
if db.portrait.classicon and nameplate.isPlayer then
self:SetTexture([[Interface\WorldStateFrame\Icons-Classes]])
self:SetTexCoord(unpack(_G.CLASS_ICON_TCOORDS[nameplate.classFile]))
self.backdrop:Hide()
else
self:SetTexCoord(.18, .82, .18, .82)
self.backdrop:Show()
end
else
self.backdrop:Hide()
end
end
function NP:Update_PortraitBackdrop()
if self.backdrop then
self.backdrop:SetShown(self:IsShown())
end
end
function NP:Construct_Portrait(nameplate)
local Portrait = nameplate:CreateTexture(nameplate:GetName() .. 'Portrait', 'OVERLAY', nil, 2)
Portrait:SetTexCoord(.18, .82, .18, .82)
Portrait:CreateBackdrop(nil, nil, nil, nil, nil, true, true)
Portrait:Hide()
Portrait.PostUpdate = NP.Portrait_PostUpdate
hooksecurefunc(Portrait, 'Hide', NP.Update_PortraitBackdrop)
hooksecurefunc(Portrait, 'Show', NP.Update_PortraitBackdrop)
return Portrait
end
function NP:Update_Portrait(nameplate)
local db = NP:PlateDB(nameplate)
local sf = NP:StyleFilterChanges(nameplate)
if sf.Portrait or (db.portrait and db.portrait.enable) then
if not nameplate:IsElementEnabled('Portrait') then
nameplate:EnableElement('Portrait')
nameplate.Portrait:ForceUpdate()
end
nameplate.Portrait:Size(db.portrait.width, db.portrait.height)
-- These values are forced in name only mode inside of DisablePlate
if not (db.nameOnly or sf.NameOnly) then
nameplate.Portrait:ClearAllPoints()
nameplate.Portrait:Point(E.InversePoints[db.portrait.position], nameplate, db.portrait.position, db.portrait.xOffset, db.portrait.yOffset)
end
elseif nameplate:IsElementEnabled('Portrait') then
nameplate:DisableElement('Portrait')
end
end
+148
View File
@@ -0,0 +1,148 @@
local E, L, V, P, G = unpack(ElvUI)
local NP = E:GetModule('NamePlates')
local UF = E:GetModule('UnitFrames')
local LSM = E.Libs.LSM
local unpack = unpack
local UnitPlayerControlled = UnitPlayerControlled
local UnitClass = UnitClass
local UnitReaction = UnitReaction
local UnitIsConnected = UnitIsConnected
local CreateFrame = CreateFrame
local UnitPowerType = UnitPowerType
local POWERTYPE_ALTERNATE = 10
function NP:Power_UpdateColor(_, unit)
if unit and self.isNamePlate and unit:sub(1, 9) ~= "nameplate" then
local isUnit = self.unit and UnitIsUnit(self.unit, unit)
if isUnit then
unit = self.unit
end
end
if self.unit ~= unit then return end
local element = self.Power
local ptype, ptoken, altR, altG, altB = UnitPowerType(unit)
element.token = ptoken
local sf = NP:StyleFilterChanges(self)
if sf.PowerColor then return end
local Selection = element.colorSelection and NP:UnitSelectionType(unit, element.considerSelectionInCombatHostile)
local r, g, b, t, atlas
if element.colorDisconnected and not UnitIsConnected(unit) then
t = self.colors.disconnected
elseif element.colorPower then
if element.displayType ~= POWERTYPE_ALTERNATE then
t = NP.db.colors.power[ptoken or ptype]
if not t then
if element.GetAlternativeColor then
r, g, b = element:GetAlternativeColor(unit, ptype, ptoken, altR, altG, altB)
elseif altR then
r, g, b = altR, altG, altB
if r > 1 or g > 1 or b > 1 then -- BUG: As of 7.0.3, altR, altG, altB may be in 0-1 or 0-255 range.
r, g, b = r / 255, g / 255, b / 255
end
end
end
else
t = NP.db.colors.power.ALT_POWER
end
if element.useAtlas and t and t.atlas then
atlas = t.atlas
end
elseif (element.colorClass and self.isPlayer) or (element.colorClassNPC and not self.isPlayer) or (element.colorClassPet and UnitPlayerControlled(unit) and not self.isPlayer) then
local _, class = UnitClass(unit)
t = self.colors.class[class]
elseif Selection then
t = NP.db.colors.selection[Selection]
elseif element.colorReaction and UnitReaction(unit, 'player') then
local reaction = UnitReaction(unit, 'player')
t = NP.db.colors.reactions[reaction == 4 and 'neutral' or reaction <= 3 and 'bad' or 'good']
elseif element.colorSmooth then
local adjust = 0 - (element.min or 0)
r, g, b = self:ColorGradient((element.cur or 1) + adjust, (element.max or 1) + adjust, unpack(element.smoothGradient or self.colors.smooth))
end
if t then
r, g, b = t[1] or t.r, t[2] or t.g, t[3] or t.b
end
if atlas then
element:SetStatusBarTexture(atlas)
element:SetStatusBarColor(1, 1, 1)
elseif b then
element:SetStatusBarColor(r, g, b)
end
if element.bg and b then element.bg:SetVertexColor(r * NP.multiplier, g * NP.multiplier, b * NP.multiplier) end
if element.PostUpdateColor then
element:PostUpdateColor(unit, r, g, b)
end
end
function NP:Power_PostUpdate(_, cur) --unit, cur, min, max
local db = NP:PlateDB(self.__owner)
if not db.enable then return end
if self.__owner.frameType ~= 'PLAYER' and db.power.displayAltPower and not self.displayType then
self:Hide()
return
end
if db.power and db.power.enable and db.power.hideWhenEmpty and (cur == 0) then
self:Hide()
else
self:Show()
end
end
function NP:Construct_Power(nameplate)
local Power = CreateFrame('StatusBar', nameplate:GetName()..'Power', nameplate)
Power:CreateBackdrop('Transparent', nil, nil, nil, nil, true, true)
NP.StatusBars[Power] = true
--Power.frequentUpdates = true
Power.colorTapping = false
Power.colorClass = false
Power.PostUpdate = NP.Power_PostUpdate
Power.UpdateColor = NP.Power_UpdateColor
local clipFrame = CreateFrame('Frame', nil, Power)
clipFrame:SetAllPoints()
clipFrame:EnableMouse(false)
clipFrame.__frame = Power
Power.ClipFrame = clipFrame
return Power
end
function NP:Update_Power(nameplate)
local db = NP:PlateDB(nameplate)
if db.power.enable then
if not nameplate:IsElementEnabled('Power') then
nameplate:EnableElement('Power')
end
nameplate.Power:SetStatusBarTexture(LSM:Fetch('statusbar', NP.db.statusbar))
nameplate.Power:Point('CENTER', nameplate, 'CENTER', db.power.xOffset, db.power.yOffset)
E:SetSmoothing(nameplate.Power, NP.db.smoothbars)
elseif nameplate:IsElementEnabled('Power') then
nameplate:DisableElement('Power')
end
nameplate.Power.displayAltPower = db.power.displayAltPower
nameplate.Power.useAtlas = db.power.useAtlas
nameplate.Power.colorClass = db.power.useClassColor
nameplate.Power.colorPower = not db.power.useClassColor
nameplate.Power.width = db.power.width
nameplate.Power.height = db.power.height
nameplate.Power:Size(db.power.width, db.power.height)
end
+64
View File
@@ -0,0 +1,64 @@
local E, L, V, P, G = unpack(ElvUI)
local NP = E:GetModule('NamePlates')
local strlower = strlower
function NP:PvPIndicator_PostUpdate(_, status)
if status and status ~= 'FFA' and (not self.Badge or not self.Badge:IsShown()) then
self:SetAtlas('bfa-landingbutton-'..strlower(status)..'-up')
self:SetTexCoord(0, 1, 0, 1)
end
end
function NP:Construct_PvPIndicator(nameplate)
local PvPIndicator = nameplate:CreateTexture(nil, 'OVERLAY')
PvPIndicator.Badge_ = nameplate:CreateTexture(nil, 'ARTWORK')
PvPIndicator.PostUpdate = NP.PvPIndicator_PostUpdate
return PvPIndicator
end
function NP:Update_PvPIndicator(nameplate)
local db = NP:PlateDB(nameplate)
if db.pvpindicator and db.pvpindicator.enable then
if not nameplate:IsElementEnabled('PvPIndicator') then
nameplate:EnableElement('PvPIndicator')
end
nameplate.PvPIndicator:Size(db.pvpindicator.size, db.pvpindicator.size)
nameplate.PvPIndicator.Badge_:Size(db.pvpindicator.size + 14, db.pvpindicator.size + 16)
nameplate.PvPIndicator.Badge = nil
if db.pvpindicator.showBadge then
nameplate.PvPIndicator.Badge = nameplate.PvPIndicator.Badge_
end
nameplate.PvPIndicator:ClearAllPoints()
nameplate.PvPIndicator:Point(E.InversePoints[db.pvpindicator.position], nameplate, db.pvpindicator.position, db.pvpindicator.xOffset, db.pvpindicator.yOffset)
elseif nameplate:IsElementEnabled('PvPIndicator') then
nameplate:DisableElement('PvPIndicator')
end
end
function NP:Construct_PvPClassificationIndicator(nameplate)
local PvPClassificationIndicator = nameplate:CreateTexture(nil, 'OVERLAY')
return PvPClassificationIndicator
end
function NP:Update_PvPClassificationIndicator(nameplate)
local db = NP:PlateDB(nameplate)
if (nameplate.frameType == 'ENEMY_PLAYER' or nameplate.frameType == 'FRIENDLY_PLAYER' or nameplate.frameType == 'PLAYER') and db.pvpclassificationindicator and db.pvpclassificationindicator.enable then
if not nameplate:IsElementEnabled('PvPClassificationIndicator') then
nameplate:EnableElement('PvPClassificationIndicator')
end
nameplate.PvPClassificationIndicator:ClearAllPoints()
nameplate.PvPClassificationIndicator:Point(E.InversePoints[db.pvpclassificationindicator.position], nameplate, db.pvpclassificationindicator.position, db.pvpclassificationindicator.xOffset, db.pvpclassificationindicator.yOffset)
nameplate.PvPClassificationIndicator:Size(db.pvpclassificationindicator.size)
elseif nameplate:IsElementEnabled('PvPClassificationIndicator') then
nameplate:DisableElement('PvPClassificationIndicator')
end
end
@@ -0,0 +1,41 @@
local E, L, V, P, G = unpack(ElvUI)
local NP = E:GetModule('NamePlates')
local GetRaidTargetIndex = GetRaidTargetIndex
local SetRaidTargetIconTexture = SetRaidTargetIconTexture
function NP:RaidTargetIndicator_Override()
local element = self.RaidTargetIndicator
local index = self.unit and GetRaidTargetIndex(self.unit)
if index then
SetRaidTargetIconTexture(element, index)
element:Show()
else
element:Hide()
end
end
function NP:Construct_RaidTargetIndicator(nameplate)
local RaidTargetIndicator = nameplate:CreateTexture(nil, 'OVERLAY', nil, 7)
RaidTargetIndicator.Override = NP.RaidTargetIndicator_Override
RaidTargetIndicator:Hide()
return RaidTargetIndicator
end
function NP:Update_RaidTargetIndicator(nameplate)
local db = NP:PlateDB(nameplate)
if db.raidTargetIndicator and db.raidTargetIndicator.enable then
if not nameplate:IsElementEnabled('RaidTargetIndicator') then
nameplate:EnableElement('RaidTargetIndicator')
end
nameplate.RaidTargetIndicator:ClearAllPoints()
nameplate.RaidTargetIndicator:Point(E.InversePoints[db.raidTargetIndicator.position], nameplate, db.raidTargetIndicator.position, db.raidTargetIndicator.xOffset, db.raidTargetIndicator.yOffset)
nameplate.RaidTargetIndicator:Size(db.raidTargetIndicator.size)
elseif nameplate:IsElementEnabled('RaidTargetIndicator') then
nameplate:DisableElement('RaidTargetIndicator')
end
end
@@ -0,0 +1,38 @@
local E, L, V, P, G = unpack(ElvUI)
local NP = E:GetModule('NamePlates')
local LSM = E.Libs.LSM
function NP:Construct_TagText(nameplate)
local Text = nameplate:CreateFontString(nil, 'OVERLAY')
Text:FontTemplate(E.LSM:Fetch('font', NP.db.font), NP.db.fontSize, NP.db.fontOutline)
return Text
end
function NP:Update_TagText(nameplate, element, db, hide)
if not db then return end
if db.enable and not hide then
nameplate:Tag(element, db.format or '')
element:FontTemplate(LSM:Fetch('font', db.font), db.fontSize, db.fontOutline)
element:UpdateTag()
element:ClearAllPoints()
element:Point(E.InversePoints[db.position], db.parent == 'Nameplate' and nameplate or nameplate[db.parent], db.position, db.xOffset, db.yOffset)
element:Show()
else
nameplate:Untag(element)
element:Hide()
end
end
function NP:Update_Tags(nameplate, nameOnlySF)
local db = NP:PlateDB(nameplate)
local hide = db.nameOnly or nameOnlySF
NP:Update_TagText(nameplate, nameplate.Name, db.name)
NP:Update_TagText(nameplate, nameplate.Title, db.title)
NP:Update_TagText(nameplate, nameplate.Level, db.level, hide)
NP:Update_TagText(nameplate, nameplate.Health.Text, db.health and db.health.text, hide)
--NP:Update_TagText(nameplate, nameplate.Power.Text, db.power and db.power.text, hide)
end
@@ -0,0 +1,96 @@
local E, L, V, P, G = unpack(ElvUI)
local NP = E:GetModule('NamePlates')
local UnitName = UnitName
local UnitExists = UnitExists
local UnitIsUnit = UnitIsUnit
NP.ThreatPets = {
}
function NP:ThreatIndicator_PreUpdate(unit, pass)
local nameplate, db, unitTarget, imTank = self.__owner, NP.db.threat, unit..'target', E.myrole == 'TANK' or NP.GroupRoles[E.myname] == 'TANK'
local unitRole = NP.IsInGroup and (UnitExists(unitTarget) and not UnitIsUnit(unitTarget, 'player')) and NP.GroupRoles[UnitName(unitTarget)] or 'NONE'
local unitTank = unitRole == 'TANK' or (db.beingTankedByPet and NP.ThreatPets[NP:UnitNPCID(unitTarget)])
local isTank, offTank, feedbackUnit = unitTank or imTank, db.beingTankedByTank and (unitTank and imTank) or false, (unitTank and unitTarget) or 'player'
nameplate.ThreatScale = nil
if pass then
return isTank, offTank, feedbackUnit
else
self.feedbackUnit = feedbackUnit
self.offTank = offTank
self.isTank = isTank
end
end
function NP:ThreatIndicator_PostUpdate(unit, status)
local nameplate, colors, db = self.__owner, NP.db.colors.threat, NP.db.threat
local sf = NP:StyleFilterChanges(nameplate)
if not status and not sf.Scale then
nameplate.ThreatScale = 1
NP:ScalePlate(nameplate, 1)
elseif status and db.enable and db.useThreatColor then
NP:Health_SetColors(nameplate, true)
nameplate.ThreatStatus = status
local Color, Scale
if status == 3 then -- securely tanking
Color = self.offTank and colors.offTankColor or self.isTank and colors.goodColor or colors.badColor
Scale = self.isTank and db.goodScale or db.badScale
elseif status == 2 then -- insecurely tanking
Color = self.offTank and colors.offTankColorBadTransition or self.isTank and colors.badTransition or colors.goodTransition
Scale = 1
elseif status == 1 then -- not tanking but threat higher than tank
Color = self.offTank and colors.offTankColorGoodTransition or self.isTank and colors.goodTransition or colors.badTransition
Scale = 1
else -- not tanking at all
Color = self.isTank and colors.badColor or colors.goodColor
Scale = self.isTank and db.badScale or db.goodScale
end
if sf.HealthColor then
self.r, self.g, self.b = Color.r, Color.g, Color.b
else
nameplate.Health:SetStatusBarColor(Color.r, Color.g, Color.b)
end
if Scale then
nameplate.ThreatScale = Scale
if not sf.Scale then
NP:ScalePlate(nameplate, Scale)
end
end
end
end
function NP:Construct_ThreatIndicator(nameplate)
local ThreatIndicator = nameplate:CreateTexture(nil, 'OVERLAY')
ThreatIndicator:Size(16, 16)
ThreatIndicator:Hide()
ThreatIndicator:Point('CENTER', nameplate, 'TOPRIGHT')
ThreatIndicator.PreUpdate = NP.ThreatIndicator_PreUpdate
ThreatIndicator.PostUpdate = NP.ThreatIndicator_PostUpdate
return ThreatIndicator
end
function NP:Update_ThreatIndicator(nameplate)
local db = NP.db.threat
if nameplate.frameType == 'ENEMY_NPC' and db.enable then
if not nameplate:IsElementEnabled('ThreatIndicator') then
nameplate:EnableElement('ThreatIndicator')
end
if db.indicator then
nameplate.ThreatIndicator:SetAlpha(1)
else
nameplate.ThreatIndicator:SetAlpha(0)
end
elseif nameplate:IsElementEnabled('ThreatIndicator') then
nameplate:DisableElement('ThreatIndicator')
end
end
+19 -17
View File
@@ -1,17 +1,19 @@
<Ui xmlns="http://www.blizzard.com/wow/ui/">
<Script file="Nameplates.lua"/>
<Script file="StyleFilter.lua"/>
<Script file="Elements\Auras.lua"/>
<Script file="Elements\CastBar.lua"/>
<Script file="Elements\ComboPoints.lua"/>
<Script file="Elements\Glow.lua"/>
<Script file="Elements\HealthBar.lua"/>
<Script file="Elements\CutawayHealth.lua"/>
<Script file="Elements\Level.lua"/>
<Script file="Elements\Name.lua"/>
<Script file="Elements\RaidIcon.lua"/>
<Script file="Elements\HealerIcon.lua"/>
<Script file="Elements\Elite.lua"/>
<Script file="Elements\Highlight.lua"/>
<Script file="Elements\IconFrame.lua"/>
</Ui>
<Ui xmlns='http://www.blizzard.com/wow/ui/'>
<Script file='Nameplates.lua'/>
<Script file='StyleFilter.lua'/>
<Script file='Elements\Auras.lua'/>
<Script file='Elements\BossMods.lua'/>
<Script file='Elements\CastBar.lua'/>
<Script file='Elements\ClassPower.lua'/>
<Script file='Elements\Health.lua'/>
<Script file='Elements\Plugins.lua'/>
<Script file='Elements\Power.lua'/>
<Script file='Elements\Portraits.lua'/>
<Script file='Elements\PvP.lua'/>
<Script file='Elements\RaidTargetIndicator.lua'/>
<Script file='Elements\Tags.lua'/>
<Script file='Elements\Threat.lua'/>
<Script file='Plugins\ClassificationIndicator.lua'/>
<Script file='Plugins\QuestIcons.lua'/>
<Script file='Plugins\TargetIndicator.lua'/>
</Ui>
File diff suppressed because it is too large Load Diff
@@ -0,0 +1,60 @@
local E, L, V, P, G = unpack(ElvUI)
local oUF = E.oUF
local function Update(self)
local element = self.ClassificationIndicator
if element.PreUpdate then
element:PreUpdate()
end
local classification = self.classification
if classification == 'elite' or classification == 'worldboss' then
element:SetAtlas('nameplates-icon-elite-gold')
element:Show()
elseif classification == 'rareelite' or classification == 'rare' then
element:SetAtlas('nameplates-icon-elite-silver')
element:Show()
else
element:Hide()
end
if element.PostUpdate then
return element:PostUpdate(classification)
end
end
local function Path(self, ...)
return (self.ClassificationIndicator.Override or Update) (self, ...)
end
local function ForceUpdate(element)
return Path(element.__owner, 'ForceUpdate', element.__owner.unit)
end
local function Enable(self)
local element = self.ClassificationIndicator
if element then
element.__owner = self
element.ForceUpdate = ForceUpdate
if element:IsObjectType('Texture') and not element:GetTexture() then
element:SetTexture([[Interface\TARGETINGFRAME\Nameplates]])
end
self:RegisterEvent('UNIT_CLASSIFICATION_CHANGED', Path)
return true
end
end
local function Disable(self)
local element = self.ClassificationIndicator
if element then
element:Hide()
self:UnregisterEvent('UNIT_CLASSIFICATION_CHANGED', Path)
end
end
oUF:AddElement('ClassificationIndicator', Path, Enable, Disable)
@@ -0,0 +1,77 @@
local E, L, V, P, G = unpack(ElvUI)
local oUF = E.oUF
local UnitExists = UnitExists
local UnitIsUnit = UnitIsUnit
local function MouseOnUnit(frame)
if frame and frame:IsVisible() and UnitExists('mouseover') then
return frame.unit and UnitIsUnit('mouseover', frame.unit)
end
return false
end
local function OnUpdate(self, elapsed)
if self.elapsed and self.elapsed > 0.1 then
if not MouseOnUnit(self) then
self:Hide()
self:ForceUpdate()
end
self.elapsed = 0
else
self.elapsed = (self.elapsed or 0) + elapsed
end
end
local function Update(self)
local element = self.Highlight
if element.PreUpdate then
element:PreUpdate()
end
if MouseOnUnit(self) then
element:Show()
else
element:Hide()
end
if element.PostUpdate then
return element:PostUpdate(element:IsShown())
end
end
local function Path(self, ...)
return (self.Highlight.Override or Update)(self, ...)
end
local function ForceUpdate(element)
return Path(element.__owner, 'ForceUpdate', element.__owner.unit)
end
local function Enable(self)
local element = self.Highlight
if element then
element.__owner = self
element.ForceUpdate = ForceUpdate
element:SetScript('OnUpdate', OnUpdate)
self:RegisterEvent('UPDATE_MOUSEOVER_UNIT', Path, true)
return true
end
end
local function Disable(self)
local element = self.Highlight
if element then
element:Hide()
element:SetScript('OnUpdate', nil)
self:UnregisterEvent('UPDATE_MOUSEOVER_UNIT', Path)
end
end
oUF:AddElement('Highlight', Path, Enable, Disable)
@@ -0,0 +1,315 @@
local E, L, V, P, G = unpack(ElvUI)
local NP = E:GetModule('NamePlates')
local oUF = E.oUF
local _G = _G
local pairs, ipairs, ceil, floor, tonumber = pairs, ipairs, ceil, floor, tonumber
local wipe, strmatch, strlower, strfind = wipe, strmatch, strlower, strfind
local IsInInstance = IsInInstance
local UnitIsPlayer = UnitIsPlayer
local GetQuestLogSpecialItemInfo = GetQuestLogSpecialItemInfo
local GetQuestLogTitle = GetQuestLogTitle
local GetNumQuestLogEntries = GetNumQuestLogEntries
local C_Quest_GetQuestID = GenerateClosure(C_Quest.GetQuestID, C_Quest)
local ThreatTooltip = THREAT_TOOLTIP:gsub('%%d', '%%d-')
local questIcons = {
iconTypes = { 'Default', 'Item', 'Skull', 'Chat' },
indexByID = {}, --[questID] = questIndex
activeQuests = {} --[questTitle] = questID
}
NP.QuestIcons = questIcons
local typesLocalized = {
enUS = {
--- short matching applies here so,
-- kill: killed, destory: destoryed, etc ...
KILL = {'slain', 'destroy', 'eliminate', 'repel', 'kill', 'defeat'},
CHAT = {'speak', 'talk'}
},
deDE = {
KILL = {'besiegen', 'besiegt', 'getötet', 'töten', 'tötet', 'vernichtet', 'zerstört', 'genährt'},
CHAT = {'befragt', 'sprecht'}
},
ruRU = {
KILL = {'убит', 'уничтож', 'разбомблен', 'разбит', 'сразит'},
CHAT = {'поговорит', 'спрашивать'}
},
esMX = {
-- asesinad: asesinado, asesinados, asesinada, asesinadas
-- derrota: derrotar, derrotado, derrotados, derrotada, derrotadas
-- destrui: destruir, destruido, destruidos, destruida, destruidas
-- elimin: eliminar, elimine, eliminadas, eliminada, eliminados, eliminado
-- repel: repele, repelido, repelidos, repelida, repelidas
KILL = {'asesinad', 'destrui', 'elimin', 'repel', 'derrota'},
CHAT = {'habla', 'pídele'}
},
ptBR = {
-- destrui: above but also destruição
-- repel: repelir, repelido, repelidos, repelida, repelidas
KILL = {'morto', 'morta', 'matar', 'destrui', 'elimin', 'repel', 'derrota'},
CHAT = {'falar', 'pedir'}
},
frFR = {
-- tué: tués, tuée, tuées
-- abattu: abattus, abattue
-- détrui: détruite, détruire, détruit, détruits, détruites
-- repouss: repousser, repoussés, repoussée, repoussées
-- élimin: éliminer, éliminé, éliminés, éliminée, éliminées
KILL = {'tué', 'tuer', 'attaqué', 'attaque', 'abattre', 'abattu', 'détrui', 'élimin', 'repouss', 'vaincu', 'vaincre'},
-- demande: demander, demandez
-- parle: parler, parlez
CHAT = {'parle', 'demande'}
},
koKR = {
KILL = {'쓰러뜨리기', '물리치기', '공격', '파괴'},
CHAT = {'대화'}
},
zhCN = {
KILL = {'消灭', '摧毁', '击败', '毁灭', '击退'},
CHAT = {'交谈', '谈一谈'}
},
zhTW = {
KILL = {'毀滅', '擊退', '殺死'},
CHAT = {'交談', '說話'}
},
}
local questTypes = typesLocalized[E.locale] or typesLocalized.enUS
local function CheckTextForQuest(text)
local x, y = strmatch(text, '(%d+)/(%d+)')
if x and y then
local diff = floor(y - x)
if diff > 0 then
return diff
end
elseif not strmatch(text, ThreatTooltip) then
local progress = tonumber(strmatch(text, '([%d%.]+)%%'))
if progress and progress <= 100 then
return ceil(100 - progress), true
end
end
end
NP.QuestIcons.CheckTextForQuest = CheckTextForQuest
local function GetQuests(unitID)
if IsInInstance() then return end
E.ScanTooltip:SetOwner(_G.UIParent, 'ANCHOR_NONE')
E.ScanTooltip:SetUnit(unitID)
E.ScanTooltip:Show()
local QuestList, notMyQuest, activeID
for i = 3, E.ScanTooltip:NumLines() do
local str = _G['ElvUI_ScanTooltipTextLeft' .. i]
local text = str and str:GetText()
if not text or text == '' then return end
if UnitIsPlayer(text) then
notMyQuest = text ~= E.myname
elseif text and not notMyQuest then
local count, percent = CheckTextForQuest(text)
-- this line comes from one line up in the tooltip
local activeQuest = questIcons.activeQuests[text]
if activeQuest then activeID = activeQuest end
if count then
local type, index, texture, _
if activeID then
index = questIcons.indexByID[activeID]
_, texture = GetQuestLogSpecialItemInfo(index)
end
if texture then
type = 'QUEST_ITEM'
else
local lowerText = strlower(text)
-- check kill type first
for _, listText in ipairs(questTypes.KILL) do
if strfind(lowerText, listText, nil, true) then
type = 'KILL'
break
end
end
-- check chat type if kill type doesn't exist
if not type then
for _, listText in ipairs(questTypes.CHAT) do
if strfind(lowerText, listText, nil, true) then
type = 'CHAT'
break
end
end
end
end
if not QuestList then QuestList = {} end
QuestList[#QuestList + 1] = {
isPercent = percent,
itemTexture = texture,
objectiveCount = count,
questType = type or 'DEFAULT',
-- below keys are currently unused
questLogIndex = index,
questID = activeID
}
end
end
end
E.ScanTooltip:Hide()
return QuestList
end
local function hideIcons(element)
for _, object in pairs(questIcons.iconTypes) do
local icon = element[object]
icon:Hide()
if icon.Text then
icon.Text:SetText('')
end
end
end
local function Update(self, event, arg1)
local element = self.QuestIcons
if not element then return end
local unit = (event == 'UNIT_NAME_UPDATE' and arg1) or self.unit
if unit ~= self.unit then return end
if element.PreUpdate then
element:PreUpdate()
end
hideIcons(element)
local QuestList = GetQuests(unit)
if QuestList then
element:Show()
else
element:Hide()
return
end
local shownCount
for i = 1, #QuestList do
local quest = QuestList[i]
local objectiveCount = quest.objectiveCount
local questType = quest.questType
local isPercent = quest.isPercent
if isPercent or objectiveCount > 0 then
local icon
if questType == 'DEFAULT' then
icon = element.Default
elseif questType == 'KILL' then
icon = element.Skull
elseif questType == 'CHAT' then
icon = element.Chat
elseif questType == 'QUEST_ITEM' then
icon = element.Item
end
if icon and not icon:IsShown() then
shownCount = (shownCount and shownCount + 1) or 0
local size = icon.size or 25
local setPosition = icon.position or 'TOPLEFT'
local newPosition = E.InversePoints[setPosition]
local offset = shownCount * (5 + size)
icon:Show()
icon:ClearAllPoints()
icon:Point(newPosition, element, newPosition, (strmatch(setPosition, 'LEFT') and -offset) or offset, 0)
if questType ~= 'CHAT' and icon.Text and (isPercent or objectiveCount > 1) then
icon.Text:SetText((isPercent and objectiveCount..'%') or objectiveCount)
end
if questType == 'QUEST_ITEM' then
element.Item:SetTexture(quest.itemTexture)
end
end
end
end
if element.PostUpdate then
return element:PostUpdate()
end
end
local function Path(self, ...)
return (self.QuestIcons.Override or Update) (self, ...)
end
local function ForceUpdate(element)
return Path(element.__owner, 'ForceUpdate', element.__owner.unit)
end
local function Enable(self)
local element = self.QuestIcons
if element then
element.__owner = self
element.ForceUpdate = ForceUpdate
if element.Default:IsObjectType('Texture') and not element.Default:GetAtlas() then
element.Default:SetAtlas('SmallQuestBang')
end
if element.Skull:IsObjectType('Texture') and not element.Skull:GetTexture() then
element.Skull:SetTexture(E.Media.Textures.SkullIcon)
end
if element.Chat:IsObjectType('StatusBar') and not element.Chat:GetTexture() then
element.Chat:SetTexture([[Interface\WorldMap\ChatBubble_64.PNG]])
end
self:RegisterEvent('QUEST_LOG_UPDATE', Path, true)
self:RegisterEvent('UNIT_NAME_UPDATE', Path, true)
self:RegisterEvent('PLAYER_ENTERING_WORLD', Path, true)
return true
end
end
local function Disable(self)
local element = self.QuestIcons
if element then
element:Hide()
hideIcons(element)
self:UnregisterEvent('QUEST_LOG_UPDATE', Path)
self:UnregisterEvent('UNIT_NAME_UPDATE', Path)
self:UnregisterEvent('PLAYER_ENTERING_WORLD', Path)
end
end
local frame = CreateFrame('Frame')
frame:RegisterEvent('QUEST_ACCEPTED')
frame:RegisterEvent('QUEST_REMOVED')
frame:RegisterEvent('PLAYER_ENTERING_WORLD')
frame:SetScript('OnEvent', function(self, event)
wipe(questIcons.indexByID)
wipe(questIcons.activeQuests)
for i = 1, GetNumQuestLogEntries() do
local id = C_Quest_GetQuestID(i)
if id and id > 0 then
questIcons.indexByID[id] = i
local title = GetQuestLogTitle(i)
if title then questIcons.activeQuests[title] = id end
end
end
if event == 'PLAYER_ENTERING_WORLD' then
self:UnregisterEvent(event)
end
end)
oUF:AddElement('QuestIcons', Path, Enable, Disable)
@@ -0,0 +1,152 @@
local E, L, V, P, G = unpack(ElvUI)
local NP = E:GetModule('NamePlates')
local ElvUF = E.oUF
local UnitHealth = UnitHealth
local UnitIsUnit = UnitIsUnit
local UnitHealthMax = UnitHealthMax
--[[ Target Glow Style Option Variables
style1:'Border',
style2:'Background',
style3:'Top Arrow Only',
style4:'Side Arrows Only',
style5:'Border + Top Arrow',
style6:'Background + Top Arrow',
style7:'Border + Side Arrows',
style8:'Background + Side Arrows'
]]
local function HideIndicators(element)
if element.TopIndicator then element.TopIndicator:Hide() end
if element.LeftIndicator then element.LeftIndicator:Hide() end
if element.RightIndicator then element.RightIndicator:Hide() end
if element.Shadow then element.Shadow:Hide() end
if element.Spark then element.Spark:Hide() end
end
local function ShowIndicators(element, isTarget, color)
if isTarget then
if element.TopIndicator and (element.style == 'style3' or element.style == 'style5' or element.style == 'style6') then
element.TopIndicator:SetVertexColor(color.r, color.g, color.b)
element.TopIndicator:SetTexture(element.arrow)
element.TopIndicator:Show()
end
if element.LeftIndicator and element.RightIndicator and (element.style == 'style4' or element.style == 'style7' or element.style == 'style8') then
element.LeftIndicator:SetVertexColor(color.r, color.g, color.b)
element.RightIndicator:SetVertexColor(color.r, color.g, color.b)
element.LeftIndicator:SetTexture(element.arrow)
element.RightIndicator:SetTexture(element.arrow)
element.RightIndicator:Show()
element.LeftIndicator:Show()
end
end
if element.Shadow and (element.style == 'style1' or element.style == 'style5' or element.style == 'style7') then
element.Shadow:SetBackdropBorderColor(color.r, color.g, color.b)
element.Shadow:Show()
end
if element.Spark and (element.style == 'style2' or element.style == 'style6' or element.style == 'style8') then
element.Spark:SetVertexColor(color.r, color.g, color.b)
element.Spark:Show()
end
end
local function Update(self)
local element = self.TargetIndicator
if element.PreUpdate then
element:PreUpdate()
end
HideIndicators(element)
if element.style ~= 'none' then
local isTarget = UnitIsUnit(self.unit, 'target')
local lowHealth = element.lowHealthThreshold > 0
if isTarget and (element.preferGlowColor or not lowHealth) then
ShowIndicators(element, isTarget, NP.db.colors.glowColor)
elseif lowHealth then
local health, maxHealth = UnitHealth(self.unit), UnitHealthMax(self.unit)
local perc = (maxHealth > 0 and health/maxHealth) or 0
-- color tables are class updated in UpdateMedia
if perc <= element.lowHealthThreshold * 0.5 then
ShowIndicators(element, isTarget, NP.db.colors.lowHealthHalf)
elseif perc <= element.lowHealthThreshold then
ShowIndicators(element, isTarget, NP.db.colors.lowHealthColor)
elseif isTarget then
ShowIndicators(element, isTarget, NP.db.colors.glowColor)
end
end
end
if element.PostUpdate then
return element:PostUpdate(self.unit)
end
end
local function Path(self, ...)
return (self.TargetIndicator.Override or Update) (self, ...)
end
local function ForceUpdate(element)
return Path(element.__owner, 'ForceUpdate', element.__owner.unit)
end
local function Enable(self)
local element = self.TargetIndicator
if element then
element.__owner = self
element.ForceUpdate = ForceUpdate
if not element.style then element.style = 'style1' end
if not element.preferGlowColor then element.preferGlowColor = true end
if not element.lowHealthThreshold then element.lowHealthThreshold = .4 end
if element.Shadow and element.Shadow:IsObjectType('Frame') and not element.Shadow:GetBackdrop() then
element.Shadow:SetBackdrop({edgeFile = E.Media.Textures.GlowTex, edgeSize = 5})
end
if element.Spark and element.Spark:IsObjectType('Texture') and not element.Spark:GetTexture() then
element.Spark:SetTexture(E.Media.Textures.Spark)
end
if element.TopIndicator and element.TopIndicator:IsObjectType('Texture') and not element.TopIndicator:GetTexture() then
element.TopIndicator:SetTexture(E.Media.Textures.ArrowUp)
element.TopIndicator:SetTexCoord(1, 1, 1, 0, 0, 1, 0, 0) --Rotates texture 180 degress (Up arrow to face down)
end
if element.LeftIndicator and element.LeftIndicator:IsObjectType('Texture') and not element.LeftIndicator:GetTexture() then
element.LeftIndicator:SetTexture(E.Media.Textures.ArrowUp)
element.LeftIndicator:SetTexCoord(1, 0, 0, 0, 1, 1, 0, 1) --Rotates texture 90 degrees clockwise (Up arrow to face right)
end
if element.RightIndicator and element.RightIndicator:IsObjectType('Texture') and not element.RightIndicator:GetTexture() then
element.RightIndicator:SetTexture(E.Media.Textures.ArrowUp)
element.RightIndicator:SetTexCoord(1, 1, 0, 1, 1, 0, 0, 0) --Flips texture horizontally (Right facing arrow to face left)
end
self:RegisterEvent('UNIT_HEALTH', Path)
self:RegisterEvent('UNIT_MAXHEALTH', Path)
self:RegisterEvent('PLAYER_TARGET_CHANGED', Path, true)
return true
end
end
local function Disable(self)
local element = self.TargetIndicator
if element then
HideIndicators(element)
self:UnregisterEvent('UNIT_HEALTH', Path)
self:UnregisterEvent('UNIT_MAXHEALTH', Path)
self:UnregisterEvent('PLAYER_TARGET_CHANGED', Path)
end
end
ElvUF:AddElement('TargetIndicator', Path, Enable, Disable)
File diff suppressed because it is too large Load Diff
@@ -137,6 +137,9 @@ S:AddCallback("Skin_BlizzardOptions", function()
"InterfaceOptionsCombatPanelTargetOfTarget",
"InterfaceOptionsCombatPanelEnemyCastBarsOnPortrait",
"InterfaceOptionsCombatPanelEnemyCastBarsOnNameplates",
"InterfaceOptionsCombatPanelAoEIndicatorsSelf",
"InterfaceOptionsCombatPanelAoEIndicatorsEnemies",
"InterfaceOptionsCombatPanelAoEIndicatorsFriendly",
"InterfaceOptionsDisplayPanelShowCloak",
"InterfaceOptionsDisplayPanelShowHelm",
"InterfaceOptionsDisplayPanelShowAggroPercentage",
@@ -257,7 +260,11 @@ S:AddCallback("Skin_BlizzardOptions", function()
"InterfaceOptionsAscensionLoseControlPanelEnableSlow",
"InterfaceOptionsAscensionLoseControlPanelEnableStun",
"InterfaceOptionsAscensionLoseControlPanelEnablePacify",
"InterfaceOptionsDraftPanelAutoPopupDraft",
"InterfaceOptionsDraftPanelAutoRevealDraft",
"InterfaceOptionsDraftPanelSkipDraftConfirmation",
"InterfaceOptionsDraftPanelSkipDraftSacrificeConfirmation",
"InterfaceOptionsDraftPanelShowBuildDraftSpellCards",
"AudioOptionsSoundPanelEnableSound",
"AudioOptionsSoundPanelSoundEffects",
@@ -306,7 +313,9 @@ S:AddCallback("Skin_BlizzardOptions", function()
"InterfaceOptionsCombatPanelSpellActivationOverlayAlpha",
"InterfaceOptionsMousePanelMouseLookSpeedSlider",
"InterfaceOptionsMousePanelMouseSensitivitySlider",
"InterfaceOptionsCombatPanelNameplateDistance",
"InterfaceOptionsCombatPanelNameplateZ",
"AudioOptionsSoundPanelSoundQuality",
"AudioOptionsSoundPanelSoundChannels",
"AudioOptionsSoundPanelMasterVolume",
-1
View File
@@ -21,7 +21,6 @@ S:AddCallback("Skin_LFD", function()
AscensionLFGFrameContent:StripTextures(true)
AscensionLFGFrameMenu:StripTextures(true)
AscensionLFGFrameInset:StripTextures(true)
AscensionLFGFrameInset:CreateBackdrop("Transparent")
AscensionLFGFrameInsetNineSlice:StripTextures(true)
AscensionLFGFrameNineSlice:StripTextures(true)
AscensionLFGFrameMenuNineSlice:StripTextures(true)
+21 -39
View File
@@ -77,47 +77,29 @@ local function createConfigEnv()
__newindex = function(_, key, value) _G[key] = value end,
})
overrideFuncs["namecolor"] = ElvUF.Tags.Methods["namecolor"]
overrideFuncs["name:veryshort"] = ElvUF.Tags.Methods["name:veryshort"]
overrideFuncs["name:short"] = ElvUF.Tags.Methods["name:short"]
overrideFuncs["name:medium"] = ElvUF.Tags.Methods["name:medium"]
overrideFuncs["name:long"] = ElvUF.Tags.Methods["name:long"]
overrideFuncs['classcolor'] = ElvUF.Tags.Methods['classcolor']
overrideFuncs['name:veryshort'] = ElvUF.Tags.Methods['name:veryshort']
overrideFuncs['name:short'] = ElvUF.Tags.Methods['name:short']
overrideFuncs['name:medium'] = ElvUF.Tags.Methods['name:medium']
overrideFuncs['name:long'] = ElvUF.Tags.Methods['name:long']
overrideFuncs["healthcolor"] = ElvUF.Tags.Methods["healthcolor"]
overrideFuncs["health:current"] = ElvUF.Tags.Methods["health:current"]
overrideFuncs["health:deficit"] = ElvUF.Tags.Methods["health:deficit"]
overrideFuncs["health:current-percent"] = ElvUF.Tags.Methods["health:current-percent"]
overrideFuncs["health:current-max"] = ElvUF.Tags.Methods["health:current-max"]
overrideFuncs["health:current-max-percent"] = ElvUF.Tags.Methods["health:current-max-percent"]
overrideFuncs["health:max"] = ElvUF.Tags.Methods["health:max"]
overrideFuncs["health:percent"] = ElvUF.Tags.Methods["health:percent"]
overrideFuncs['healthcolor'] = ElvUF.Tags.Methods['healthcolor']
overrideFuncs['health:current'] = ElvUF.Tags.Methods['health:current']
overrideFuncs['health:deficit'] = ElvUF.Tags.Methods['health:deficit']
overrideFuncs['health:current-percent'] = ElvUF.Tags.Methods['health:current-percent']
overrideFuncs['health:current-max'] = ElvUF.Tags.Methods['health:current-max']
overrideFuncs['health:current-max-percent'] = ElvUF.Tags.Methods['health:current-max-percent']
overrideFuncs['health:max'] = ElvUF.Tags.Methods['health:max']
overrideFuncs['health:percent'] = ElvUF.Tags.Methods['health:percent']
overrideFuncs["powercolor"] = ElvUF.Tags.Methods["powercolor"]
overrideFuncs["power:current"] = ElvUF.Tags.Methods["power:current"]
overrideFuncs["power:deficit"] = ElvUF.Tags.Methods["power:deficit"]
overrideFuncs["power:current-percent"] = ElvUF.Tags.Methods["power:current-percent"]
overrideFuncs["power:current-max"] = ElvUF.Tags.Methods["power:current-max"]
overrideFuncs["power:current-max-percent"] = ElvUF.Tags.Methods["power:current-max-percent"]
overrideFuncs["power:max"] = ElvUF.Tags.Methods["power:max"]
overrideFuncs["power:percent"] = ElvUF.Tags.Methods["power:percent"]
overrideFuncs["energycolor"] = ElvUF.Tags.Methods["energycolor"]
overrideFuncs["energy:current"] = ElvUF.Tags.Methods["energy:current"]
overrideFuncs["energy:deficit"] = ElvUF.Tags.Methods["energy:deficit"]
overrideFuncs["energy:current-percent"] = ElvUF.Tags.Methods["energy:current-percent"]
overrideFuncs["energy:current-max"] = ElvUF.Tags.Methods["energy:current-max"]
overrideFuncs["energy:current-max-percent"] = ElvUF.Tags.Methods["energy:current-max-percent"]
overrideFuncs["energy:max"] = ElvUF.Tags.Methods["energy:max"]
overrideFuncs["energy:percent"] = ElvUF.Tags.Methods["energy:percent"]
overrideFuncs["ragecolor"] = ElvUF.Tags.Methods["ragecolor"]
overrideFuncs["rage:current"] = ElvUF.Tags.Methods["rage:current"]
overrideFuncs["rage:deficit"] = ElvUF.Tags.Methods["rage:deficit"]
overrideFuncs["rage:current-percent"] = ElvUF.Tags.Methods["rage:current-percent"]
overrideFuncs["rage:current-max"] = ElvUF.Tags.Methods["rage:current-max"]
overrideFuncs["rage:current-max-percent"] = ElvUF.Tags.Methods["rage:current-max-percent"]
overrideFuncs["rage:max"] = ElvUF.Tags.Methods["rage:max"]
overrideFuncs["rage:percent"] = ElvUF.Tags.Methods["rage:percent"]
overrideFuncs['powercolor'] = ElvUF.Tags.Methods['powercolor']
overrideFuncs['power:current'] = ElvUF.Tags.Methods['power:current']
overrideFuncs['power:deficit'] = ElvUF.Tags.Methods['power:deficit']
overrideFuncs['power:current-percent'] = ElvUF.Tags.Methods['power:current-percent']
overrideFuncs['power:current-max'] = ElvUF.Tags.Methods['power:current-max']
overrideFuncs['power:current-max-percent'] = ElvUF.Tags.Methods['power:current-max-percent']
overrideFuncs['power:max'] = ElvUF.Tags.Methods['power:max']
overrideFuncs['power:percent'] = ElvUF.Tags.Methods['power:percent']
end
function UF:ForceShow(frame)
@@ -173,6 +173,33 @@ function UF.SortAuraBarName(a, b)
return a.name > b.name
end
function UF:ConvertFilters(auras, priority)
if not priority or priority == '' then return end
local list = auras.filterList or {}
if next(list) then wipe(list) end
local special, filters = G.unitframe.specialFilters, E.global.unitframe.aurafilters
for _, name in next, { strsplit(',', priority) } do
local friend, enemy = strmatch(name, '^Friendly:([^,]*)'), strmatch(name, '^Enemy:([^,]*)')
local real = friend or enemy or name
local custom = filters[real]
if special[real] or custom then
tinsert(list, {
name = real,
custom = custom,
status = (friend and 1) or (enemy and 2)
})
end
end
if next(list) then
return list
end
end
function UF:CheckFilter(name, caster, spellID, isFriend, isPlayer, isUnit, allowDuration, noDuration, canDispell, ...)
for i = 1, select("#", ...) do
local filterName = select(i, ...)
+120
View File
@@ -1,5 +1,6 @@
local E, L, V, P, G = unpack(select(2, ...)); --Import: Engine, Locales, PrivateDB, ProfileDB, GlobalDB
local UF = E:GetModule("UnitFrames")
local NP = E:GetModule('NamePlates')
local LSM = E.Libs.LSM
--Lua functions
@@ -16,6 +17,58 @@ local UnitCanAttack = UnitCanAttack
local UnitIsFriend = UnitIsFriend
local UnitIsUnit = UnitIsUnit
UF.MatchGrowthY = { TOP = 'TOP', BOTTOM = 'BOTTOM' }
UF.MatchGrowthX = { LEFT = 'LEFT', RIGHT = 'RIGHT' }
UF.SortAuraFuncs = {
TIME_REMAINING = function(a, b, dir)
local A = a.noTime and huge or a.expiration or -huge
local B = b.noTime and huge or b.expiration or -huge
if dir == 'DESCENDING' then return A < B else return A > B end
end,
DURATION = function(a, b, dir)
local A = a.noTime and huge or a.duration or -huge
local B = b.noTime and huge or b.duration or -huge
if dir == 'DESCENDING' then return A < B else return A > B end
end,
NAME = function(a, b, dir)
local A, B = a.name or '', b.name or ''
if dir == 'DESCENDING' then return A < B else return A > B end
end,
PLAYER = function(a, b, dir)
local A, B = a.isPlayer or false, b.isPlayer or false
if dir == 'DESCENDING' then return A and not B else return not A and B end
end,
}
UF.SmartPosition = {
BUFFS_ON_DEBUFFS = {
from = 'BUFFS', to = 'Debuffs',
warning = format(L["This setting caused a conflicting anchor point, where '%s' would be attached to itself. Please check your anchor points. Setting '%s' to be attached to '%s'."], L["Buffs"], L["Debuffs"], L["Frame"]),
func = function(db, buffs, debuffs)
db.buffs.attachTo = 'DEBUFFS'
buffs.attachTo = debuffs
buffs.PostUpdate = nil
debuffs.PostUpdate = UF.UpdateAuraSmartPoisition
end
},
DEBUFFS_ON_BUFFS = {
from = 'DEBUFFS', to = 'Buffs',
warning = format(L["This setting caused a conflicting anchor point, where '%s' would be attached to itself. Please check your anchor points. Setting '%s' to be attached to '%s'."], L["Debuffs"], L["Buffs"], L["Frame"]),
func = function(db, buffs, debuffs)
db.debuffs.attachTo = 'BUFFS'
debuffs.attachTo = buffs
debuffs.PostUpdate = nil
buffs.PostUpdate = UF.UpdateAuraSmartPoisition
end
}
}
UF.SmartPosition.FLUID_BUFFS_ON_DEBUFFS = E:CopyTable({fluid = true}, UF.SmartPosition.BUFFS_ON_DEBUFFS)
UF.SmartPosition.FLUID_DEBUFFS_ON_BUFFS = E:CopyTable({fluid = true}, UF.SmartPosition.DEBUFFS_ON_BUFFS)
function UF:Construct_Buffs(frame)
local buffs = CreateFrame("Frame", frame:GetName().."Buffs", frame)
buffs.spacing = E.Spacing
@@ -134,6 +187,48 @@ function UF:UpdateAuraCooldownPosition(button)
button.needsUpdateCooldownPosition = nil
end
function UF:GetAuraElements(frame)
if frame.isNamePlate then
return frame.Buffs_, frame.Debuffs_
else
return frame.Buffs, frame.Debuffs
end
end
function UF:SetSmartPosition(frame, db)
if frame.isNamePlate then db = NP:PlateDB(frame) end
local position, fluid = db.smartAuraPosition
local buffs, debuffs = UF:GetAuraElements(frame)
local info = UF.SmartPosition[position]
if info then
local TO = db[strlower(info.to)]
if TO.attachTo == info.from then
TO.attachTo = 'FRAME'
E:Print(info.warning)
local element = (info.to == 'Debuffs' and debuffs) or buffs
element.attachTo = frame
element:ClearAllPoints()
element:Point(element.initialAnchor, element.attachTo, element.anchorPoint, element.xOffset, element.yOffset)
end
fluid = info.fluid
info.func(db, buffs, debuffs, info.isFuild)
else
buffs.PostUpdate = nil
debuffs.PostUpdate = nil
end
if db.debuffs.attachTo == 'BUFFS' and db.buffs.attachTo == 'DEBUFFS' then
E:Print(format(L["%s frame has a conflicting anchor point. Forcing the Buffs to be attached to the main unitframe."], E:StringTitle(frame:GetName())))
db.buffs.attachTo = 'FRAME'
end
return position, fluid
end
function UF:Configure_Auras(frame, auraType)
if not frame.VARIABLES_SET then return end
@@ -382,6 +477,31 @@ function UF:PostUpdateAura(unit, button)
end
end
function UF:GetSmartAuraElements(auras)
local Buffs, Debuffs = UF:GetAuraElements(auras:GetParent())
if auras == Buffs then
return Debuffs, Buffs, auras.visibleBuffs
else
return Buffs, Debuffs, auras.visibleDebuffs
end
end
function UF:UpdateAuraSmartPoisition()
local element, other, visible = UF:GetSmartAuraElements(self)
if visible == 0 then
if self.smartFluid then
element:ClearAllPoints()
element:Point(other.initialAnchor, other.attachTo, other.anchorPoint, other.xOffset, other.yOffset)
else
other:Height(UF:GetAuraPosition(other, true))
end
else
element:ClearAllPoints()
element:Point(element.initialAnchor, element.attachTo, element.anchorPoint, element.xOffset, element.yOffset)
end
end
function UF:AuraFilter(unit, button, name, _, _, _, debuffType, duration, expiration, caster, isStealable, _, spellID)
if not name then return end -- checking for an aura that is not there, pass nil to break while loop
@@ -10,7 +10,7 @@ function UF:Construct_Cutaway(frame)
if frame.Power then
local powerTexture = frame.Power:GetStatusBarTexture()
local cutawayPower = frame.Power.ClipFrame:CreateTexture(frameName.."CutawayPower")
local cutawayPower = frame.Power:CreateTexture(frameName.."CutawayPower")
cutawayPower:SetPoint("TOPLEFT", powerTexture, "TOPRIGHT")
cutawayPower:SetPoint("BOTTOMLEFT", powerTexture, "BOTTOMRIGHT")
cutawayPower:SetTexture(E.media.blankTex)
@@ -18,7 +18,7 @@ function UF:Construct_Cutaway(frame)
end
local healthTexture = frame.Health:GetStatusBarTexture()
local cutawayHealth = frame.Health.ClipFrame:CreateTexture(frameName.."CutawayHealth")
local cutawayHealth = frame.Health:CreateTexture(frameName.."CutawayHealth")
cutawayHealth:SetPoint("TOPLEFT", healthTexture, "TOPRIGHT")
cutawayHealth:SetPoint("BOTTOMLEFT", healthTexture, "BOTTOMRIGHT")
cutawayHealth:SetTexture(E.media.blankTex)
@@ -65,6 +65,12 @@ function UF:Configure_Happiness(frame)
end
function UF:HappinessOverride(event, unit)
if unit and self.isNamePlate and unit:sub(1, 9) ~= "nameplate" then
local isUnit = self.unit and UnitIsUnit(self.unit, unit)
if isUnit then
unit = self.unit
end
end
if not unit or self.unit ~= unit then return end
local db = self.db
@@ -60,7 +60,7 @@ function UF:Configure_Energy(frame)
local energy = frame.Energy
energy.origParent = frame
if frame.USE_ENERGYBAR then
if frame.USE_ENERGYBAR and C_Player:IsHero() then
if not frame:IsElementEnabled("Energy") then
frame:EnableElement("Energy")
energy:Show()
@@ -60,7 +60,7 @@ function UF:Configure_Rage(frame)
local rage = frame.Rage
rage.origParent = frame
if frame.USE_RAGEBAR then
if frame.USE_RAGEBAR and C_Player:IsHero() then
if not frame:IsElementEnabled("Rage") then
frame:EnableElement("Rage")
rage:Show()
@@ -30,6 +30,12 @@ function UF:Configure_PVPIcon(frame)
end
function UF:UpdateOverridePvP(event, unit)
if unit and self.isNamePlate and unit:sub(1, 9) ~= "nameplate" then
local isUnit = self.unit and UnitIsUnit(self.unit, unit)
if isUnit then
unit = self.unit
end
end
if not unit or self.unit ~= unit then return end
local element = self.PvPIndicator
+6 -1
View File
@@ -95,7 +95,12 @@ end
function UF:UpdateThreat(unit, status, r, g, b)
local parent = self:GetParent()
if unit and parent.isNamePlate and unit:sub(1, 9) ~= "nameplate" then
local isUnit = parent.unit and UnitIsUnit(parent.unit, unit)
if isUnit then
unit = parent.unit
end
end
if (parent.unit ~= unit) or not unit then return end
local db = parent.db
+15
View File
@@ -461,6 +461,21 @@ function UF:Configure_Fader(frame)
end
end
function UF:Construct_ClipFrame(frame, bar)
local clipFrame = CreateFrame('ScrollFrame', nil, bar)
clipFrame:SetAllPoints()
clipFrame:EnableMouse(false)
local child = CreateFrame("Frame", nil, clipFrame)
child:SetPoint("CENTER")
child:SetSize(clipFrame:GetSize())
child.__frame = frame
bar.ClipFrame = child
return child
end
function UF:Configure_FontString(obj)
UF.fontstrings[obj] = true
obj:FontTemplate() --This is temporary.