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.growthDirection = db.growthDirection or "RIGHT_UP" 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