diff --git a/AllTheLittleThings.toc b/AllTheLittleThings.toc index 6d42fc2..b040436 100644 --- a/AllTheLittleThings.toc +++ b/AllTheLittleThings.toc @@ -27,5 +27,6 @@ modules\potions.lua modules\prat.lua modules\raid.lua modules\rbs.lua +modules\spellcast.lua modules\staging.lua diff --git a/modules/spellcast.lua b/modules/spellcast.lua new file mode 100644 index 0000000..5428a69 --- /dev/null +++ b/modules/spellcast.lua @@ -0,0 +1,327 @@ +local core = LibStub("AceAddon-3.0"):GetAddon("AllTheLittleThings") +local mod = core:NewModule("Spellcast", "AceEvent-3.0", "AceTimer-3.0") +local db + +local defaults = { + anchor = { + x = 500, + y = 500, + locked = false, + }, + + buttonSize = 40, + textSize = 10, + spacing = 5, +} +local options = { + locked = { + name = "Locked", + type = 'toggle', + order = 1, + get = function() return db.anchor.locked end, + set = function(_, val) db.anchor.locked = val mod:SetLocked(val) end, + }, +} + +local spellWatch = { + -- Polymorph + [118] = "Polymorph", + [61305] = "Polymorph", + [28272] = "Polymorph", + [61721] = "Polymorph", + [61780] = "Polymorph", + [28271] = "Polymorph", + -- Counterspell + [2139] = "Counterspell", + -- Deep Freeze + [44572] = "Deep Freeze", + -- Frostbolt + [116] = "Frostbolt", +} +local auras = { + ["Polymorph"] = true, +} +local durations = { + ["Polymorph"] = 8, + ["Deep Freeze"] = 30, + ["Counterspell"] = 24, + ["Ice Lance"] = 10, +} +local validZones = { + -- Battlegrounds + ["Alterac Valley"] = true, + ["Arathi Basin"] = true, + ["Eye of the Storm"] = true, + ["Isle of Conquest"] = true, + ["Strand of the Ancients"] = true, + ["The Battle for Gilneas"] = true, + ["Twin Peaks"] = true, + ["Warsong Gulch"] = true, + + -- Arenas + ["Blade's Edge Arena"] = true, + ["Dalaran Arena"] = true, + ["Nagrand Arena"] = true, + ["Ruins of Lordaeron"] = true, + ["The Ring of Valor"] = true, + + -- Testing + -- ["Stormwind City"] = true, +} +local combatEvents = { + ["SPELL_AURA_APPLIED"] = true, + ["SPELL_AURA_REFRESHED"] = true, + ["SPELL_AURA_REMOVED"] = true, +} +local icons = {} +local lastAvailable = {} +local anchor, enabled, updateTimer + +function mod:OnInitialize() + self:RegisterOptions(options, defaults, function(d) db = d end) +end + +function mod:OnEnable() + self:SetupIcons() + self:RegisterEvent("ZONE_CHANGED_NEW_AREA") + self:RegisterEvent("COMBAT_LOG_EVENT_UNFILTERED") + self:RegisterEvent("UNIT_SPELLCAST_SUCCEEDED") + + -- This doesn't always fire on load + self:ZONE_CHANGED_NEW_AREA() +end + +function mod:SetLocked(val) + if val then + anchor:Hide() + else + anchor:Show() + end +end + +function mod:ZONE_CHANGED_NEW_AREA() + local before = enabled + enabled = not not validZones[GetRealZoneText() or ""] + + if before ~= enabled then + -- wipe last table so that we don't have an accumulated time + wipe(lastAvailable) + self:UpdateDisplay() + end + + if not enabled then + self:CancelTimer(updateTimer, true) + updateTimer = nil + end + + if enabled and not updateTimer then + updateTimer = self:ScheduleRepeatingTimer("UpdateDisplay", 0.1) + end +end + +local pid = UnitGUID("player") +function mod:COMBAT_LOG_EVENT_UNFILTERED(_, _, event, _, ...) + if not enabled or not combatEvents[event] then return end + + local srcGUID, dstGUID, spellId, _ + if select(4, GetBuildInfo()) > 40100 then + srcGUID, _, _, _, dstGUID, _, _, _, spellId = ... + else + srcGUID, _, _, dstGUID, _, _, spellId = ... + end + + -- source is player + if pid ~= srcGUID then return end + + local category = spellWatch[spellId] + if category then + -- only handling auras here + if auras[category] then + if event == "SPELL_AURA_APPLIED" then + local endTime = select(7, UnitDebuff(self:FindGUID(dstGUID), GetSpellInfo(spellId))) or (durations[category] or 0)+GetTime() + self:SpellStart(category, endTime) + elseif event == "SPELL_AURA_REMOVED" then + self:SpellStop(category) + end + end + end +end + +function mod:UNIT_SPELLCAST_SUCCEEDED(_, unit, _, _, _, spellId) + if not enabled or UnitGUID(unit) ~= pid then return end + + local category = spellWatch[spellId] + if category then + if not auras[category] then + local duration = durations[category] + if not duration then + -- no duration means it has no cooldown, so we just start the timer + self:SpellStop(category, true) + else + self:SpellStart(category, duration+GetTime()) + end + end + end +end + +function mod:SpellStart(category, endTime) + local icon = icons[category] + local time = GetTime() + if not icon or endTime