This site makes extensive use of JavaScript.
Please enable JavaScript in your browser.
Classic Theme
Thottbot Theme
Macro to change talents
Post Reply
Return to board index
Post by
168962
This post was from a user who has deleted their account.
Post by
janniie
#showtooltip Dust of Disappearance
/usetalents 2; 1
Should show the amount of dust you have if you pick the "?" icon when you make the macro. It will switch between your talents each click.
Post by
Wanderingfox
Not what he's looking for. He's trying to swap individual talents within a single spec, which to my knowledge requires a hardware event.
Post by
pelf
Not what he's looking for. He's trying to swap individual talents within a single spec, which to my knowledge requires a hardware event.
My brief investigation seems to agree with that.
Post by
Neffi
Unless my understanding of the macro system is flawed, any macro
is
a hardware event (since it has to originate from a click or keypress). There's no reason this cannot be done from within /run, though it will be limited to out-of-combat.
I'll look up the API later on and whip up a script for you. I'm too busy now to craft you a macro.
Post by
GTMistral
If you want to switch a talent, I think it's going to ask a confirmation that you really want to change your talent. First, deactivate the old one, confirm is going to remove it and then click on the one you want in replacement and then click "Learn". You "physically" have to click the talent and learn it and not click on a macro which will learn your talent for you. I agree with pelf here.
Post by
Neffi
On the inside (the actual FrameXML that constructs the talent UI), all that is being done by the same basic API that's available to the /run command. (Assuming these are not protected commands requiring the use of secure frames, which I'm quite sure they are not,) the only distinguishing factor is whether or not it was generated by a hardware event (a physical button press) or a software event (an event, an OnUpdate, etc). When the C-side system fires a hardware event, it sets a flag letting any subsequent API calls know whether or not the script traced its origins from a hardware event. Since the /run command is triggered by a macro, which is triggered by a physical button press, it will
always
trace back to a hardware event (as long as it's not invoking an OnUpdate delay or similar to actually perform the API calls).
This can be easily verified by making a macro that does:
/run ReloadUI()
Obviously this works.
ReloadUI()
doesn't however work if it's generated from a software event. The macro constitutes a hardware event because it traces its origins to one.
Other people have made macros wherein they perform an API call, and then do something like
PopupFrameButton1:Click()
(incorrect name but I'm generalizing) to simulate a "confirm" from a player. This is not difficult. It all works because it all traces back to a hardware event.
When Blizzard wants to prevent this behavior (such as with casting and targeting) they don't use the hardware-event mechanism but instead use the protected mechanism. This is why the protected mechanism was invented in the first place (some of you may recall CastSpellByName once upon a time only required a hardware event).
I would be
very
surprised if I'm incorrect in this rationalization. I'm pretty confident I can craft a macro to do this. When I've finished what work I'm currently busy with, I'll try it out. I'll post a finished script sometime tomorrow.
Post by
pelf
My problem was that I couldn't find any API to
remove
the current talent selection. Trying to use
LearnTalent
didn't work if the talent was already selected. There are a slew of other functions, but none of them seem to actually initiate the talent clear. Good luck!
Post by
Neffi
That always requires digging through the FrameXML. This exchange actually gave me an idea for my development addon, an option to trace all API calls in realtime, so that you can open an "API log" window and then perform a command to see what's happening. That feature's going to be invaluable and is definitely going to make it into nfDevelopment.
Anyway, the function in question:
-- PlayerTalentFrameTalents
function PlayerTalentFrameTalent_OnClick(self, button)
-- ...
local _, _, _, _, selected, available = GetTalentInfo(self:GetID());
if ( available ) then
-- ...
elseif ( button == "RightButton" and selected ) then
if ( UnitIsDeadOrGhost("player") ) then
UIErrorsFrame:AddMessage(ERR_PLAYER_DEAD, 1.0, 0.1, 0.1, 1.0);
else
StaticPopup_Show("CONFIRM_REMOVE_TALENT", nil, nil, {id = self:GetID()}); --! Invokes the confirmation dialog.
end
end
-- ...
end
end
end
and then above:
StaticPopupDialogs = {
-- ...
-- There's also an OnShow to figure out if it CAN be removed and disable/enable the button and change the text accordingly.
OnAccept = function (self)
local talentGroup = PlayerTalentFrame and PlayerTalentFrame.talentGroup or 1;
if ( talentGroup == GetActiveSpecGroup() ) then
RemoveTalent(self.data.id); --! And here we are!
end
end,
-- ...
}
I see where you ran into the problem, as I've run into it several times since 5.0 as well: the API is not documented anywhere. Wowprogramming only has a stub page, the others don't even have that. It's only in the Global Functions list, not even listed in the API overview page on Wowpedia/wiki.
I'm logging in now to play with the function and see how it works. I'll craft a macro in a few moments.
Post by
Neffi
Interesting results indeed. pelf was partially right. The API is indeed protected, /run cannot perform it. However some trickery with /click
can
except for the fact that it seems to be hitting a wall of taint. I cannot immediately trace the source of taint, but I'm guessing it's related to the popup dialog (since it's been problematic for a long time).
I tested it on the default UI and it worked. I tested it on my UI and hit this taint. I'm gonna chalk this up to a bug in the default UI itself (like I said, the popup dialog has long been a source of problem that's only now getting fixed at a very slow pace each patch).
Anyway, the macro to
unlearn
is as follows:
(The first line is required to load the talent UI, in order for the subsequent lines to do anything useful. Otherwise, the buttons in question won't even exist unless you open the talent UI before using the macro.)
/run LoadAddOn('Blizzard_TalentUI')
/click PlayerTalentFrameTalentsTalent
Row1Talent2
RightButton
/click StaticPopup1Button1
Change
Row1Talent2
to the correct row and talent number (TalentN refers to the talent within that row, so tier 2 middle talent would be Row2Talent2).
Test this out to see if it works correctly. If it pops up with a warning that an addon is attempting to perform a protected action, you may not be able to do it. Since the source of taint collision seems to be in the default UI, there's no way around this except yelling at Blizzard to finally make the default UI safe from unintentional tainting. If it does work, you can then relearn the next talent using:
/run LearnTalent(
tab
,
talent
)
where
tab
is the tab number (1 for primary talents, 2 for secondary) and
talent
is the talent number (top left talent = 1, then it increases by one towards the right and down; eg top right talent is 3 and row 2 talent 1 is 4).
This whole thing is quirky indeed. One day I'll finally trace every relevant part of FrameXML and submit a patch to Blizzard to fix these 7-year-long issues.
Post by
pelf
"wall of taint"
That's a great line.
As for the tracing method ... I would love to see that. Does the WoW-flavored Lua give you enough hooks to read that much meta-stuff?
EDIT
: Also, if
RemoveTalent
is actually on wowprogramming now (even as a stub), it wasn't when I was looking. I guess I should expect having to dig into the Blizzard UI code more often.
Post by
Neffi
for k,v in pairs(_G) do
if type(v) == 'function' then
hooksecurefunc(k, trace_handler)
end
end
You can even get the arguments. Obviously it will be handling thousands of calls per second so it will need some nice streamlined implementation to pick through what you want. I'd probably also record the debug stack at each call; use that info to build a nice call hierarchy, and provide lots of info to the user, so they can see (among other things) the exact route code is going through the functions.
Also,
local f = EnumerateFrames()
while f do
-- hook its methods and :SetScript handlers with trace_handler
f = EnumerateFrames(f)
end
I can do frames too.
You can easily listen to all events with :RegisterAllEvents. You can do things like real-time performance metrics by measuring OnUpdate deltas, using debugprofilestart/stop, and the like. There's actually a ton of things you can do to see exactly what's going on. You just need to be clever with how you treat what's available.
Post Reply
You are not logged in. Please
log in
to post a reply or
register
if you don't already have an account.