This week i decided to learn LUA and seeing it can be used to make addons, i think it’s the perfect motivation for me use this as a learning platform.
For this occasion i am trying to create a simple addon showing me the icon of the ability (from a set of abilities) whenever it comes off cooldown.
I want to icon to just be present for 2 or 3 seconds.
Whenever i reload wow UI to test my changes, the print message is just showing once and that’s it (currently using print messages in stead of showing me the icon for sake of ease).
What i need help with is how do i make this print message show up whenever it is going off CD without having to reload the UI?
My current code is:
local SerpentKickFrame = CreateFrame("Frame");
SerpentKickFrame:SetSize(60, 60);
SerpentKickFrame:SetPoint("CENTER");
SerpentKickFrame.texture = SerpentKickFrame:CreateTexture(nil, "BACKGROUND");
SerpentKickFrame.texture:SetPoint("CENTER");
SerpentKickFrame.texture:SetTexture(GetSpellTexture("Flying Serpent Kick"));
SerpentKickFrame:Hide();
local start, duration, enabled = GetSpellCooldown("Flying Serpent Kick", "BOOKTYPE_SPELL");
if start == 0 then
DEFAULT_CHAT_FRAME:AddMessage("Flying Serpent Kick is ready!");
else
DEFAULT_CHAT_FRAME:AddMessage("Flying Serpent Kick is on cooldown!");
end
Are you familiar with event based programming? You need to create a function and make your frame call it whenever a proper event happen. You can also use print function instead of DEFAULT_CHAT_FRAME:AddMessage. And if a function returns more than one value you don’t need to create a variable for each one. If you need only first one then you can ommit other ones and if you need another value that is not first or multiple ones that are not in a row you can put an underscore _ instead of names you don’t need.
You can try this code. I’m not sure if it’s a proper event but it’s the only one that seems to make sense in this situtation.
local SerpentKickFrame = CreateFrame("Frame");
SerpentKickFrame:SetSize(60, 60);
SerpentKickFrame:SetPoint("CENTER");
SerpentKickFrame:RegisterEvent("SPELL_UPDATE_USABLE");
SerpentKickFrame:SetScript("OnEvent", serpentKickFunction);
SerpentKickFrame.texture = SerpentKickFrame:CreateTexture(nil, "BACKGROUND");
SerpentKickFrame.texture:SetPoint("CENTER");
SerpentKickFrame.texture:SetTexture(GetSpellTexture("Flying Serpent Kick"));
SerpentKickFrame:Hide();
function serpentKickFunction()
local start = GetSpellCooldown("Flying Serpent Kick", "BOOKTYPE_SPELL");
if start == 0 then
print("Flying Serpent Kick is ready!");
else
print("Flying Serpent Kick is on cooldown!");
end
end
Event based programming basicly works like this. You have in the background a loop that announces what event happened. You in your code make functions and hook them up to whatever events you want. Then whenever this event occures your function will be called. The problem is just to find a correct event.
You can download some addons that deal with cooldowns and analyze their code to see how to do it.
I won’t pretend I’ve done anything with WoW addons before, but looking at the API docs, wouldn’t the second return value to GetSpellCooldown be better?
duration
Number - Cooldown duration in seconds, 0 if spell is ready to be cast.
So something like
local start, duration = GetSpellCooldown("Flying Serpent Kick",
"BOOKTYPE_SPELL");
if duration == 0 then
There doesn’t seem to be any event that explicitly fires when a specific cooldown ends.
I tried using GetSpellCooldown() but it returns 0, 0 when casting the spell, you’d have to use a timer or keep polling it to get the actual cooldown.
I went with hooking CooldownFrame_Set()
local casts = {}
local spells = {
[101545] = true, -- Flying Serpent Kick
[101643] = true, -- Transcendence
}
local function CreateFancyTexture(spellID)
local f = CreateFrame("Frame")
f:SetSize(60, 60)
f:SetPoint("CENTER")
local tex = f:CreateTexture()
tex:SetAllPoints(f)
tex:SetTexture(GetSpellTexture(spellID))
return tex
end
hooksecurefunc("CooldownFrame_Set", function(self)
local btn = self:GetParent()
if btn.action then
local actionType, id = GetActionInfo(btn.action)
if actionType == "spell" and spells[id] then
if not self.HookedScript then
self:HookScript("OnCooldownDone", function()
if casts[id] then
casts[id] = false
self.fancyTexture = self.fancyTexture or CreateFancyTexture(id)
self.fancyTexture:Show()
C_Timer.After(2, function() self.fancyTexture:Hide() end)
end
end)
self.HookedScript = true
end
end
end
end)
-- ignore OnCooldownDone script when fired from the GCD by tracking for actual spell casts
local function OnEvent(self, event, unit, _, spellID)
if unit == "player" and spells[spellID] then
casts[spellID] = true
end
end
local f = CreateFrame("Frame")
f:RegisterEvent("UNIT_SPELLCAST_SUCCEEDED")
f:SetScript("OnEvent", OnEvent)
That makes sense!
Thank you for a good explanation.
@Ketho - Thank you for linking me to some great resources and your code examples.
I will have to look further into Lua in order to understand everything from it.