Thread Tools Display Modes
01-25-13, 04:45 PM   #1
Crabnab
A Defias Bandit
Join Date: Jan 2013
Posts: 2
Function to find a spell on action bar

I'm currently working on an addon of my own and have run into a few snags, chief among them is the ability to determine which action bar slot a specified spell is in.

I'm curious if anybody has developed a function that when given a specific spell name, perhaps passed as an argument, if it can loop through the standard actionbar slots (1-72?) to determine which of those slots, if any, that spell is currently sitting in.

Ideally, I will use whatever this function returns and place it in:
Code:
ActionButton_ShowOverlayGlow($functionreturn)
Thanks in advance!
  Reply With Quote
01-25-13, 06:02 PM   #2
Phanx
Cat.
 
Phanx's Avatar
AddOn Author - Click to view addons
Join Date: Mar 2006
Posts: 5,617
LearningAid has a function to search for spells that are in your spellbook but not on any action button. Its code might be helpful.
__________________
Retired author of too many addons.
Message me if you're interested in taking over one of my addons.
Don’t message me about addon bugs or programming questions.
  Reply With Quote
01-25-13, 06:42 PM   #3
semlar
A Pyroguard Emberseer
 
semlar's Avatar
AddOn Author - Click to view addons
Join Date: Sep 2007
Posts: 1,060
I address this problem (more or less) in my addon Crack Cooldown by 1) attempting to identify every action button on the screen and 2) keeping a table of their current actions.

If you only want it to work for the default action buttons, then it's a simple matter of keeping a list of the bar names and then looping through the 12 action buttons on each bar and getting their current actions, then if the action is a spell you compare the name with the one you're looking for and if they match you call your glow function.

However, depending on what you're trying to do it might be possible to just hook an existing function that acts on a particular button and call your function on that same button.

Sorry, my addon is probably not a great example. Here's something to get you started..
Lua Code:
  1. local ActionBars = {'Action','MultiBarBottomLeft','MultiBarBottomRight','MultiBarRight','MultiBarLeft'}
  2. function PrintActions()
  3.     for _, barName in pairs(ActionBars) do
  4.         for i = 1, 12 do
  5.             local button = _G[barName .. 'Button' .. i]
  6.             local slot = ActionButton_GetPagedID(button) or ActionButton_CalculateAction(button) or button:GetAttribute('action') or 0
  7.             if HasAction(slot) then
  8.                 local actionName, _
  9.                 local actionType, id = GetActionInfo(slot)
  10.                 if actionType == 'macro' then _, _ , id = GetMacroSpell(id) end
  11.                 if actionType == 'item' then
  12.                     actionName = GetItemInfo(id)
  13.                 elseif actionType == 'spell' or (actionType == 'macro' and id) then
  14.                     actionName = GetSpellInfo(id)
  15.                 end
  16.                 if actionName then
  17.                     print(button:GetName(), actionType, (GetSpellLink(id)), actionName)
  18.                 end
  19.             end
  20.         end
  21.     end
  22. end

I hope that's comprehensible.

Last edited by semlar : 01-25-13 at 07:18 PM.
  Reply With Quote
01-25-13, 09:03 PM   #4
Phanx
Cat.
 
Phanx's Avatar
AddOn Author - Click to view addons
Join Date: Mar 2006
Posts: 5,617
That should work, though for the OP's purpose you'd want to search the whole macro to see if the spell you were looking for was in there, instead of only checking its current action.

Also, I'd rewrite this part slightly:

Code:
if actionType == 'macro' then _, _ , id = GetMacroSpell(id) end
if actionType == 'item' then
    actionName = GetItemInfo(id)
elseif actionType == 'spell' or (actionType == 'macro' and id) then
    actionName = GetSpellInfo(id)
end
to something more like this:

Code:
if actionType == 'macro' then
    actionName, _ , id = GetMacroSpell(id)
    -- The first return value from GetMacroSpell is the spell name,
    -- so there's no need for an additional call to GetSpellInfo.
elseif actionType == 'item' then
    actionName = GetItemInfo(id)
elseif actionType == 'spell' then
    actionName = GetSpellInfo(id)
end
to avoid unnecessary checks and duplication.

Edit:
This variation of Semlar's code should do the trick for finding actions by name. It returns the button object, so you can then pass that to ActionButton_ShowOverlayGlow or whatever.

Code:
local ActionBars = { "Action", "MultiBarBottomLeft", "MultiBarBottomRight", "MultiBarRight", "MultiBarLeft" }

