Macro Help. Events on Target Area of a spell

I am trying to script a macro that my character says a random thing when casting Heroic Leap. However, I would like the phrase to appear when the leap is active.
Heroic Leap has 2 parts for casting. First click brings up a target circle. Second click activates the leap.
I am using this script for the message. From this topic : Macro Help :D

/script randNum = random(0, 10); myList = {“Hello”,“Hey”,“What’s up?”,“Yo!”}; SendChatMessage(myList[randNum], “SAY”);

How would I get this script to run only when I have confirmed my target area for Heroic Leap?

*There is another way to write this according to Fizzle in that post but, his way breaks Bagnon for some reason.

Thanks!

You should use “local” in that script for the variable declarations otherwise they are declared as global and could interfere with other addon’s code.
/script local randNum= blah blah ; local myList = blah blah…

There are 2 possible ways to do what you want

  1. change the macro to use @cursor /cast [@cursor] GroundTargetingAbility makes the spell a 1-click cast. Whatever piece of ground your mouse is touching, is what you target. If you are aiming at a mob, aim at their feet. If you aim at the “chest” or higher you’ll hit the ground behind the mob, because that’s the ground your mouse is actually touching.

  2. You would need a frame to handle an event but I’m not sure which event though (sorry). This means that the script can’t be in your macro but would be in the event handler code. If you use WeakAuras you could create an Aura that is visible but not actually displayed on the screen (like an Empty Text or a 1x1 pixel icon), and you could put the script in a Custom Event Trigger.

  1. won’t work because using SendChatMessage to SAY or YELL etc. (any channel not group, raid, guild related) requires a hardware event (keyboard/mouse click) so you can’t click and wait for an event to run the message.
1 Like

Would the mouse click you have to do in order to confirm the target destination of the leap count as the hardware event you mention above?

/cast [@cursor] Heroic Leap
/run local myList = {"Hello", "Hey", "What’s up?","Yo!"} local randdomMessage = myList[random(1, 10)] if randdomMessage then SendChatMessage(randdomMessage, "SAY") end

If your random range is larger than the No. of entries in your table, you need to check you have a message or, as mentioned by Elvenbane, SendChatMessage will error.

While SendChatMessage does require a hardware event now, an interesting thing with hardware events is that you can do stuff while a hardware event is happening and get “credit” for it. (In Vanilla I wrote an addon that would cast the instant-cast Inner Fire self buff when you needed it while you were moving around by piggy backing CastSpellByName onto the movement keys.)

And while it’s been almost 14 years since we could CastSpellByName for class buffs, we can still use the same principle in events that happen during hardware events.

This is how my warriors heroic leap:

local key = "SHIFT-C"
if select(2,UnitClass("player"))=="WARRIOR" then
   local button = CreateFrame("Button","HeroicLeapOnUp",nil,"SecureActionButtonTemplate")
   button:RegisterForClicks("AnyDown","AnyUp")
   button:SetAttribute("type","macro")
   SecureHandlerWrapScript(button,"OnClick",button,[[
     if down then
       self:SetAttribute("macrotext","/cast heroic leap")
     else
       self:SetAttribute("macrotext","/stopspelltarget\n/cast [@cursor] heroic leap")
     end
   ]])
   button:RegisterEvent("PLAYER_LOGIN")
   button:SetScript("OnEvent",function(self,event,...)
     SetOverrideBindingClick(self,true,key,"HeroicLeapOnUp")
   end)
end

Rather than hitting a key, moving the reticle where you want to leap and then clicking the mouse; with this you press the key down, move the reticle where you want to leap and then release the key. You’ll leap to wherever the mouse was when you let go. (The @cursor does the same thing but without the ability to use the reticle to target a spot.)

In this scenario you can choose an OnKeyUp or OnAttributeChanged or probably a few other options that are valid during the hardware events that caused them. The following uses OnAttributeChanged because it’s one you wouldn’t intuitively expect to work:

