You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

383 lines
11 KiB

-- Neuron is a World of Warcraft® user interface addon.
-- Copyright (c) 2017-2021 Britt W. Yazel
-- Copyright (c) 2006-2014 Connor H. Chenoweth
-- This code is licensed under the MIT license (see LICENSE for details)
local _, addonTable = ...
local Neuron = addonTable.Neuron
---@class CastButton : StatusButton @define class CastButton inherits from class StatusButton
local CastButton = setmetatable({}, { __index = Neuron.StatusButton })
Neuron.CastButton = CastButton
local L = LibStub("AceLocale-3.0"):GetLocale("Neuron")
local castWatch = {}
CastButton.sbStrings = {
[1] = { L["None"], function(self) return "" end },
[2] = { L["Spell"], function(self) if castWatch[self:GetUnit()] then return castWatch[self:GetUnit()].spell end end },
[3] = { L["Timer"], function(self) if castWatch[self:GetUnit()] then return castWatch[self:GetUnit()].timer end end },
}
--these used to be a part of the core UI before being removed in 10.0
local CASTING_BAR_ALPHA_STEP = 0.05
local CASTING_BAR_FLASH_STEP = 0.2
local CASTING_BAR_HOLD_TIME = 1
---Constructor: Create a new Neuron Button object (this is the base object for all Neuron button types)
---@param bar Bar @Bar Object this button will be a child of
---@param buttonID number @Button ID that this button will be assigned
---@param defaults table @Default options table to be loaded onto the given button
---@return CastButton @ A newly created StatusButton object
function CastButton.new(bar, buttonID, defaults)
--call the parent object constructor with the provided information specific to this button type
local newButton = Neuron.StatusButton.new(bar, buttonID, defaults, CastButton, "CastBar", "Cast Button")
return newButton
end
function CastButton:InitializeButton()
self:RegisterEvent("UNIT_SPELLCAST_START", "OnEvent")
self:RegisterEvent("UNIT_SPELLCAST_SUCCEEDED", "OnEvent")
self:RegisterEvent("UNIT_SPELLCAST_FAILED", "OnEvent")
self:RegisterEvent("UNIT_SPELLCAST_INTERRUPTED", "OnEvent")
self:RegisterEvent("UNIT_SPELLCAST_DELAYED", "OnEvent")
self:RegisterEvent("UNIT_SPELLCAST_CHANNEL_START", "OnEvent")
self:RegisterEvent("UNIT_SPELLCAST_CHANNEL_UPDATE", "OnEvent")
self:RegisterEvent("UNIT_SPELLCAST_CHANNEL_STOP", "OnEvent")
if Neuron.isWoWRetail then
self:RegisterEvent("UNIT_SPELLCAST_INTERRUPTIBLE", "OnEvent")
self:RegisterEvent("UNIT_SPELLCAST_NOT_INTERRUPTIBLE", "OnEvent")
end
self.holdTime = 0
self:SetScript("OnUpdate", function(self, elapsed) self:OnUpdate(elapsed) end)
self.StatusBar:Hide()
self.typeString = L["Cast Bar"]
self:InitializeButtonSettings()
end
function CastButton:OnEvent(event,...)
local unit = select(1, ...)
local eventCastID = select(2,...) --return payload is "unitTarget", "castGUID", spellID
if unit ~= self:GetUnit() then
return
end
if not castWatch[unit] then
castWatch[unit] = {}
end
if event == "UNIT_SPELLCAST_START" then
local name, text, texture, startTime, endTime, isTradeSkill, castID, notInterruptible
if Neuron.isWoWRetail then
name, text, texture, startTime, endTime, isTradeSkill, castID, notInterruptible = UnitCastingInfo(unit)
else
name, text, texture, startTime, endTime, isTradeSkill, castID, notInterruptible = CastingInfo() --classic doesn't have UnitCastingInfo()
end
if not name then
self:Reset()
return
end
self.StatusBar:SetStatusBarColor(self.config.castColor[1], self.config.castColor[2], self.config.castColor[3])
self.StatusBar.Spark:SetTexture("Interface\\AddOns\\Neuron\\Images\\CastingBar_Spark_"..self.orientation)
self.StatusBar.Spark:Show()
self.value = (GetTime()-(startTime/1000))
self.maxValue = (endTime-startTime)/1000
self.StatusBar:SetMinMaxValues(0, self.maxValue)
self.StatusBar:SetValue(self.value)
self.StatusBar.totalTime = self.maxValue - self.StatusBar:GetValue()
castWatch[unit].spell = text
if self:GetShowIcon() then
self.StatusBar.Icon:SetTexture(texture)
self.StatusBar.Icon:Show()
if notInterruptible then
self.StatusBar.Shield:Show()
else
self.StatusBar.Shield:Hide()
end
else
self.StatusBar.Icon:Hide()
self.StatusBar.Shield:Hide()
end
self.StatusBar:SetAlpha(1.0)
self.holdTime = 0
self.casting = true
self.castID = castID
self.channeling = nil
self.fadeout = nil
self.StatusBar:Show()
elseif event == "UNIT_SPELLCAST_CHANNEL_START" then
local name, text, texture, startTime, endTime, isTradeSkill, notInterruptible = UnitChannelInfo(unit)
if not name then
self:Reset()
return
end
self.StatusBar:SetStatusBarColor(self.config.channelColor[1], self.config.channelColor[2], self.config.channelColor[3])
self.value = ((endTime/1000)-GetTime())
self.maxValue = (endTime - startTime) / 1000;
self.StatusBar:SetMinMaxValues(0, self.maxValue);
self.StatusBar:SetValue(self.value)
castWatch[unit].spell = text
if self:GetShowIcon() then
self.StatusBar.Icon:SetTexture(texture)
self.StatusBar.Icon:Show()
if notInterruptible then
self.StatusBar.Shield:Show()
else
self.StatusBar.Shield:Hide()
end
else
self.StatusBar.Icon:Hide()
self.StatusBar.Shield:Hide()
end
self.StatusBar.Spark:Hide()
self.StatusBar:SetAlpha(1.0)
self.holdTime = 0
self.casting = nil
self.channeling = true
self.fadeout = nil
self.StatusBar:Show()
elseif event == "UNIT_SPELLCAST_SUCCEEDED" and not self.channeling then --don't do anything with this event when channeling as it fires at each pulse of a spell channel
self.StatusBar:SetStatusBarColor(self.config.successColor[1], self.config.successColor[2], self.config.successColor[3])
elseif event == "UNIT_SPELLCAST_SUCCEEDED" and self.channeling then
-- do nothing (when Tranquility is channeling if reports UNIT_SPELLCAST_SUCCEEDED many times during the duration)
elseif (event == "UNIT_SPELLCAST_FAILED" or event == "UNIT_SPELLCAST_INTERRUPTED") and self.castID == eventCastID or event == "UNIT_SPELLCAST_CHANNEL_STOP" then
if self.StatusBar:IsShown() and (self.casting or self.channeling) and not self.fadeout then
self.StatusBar:SetValue(self.maxValue)
self.StatusBar:SetStatusBarColor(self.config.failColor[1], self.config.failColor[2], self.config.failColor[3])
self.StatusBar.Spark:Hide()
if event == "UNIT_SPELLCAST_FAILED" then
castWatch[unit].spell = FAILED
elseif event == "UNIT_SPELLCAST_CHANNEL_STOP" then
-- empty --
else
castWatch[unit].spell = INTERRUPTED
end
self.casting = nil
self.channeling = nil
self.fadeout = true
self.holdTime = GetTime() + CASTING_BAR_HOLD_TIME
end
elseif event == "UNIT_SPELLCAST_DELAYED" then
if self.StatusBar:IsShown() then
local name, text, texture, startTime, endTime, isTradeSkill = UnitCastingInfo(unit)
if not name then
self:Reset()
return
end
self.value = (GetTime()-(startTime/1000))
self.maxValue = (endTime-startTime)/1000
self.StatusBar:SetMinMaxValues(0, self.maxValue)
if not self.casting then
self.StatusBar:SetStatusBarColor(self.config.castColor[1], self.config.castColor[2], self.config.castColor[3])
self.StatusBar.Spark:Show()
self.StatusBar.BarFlash:SetAlpha(0.0)
self.StatusBar.BarFlash:Hide()
self.casting = true
self.channeling = nil
self.flash = nil
self.fadeout = nil
end
end
elseif event == "UNIT_SPELLCAST_CHANNEL_UPDATE" then
if self.StatusBar:IsShown() then
local name, text, texture, startTime, endTime, isTradeSkill = UnitChannelInfo(unit)
if not name then
self:Reset()
return
end
self.value = ((endTime/1000)-GetTime())
self.maxValue = (endTime-startTime)/1000
self.StatusBar:SetMinMaxValues(0, self.maxValue)
self.StatusBar:SetValue(self.value)
end
elseif self.StatusBar.showShield and event == "UNIT_SPELLCAST_INTERRUPTIBLE" then
self.StatusBar.Shield:Hide()
elseif self.StatusBar.showShield and event == "UNIT_SPELLCAST_NOT_INTERRUPTIBLE" then
self.StatusBar.Shield:Show()
end
if not Neuron.barEditMode and not Neuron.buttonEditMode then
self.StatusBar.CenterText:SetText(self:cFunc())
self.StatusBar.LeftText:SetText(self:lFunc())
self.StatusBar.RightText:SetText(self:rFunc())
self.StatusBar.MouseoverText:SetText(self:mFunc())
end
end
function CastButton:OnUpdate(elapsed)
if Neuron.pendingReload then
return
end
--bail out if these values don't exist. Otherwise we will error later on
if not self.value and not self.maxValue then
self:Reset()
return
end
if not castWatch[self:GetUnit()] then
castWatch[self:GetUnit()] = {}
end
if self.maxValue then
castWatch[self:GetUnit()].timer = string.format("%0.1f", self.value).."/"..format("%0.1f", self.maxValue)
else
castWatch[self:GetUnit()].timer = string.format("%0.1f", self.value)
end
if self.casting then
self.value = self.value + elapsed
if self.value >= self.maxValue then
self.StatusBar:SetValue(self.maxValue)
self:FinishCast()
return
end
self.StatusBar:SetValue(self.value)
self.StatusBar.BarFlash:Hide()
if self.orientation == 1 then
local sparkPosition = (self.value/self.maxValue)*self.StatusBar:GetWidth()
if sparkPosition < 0 then
sparkPosition = 0
end
self.StatusBar.Spark:SetPoint("CENTER", self.StatusBar, "LEFT", sparkPosition, 0)
else
local sparkPosition = (self.value/self.maxValue) * self.StatusBar:GetHeight()
if sparkPosition < 0 then
sparkPosition = 0
end
self.StatusBar.Spark:SetPoint("CENTER", self.StatusBar, "BOTTOM", 0, sparkPosition)
end
elseif self.channeling then
self.value = self.value - elapsed
if self.value <= 0 then
self:FinishCast()
return
end
self.StatusBar:SetValue(self.value)
self.StatusBar.BarFlash:Hide()
elseif GetTime() < self.holdTime then
return
elseif self.flash then
local alpha = self.StatusBar.BarFlash:GetAlpha() + CASTING_BAR_FLASH_STEP or 0
if alpha < 1 then
self.StatusBar.BarFlash:SetAlpha(alpha)
else
self.StatusBar.BarFlash:SetAlpha(1.0)
self.flash = nil
end
elseif self.fadeout and (not Neuron.barEditMode and not Neuron.buttonEditMode) then
local alpha = self.StatusBar:GetAlpha() - CASTING_BAR_ALPHA_STEP
if alpha > 0 then
self.StatusBar:SetAlpha(alpha)
else
self:Reset()
end
else
self:Reset()
end
if not Neuron.barEditMode and not Neuron.buttonEditMode then
self.StatusBar.CenterText:SetText(self:cFunc())
self.StatusBar.LeftText:SetText(self:lFunc())
self.StatusBar.RightText:SetText(self:rFunc())
self.StatusBar.MouseoverText:SetText(self:mFunc())
end
end
function CastButton:FinishCast()
self.StatusBar.Spark:Hide()
self.StatusBar.BarFlash:SetAlpha(1.0)
self.StatusBar.BarFlash:Show()
self.flash = true
self.fadeout = true
self.casting = nil
self.channeling = nil
end
function CastButton:Reset()
self.fadeout = true
self.casting = nil
self.channeling = nil
self.StatusBar:SetStatusBarColor(self.config.castColor[1], self.config.castColor[2], self.config.castColor[3])
if not Neuron.barEditMode and not Neuron.buttonEditMode then
self.StatusBar:Hide()
end
end
-----------------------------------------------------
-------------------Sets and Gets---------------------
-----------------------------------------------------
---@alias BarUnit "player"|"pet"|"target"|"targettarget"|"focus"|"mouseover"|"party1"|"party2"|"party3"|"party4"
---@param unit BarUnid
function CastButton:SetUnit(unit)
if unit then
self.config.unit = unit
else
unit = "player"
end
end
function CastButton:GetUnit()
return self.config.unit
end
function CastButton:SetShowIcon(show)
self.config.showIcon = show
end
function CastButton:GetShowIcon()
return self.config.showIcon
end