function MyAddon_FindActionByName(searchName)
	print("Searching action buttons for", searchName)
	for _, barName in pairs(ActionBars) do
		for i = 1, 12 do
			local buttonName = barName .. "Button" .. i
			local button = _G[buttonName]
			local slot = ActionButton_GetPagedID(button) or ActionButton_CalculateAction(button) or button:GetAttribute("action") or 0
			if HasAction(slot) then
				local actionType, id, _, actionName = GetActionInfo(slot)
				if actionType == "macro" then
					actionName, _, id = GetMacroSpell(id)
				elseif actionType == "item" then
					actionName = GetItemInfo(id)
				elseif actionType == "spell" then
					actionName = GetSpellInfo(id)
				end
				
				if actionName and string.match(string.lower(actionName), string.lower(searchName)) then
					print("Found", searchName, "as", actionType, actionName, "on", buttonName)
					return button
				end
			end
		end
	end
	print("Could not find", searchName, "on any action buttons")
end
__________________
Retired author of too many addons.
Message me if you're interested in taking over one of my addons.
Don’t message me about addon bugs or programming questions.

Last edited by Phanx : 01-25-13 at 09:11 PM.
  Reply With Quote
01-25-13, 09:35 PM   #5
semlar
A Pyroguard Emberseer
 
semlar's Avatar
AddOn Author - Click to view addons
Join Date: Sep 2007
Posts: 1,060
The same spell can be on multiple buttons so I'm not sure if returning the first result is what they want.

I'm also not entirely sure they want to search through a macro for the text, they might just want to match it if it's the active spell.
  Reply With Quote
01-25-13, 10:11 PM   #6
Phanx
Cat.
 
Phanx's Avatar
AddOn Author - Click to view addons
Join Date: Mar 2006
Posts: 5,617
True. It might also be a good idea to make sure the button is visible before checking its action; it's unlikely (and probably undesirable) to have the same action on multiple buttons that are visible at the same time.

Code:
			local buttonName = barName .. "Button" .. i
			local button = _G[buttonName]
			if button:IsVisible() then
				...
			end
__________________
Retired author of too many addons.
Message me if you're interested in taking over one of my addons.
Don’t message me about addon bugs or programming questions.
  Reply With Quote
01-28-13, 11:07 AM   #7
Crabnab
A Defias Bandit
Join Date: Jan 2013
Posts: 2
To all that have discussed/replied thus far- Thank you so much for your contribution. I will do a bit of development and debugging tonight and let you know how it goes. If I'm still having trouble, rather than theory craft, I'll post my source. Until then- again, thank you so much for your help!

I do have a few questions however- first of all, why is this loop done in pairs?
for _, barName in pairs(ActionBars) do
The variable above is set to single entries and you aren't doing anything with the first variable so far as I can tell- can you explain what's going on a bit more, please?

Additionally- can you please explain the semantic difference and need for needing to set a new variable to the same value as another variable but using the get global "_G"?
local button = _G[buttonName]
Thanks for the help!

Last edited by Crabnab : 01-28-13 at 12:38 PM. Reason: Further questions.
  Reply With Quote
01-28-13, 08:56 PM   #8
Phanx
Cat.
 
Phanx's Avatar
AddOn Author - Click to view addons
Join Date: Mar 2006
Posts: 5,617
If you have a list-type table like { a, b, c } you can use ipairs to return the values in sequential order, eg. 1/a 2/b 3/c, or you can use pairs to return the values in undefined order, eg. 2/b, 1/a, 3/c. In either case, the key returned is the numeric index; in this case, we don't care about the order so we just use pairs, and we don't care about the index, so we just assign it to the underscore, which is commonly used to indicate a "junk" variable whose value is irrelevant.

We then take the value, assign it to the variable barName, and use it to construct the name of an action button. For example, when barName is "MultiBarLeft", on the 7th iteration of the inner loop, we would construct the button name "MultiBarLeftButton7".

Code:
for _, barName in pairs(ActionBars) do
	for i = 1, 12 do
		local buttonName = barName .. "Button" .. i
At this point, we have a string value. In order to get a reference to the actual button object whose global name matches that string value, we need to look up the string as a key in the global environment:

Code:
local button = _G[buttonName]
You could just do that in one line:

Code:
local button = _G[barName .. "Button" .. i]
...except that you use the button name again later as a string, so it's far more efficient to keep the string and object reference in separate variables and reuse the string variable, than to add a call to button:GetName() like Semlar's original code.
__________________
Retired author of too many addons.
Message me if you're interested in taking over one of my addons.
Don’t message me about addon bugs or programming questions.
  Reply With Quote

WoWInterface » Developer Discussions » General Authoring Discussion » Function to find a spell on action bar

Thread Tools
Display Modes

Posting Rules
You may not post new threads
You may not post replies
You may not post attachments
You may not edit your posts

vB code is On
Smilies are On
[IMG] code is On
HTML code is Off