First, some general suggestions for your code:
1.
Don't create global variables. Not only are they slower to access than local variables, but they can easily be overwritten by other addons, especially when they have generic names like
target.
2.
Use a table for spell data instead of a long if-else chain. You already mentioned this; see below to see how to implement it.
3.
Don't create one-use functions. In your code, the
interruptgo function is only called once, from inside the
onEvent function. Function closures cost memory, so it's more efficient to just move the contents of the
interruptgo function into the
onEvent function. If you were going to call the
interruptgo function from different places (eg. more than one frame would call it from its event handler), then factoring out that code into its own function would be a good idea, but that's not the case here.
4.
Use consistent, proper indentation. This will make your code much easier to read.
Second, to hide the icon when it's not displaying anything, hook the cooldown object's
:Hide() method.
Here is your code with the above optimizations and changes applied, plus lots of comments to help you understand what's going on, and
print statements to help you see what's going on in-game. You'll want to comment out the
print statements once you know it's working.
I've also attached a copy in Lua file form to this post, so you don't have to copy and paste (and deal with the extra blank lines that are inserted when you copy from highlighted code blocks on this forum).
Lua Code:
local addon, addonName = ...
------------------------------------------------------------------------
-- 1. Define a list of spells to track:
------------------------------------------------------------------------
local spellData = {
[2139] = { -- Counterspell
duration = 7,
texture = "Interface\\Icons\\spell_frost_iceshock",
},
[1766] = { -- Kick
duration = 5,
texture = "Interface\\Icons\\ability_kick",
},
[47528] = { -- Mind Freeze
duration = 4,
texture = "Interface\\Icons\\spell_deathknight_mindfreeze",
},
[6522] = { -- Pummel
duration = 4,
texture = "Interface\\Icons\\inv_gauntlets_04",
},
[96231] = { -- Rebuke
duration = 4,
texture = "Interface\\Icons\\spell_holy_rebuke",
},
[80964] = { -- Skull Bash (Bear Form)
duration = 4,
texture = "Interface\\Icons\\inv_misc_bone_taurenskull_01",
},
[80965] = { -- Skull Bash (Cat Form)
duration = 4,
texture = "Interface\\Icons\\inv_bone_skull_04",
},
[57994] = { -- Wind Shear
duration = 2,
texture = "Interface\\Icons\\spell_nature_cyclone",
},
}
------------------------------------------------------------------------
-- 2. Create the icons to display:
------------------------------------------------------------------------
-- 2.1. Create a table to hold the icons:
local unitIcons = {}
-- 2.2. Create a function that makes an icon:
local newIcon
do
-- Use scoping to keep variables limited to where they are useful.
-- The following two functions are only used by the following third
-- function, and do not need to be accessible anywhere else.
local function icon_OnDragStart(self, mouseButton)
-- Only allow the icon to be moved if the Alt key is pressed.
if IsAltKeyDown() then
self:StartMoving()
end
end
local function cooldown_OnHide(self)
-- Hide the icon when the cooldown ends.
local icon = self:GetParent()
icon.texture:SetTexture("")
icon:Hide()
end
function newIcon(unit, parentFrame)
print("newIcon:", unit, parentFrame:GetName())
local icon = CreateFrame("Frame", "$parentInterruptIcon", parentFrame)
icon:SetPoint("CENTER", parentFrame, -130, 0)
icon:SetSize(40, 40)
icon:EnableMouse(true)
icon:RegisterForDrag("LeftButton")
icon:SetScript("OnDragStart", icon_OnDragStart)
icon:SetScript("OnDragStop", icon.StopMovingOrSizing)
icon:SetScript("OnHide", icon.StopMovingOrSizing)
-- The OnHide script is needed so the icon doesn't get stuck to
-- the cursor if it gets hidden while it's being dragged.
local texture = icon:CreateTexture(nil, "ARTWORK")
texture:SetAllPoints(true)
icon.texture = texture
local cooldown = CreateFrame("Cooldown", "$parentCooldown", icon)
cooldown:SetAllPoints(true)
cooldown:HookScript("OnHide", cooldown_OnHide)
icon.cooldown = cooldown
icon.unit = unit
unitIcons[unit] = icon
return icon
end
end
-- 2.3. Create the icons you want.
newIcon("target", TargetFrame)
newIcon("focus", FocusFrame)
-- You could easily extend this to, for example, add an icon to the
-- arena enemy frames, the boss frames, or even the player frame and
-- party frames to see when your allies were interrupted!
-- The newIcon function returns the icon created, in addition to adding
-- it to the unitIcons table, so you could easily apply custom points
-- or other attributes to a specific icon, eg:
-- local playerIcon = newIcon("player", PlayerFrame)
-- playerIcon:ClearAllPoints()
-- playerIcon:SetPoint("LEFT", PlayerFrame, "RIGHT", 40, 0)
------------------------------------------------------------------------
-- 3. Watch the combat log for interrupts:
------------------------------------------------------------------------
-- 3.1. Create a frame to listen for combat log events:
local eventFrame = CreateFrame("Frame")
-- 3.2. Tell the frame which event to listen for:
eventFrame:RegisterEvent("COMBAT_LOG_EVENT_UNFILTERED")
-- 3.3. Tell the frame what to do when the event happens:
eventFrame:SetScript("OnEvent", function(self, event, timestap, combatEvent, hideCaster, sourceGUID, sourceName, sourceFlags, sourceRaidFlags, destGUID, destName, destFlags, destRaidFlags, spellID, spellName, spellSchool, extraSpellID, extraSpellName, ...)
-- 3.3.1. Check the combat event:
if combatEvent ~= "SPELL_INTERRUPT" then
-- We don't care about this combat event.
return
end
-- 3.3.2. Check the spell:
local spell = spellData[spellID]
if not spell then
-- We don't care about this spell.
return
end
print("event:", combatEvent, "spell:", spellName)
-- 3.3.3. Look for an icon for this unit:
for unit, icon in pairs(unitIcons) do
print("unit:", unit, "destGUID:", destGUID, "unitGUID:", UnitGUID(unit))
if destGUID == UnitGUID(unit) then
-- We found the icon for the affected unit.
print("Found an icon!")
-- Show the icon:
icon:Show()
-- Set the icon's texture:
icon.texture:SetTexture(spell.texture)
-- Show the icon's cooldown:
icon.cooldown:Show()
-- Start the cooldown animation:
icon.cooldown:SetCooldown(GetTime(), spell.duration)
-- Done!
return
end
end
-- 3.3.4. If we get here, that means we couldn't find an icon.
-- At this point you don't need to do anything, but if you later
-- wanted to do something when this happens, you'd do it here.
print("Could not find icon for unit!")
end)