WoWInterface

WoWInterface (https://www.wowinterface.com/forums/index.php)
-   Lua/XML Help (https://www.wowinterface.com/forums/forumdisplay.php?f=16)
-   -   Semi-automatically change talents (https://www.wowinterface.com/forums/showthread.php?t=51896)

Malsomnus 02-13-15 07:02 AM

Semi-automatically change talents
 
I'm working on an add-on that will remind people to change their talents before specific boss fights (by their personal choice, of course). Is there a way to automate any part of the talent switching process?
(The holy grail here would be creating a button that says Click Here To Learn These 4 Talents, but I've been unable to find a way to do that)

Choonstertwo 02-13-15 07:35 AM

Ro posted a talent-swapping macro here, but apparently it's not always reliable when trying to switch multiple talent tiers at once.

You could use a secure action button with type = macro and dynamically build up a macro for each tier you need to swap.

Malsomnus 02-13-15 09:02 AM

Hmmm... that thread implies that it's possible to switch one talent with an add-on, but doesn't say how. Does it mean the way to do this via add-on is, as you said, to make a secure button which creates and calls that sort of talent swapping macro?

Also I'm starting to think it might be best to not fully automate it anyway, but to list the talents that you presumably want to learn and put a button next to each.

Dorwido 02-13-15 09:08 AM

should be possible:
http://wow.gamepedia.com/World_of_Wa...lent_Functions

have a look at the last 3 there.

Malsomnus 02-13-15 11:34 AM

Quote:

Originally Posted by Dorwido (Post 306423)
should be possible:
http://wow.gamepedia.com/World_of_Wa...lent_Functions

have a look at the last 3 there.

None of these functions are usable from add-ons, or even from macros :/

[Edit]
And while I'm at it, how can I open the talents frame programmatically?

elcius 02-13-15 01:13 PM

You can call LearnTalents, you don't even need a hardware event for it.
All the issues are from RemoveTalent, which is not only locked to hardware events, but can only be called from blizzard code.
The only calls to the function and made in the StaticPopup handlers in Blizzard_TalentUI.lua, trigged in PlayerTalentFrameTalent_OnClick, only called by the OnClick handler for PlayerTalentButtonTemplate in Blizzard_TalentUI.xml.
The talent UI needs to be loaded though a hardware event to avoid taint, the easiest way to do that is to toggle the frame though a double /click TalentMicroButton.

Eventually you'll end up with something like this:
Code:

/stopmacro [combat]
/click TalentMicroButton
/click TalentMicroButton
/click PlayerTalentFrameTalentsTalentRowXTalentY -- talent you want to learn (row/col)
/click StaticPopup1Button1 -- should probaly had some checking for which popup is actually the talent one.
/click PlayerTalentFrameTalentsTalentRowXTalentY -- repeat as needed....
/click StaticPopup1Button1
...
/run LearnTalents(a,b,c,d,e,...) -- will need to be a slightly delayed call to give the server time to process the unlearns


Dorwido 02-13-15 01:14 PM

Thought cause it is flagged as noncombat and not as protected it works, but while removetalent is protected learntalents is not, just tested that.

semlar 02-13-15 02:35 PM

Quote:

Originally Posted by elcius (Post 306427)
Eventually you'll end up with something like this:
Code:

/stopmacro [combat]
/click TalentMicroButton
/click TalentMicroButton
/click PlayerTalentFrameTalentsTalentRowXTalentY -- talent you want to learn (row/col)
/click StaticPopup1Button1 -- should probaly had some checking for which popup is actually the talent one.
/click PlayerTalentFrameTalentsTalentRowXTalentY -- repeat as needed....
/click StaticPopup1Button1
...
/run LearnTalents(a,b,c,d,e,...) -- will need to be a slightly delayed call to give the server time to process the unlearns


I explained in the other thread that the game generally won't let you unlearn multiple talents at once, you will get "another action is in progress" error if you try to make one large macro like that.

Occasionally it does let you swap more than one at a time, the problem is that since it's completely inconsistent you can't rely on it correctly changing out your talents.

SDPhantom 02-13-15 02:44 PM

You could probably dispatch the LearnTalents() call to a C_Timer.After() function.
Code:

/run C_Timer.After(1,function() LearnTalents(a,b,c,d,e,...) end)
The first argument to C_Timer.After() is how many seconds to delay running the function defined as the second argument.

semlar 02-13-15 02:59 PM

Alright, here's a video showing how much this doesn't work: http://youtu.be/T15HLHGL8Js

It takes 4 clicks to get it to unlearn all 7 talents because it tends to only swap up to 2 at a time, interestingly it seems to prefer the first and last ones in the macro to actually change and ignores the rest.

Banknorris 02-13-15 03:46 PM

Quote:

Originally Posted by SDPhantom (Post 306435)
You could probably dispatch the LearnTalents() call to a C_Timer.After() function.
Code:

/run C_Timer.After(1,function() LearnTalents(a,b,c,d,e,...) end)
The first argument to C_Timer.After() is how many seconds to delay running the function defined as the second argument.

Delaying LearnTalents is not enough since the problem is to unlearn, you can remove the LearnTalents all together and it will still not unlearn all talents. I would say the best approach is to do a "gnomesequencer style", pressing one button per talent. Not as good as a one press but still better than doing manually.

Malsomnus 02-13-15 05:46 PM

Quote:

Originally Posted by Banknorris (Post 306444)
I would say the best approach is to do a "gnomesequencer style", pressing one button per talent. Not as good as a one press but still better than doing manually.

Yep, that's the current plan. When the player approaches a raid boss he had saved specific talents for, it'll pop up a list of the missing talents, with a Learn This button next to each. This has the extra advantage of allowing the player to easily use only some of the talents.
Now I just need to figure out a) how to bind a secure action button to a dynamically created macro, and b) what sort of interface would make sense for picking those talents to begin with :p

semlar 02-13-15 07:42 PM

It's likely going to be more complicated than that because there is a time delay before you can change another talent, if you spam a button like that it's going to skip some of the talents because it will advance to the next item in the sequence regardless of whether it succeeded or not.

Malsomnus 02-14-15 10:46 AM

I can't manage to make a working macro for changing even one talent. It seems that unlearning a talent and learning another one simply won't happen from a single button press, no matter what.

semlar 02-14-15 12:09 PM

Quote:

Originally Posted by Malsomnus (Post 306467)
I can't manage to make a working macro for changing even one talent. It seems that unlearning a talent and learning another one simply won't happen from a single button press, no matter what.

I do it in my addon AutoConfirmTalents, if you're interested.

Malsomnus 02-14-15 02:52 PM

Quote:

Originally Posted by semlar (Post 306470)
I do it in my addon AutoConfirmTalents, if you're interested.

I don't understand all of the code (specifically the attributes *macrotext31and macrotext1, what do those mean?), but it seems like this only saves you all the extra button presses.
What I'm looking for is a way to make a button unlearn a talent, pick another talent, and press the Learn button, all at once. I can't seem to write a macro that'll make that happen, and I have no idea why.

Phanx 02-14-15 08:27 PM

Quote:

Originally Posted by Malsomnus (Post 306474)
I don't understand all of the code (specifically the attributes *macrotext31and macrotext1, what do those mean?) ...

Some basics:
Code:

button:SetAttribute("type", "spell")
button:SetAttribute("spell", "Frostbolt")

^ This button will cast Frostbolt no matter which mouse button you click on it.

Code:

button:SetAttribute("type", "spell")
button:SetAttribute("type1", "Frostbolt")
button:SetAttribute("type2", "Fireball")

^ This button will cast Frostbolt when left-clicked (button1) or Fireball when right-clicked (button2).

Code:

button:SetAttribute("type", "macro")
button:SetAttribute("macrotext", "/cast Frostbolt")

^ Same as example #1, but using a macro command instead of a spell.

Code:

button:SetAttribute("type", "macro")
button:SetAttribute("macrotext1", "Frostbolt")
button:SetAttribute("macrotext2", "Fireball")

^ Same as example #2, but using macro commands instead of spells.

In Semlar's code:

Code:

macro:RegisterForClicks('AnyUp', 'AnyDown')
^ This tells the button to respond to both mousedown and mouseup events.

Code:

macro:SetAttribute('downbutton', 'Button31')
^ This tells the button to treat all mousedown events as if they were triggered by pressing button31. WoW supports up to 32 mouse buttons, but I don't think any of the "gaming" mice it supports actually have 32 buttons (???) so the only real use for these high-numbered buttons is in secure attribute trickery like this.

Code:

macro:WrapScript(macro, 'OnClick', [[ <snip> ]])
^ This provides secure snippets to be run before and/or after the button's original OnClick handler. In this case, only a "before" snippet is given. Basically this is setting a PreClick script, but using the secure handler API instead. (See here for the internal implementation.)

Code:

self:SetAttribute('*macrotext31', '/click ' .. parent .. ' ' .. button .. '\n/click StaticPopup1Button1')
^ This tells the button what to do when it receives a click from button31. Since we're in (effectively) a PreClick script, the current mousedown event hasn't been handled yet.

Code:

self:SetAttribute('macrotext1', '/click PlayerTalentFrameTalentsLearnButton\n/use [nomounted] !Trap Launcher')
^ This tells the button what to do when it recieves a click from button1. (I have no idea why Trap Launcher is mentioned here though!)

This is what occurs when this button is left-clicked:

1. The "before" wrapper snippet is run.

2. The "what to do when clicked with button31" attribute is set to a macro that clicks on the currently hovered talent or glyph button (if you look elsewhere in the code you'll see that the "macro" button is parented to those OnEnter) and then accepts the current static popup.

3. The "what to do when clicked with button1" attribute is set to a macro that clicks the "Learn Talents" button. (Just going to ignore Trap Launcher.)

4. The mousedown event is received.

5. The button arg is remapped to button31.

6. The "what to do when clicked with button31" attribute is invoked, causing its macro to run. The talent is clicked and the popup is accepted.

7. The mouseup event is received.

8. The "what to do when clicked with button1" attribute is invoked, causing its macro to run. The "Learn Talents" button is clicked.

You are correct that it doesn't do exactly what you wanted, but you may be able to use similar principles to accomplish what you want.

semlar 02-14-15 11:10 PM

Quote:

Originally Posted by Phanx (Post 306485)
Code:

self:SetAttribute('macrotext1', '/click PlayerTalentFrameTalentsLearnButton\n/use [nomounted] !Trap Launcher')
^ This tells the button what to do when it recieves a click from button1. (I have no idea why Trap Launcher is mentioned here though!)

I play a hunter and every time I switch talents it turns off trap launcher, it was driving me insane so I just macroed it into the addon.

Thanks for explaining my code because I don't have the attention span to write all that.

The reason I use two different macrotexts on the button is because one is run when you click the button down (to select the new talent) and the other is run when you release the button which clicks the "learn talents" button.

If LearnTalents is not protected then that isn't necessary and you can simply call that directly when the previous talent is unlearned.

Phanx 02-14-15 11:42 PM

Quote:

Originally Posted by semlar (Post 306490)
I play a hunter and every time I switch talents it turns off trap launcher, it was driving me insane so I just macroed it into the addon.

:D

Quote:

Originally Posted by semlar (Post 306490)
Thanks for explaining my code because I don't have the attention span to write all that.

I like explaining things. Also, I was supposed to be around to help him with secure button stuff earlier but got roped into helping with some event at work that I'd forgotten about. :mad:

Malsomnus 02-16-15 04:31 PM

Thanks for all the help and explanations :p

After a lot of experimentation around semlar's code, I technically have a button that switches one talent for me every time I press it. I haven't gotten around to trying to make it work for several talents yet, but here's the code I have so far, in case somebody finds it useful:

Lua Code:
  1. function pickTalent(row,col)
  2.   local s = [[
  3.     /stopmacro [combat]
  4.     /click PlayerTalentFrameTalentsTalentRow%sTalent%s
  5.     /click StaticPopup1Button1
  6.   ]]
  7.   return s:format(row,col)
  8. end
  9.  
  10. f.btn = CreateFrame ("Button", nil, f, 'SecureActionButtonTemplate, SecureHandlerBaseTemplate')
  11. f.btn:RegisterForClicks ("AnyDown")
  12. f.btn:SetAttribute ("type","macro")
  13. f.btn:SetAttribute ('macrotext', pickTalent(1,2))
  14.  
  15. f.btn:SetScript ('PostClick', function()
  16.   C_Timer.After(1, function ()
  17.     PlayerTalentFrameTalentsLearnButton:GetScript("OnClick")(PlayerTalentFrameTalentsLearnButton)
  18.   end)  
  19. end)


All times are GMT -6. The time now is 04:46 AM.

vBulletin © 2024, Jelsoft Enterprises Ltd
© 2004 - 2022 MMOUI