local key = "SHIFT-C"
if select(2,UnitClass("player"))=="WARRIOR" then
   local button = CreateFrame("Button","HeroicLeapOnUp",nil,"SecureActionButtonTemplate")
   button:RegisterForClicks("AnyDown","AnyUp")
   button:SetAttribute("type","macro")
   SecureHandlerWrapScript(button,"OnClick",button,[[
 if down then
   self:SetAttribute("macrotext","/cast heroic leap")
 else
   self:SetAttribute("macrotext","/stopspelltarget\n/cast [@cursor] heroic leap")
 end
   ]])
   button:RegisterEvent("PLAYER_LOGIN")
   button:SetScript("OnEvent",function(self,event,...)
 SetOverrideBindingClick(self,true,key,"HeroicLeapOnUp")
   end)
   button:SetScript("OnAttributeChanged",function(self,attribType,attribValue)
  if (attribValue or ""):match("^/stopspell.+heroic leap$") then
      if GetSpellCooldown(6544)==0 then
          SendChatMessage("Hi there","say")
      end
  end
   end)
   button:SetScript("PostClick",function(self) self:SetAttribute("macrotext",nil) end)
end

The PostClick is there so that if the attribute changes by some other means it won’t trigger a chat when you’re not leaping. For a more practical use I recommend OnKeyUp.

3 Likes

Can this actually dynamically change a macro’s text during combat?

This can change the macrotext during combat. The trick is you can SetAttribute from within a snippet pre-defined outside of combat and those snippets have a very restricted exposure to the game’s api. But you cannot change this snippet during combat so you don’t get true dynamic/programmable changes in combat.

That SecureHandlerWrapScript is basically saying, before the button’s click behavior happens, run this snippet. The snippet changes the button’s click behavior. And registering both AnyUp and AnyDown means the button is clicked twice: once when it goes down and again when it goes up.

So while this can’t be used to choose whether to cast execute if a target is at low health and mortal strike otherwise (that information is not available in the restricted environment), it can be used for “dumb logic” behaviors such as toggling macrotexts or cycling through spells.

edit: And now that you mention it, that PostClick won’t work in combat since we can’t SetAttributes in combat. I think removing the PostClick entirely is fine, since the OnAttributeChanged is already checking to see if the attribute is changing to that specific macrotext:

local key = "SHIFT-C"
if select(2,UnitClass("player"))=="WARRIOR" then
   local button = CreateFrame("Button","HeroicLeapOnUp",nil,"SecureActionButtonTemplate")
    button:RegisterForClicks("AnyDown","AnyUp")
    button:SetAttribute("type","macro")
    SecureHandlerWrapScript(button,"OnClick",button,[[
      if down then
         self:SetAttribute("macrotext","/cast heroic leap")
      else
         self:SetAttribute("macrotext","/stopspelltarget\n/cast [@cursor] heroic leap")
      end
    ]])
    button:RegisterEvent("PLAYER_LOGIN")
    button:SetScript("OnEvent",function(self,event,...)
        SetOverrideBindingClick(self,true,key,"HeroicLeapOnUp")
    end)
    button:SetScript("OnAttributeChanged",function(self,attribType,attribValue)
        if (attribValue or ""):match("^/stopspell.+heroic leap$") and GetSpellCooldown(6544)==0 then
          SendChatMessage("Hi there","say")
        end
    end)
end
3 Likes

Thank you so much, your posts have been extremely educational.

Looks like this method could have been used to help that guy who wanted to target/buff a random mage in his party and everyone said it wasn’t possible.

If there’s anyone else reading who finds this functionality interesting and wants to learn more, I found this PDF guide written about SecureHeaders:
http://www.iriel.org/wow/docs/SecureHeadersGuide-4.0-r1.pdf

Is there any reason this needs to have a keybind defined in the Lua, or could I create a button and call it in a macro with /click instead?

The button triggering the hardware event needs to be RegisterForClicks(“AnyDown”,“AnyUp”), or if defined in Bindings.xml it needs to have runOnUp=“true”.

It’s not enough that the above HeroicLeapOnUp button has AnyDown,AnyUp registered for clicks if you put it into a macro and drag it to your bars–unless the action buttons meet that criteria too–since the action buttons typically do not have AnyDown,AnyUp or runOnUp defined.

To create a binding in Bindings.xml for the above HeroicLeapOnUp button:

Binding name="CLICK HeroicLeapOnUp:LeftButton" runOnUp="true" category="ADDONS"

(The forum is treating XML brackets as format code so pretend there’s a less-than and greater-than symbols around that.)

If I had more time I’d make an addon to let you define any reticle spell to cast this way. But then it’d be “necessary” to include bombs and then toys so yeah you’re welcome to taking this and writing one up.

1 Like

Can you modify the default action buttons to register those events, or is that in protected space?

