--------------------------------------------------------------------------------------------------- -- Boss Mod Widget --------------------------------------------------------------------------------------------------- local ADDON_NAME, Addon = ... local ThreatPlates = Addon.ThreatPlates local Widget = Addon.Widgets:NewWidget("BossMods") --------------------------------------------------------------------------------------------------- -- Imported functions and constants --------------------------------------------------------------------------------------------------- -- Lua APIs local floor = math.floor -- WoW APIs local GetSpellTexture = GetSpellTexture local GetTime = GetTime local tremove = tremove -- ThreatPlates APIs local L = Addon.ThreatPlates.L local _G =_G -- Global vars/functions that we don't upvalue since they might get hooked, or upgraded -- List them here for Mikk's FindGlobals script -- GLOBALS: CreateFrame, UnitGUID -- local DBM = DBM local GUIDAuraList = {} local ConfigDB local EnabledByBossmod = false local MAX_AURAS_NO = 5 local UPDATE_INTERVAL = 0.5 --------------------------------------------------------------------------------------------------- -- Boss Mods Widget Functions --------------------------------------------------------------------------------------------------- local function AlignWidget(widget_frame) local db = Addon.db.profile.BossModsWidget local offset_x = 0 if widget_frame.AurasNo > 1 then offset_x = (widget_frame.AurasNo - 1) * (db.scale + db.AuraSpacing) / 2 end local style = widget_frame:GetParent().stylename if style == "NameOnly" or style == "NameOnly-Unique" then widget_frame:SetPoint("CENTER", widget_frame:GetParent(), - offset_x + db.x_hv, db.y_hv) else widget_frame:SetPoint("CENTER", widget_frame:GetParent(), - offset_x + db.x, db.y) end widget_frame:SetSize(64, 64) end local function UpdateAuraTexture(frame, aura, index) if index == 1 then aura:SetPoint("CENTER", frame, 0, 0) else aura:SetPoint("LEFT", frame.Auras[index - 1], "RIGHT", ConfigDB.AuraSpacing, 0) end aura:SetSize(ConfigDB.scale, ConfigDB.scale) -- Duration Text local color = ConfigDB.FontColor aura.Time:SetFont(Addon.LibSharedMedia:Fetch('font', ConfigDB.Font), ConfigDB.FontSize) aura.Time:SetAllPoints(aura) aura.Time:SetTextColor(color.r, color.g, color.b) end local function CreateAuraTexture(frame, index) local aura = frame:CreateTexture(nil, "ARTWORK") local time = frame:CreateFontString(nil, "OVERLAY") -- Duration Text time:SetJustifyH("CENTER") time:SetJustifyV("MIDDLE") time:SetShadowOffset(1, -1) aura.Time = time UpdateAuraTexture(frame, aura, index) return aura end local function UpdateFrameWithAuras(widget_frame, unit_auras) local aura_texture, aura_info local no_auras = #unit_auras local index = 1 while index <= no_auras do aura_info = unit_auras[index] aura_texture = widget_frame.Auras[index] if not aura_texture then aura_texture = CreateAuraTexture(widget_frame, index) widget_frame.Auras[index] = aura_texture end if aura_info[2] then -- aura with duration local remaining_time = floor(aura_info[2] - GetTime()) if remaining_time >= 0 then aura_texture:SetTexture(aura_info[1]) aura_texture.Time:SetText(remaining_time) aura_texture.Time:Show() aura_texture:Show() index = index + 1 else -- aura has run out tremove(unit_auras, index) no_auras = no_auras - 1 end else -- aura without duration aura_texture:SetTexture(aura_info[1]) aura_texture.Time:SetText(nil) aura_texture.Time:Show() aura_texture:Show() index = index + 1 end end -- Hide all unused aura textures for i = index, widget_frame.AurasNo do aura_texture = widget_frame.Auras[i] aura_texture.Time:Hide() aura_texture:Hide() end widget_frame.AurasNo = no_auras AlignWidget(widget_frame) end local function OnUpdateBossModsWidget(widget_frame, elapsed) widget_frame.LastUpdate = widget_frame.LastUpdate + elapsed if widget_frame.LastUpdate < UPDATE_INTERVAL then return end widget_frame.LastUpdate = 0 if not EnabledByBossmod then widget_frame:Hide() return end local unit_auras = GUIDAuraList[widget_frame.unit.guid] if not unit_auras or #unit_auras == 0 then widget_frame:Hide() return end UpdateFrameWithAuras(widget_frame, unit_auras) end --------------------------------------------------------------------------------------------------- -- Callback functions for DBM --------------------------------------------------------------------------------------------------- -- DBM:FireEvent("BossMod_ShowNameplateAura", isGUID, unit, currentTexture, duration, desaturate, addLine, lineColor) local function BossMod_ShowNameplateAura(msg, is_guid, unit, aura_texture, duration, desaturate, addLine, lineColor) local guid = (is_guid and unit) or _G.UnitGUID(unit) if not guid then -- ThreatPlates.DEBUG('bossmods show discarded unmatched name: ' .. unit) return end EnabledByBossmod = true -- Aura Info: -- 1: aura texture (spell id) -- 2: time the aura ends local no_auras = 0 local unit_auras = GUIDAuraList[guid] if unit_auras then no_auras = #unit_auras if no_auras < MAX_AURAS_NO then for i = 1, no_auras do if unit_auras[i][1] == aura_texture then unit_auras[i][2] = (duration and (GetTime() + duration)) or nil return end end -- append a new aura unit_auras[no_auras + 1] = { aura_texture, (duration and (GetTime() + duration)) or nil, } end else GUIDAuraList[guid] = { { aura_texture, (duration and GetTime() + duration) or nil, } } --guid_aura_list[guid] = unit_auras end -- Show frame is this is the first aura shown (no_auras == 0 in this case) if no_auras == 0 then local plate = Addon.PlatesByGUID[guid] if plate and plate.TPFrame.Active then local widget_frame = plate.TPFrame.widgets.BossMods if widget_frame and widget_frame.Active then UpdateFrameWithAuras(widget_frame, GUIDAuraList[guid]) widget_frame.LastUpdate = 0.5 -- to show the update immediately widget_frame:Show() end end end end -- DBM:FireEvent("BossMod_HideNameplateAura", isGUID, unit, currentTexture) local function BossMod_HideNameplateAura(msg, is_guid, unit, aura_texture) local guid = (is_guid and unit) or _G.UnitGUID(unit) if not guid then return end local unit_auras = GUIDAuraList[guid] if unit_auras then for i = 1, #unit_auras do if unit_auras[i][1] == aura_texture then tremove(unit_auras, i) local plate = Addon.PlatesByGUID[guid] if plate then UpdateFrameWithAuras(plate.TPFrame.widgets["BossMods"], unit_auras) --frame.LastUpdate = 0.5 -- to show the update immediately end return end end end end local function BossMod_DisableFriendlyNameplates() EnabledByBossmod = false -- Cleanup, widget frame will be hidden on next update cycle, including with cleanup of all script handlers GUIDAuraList = {} end local function BossMod_DisableHostileNameplates() EnabledByBossmod = false -- Cleanup, widget frame will be hidden on next update cycle, including with cleanup of all script handlers GUIDAuraList = {} end --------------------------------------------------------------------------------------------------- -- Widget functions for creation and update --------------------------------------------------------------------------------------------------- function Widget:Create(tp_frame) -- Required Widget Code local widget_frame = _G.CreateFrame("Frame", nil, tp_frame) widget_frame:Hide() -- Custom Code -------------------------------------- widget_frame:SetFrameLevel(tp_frame:GetFrameLevel()) widget_frame.Auras = {} widget_frame.AurasNo = 0 widget_frame.LastUpdate = 0.5 widget_frame:SetScript("OnUpdate", OnUpdateBossModsWidget) -------------------------------------- -- End Custom Code return widget_frame end function Widget:IsEnabled() local db = Addon.db.profile.BossModsWidget return db.ON or db.ShowInHeadlineView end function Widget:OnEnable() if DBM then DBM:RegisterCallback('BossMod_ShowNameplateAura', BossMod_ShowNameplateAura) DBM:RegisterCallback('BossMod_DisableFriendlyNameplates', BossMod_DisableFriendlyNameplates) DBM:RegisterCallback('BossMod_HideNameplateAura', BossMod_HideNameplateAura) DBM:RegisterCallback('BossMod_DisableHostileNameplates', BossMod_DisableHostileNameplates) end end function Widget:OnDisable() if DBM then DBM:UnregisterCallback('BossMod_ShowNameplateAura', BossMod_ShowNameplateAura) DBM:UnregisterCallback('BossMod_HideNameplateAura', BossMod_HideNameplateAura) DBM:UnregisterCallback('BossMod_DisableFriendlyNameplates', BossMod_DisableFriendlyNameplates) DBM:UnregisterCallback('BossMod_DisableHostileNameplates', BossMod_DisableHostileNameplates) end end function Widget:EnabledForStyle(style, unit) if (style == "NameOnly" or style == "NameOnly-Unique") then return Addon.db.profile.BossModsWidget.ShowInHeadlineView elseif style ~= "etotem" then return Addon.db.profile.BossModsWidget.ON end end function Widget:OnUnitAdded(widget_frame, unit) ConfigDB = Addon.db.profile.BossModsWidget if not EnabledByBossmod then widget_frame:Hide() return end local unit_auras = GUIDAuraList[unit.guid] if not unit_auras or #unit_auras == 0 then widget_frame:Hide() return end -- Update auras and alignment if settings were change or plate is re-shown for i = 1, widget_frame.AurasNo do UpdateAuraTexture(widget_frame, widget_frame.Auras[i], i) end UpdateFrameWithAuras(widget_frame, unit_auras) widget_frame:Show() end --function Widget:OnUpdateStyle(widget_frame, unit) -- local db = Addon.db.profile.BossModsWidget -- -- local offset_x = 0 -- if widget_frame.AurasNo > 1 then -- offset_x = (widget_frame.AurasNo - 1) * (db.scale + db.AuraSpacing) / 2 -- end -- -- if unit.style == "NameOnly" or unit.style == "NameOnly-Unique" then -- widget_frame:SetPoint("CENTER", widget_frame:GetParent(), - offset_x + db.x_hv, db.y_hv) -- else -- widget_frame:SetPoint("CENTER", widget_frame:GetParent(), - offset_x + db.x, db.y) -- end --end --------------------------------------------------------------------------------------------------- -- Configuration Mode --------------------------------------------------------------------------------------------------- local EnabledConfigMode = false function Addon:ConfigBossModsWidget() if not EnabledConfigMode then local tp_frame = Widget:GetThreatPlateForUnit("target") if tp_frame then local guid = _G.UnitGUID("target") BossMod_ShowNameplateAura("Configuration Mode", true, guid, GetSpellTexture(6603), nil, false, true, {1, 1, 0.5, 1}) BossMod_ShowNameplateAura("Configuration Mode", true, guid, GetSpellTexture(7620), 7, false, true, {0, 0, 1, 1}) BossMod_ShowNameplateAura("Configuration Mode", true, guid, GetSpellTexture(818), 60) EnabledConfigMode = true else Addon.Logging.Warning(L["Please select a target unit with a nameplate to enable configuration mode."]) end else BossMod_DisableHostileNameplates() BossMod_DisableFriendlyNameplates() EnabledConfigMode = false end end