diff --git a/Modules/TotemPulse.lua b/Modules/TotemPulse.lua new file mode 100644 index 0000000..a2a49a9 --- /dev/null +++ b/Modules/TotemPulse.lua @@ -0,0 +1,476 @@ +local C_NamePlate = C_NamePlate +local Gladdy = LibStub("Gladdy") +local L = Gladdy.L +local tremove, tinsert = tremove, tinsert +local GetSpellInfo, CreateFrame = GetSpellInfo, CreateFrame +local GetTime, GetPlayerInfoByGUID, UnitIsEnemy, UnitGUID = GetTime, GetPlayerInfoByGUID, UnitIsEnemy, UnitGUID +local CombatLogGetCurrentEventInfo = CombatLogGetCurrentEventInfo + +local cooldowns = { + [2484] = 3, --Earthbind + [8143] = 4, -- Tremor + [8166] = 4, -- Poison Cleansing + [8170] = 4, -- Disease Cleansing + [1535] = { cd = 4, once = true }, -- Fire Nova 1 + [8498] = { cd = 4, once = true }, -- Fire Nova 2 + [8499] = { cd = 4, once = true }, -- Fire Nova 3 + [11314] = { cd = 4, once = true }, -- Fire Nova 4 + [11315] = { cd = 4, once = true }, -- Fire Nova 5 + [25546] = { cd = 4, once = true }, -- Fire Nova 6 + [25547] = { cd = 4, once = true }, -- Fire Nova 7 + [8190] = 2, -- Magma 1 + [10585] = 2, -- Magma 2 + [10586] = 2, -- Magma 3 + [10587] = 2, -- Magma 4 + [25552] = 2, -- Magma 5 + [5394] = 2, -- Healing Stream 1 + [6375] = 2, -- Healing Stream 2 + [6377] = 2, -- Healing Stream 3 + [10462] = 2, -- Healing Stream 4 + [10463] = 2, -- Healing Stream 5 + [25567] = 2, -- Healing Stream 6 + [5675] = 2, -- Mana Spring 1 + [10495] = 2, -- Mana Spring 2 + [10496] = 2, -- Mana Spring 3 + [10497] = 2, -- Mana Spring 4 + [25570] = 2, -- Mana Spring 5 +} + +local ninetyDegreeInRad = 90 * math.pi / 180 + +--------------------------------------------------- + +-- Core + +--------------------------------------------------- + + +local TotemPulse = Gladdy:NewModule("Totem Pulse", nil, { + totemPulseEnabled = true, + totemPulseEnabledShowFriendly = true, + totemPulseEnabledShowEnemy = true, + totemPulseAttachToTotemPlate = true, + totemPulseStyle = "", -- "COOLDOWN", "COOLDOWNREVERSE", "BARVERTICAL", "BARHORIZONTAL" + totemPulseTextColor = { r = 1, g = 1, b = 1, a = 0 }, + --bar + totemPulseBarWidth = 40, + totemPulseBarHeight = 20, + totemPulseBarColor = { r = 1, g = 0, b = 0, a = 1 }, + totemPulseBarBgColor = { r = 0, g = 1, b = 0, a = 1 }, + totemPulseBarBorderColor = { r = 0, g = 0, b = 0, a = 1 }, + totemPulseBarBorderSize = 5, + totemPulseBarBorderStyle = "Gladdy Tooltip squared", + totemPulseBarTexture = "Smooth", + --cooldown + totemPulseCooldownAlpha = 1, +}) + +function TotemPulse.OnEvent(self, event, ...) + TotemPulse[event](self, ...) +end + +function TotemPulse:Initialize() + self.cooldowns = cooldowns + self.timeStamps = {} + self.cooldownCache = {} + self.barCache = {} + self.activeFrames = { bars = {}, cooldowns = {} } + self:SetScript("OnEvent", self.OnEvent) + self:RegisterEvent("COMBAT_LOG_EVENT_UNFILTERED") + self:RegisterEvent("NAME_PLATE_UNIT_REMOVED") + self:RegisterEvent("NAME_PLATE_UNIT_ADDED") + self:RegisterEvent("UNIT_NAME_UPDATE") +end + +--------------------------------------------------- + +-- EVENTS + +--------------------------------------------------- + +function TotemPulse:COMBAT_LOG_EVENT_UNFILTERED() + local _,eventType,_,sourceGUID,_,_,_,destGUID,_,_,_,spellID,spellName,spellSchool,extraSpellId,extraSpellName,extraSpellSchool = CombatLogGetCurrentEventInfo() + print(eventType, spellName, spellID, destGUID) + if eventType == "SPELL_SUMMON" then + if cooldowns[spellID] then + print(eventType, spellName, spellID, GetPlayerInfoByGUID(sourceGUID)) + self.timeStamps[destGUID] = { timeStamp = GetTime(), spellID = spellID } + end + elseif eventType == "UNIT_DESTROYED" then + self.timeStamps[destGUID] = nil + end +end + +function TotemPulse:NAME_PLATE_UNIT_REMOVED(unitId) + local nameplate = C_NamePlate.GetNamePlateForUnit(unitId) + if nameplate.totemTick then + print("NAME_PLATE_UNIT_REMOVED", nameplate.totemTick) + nameplate.totemTick:SetScript("OnUpdate", nil) + nameplate.totemTick:Hide() + nameplate.totemTick:SetParent(nil) + tinsert(nameplate.totemTick.bar and self.barCache or self.cooldownCache, nameplate.totemTick) + self.activeFrames.bars[nameplate.totemTick] = nil + self.activeFrames.cooldowns[nameplate.totemTick] = nil + nameplate.totemTick = nil + end +end + +function TotemPulse:NAME_PLATE_UNIT_ADDED(unitId) + self:OnUnitAdded(unitId, "NAME_PLATE_UNIT_ADDED") +end + +function TotemPulse:UNIT_NAME_UPDATE(unitId) + self:OnUnitAdded(unitId, "UNIT_NAME_UPDATE") +end + +function TotemPulse:OnUnitAdded(unitId, event) + local isEnemy = UnitIsEnemy("player", unitId) + local guid = UnitGUID(unitId) + + local nameplate = C_NamePlate.GetNamePlateForUnit(unitId) + + if nameplate then + print(event, self.timeStamps[guid], nameplate.totemTick) + if self.timeStamps[guid] then + self:AddTimerFrame(nameplate, self.timeStamps[guid], Gladdy.db.totemPulseAttachToTotemPlate and nameplate.gladdyTotemFrame) + else + if nameplate.totemTick then + nameplate.totemTick:SetScript("OnUpdate", nil) + nameplate.totemTick:Hide() + nameplate.totemTick:SetParent(nil) + tinsert(nameplate.totemTick.bar and self.barCache or self.cooldownCache, nameplate.totemTick) + self.activeFrames.bars[nameplate.totemTick] = nil + self.activeFrames.cooldowns[nameplate.totemTick] = nil + nameplate.totemTick = nil + end + end + end +end + +--------------------------------------------------- + +-- FRAMES + +--------------------------------------------------- + +function TotemPulse:CreateCooldownFrame(gladdyTotemFrame) + local totemTick + + if gladdyTotemFrame then + if #self.cooldownCache > 0 then + totemTick = tremove(self.cooldownCache, #self.cooldownCache) + else + Gladdy:Print("TotemPulse:CreateCooldownFrame()", "CreateCooldown") + totemTick = CreateFrame("Cooldown", nil, nil, "CooldownFrameTemplate") + totemTick.noCooldownCount = true + totemTick:SetFrameStrata("MEDIUM") + totemTick:SetFrameLevel(4) + totemTick:SetReverse(true) + totemTick:SetHideCountdownNumbers(true) + totemTick:SetAlpha(Gladdy.db.totemPulseCooldownAlpha) + + totemTick.text = totemTick:CreateFontString(nil, "OVERLAY") + totemTick.text:SetPoint("LEFT", totemTick, "LEFT", 4, 0) + totemTick.text:SetFont("Fonts\\FRIZQT__.TTF", 16, "OUTLINE") + totemTick.text:SetJustifyH("LEFT") + totemTick.text:SetShadowOffset(1, -1) + totemTick.text:SetTextColor(Gladdy:SetColor(Gladdy.db.totemPulseTextColor)) + end + else + if #self.barCache > 0 then + Gladdy:Print("TotemPulse:CreateCooldownFrame()", #self.barCache) + totemTick = tremove(self.barCache, #self.barCache) + else + Gladdy:Print("TotemPulse:CreateCooldownFrame()", "CreateBar") + totemTick = CreateFrame("Frame", nil) + + totemTick:SetWidth(Gladdy.db.totemPulseBarWidth) + totemTick:SetHeight(Gladdy.db.totemPulseBarHeight) + + totemTick.backdrop = CreateFrame("Frame", nil, totemTick, BackdropTemplateMixin and "BackdropTemplate") + totemTick.backdrop:SetAllPoints(totemTick) + totemTick.backdrop:SetBackdrop({ edgeFile = Gladdy:SMFetch("border", "totemPulseBarBorderStyle"), + edgeSize = Gladdy.db.totemPulseBarBorderSize }) + totemTick.backdrop:SetBackdropBorderColor(Gladdy:SetColor(Gladdy.db.totemPulseBarBorderColor)) + totemTick.backdrop:SetFrameLevel(1) + --totemTick.backdrop:SetFrameStrata(Gladdy.db.castBarFrameStrata) + --totemTick.backdrop:SetFrameLevel(Gladdy.db.castBarFrameLevel - 1) + + totemTick.bar = CreateFrame("StatusBar", nil, totemTick) + totemTick.bar:SetStatusBarTexture(Gladdy:SMFetch("statusbar", "totemPulseBarTexture")) + totemTick.bar:SetStatusBarColor(Gladdy:SetColor(Gladdy.db.totemPulseBarColor)) + totemTick.bar:SetOrientation("Vertical") + totemTick.bar:SetFrameLevel(0) + totemTick.bar:SetPoint("TOPLEFT", totemTick, "TOPLEFT", (Gladdy.db.totemPulseBarBorderSize/Gladdy.db.statusbarBorderOffset), -(Gladdy.db.totemPulseBarBorderSize/Gladdy.db.statusbarBorderOffset)) + totemTick.bar:SetPoint("BOTTOMRIGHT", totemTick, "BOTTOMRIGHT", -(Gladdy.db.totemPulseBarBorderSize/Gladdy.db.statusbarBorderOffset), (Gladdy.db.totemPulseBarBorderSize/Gladdy.db.statusbarBorderOffset)) + + totemTick.spark = totemTick.bar:CreateTexture(nil, "OVERLAY") + totemTick.spark:SetTexture("Interface\\CastingBar\\UI-CastingBar-Spark") + totemTick.spark:SetBlendMode("ADD") + totemTick.spark:SetWidth(8) + totemTick.spark:SetHeight(40) + totemTick.spark.position = 0 + totemTick.spark:SetRotation(ninetyDegreeInRad) + + totemTick.bg = totemTick.bar:CreateTexture(nil, "BACKGROUND") + totemTick.bg:SetTexture(Gladdy:SMFetch("statusbar", "totemPulseBarTexture")) + totemTick.bg:SetAllPoints(totemTick.bar) + totemTick.bg:SetVertexColor(Gladdy:SetColor(Gladdy.db.totemPulseBarBgColor)) + + totemTick.text = totemTick.bar:CreateFontString(nil, "OVERLAY") + totemTick.text:SetPoint("LEFT", totemTick, "LEFT", 4, 0) + totemTick.text:SetFont("Fonts\\FRIZQT__.TTF", 16, "OUTLINE") + totemTick.text:SetJustifyH("LEFT") + totemTick.text:SetShadowOffset(1, -1) + totemTick.text:SetTextColor(Gladdy:SetColor(Gladdy.db.totemPulseTextColor)) + end + end + return totemTick +end + +function TotemPulse:AddTimerFrame(nameplate, timestamp, gladdyTotemFrame) + if nameplate:IsShown() and cooldowns[timestamp.spellID] then + if not nameplate.totemTick then + nameplate.totemTick = TotemPulse:CreateCooldownFrame(gladdyTotemFrame) + end + nameplate.totemTick:SetParent(nameplate) + nameplate.totemTick:ClearAllPoints() + if gladdyTotemFrame then + nameplate.totemTick:SetPoint("TOPLEFT", gladdyTotemFrame, "TOPLEFT", Gladdy.db.npTotemPlatesSize/16, -Gladdy.db.npTotemPlatesSize/16) + nameplate.totemTick:SetPoint("BOTTOMRIGHT", gladdyTotemFrame, "BOTTOMRIGHT", -Gladdy.db.npTotemPlatesSize/16, Gladdy.db.npTotemPlatesSize/16) + else + nameplate.totemTick:SetPoint("TOP", nameplate, "BOTTOM") + end + + local cd = type(cooldowns[timestamp.spellID]) == "table" and cooldowns[timestamp.spellID].cd or cooldowns[timestamp.spellID] + local once = type(cooldowns[timestamp.spellID]) == "table" + local cooldown = (timestamp.timeStamp - GetTime()) % cd + + if not gladdyTotemFrame then + nameplate.totemTick.bar:SetMinMaxValues(0, cd) + nameplate.totemTick.bar:SetValue(cooldown) + self.activeFrames.bars[nameplate.totemTick] = nameplate.totemTick + else + self.activeFrames.cooldowns[nameplate.totemTick] = nameplate.totemTick + end + + nameplate.totemTick.timestamp = timestamp.timeStamp + nameplate.totemTick.maxValue = cd + nameplate.totemTick.value = cooldown + nameplate.totemTick.once = once + + print("once", once, " - totemTick.once", nameplate.totemTick.once, " - cd off", math.abs(timestamp.timeStamp - GetTime()) > cd) + if once and GetTime() - timestamp.timeStamp > cd then + nameplate.totemTick:SetScript("OnUpdate", nil) + nameplate.totemTick:Hide() + print("nameplate.totemTick:Hide()") + else + nameplate.totemTick:SetScript("OnUpdate", function(totemTick, elapsed) + totemTick.now = GetTime() + totemTick.value = (totemTick.timestamp - totemTick.now) % totemTick.maxValue + if totemTick.once and totemTick.now - totemTick.timestamp >= totemTick.maxValue then + totemTick:SetScript("OnUpdate", nil) + print("OnUpdate totemTick:Hide()") + totemTick:Hide() + end + if not totemTick.bar and not (totemTick.once and totemTick.now - totemTick.timestamp >= totemTick.maxValue) then + totemTick:SetCooldown(totemTick.now - totemTick.value, totemTick.maxValue) + elseif totemTick.bar then + totemTick.spark.position = (totemTick.value / totemTick.maxValue) * totemTick.bar:GetHeight() + if ( totemTick.spark.position < 0 ) then + totemTick.spark.position = 0 + end + totemTick.spark:SetPoint("CENTER", totemTick.bar, "BOTTOM", 0, totemTick.spark.position) + totemTick.bar:SetValue(totemTick.value) + end + totemTick.text:SetFormattedText("%.1f", totemTick.value) + end) + print("nameplate.totemTick:Show()") + nameplate.totemTick:Show() + end + else + if nameplate.totemTick then + nameplate.totemTick:SetScript("OnUpdate", nil) + nameplate.totemTick:Hide() + nameplate.totemTick:SetParent(nil) + tinsert(nameplate.totemTick.bar and self.barCache or self.cooldownCache, nameplate.totemTick) + self.activeFrames.bars[nameplate.totemTick] = nil + self.activeFrames.cooldowns[nameplate.totemTick] = nil + nameplate.totemTick = nil + end + end +end + +function TotemPulse:UpdateBar(bar) + bar:SetWidth(Gladdy.db.totemPulseBarWidth) + bar:SetHeight(Gladdy.db.totemPulseBarHeight) + + bar.backdrop:SetBackdrop({ edgeFile = Gladdy:SMFetch("border", "totemPulseBarBorderStyle"), + edgeSize = Gladdy.db.totemPulseBarBorderSize }) + bar.backdrop:SetBackdropBorderColor(Gladdy:SetColor(Gladdy.db.totemPulseBarBorderColor)) + + bar.bar:SetStatusBarTexture(Gladdy:SMFetch("statusbar", "totemPulseBarTexture")) + bar.bar:SetStatusBarColor(Gladdy:SetColor(Gladdy.db.totemPulseBarColor)) + bar.bar:SetOrientation("Vertical") + bar.bar:SetPoint("TOPLEFT", bar, "TOPLEFT", (Gladdy.db.totemPulseBarBorderSize/Gladdy.db.statusbarBorderOffset), -(Gladdy.db.totemPulseBarBorderSize/Gladdy.db.statusbarBorderOffset)) + bar.bar:SetPoint("BOTTOMRIGHT", bar, "BOTTOMRIGHT", -(Gladdy.db.totemPulseBarBorderSize/Gladdy.db.statusbarBorderOffset), (Gladdy.db.totemPulseBarBorderSize/Gladdy.db.statusbarBorderOffset)) + + bar.spark:SetWidth(8) + bar.spark:SetHeight(40) + bar.spark:SetRotation(ninetyDegreeInRad) + + bar.bg:SetTexture(Gladdy:SMFetch("statusbar", "totemPulseBarTexture")) + bar.bg:SetVertexColor(Gladdy:SetColor(Gladdy.db.totemPulseBarBgColor)) + + bar.text:SetFont("Fonts\\FRIZQT__.TTF", 16, "OUTLINE") + bar.text:SetTextColor(Gladdy:SetColor(Gladdy.db.totemPulseTextColor)) +end + +function TotemPulse:UpdateCooldown(cooldown) + cooldown:SetReverse(true) + cooldown:SetAlpha(Gladdy.db.totemPulseCooldownAlpha) + cooldown.text:SetFont("Fonts\\FRIZQT__.TTF", 16, "OUTLINE") + cooldown.text:SetTextColor(Gladdy:SetColor(Gladdy.db.totemPulseTextColor)) +end + +function TotemPulse:UpdateFrameOnce() + for _,bar in pairs(self.activeFrames.bars) do + self:UpdateBar(bar) + end + for _,cooldown in pairs(self.activeFrames.cooldowns) do + self:UpdateCooldown(cooldown) + end + for _,bar in pairs(self.barCache) do + self:UpdateBar(bar) + end + for _,cooldown in pairs(self.cooldownCache) do + self:UpdateCooldown(cooldown) + end +end + +--------------------------------------------------- + +-- TEST + +--------------------------------------------------- + + +--------------------------------------------------- + +-- OPTIONS + +--------------------------------------------------- + +function TotemPulse:GetOptions() + return { + headerClassicon = { + type = "header", + name = L["Totem Pulse"], + order = 2, + }, + totemPulseEnabled = Gladdy:option({ + type = "toggle", + name = L["Totem Pulse Enabled"], + order = 3, + }), + totemPulseAttachToTotemPlate = Gladdy:option({ + type = "toggle", + name = L["Attach to Totem Plates"], + order = 4, + }), + group = { + type = "group", + childGroups = "tree", + name = L["Frame"], + order = 4, + args = { + barFrame = { + type = "group", + name = L["Bar"], + order = 1, + args = { + headerSize = { + type = "header", + name = L["Bar Size"], + order = 1, + }, + totemPulseBarHeight = Gladdy:option({ + type = "range", + name = L["Bar height"], + desc = L["Height of the bar"], + order = 3, + min = 0.1, + max = 200, + step = .1, + width = "full", + }), + totemPulseBarWidth = Gladdy:option({ + type = "range", + name = L["Bar width"], + desc = L["Width of the bars"], + order = 4, + min = 0.1, + max = 600, + step = .1, + width = "full", + }), + headerTexture = { + type = "header", + name = L["Texture"], + order = 5, + }, + totemPulseBarTexture = Gladdy:option({ + type = "select", + name = L["Bar texture"], + desc = L["Texture of the bar"], + order = 9, + dialogControl = "LSM30_Statusbar", + values = AceGUIWidgetLSMlists.statusbar, + }), + totemPulseBarColor = Gladdy:colorOption({ + type = "color", + name = L["Bar color"], + desc = L["Color of the cast bar"], + order = 10, + hasAlpha = true, + }), + totemPulseBarBgColor = Gladdy:colorOption({ + type = "color", + name = L["Background color"], + desc = L["Color of the cast bar background"], + order = 11, + hasAlpha = true, + }), + headerBorder = { + type = "header", + name = L["Border"], + order = 12, + }, + totemPulseBarBorderSize = Gladdy:option({ + type = "range", + name = L["Border size"], + order = 13, + min = 0.5, + max = Gladdy.db.castBarHeight/2, + step = 0.5, + width = "full", + }), + totemPulseBarBorderStyle = Gladdy:option({ + type = "select", + name = L["Status Bar border"], + order = 51, + dialogControl = "LSM30_Border", + values = AceGUIWidgetLSMlists.border, + }), + totemPulseBarBorderColor = Gladdy:colorOption({ + type = "color", + name = L["Status Bar border color"], + order = 52, + hasAlpha = true, + }), + }, + }, + }, + }, + } +end \ No newline at end of file