vanilla-wow-addons – Rev 1
?pathlinks?
--[[
Name: SpellStatus-1.0
Revision: $Rev: 14589 $
Author(s): Nightdew (denzsolnightdew@gmail.com)
Website: http://www.wowace.com/index.php/SpellStatus-1.0
Documentation: http://www.wowace.com/index.php/SpellStatus-1.0
SVN: http://svn.wowace.com/root/trunk/SpellStatusLib/SpellStatus-1.0
Description: Status library that simplifies retrieving spell status information from the player
Dependencies: AceLibrary, AceDebug-2.0, AceEvent-2.0, AceHook-2.1, Deformat-2.0, Gratuity-2.0, SpellCache-1.0, (optional) SpellStatus-AimedShot-1.0
]]
local MAJOR_VERSION = "SpellStatus-1.0"
local MINOR_VERSION = "$Revision: 14589 $"
if (not AceLibrary) then
error(MAJOR_VERSION .. " requires AceLibrary.")
end
if (not AceLibrary:IsNewVersion(MAJOR_VERSION, MINOR_VERSION)) then
return
end
local function CheckDependency(dependencies)
for index, value in ipairs(dependencies) do
if (not AceLibrary:HasInstance(value)) then
error(format("%s requires %s to function properly", MAJOR_VERSION, value))
end
end
end
local dependencyLibraries = {
"AceDebug-2.0",
"AceEvent-2.0",
"AceHook-2.1",
"Deformat-2.0",
"Gratuity-2.0",
"SpellCache-1.0"
}
CheckDependency(dependencyLibraries)
local deformat = AceLibrary("Deformat-2.0")
local gratuity = AceLibrary("Gratuity-2.0")
local spellcache = AceLibrary("SpellCache-1.0")
--Create Library Object
local SpellStatus = {}
--Embed all needed mixins into the Library Object SpellStatus
AceLibrary("AceDebug-2.0"):embed(SpellStatus)
AceLibrary("AceEvent-2.0"):embed(SpellStatus)
AceLibrary("AceHook-2.1"):embed(SpellStatus)
--
-- Local functions not to be called from outside
--
local function InitializeHooks(self)
self:Hook("CastSpell")
self:Hook("CastSpellByName")
self:Hook("UseAction")
self:Hook("CastShapeshiftForm")
self:Hook("UseInventoryItem")
self:Hook("UseContainerItem")
self:Hook("ToggleGameMenu")
self:Hook("SpellStopCasting")
end
local function InitializeEventRegisters(self)
self:RegisterEvent("SPELLCAST_START")
self:RegisterEvent("SPELLCAST_STOP")
self:RegisterEvent("SPELLCAST_INTERRUPTED")
self:RegisterEvent("SPELLCAST_FAILED")
self:RegisterEvent("SPELLCAST_DELAYED")
self:RegisterEvent("SPELLCAST_CHANNEL_START")
self:RegisterEvent("SPELLCAST_CHANNEL_STOP")
self:RegisterEvent("SPELLCAST_CHANNEL_UPDATE")
self:RegisterEvent("UI_ERROR_MESSAGE")
self:RegisterEvent("CHAT_MSG_SPELL_FAILED_LOCALPLAYER")
self:RegisterEvent("CHAT_MSG_SPELL_AURA_GONE_SELF")
self:RegisterEvent("CHAT_MSG_COMBAT_SELF_HITS")
self:RegisterEvent("CHAT_MSG_COMBAT_SELF_MISSES")
self:RegisterEvent("CHAT_MSG_SPELL_SELF_DAMAGE")
--SPELLLOGSELFOTHER
--Used to determine if we are wanding.
self:RegisterEvent("START_AUTOREPEAT_SPELL")
self:RegisterEvent("STOP_AUTOREPEAT_SPELL")
self:RegisterEvent("PLAYER_ENTER_COMBAT")
self:RegisterEvent("PLAYER_LEAVE_COMBAT")
self:RegisterEvent("PLAYER_REGEN_DISABLED")
self:RegisterEvent("PLAYER_REGEN_ENABLED")
self:RegisterEvent("SpellCache_Updated")
end
local function ResetActiveVariables(self)
self:LevelDebug(2, "ResetActiveVariables")
--Active Spell
self.vars.ActiveId = nil
self.vars.ActiveName = nil
self.vars.ActiveRank = nil
self.vars.ActiveFullName = nil
self.vars.ActiveCastStartTime = nil
self.vars.ActiveCastStopTime = nil
self.vars.ActiveCastDuration = nil
--Casting
self.vars.ActiveCastDelay = nil
self.vars.ActiveCastDelayTotal = nil
--Channeling
self.vars.ActiveAction = nil
self.vars.ActiveCastDisruption = nil
self.vars.ActiveCastDisruptionTotal = nil
--NextMelee
self.vars.NextMeleeId = nil
self.vars.NextMeleeName = nil
self.vars.NextMeleeRank = nil
self.vars.NextMeleeFullName = nil
end
local function ResetVariables(self)
self:LevelDebug(2, "ResetVariables")
--Spell Attempted to cast
self.vars.AttemptId = nil
self.vars.AttemptName = nil
self.vars.AttemptRank = nil
self.vars.AttemptFullName = nil
ResetActiveVariables(self)
--UI_ERROR_MESSAGE
self.vars.UIEM_Message = nil
--CHATMSGSPELLFAILEDLOCALPLAYER
self.vars.CMSFLP_SpellName = nil
self.vars.CMSFLP_Message = nil
end
local function InitializeVariables(self)
self:LevelDebug(2, "InitializeVariables")
self.vars = {}
--True while data is assigned until fail or stop or start and no SpellId
self.vars.Using = false
--True while data is assigned until fail or stop or start and SpellId
self.vars.Preparing = false
--Only true for spell with a casting time
self.vars.Casting = false
--Only true for channeling spells
self.vars.Channeling = false
--Only true for spells that are next melee
self.vars.NextMeleeing = false
--Whether or not the character is auto repeating
self.vars.AutoRepeating = false
--Are we attacking currently
self.vars.Attacking = false
--Are we currently in combat
self.vars.Combating = false
self.vars.Targeting = false
--True when hooked into ToggleGameMenu
self.vars.CancelTargeting = false
self.vars.CancelCasting = false
self.vars.CancelChanneling = false
ResetVariables(self)
end
--
-- Activate method
--
local function activate(self, oldLib, oldDeactivate)
--self:SetDebugging(true)
--self:SetDebugLevel(3)
self:LevelDebug(2, "SpellStatus - activate")
if (oldLib) then
oldLib:UnregisterAllEvents()
oldLib:UnhookAll()
end
--Default code to clean up the oldlib
if (oldDeactivate) then
oldDeactivate(oldLib)
end
InitializeVariables(self)
InitializeHooks(self)
InitializeEventRegisters(self)
end
function SpellStatus:Report()
self:LevelDebug(3,
format("Using: %s", tostring(self.vars.Using)),
format("Preparing: %s", tostring(self.vars.Preparing)),
format("Casting: %s", tostring(self.vars.Casting)),
format("Channeling: %s", tostring(self.vars.Channeling)),
format("SpellName: %s", tostring(self:GetActiveSpellName()))
)
end
function SpellStatus:IsUsing()
return self.vars.Using == true
end
function SpellStatus:IsPreparing()
return self.vars.Preparing == true
end
function SpellStatus:IsCasting()
return self.vars.Casting == true
end
function SpellStatus:IsChanneling()
return self.vars.Channeling == true
end
function SpellStatus:IsNextMeleeing()
return self.vars.NextMeleeing == true
end
function SpellStatus:IsCastingOrChanneling()
return self:IsCasting() or self:IsChanneling()
end
function SpellStatus:IsPreparingOrCastingOrChanneling()
return self:IsPreparing() or self:IsCasting() or self:IsChanneling()
end
function SpellStatus:IsAutoRepeating()
return self.vars.AutoRepeating == true
end
function SpellStatus:IsWanding()
return ((self.vars.AutoRepeating == true) and HasWandEquipped()) and true or false
end
function SpellStatus:IsAttacking()
return self.vars.Attacking == true
end
function SpellStatus:IsCombating()
return self.vars.Combating == true
end
function SpellStatus:IsActiveSpell(spellId, spellName)
local sId, sName = self:GetActiveSpellData()
self:LevelDebug(2, "IsActiveSpell", spellId, sId, spellName, sName)
--sId and spellId might be nil
return (sId == spellId) and (sName == spellName)
end
function SpellStatus:GetActiveSpellData()
return self.vars.ActiveId, self.vars.ActiveName, self.vars.ActiveRank, self.vars.ActiveFullName,
self.vars.ActiveCastStartTime, self.vars.ActiveCastStopTime, self.vars.ActiveCastDuration,
self.vars.ActiveAction
end
function SpellStatus:GetActiveSpellName()
local _, spellName = self:GetActiveSpellData()
return spellName
end
function SpellStatus:GetNextMeleeSpellData()
return self.vars.NextMeleeId, self.vars.NextMeleeName, self.vars.NextMeleeRank, self.vars.NextMeleeFullName
end
--
-- Function Hooking
--
function SpellStatus:SpellCache_Updated()
end
local function AssignNextMeleeSpellData(self, spellId, spellName, spellRank, spellFullName)
if (not spellId) then
return false
end
gratuity:SetSpell(spellId, BOOKTYPE_SPELL)
if (gratuity:Find(SPELL_ON_NEXT_SWING, 2, 3, false, true, true) == nil) then
return false
end
self:LevelDebug(1, "AssignNextMeleeSpellData", spellId, spellName, spellRank, spellFullName)
self.vars.NextMeleeing = true
self.vars.NextMeleeId = spellId
self.vars.NextMeleeName = spellName
self.vars.NextMeleeRank = spellRank
self.vars.NextMeleeFullName = spellFullName
return true
end
local function AssignSpellData(self, spellId, spellName, spellRank, spellFullName)
--self:LevelDebug(1, "AssignSpellData", spellId, spellName, spellRank, spellFullName)
--If Next Melee spell stop dont continue
if (AssignNextMeleeSpellData(self, spellId, spellName, spellRank, spellFullName)) then
return
end
if (self.vars.Preparing or self.vars.Casting or self.vars.Channeling) then
return
end
if (self.vars.Using and (spellName == self.vars.ActiveName)) then
return
end
self:LevelDebug(1, "AssignSpellData", spellId, spellName, spellRank, spellFullName)
ResetVariables(self)
self.vars.ActiveId = spellId
self.vars.ActiveName = spellName
self.vars.ActiveRank = spellRank
self.vars.ActiveFullName = spellFullName
self.vars.Preparing = spellId ~= nil
self.vars.Using = not self.vars.Preparing
--Only preparing if you have a spellId
if (self.vars.Preparing) then
local aimedShot = AceLibrary:HasInstance("SpellStatus-AimedShot-1.0") and AceLibrary("SpellStatus-AimedShot-1.0") or nil
if (aimedShot and aimedShot:Active()) then
local aimedShotId, aimedShotDuration = aimedShot:MatchSpellId(spellId)
if (aimedShotId) then
self:SPELLCAST_START(spellName, aimedShotDuration)
end
end
end
end
local function TriggerFailureEvent(self, overrideHasMessage)
overrideHasMessage = overrideHasMessage == true
--self:LevelDebug(2, "TriggerFailureEvent", overrideHasMessage)
local hasMessage = self.vars.UIEM_Message or self.vars.CMSFLP_Message
self:LevelDebug(2, "TriggerFailureEvent", hasMessage, overrideHasMessage)
if (not (hasMessage or overrideHasMessage)) then
return false
end
self:LevelDebug(2, "TriggerFailureEvent", overrideHasMessage)
local isActiveSpell = false
local sId, sName, sRank, sFullName
if (self.vars.AttemptName) then
sId = self.vars.AttemptId
sName = self.vars.AttemptName
sRank = self.vars.AttemptRank
sFullName = self.vars.AttemptFullName
self:LevelDebug(2, "TriggerFailureEvent Attempt", sId, sName, sRank, sFullName)
self.vars.Using = false
self.vars.Preparing = false
self.vars.NextMeleeing = false
--Necessary because the error might happen through multiple paths
self.vars.AttemptCastFailure = true
elseif (self.vars.CMSFLP_SpellName and (self.vars.CMSFLP_SpellName == self.vars.NextMeleeName)) then
sId = self.vars.NextMeleeId
sName = self.vars.NextMeleeName
sRank = self.vars.NextMeleeRank
sFullName = self.vars.NextMeleeFullName
self:LevelDebug(2, "TriggerFailureEvent NextMelee", sId, sName, sRank, sFullName)
self.vars.NextMeleeing = false
elseif (overrideHasMessage or (self.vars.CMSFLP_SpellName and (self.vars.CMSFLP_SpellName == self.vars.ActiveName))) then
isActiveSpell = true
sId = self.vars.ActiveId
sName = self.vars.ActiveName
sRank = self.vars.ActiveRank
sFullName = self.vars.ActiveFullName
self:LevelDebug(2, "TriggerFailureEvent Active", sId, sName, sRank, sFullName)
self.vars.Using = false
self.vars.Preparing = false
self.vars.Casting = false
self.vars.Channeling = false
else --must have been unrelated
return false
end
self:TriggerEvent("SpellStatus_SpellCastFailure",
sId, sName, sRank, sFullName, isActiveSpell,
self.vars.UIEM_Message, self.vars.CMSFLP_SpellName, self.vars.CMSFLP_Message
)
self.vars.UIEM_Message = nil
self.vars.CMSFLP_SpellName = nil
self.vars.CMSFLP_Message = nil
return true
end
function ResetCastOriginal(self, sId, sName, sRank, sFullName)
--setup variables if failing immediately
self.vars.AttemptId = sId
self.vars.AttemptName = sName
self.vars.AttemptRank = sRank
self.vars.AttemptFullName = sFullName
--reset Error Message
self.vars.UIEM_Message = nil
self.vars.CMSFLP_SpellName = nil
self.vars.CMSFLP_Message = nil
self.vars.AttemptCastFailure = false
end
function CastOriginal(self, methodName, param1, param2, param3, sId, sName, sRank, sFullName)
self:LevelDebug(1, ">>>> CastOriginal",
methodName, param1, param2, param3,
sId, sName, sRank, sFullName)
ResetCastOriginal(self, sId, sName, sRank, sFullName)
self:LevelDebug(3, "-> CastOriginal")
self.hooks[methodName](param1, param2, param3)
self:LevelDebug(3, "<- CastOriginal")
TriggerFailureEvent(self)
if (not self.vars.AttemptCastFailure) then
AssignSpellData(self, sId, sName, sRank, sFullName)
end
ResetCastOriginal(self, nil, nil, nil, nil)
self:LevelDebug(1, "<<<< CastOriginal",
methodName, param1, param2, param3,
sId, sName, sRank, sFullName)
end
function SpellStatus:CastSpellByName(spellName, onSelf)
self:LevelDebug(2, ">>>> CastSpellByName", spellName, onSelf)
local sName, sId, sRank, sFullName
sName, sRank, sId, sFullName = spellcache:GetSpellData(spellName)
CastOriginal(self, "CastSpellByName", spellName, onSelf, nil, sId, sName, sRank, sFullName)
self:LevelDebug(2, "<<<< CastSpellByName2", spellName, onSelf)
end
function SpellStatus:CastSpell(spellId, spellbookType)
self:LevelDebug(2, ">>>> CastSpell", spellId, spellbookType)
local sId, sName, sRank, sFullName
if (spellbookType == BOOKTYPE_SPELL) then
sName, sRank, sId, sFullName = spellcache:GetSpellData(spellId)
end
CastOriginal(self, "CastSpell", spellId, spellbookType, nil, sId, sName, sRank, sFullName)
self:LevelDebug(2, "<<<< CastSpell", spellId, spellbookType)
end
--When using UseAction through clicking an actiobar button, we need to get in
local function GetGratuitySpellData(self, slotId)
local spellName = gratuity:GetLine(1)
local spellRank = gratuity:GetLine(1, true)
--empty slot?
if (not spellName) then
return
end
self:LevelDebug(3, "GetGratuitySpellData", spellName, spellRank)
local sName, sRank, sId, sFullName = spellcache:GetSpellData(spellName, spellRank)
if (sName) then
return sId, sName, sRank, sFullName
else
return nil, spellName, nil, nil
end
end
function SpellStatus:UseAction(slotId, checkCursor, onSelf)
self:LevelDebug(1, ">>>> UseAction", slotId, checkCursor, onSelf)
local actionText = GetActionText(slotId)
local isMacro = actionText ~= nil
--self:LevelDebug(2, "UseAction", actionText, tostring(isMacro))
if (isMacro) then
self.hooks["UseAction"](slotId, checkCursor, onSelf)
else
gratuity:SetAction(slotId)
local sId, sName, sRank, sFullName = GetGratuitySpellData(self, slotId)
if (sName) then
CastOriginal(self, "UseAction", slotId, checkCursor, onSelf, sId, sName, sRank, sFullName)
else
self.hooks["UseAction"](slotId, checkCursor, onSelf)
end
end
self:LevelDebug(1, "<<<< UseAction", slotId, checkCursor, onSelf)
end
function SpellStatus:CastShapeshiftForm(index)
self:LevelDebug(2, ">>>> CastShapeshiftForm", index)
gratuity:SetShapeshift(index)
local sId, sName, sRank, sFullName = GetGratuitySpellData(self, slotId)
if (sName) then
CastOriginal(self, "CastShapeshiftForm", index, nil, nil, sId, sName, sRank, sFullName)
else
self.hooks["CastShapeshiftForm"](index)
end
self:LevelDebug(2, "<<<< CastShapeshiftForm", index)
end
local function GetItemLinkData(slotId, bagId)
local itemLink = nil
if (bagId == nil) then
itemLink = GetInventoryItemLink("player", slotId)
else
itemLink = GetContainerItemLink(bagId, slotId)
end
if (itemLink) then
local _, _, itemName = string.find(itemLink, "^.*%[(.*)%].*$")
return itemName, itemLink
end
end
function SpellStatus:UseInventoryItem(slotId)
self:LevelDebug(2, ">>>> UseInventoryItem", slotId)
local itemName, itemLink = GetItemLinkData(slotId)
if (itemLink) then
CastOriginal(self, "UseInventoryItem", slotId, nil, nil, nil, itemName, nil, itemLink)
else
self.hooks["UseInventoryItem"](slotId)
end
self:LevelDebug(2, "<<<< UseInventoryItem", slotId)
end
function SpellStatus:UseContainerItem(bagId, slotId)
self:LevelDebug(2, ">>>> UseContainerItem", bagId, slotId)
local itemName, itemLink = GetItemLinkData(slotId, bagId)
if (itemLink) then
CastOriginal(self, "UseContainerItem", bagId, slotId, nil, nil, itemName, nil, itemLink)
else
self.hooks["UseContainerItem"](bagId, slotId)
end
self:LevelDebug(2, "<<<< UseContainerItem", bagId, slotId)
end
function SpellStatus:ToggleGameMenu()
--self:LevelDebug(3, "ToggleGameMenu1", SpellIsTargeting())
--If these hook is called and targeting, targeting will always be killed first
self.vars.CancelTargeting = SpellIsTargeting()
self.vars.CancelCasting = self.vars.Casting
self.vars.CancelChanneling = self.vars.Channeling
self.hooks["ToggleGameMenu"]()
self.vars.CancelTargeting = false
self.vars.CancelCasting = false
self.vars.CancelChanneling = false
--self:LevelDebug(3, "ToggleGameMenu2", SpellIsTargeting())
end
function SpellStatus:SpellStopCasting()
self:LevelDebug(2, ">>>> SpellStopCasting")
if (self:IsCastingOrChanneling()) then
self.vars.SpellStopCastingActiveName = self.vars.ActiveName
end
self.hooks["SpellStopCasting"]()
self:LevelDebug(2, "<<<< SpellStopCasting")
end
function SpellStatus:SPELLCAST_START(spellName, duration)
self:LevelDebug(1, "SPELLCAST_START", spellName, duration)
self.vars.SpellStopCastingActiveName = nil
self.vars.Using = false
self.vars.Preparing = false
self.vars.Casting = true
if (self.vars.ActiveName ~= spellName) then
ResetActiveVariables(self)
self.vars.ActiveName = spellName
self.vars.ActiveFullName = spellName
end
self.vars.ActiveCastStartTime = GetTime()
self.vars.ActiveCastDuration = duration
self.vars.ActiveCastStopTime = self.vars.ActiveCastStartTime + (self.vars.ActiveCastDuration/1000)
self.vars.ActiveCastDelay = nil
self.vars.ActiveCastDelayTotal = nil
self:TriggerEvent(
"SpellStatus_SpellCastCastingStart",
self.vars.ActiveId,
self.vars.ActiveName,
self.vars.ActiveRank,
self.vars.ActiveFullName,
self.vars.ActiveCastStartTime,
self.vars.ActiveCastStopTime,
self.vars.ActiveCastDuration
)
end
function SpellStatus:SPELLCAST_DELAYED(delay)
self:LevelDebug(1, "SPELLCAST_DELAYED", delay)
if (self.vars.ActiveCastStopTime == nil) then
return
end
self.vars.ActiveCastDelay = delay/1000
self.vars.ActiveCastDelayTotal = (self.vars.ActiveCastDelayTotal or 0) + self.vars.ActiveCastDelay
self.vars.ActiveCastStopTime = self.vars.ActiveCastStopTime + self.vars.ActiveCastDelay
self:TriggerEvent(
"SpellStatus_SpellCastCastingChange",
self.vars.ActiveId,
self.vars.ActiveName,
self.vars.ActiveRank,
self.vars.ActiveFullName,
self.vars.ActiveCastStartTime,
self.vars.ActiveCastStopTime,
self.vars.ActiveCastDuration,
self.vars.ActiveCastDelay,
self.vars.ActiveCastDelayTotal
)
end
function SpellStatus:SPELLCAST_STOP()
self:LevelDebug(1, "SPELLCAST_STOP")
--If canceling targeting.. ignore stop!
if (self.vars.CancelTargeting or self.vars.CancelCasting or self.vars.CancelChanneling) then
return
end
--if (self.vars.ActiveId == nil) then
if (self.vars.ActiveName == nil) then
return
end
--Player probably moved initiating a client and server side SPELLCAST_STOP
if (not( self.vars.Using or
self.vars.Preparing or
self.vars.Casting or
self.vars.Channeling or
self.vars.AutoRepeating )) then
return
end
if (TriggerFailureEvent(self)) then
return
end
self.vars.Using = false
self.vars.Preparing = false
--Second SPELLCAST_STOP received from server after SpellStopCasting was called
if ((not self.vars.Casting) and
self.vars.SpellStopCastingActiveName and
(self.vars.ActiveName == self.vars.SpellStopCastingActiveName)) then
self.vars.SpellStopCastingActiveName = nil
return
end
local castingInstant = (not self.vars.Casting) and (not self.vars.Channeling)
self.vars.Casting = false
--Generate Finish Event if not channeling
if (not self.vars.Channeling) then
local sD = castingInstant and self or self.vars.ActiveCastingData
self.vars.ActiveCastStartTime = self.vars.ActiveCastStartTime or GetTime()
self.vars.ActiveCastStopTime = GetTime()
self:TriggerEvent(
castingInstant and "SpellStatus_SpellCastInstant" or "SpellStatus_SpellCastCastingFinish",
self.vars.ActiveId,
self.vars.ActiveName,
self.vars.ActiveRank,
self.vars.ActiveFullName,
self.vars.ActiveCastStartTime,
self.vars.ActiveCastStopTime,
self.vars.ActiveCastDuration,
self.vars.ActiveCastDelayTotal
)
--We cant reset because maybe we have a failure!!!
--ResetActiveVariables(self)
end
end
function SpellStatus:SPELLCAST_CHANNEL_START(duration, action)
self:LevelDebug(2, "SPELLCAST_CHANNEL_START", duration, action)
self.vars.SpellStopCastingActiveName = nil
self.vars.Using = false
self.vars.Preparing = false
self.vars.Channeling = true
local sD = self.vars.ActiveChannelingData
self.vars.ActiveCastStartTime = GetTime()
self.vars.ActiveCastDuration = duration / 1000
self.vars.ActiveCastStopTime = self.vars.ActiveCastStartTime + self.vars.ActiveCastDuration
self.vars.ActiveAction = action
self.vars.ActiveId = self.vars.ActiveId
self.vars.ActiveName = self.vars.ActiveName
self.vars.ActiveRank = self.vars.ActiveRank
self.vars.ActiveFullName = self.vars.ActiveFullName
self.vars.ActiveCastDisruption = nil
self.vars.ActiveCastDisruptionTotal = nil
self:TriggerEvent(
"SpellStatus_SpellCastChannelingStart",
self.vars.ActiveId,
self.vars.ActiveName,
self.vars.ActiveRank,
self.vars.ActiveFullName,
self.vars.ActiveCastStartTime,
self.vars.ActiveCastStopTime,
self.vars.ActiveCastDuration,
self.vars.ActiveAction
)
end
--Any changes while channeling will come through this event
function SpellStatus:SPELLCAST_CHANNEL_UPDATE(duration)
self:LevelDebug(2, "SPELLCAST_CHANNEL_UPDATE", duration)
local sD = self.vars.ActiveChannelingData
local timeStamp = GetTime()
--New Duration
local spellCastDuration = duration / 1000
self:LevelDebug(3, "spellCastDuration", spellCastDuration)
--Store old stop time
local spellCastStopTime = self.vars.ActiveCastStopTime
--Time Passed since Channeling
local spellCastTimePassed = timeStamp - self.vars.ActiveCastStartTime
self:LevelDebug(3, "spellCastTimePassed", spellCastTimePassed)
--What channel time did we loose
self.vars.ActiveCastDisruption = self.vars.ActiveCastDuration - spellCastDuration - spellCastTimePassed
self.vars.ActiveCastDisruptionTotal = (self.vars.ActiveCastDisruptionTotal or 0) + self.vars.ActiveCastDisruption
self.vars.ActiveCastStopTime = timeStamp + spellCastDuration
self:TriggerEvent(
"SpellStatus_SpellCastChannelingChange",
self.vars.ActiveId,
self.vars.ActiveName,
self.vars.ActiveRank,
self.vars.ActiveFullName,
self.vars.ActiveCastStartTime,
self.vars.ActiveCastStopTime,
self.vars.ActiveCastDuration,
self.vars.ActiveAction,
self.vars.ActiveCastDisruption,
self.vars.ActiveCastDisruptionTotal
)
end
function SpellStatus:SPELLCAST_CHANNEL_STOP()
self:LevelDebug(2, "SPELLCAST_CHANNEL_STOP")
self.vars.Using = false
self.vars.Preparing = false
self.vars.Channeling = false
self.vars.ActiveCastStopTime = GetTime()
self:TriggerEvent(
"SpellStatus_SpellCastChannelingFinish",
self.vars.ActiveId,
self.vars.ActiveName,
self.vars.ActiveRank,
self.vars.ActiveFullName,
self.vars.ActiveCastStartTime,
self.vars.ActiveCastStopTime,
self.vars.ActiveCastDuration,
self.vars.ActiveAction,
self.vars.ActiveCastDisruptionTotal
)
end
--Always thrown before CHAT_MSG_SPELL_FAILED_LOCALPLAYER which might be thrown
function SpellStatus:UI_ERROR_MESSAGE(message)
self:LevelDebug(2, "UI_ERROR_MESSAGE", message)
self.vars.UIEM_Message = message
end
local FAILUREMESSAGE = {
SPELLFAILCASTSELF,
SPELLFAILPERFORMSELF
}
function SpellStatus:CHAT_MSG_SPELL_FAILED_LOCALPLAYER(message)
self:LevelDebug(2, "CHAT_MSG_SPELL_FAILED_LOCALPLAYER", message)
table.foreach(FAILUREMESSAGE,
function(key, value)
local spellName, spellFailureMessage = deformat:Deformat(message, value)
if (spellName) then
self.vars.CMSFLP_SpellName = spellName
self.vars.CMSFLP_Message = spellFailureMessage
end
--if returning ~= nil the foreach will stop.
return spellName
end
)
end
local CHAT_MSG_SPELL_SELF_DAMAGEMESSAGES = {
IMMUNESPELLSELFOTHER,
SIMPLECASTSELFOTHER,
SIMPLEPERFORMSELFOTHER,
SPELLBLOCKEDSELFOTHER,
SPELLDODGEDSELFOTHER,
SPELLEVADEDSELFOTHER,
SPELLIMMUNESELFOTHER,
SPELLINTERRUPTSELFOTHER,
SPELLLOGABSORBSELFOTHER,
SPELLLOGABSORBSELFSELF,
SPELLLOGCRITSCHOOLSELFOTHER,
SPELLLOGCRITSCHOOLSELFSELF,
SPELLLOGCRITSELFOTHER,
SPELLLOGSCHOOLSELFOTHER,
SPELLLOGSCHOOLSELFSELF,
SPELLLOGSELFOTHER,
SPELLMISSSELFOTHER,
SPELLPARRIEDSELFOTHER,
SPELLREFLECTSELFOTHER,
SPELLRESISTSELFOTHER,
SPELLRESISTSELFSELF,
SPELLTERSEPERFORM_SELF,
SPELLTERSE_SELF
}
local CHAT_MSG_SPELL_SELF_DAMAGEMESSAGETRAILERS = {
"",
ABSORB_TRAILER,
BLOCK_TRAILER,
CRUSHING_TRAILER,
GLANCING_TRAILER,
RESIST_TRAILER,
VULNERABLE_TRAILER
}
function ParseCHAT_MSG_SPELL_SELF_DAMAGE(self, message, damageMessage, damageMessageTrailer)
local spellName = deformat:Deformat(message, damageMessage..damageMessageTrailer)
--self:LevelDebug(2, "ParseCHAT_MSG_SPELL_SELF_DAMAGE", self.vars.NextMeleeing, self.vars.NextMeleeName, spellName)
if (spellName and (spellName == self.vars.NextMeleeName)) then
self.vars.NextMeleeing = false
self:TriggerEvent(
"SpellStatus_SpellCastInstant",
self.vars.NextMeleeId,
self.vars.NextMeleeName,
self.vars.NextMeleeRank,
self.vars.NextMeleeFullName
)
end
end
function SpellStatus:CHAT_MSG_SPELL_SELF_DAMAGE(message)
self:LevelDebug(2, "CHAT_MSG_SPELL_SELF_DAMAGE", message)
if (not self.vars.NextMeleeing) then
return
end
table.foreach(
CHAT_MSG_SPELL_SELF_DAMAGEMESSAGES,
function(_, damageMessage)
table.foreach(
CHAT_MSG_SPELL_SELF_DAMAGEMESSAGETRAILERS,
function(_, damageMessageTrailer)
ParseCHAT_MSG_SPELL_SELF_DAMAGE(self, message, damageMessage, damageMessageTrailer)
if (not self.vars.NextMeleeing) then
return true
end
end
)
if (not self.vars.NextMeleeing) then
return true
end
end
)
end
function SpellStatus:CHAT_MSG_SPELL_AURA_GONE_SELF(message)
self:LevelDebug(2, "CHAT_MSG_SPELL_AURA_GONE_SELF", message)
if (not(self.vars.Using or self.vars.Preparing or self.vars.Casting or self.vars.Channeling)) then
return
end
local spellName = deformat:Deformat(message, AURAREMOVEDSELF)
if ((not spellName) or (spellName ~= self.vars.ActiveName)) then
return
end
self.vars.Using = false
self.vars.Preparing = false
self.vars.Casting = false
self.vars.Channeling = false
self:TriggerEvent(
"SpellStatus_SpellCastCancelAura",
self.vars.ActiveId, self.vars.ActiveName, self.vars.ActiveRank,
self.vars.ActiveFullName or self.vars.ActiveName, GetTime()
)
end
--Failed is called only when it was semi possible to cast the spell
function SpellStatus:SPELLCAST_INTERRUPTED()
self:LevelDebug(2, "SPELLCAST_INTERRUPTED")
TriggerFailureEvent(self, true)
end
function SpellStatus:SPELLCAST_FAILED()
self:LevelDebug(2, "SPELLCAST_FAILED")
TriggerFailureEvent(self, true)
end
function SpellStatus:START_AUTOREPEAT_SPELL()
self:LevelDebug(2, "START_AUTOREPEAT_SPELL")
self.vars.AutoRepeating = true
end
function SpellStatus:STOP_AUTOREPEAT_SPELL()
self:LevelDebug(2, "STOP_AUTOREPEAT_SPELL")
self.vars.AutoRepeating = false
end
function SpellStatus:PLAYER_ENTER_COMBAT()
self:LevelDebug(2, "PLAYER_ENTER_COMBAT")
self.vars.Attacking = true
end
function SpellStatus:PLAYER_LEAVE_COMBAT()
self:LevelDebug(2, "PLAYER_LEAVE_COMBAT")
self.vars.Attacking = false
end
function SpellStatus:PLAYER_REGEN_DISABLED()
self:LevelDebug(2, "PLAYER_REGEN_DISABLED")
self.vars.Combating = true
end
function SpellStatus:PLAYER_REGEN_ENABLED()
self:LevelDebug(2, "PLAYER_REGEN_ENABLED")
self.vars.Combating = false
end
function SpellStatus:CHAT_MSG_COMBAT_SELF_HITS(chatMessage)
self:LevelDebug(2, "CHAT_MSG_COMBAT_SELF_HITS", chatMessage)
end
function SpellStatus:CHAT_MSG_COMBAT_SELF_MISSES(chatMessage)
self:LevelDebug(2, "CHAT_MSG_COMBAT_SELF_MISSES", chatMessage)
end
--
-- Final Registration of the library.
--
AceLibrary:Register(SpellStatus, MAJOR_VERSION, MINOR_VERSION, activate)
SpellStatus = AceLibrary(MAJOR_VERSION)