I’m trying to make this work with Bartender and similar action bar add-ons that repurpose the default bars, rather than going a completely custom bar solution, or having anything keybind outside the normal keybindings UI.

Looking like this is a herculean task.

I don’t think you can directly/trivially make default action button bindings runOnUp for this behavior for a /click macro. You can MultiBarBottomLeftButton1:RegisterForClicks(“AnyDown”,“AnyUp”) but the up/down-ness won’t get to the click which will at best be two separate events.

Also keep in mind you don’t want all your action buttons to be runOnUp. A rogue would have difficulty going in and out of stealth.

One solution is to use keybind overrides for already-existing binds. So if MultiBarBottomLeftButton1 is bound to ‘F’ and it contains a macro which contains /cast heroic leap, then it can make a button for heroic leap with an override for ‘F’.

1 Like

And that should work for complex modifier macro binds as well right?

I’m wanting this for Hunter traps, which I currently have on PgUp (remapped to an extra mouse button). I’d want PgUp to fire Freezing Trap, Ctrl+PgUp to fire Tar Trap, and Shift+PgUp to fire Binding Shot, all using the KeyUp functionality, but without affecting my Alt+PgUp, CtrlAlt+PgUp, and ShiftAlt+PgUp binds, which fire the same spells [@player].

Why not just macro them normally? Or are you wanting the reticle to display rather than just @cursor

You can adjust CVars/bar addons to fire on key up rather than down np.

Yes currently I have them [@cursor] but I find when trying to drop traps on distant foes out of combat I’m overestimating the range and dropping the traps a few yards ahead of the enemy.

Showing the reticle on KeyDown would allow me to move a little closer for proper placement if needed. I’d also like to avoid the additional click of placing the trap once the reticle is out.

Yeah modified bindings are distinct.

1 Like

And IIRC, the modified bindings will eat the key press before the macro gets them correct? So I could leave my existing macro as is for tooltip purposes and the keybinds set via addon should just work?

Yeah. In the code above Shift-C is an override bindings. In game I have Heroic Leap slotted in an action button bound to Shift-C. The override binding eats the key so really the heroic leap button is never pressed. (But the game is pretty good at giving feedback to a spell being cast on macro buttons regardless if the button was used to cast.)

2 Likes

Thanks so much for this - works awesome for mages too!

I saw this post when I was trying to figure this out on my mage, but I didn’t really understand this; a buddy over on the MooreaTv discord hooked me up. Its quite easy.

Step 1 - create addon folder.
In your addons folder, create a folder called SpellOnKeyUp
(default path is: C:\Program Files (x86)\World of Warcraft_classic_\Interface\AddOns\SpellOnKeyUp)

Step 2 - create the .toc file.
Open notepad (or any txt editor) and copy/paste this into it - save the file as “SpellOnKeyUp.toc” inside your SpellOnKeyUp folder

## Interface: 11306
## Title: SpellOnKeyUp
## Notes: ^
## Author: Gello ?

SpellOnKeyUp.lua

Step 3 - create the .lua file
Open any txt editor again and copy paste this into it - save the file as “SpellOnKeyUp.lua” inside your SpellOnKeyUp folder

local key = "5"if select(2,UnitClass("player"))=="MAGE" then
   local button = CreateFrame("Button","BlizzardOnUp",nil,"SecureActionButtonTemplate")
   button:RegisterForClicks("AnyDown","AnyUp")
   button:SetAttribute("type","macro")
   SecureHandlerWrapScript(button,"OnClick",button,[[
     if down then
       self:SetAttribute("macrotext","/cast blizzard")
     else
       self:SetAttribute("macrotext","/stopspelltarget\n/cast [@cursor] blizzard")
     end
   ]])
   button:RegisterEvent("PLAYER_LOGIN")
   button:SetScript("OnEvent",function(self,event,...)
     SetOverrideBindingClick(self,true,key,"BlizzardOnUp")
   end)
end

This turns your blizzard into a 1 button ordeal - press down to target, and release to cast the spell. You can change the button (default is 5) and even the spell (switch to flamestrike, or any targetable spell like heroic leap) by manually editing the .lua file - its not much more complex than editing a macro.

The default for this is your 5 key and max rank blizzard - press 5 and you’ll get the targeting reticle under your mouse like normal, but the spell will cast as soon as you release 5. It just saves 1 extra mouse click - which I find very useful in PvP, and I think it’ll work well for boosting.

Thank you all for your help!