Goto page Previous  1, 2 Public Macros EQBC hotkeys
Reply
BC and macro interaction, check. I should have looked at the forum last night so I could give the mac a shot! The script looks... like I actually understand it. Let me see if I can break it down:

+ Sub Main: defines the beginning of the script - multiple Sub XYZ allow for multiple subroutines
+ /declare int i: this doesn't seem to follow the /declare name,type,scope,value syntax that I've seen elsewhere - should it be /declare i int inner? I also seem to remember seeing a lot of /varset lines after /declares... is line 4 basically doing the same thing as /varset?
+ :foreverloop: a recall anchor for /goto
+ /for i 0 to ${Group.GroupSize}: this defines the variable "i" and specifically this line defines it by checking the current group size: if no group, 0 is returned so this script can be skipped for the next sub, if grouped 1 - 6 is returned and the variable "i" is defined as having that many... checks (better word here?) and moves to the /if qualifier
+ /if (${Group.Member[${i}].PctHPs < 70) /casting "name of heal spell" gem1 -targetid|${Group.Member[${i}].ID} -maxtries|4: this line tells the character to check group members health as defined by the above /for and if one returns HP <70 the character will cast the defined heal on the player reporting <70 via targetid, we also have maxtries to counteract fizzles
+ /next i: this tells the macro to check the remaining players defined by /for and heal if necessary
+ /goto :foreverloop: tells the script to move to the :foreverloop anchor to continuously run
+ /return: defines the end of the routine

Am I looking at this in the right way? With the great help I've received I feel like I'm getting a hang for the syntax and structure. The biggest struggle I have is finding valid strings: {Me.Buff}, {Target.ID}, {Group.GroupSize}, etc. Is there a list or breakdown anywhere? I've found the / commands on the wiki (invaluable for my BC hotkeys), and each plugin's page has some {string} lines, but I'm looking for something more overarching that lists them all, or at least the most commonly used.
Thu May 08, 2014 11:35 am
+ /declare int i: this doesn't seem to follow the /declare name,type,scope,value syntax that I've seen elsewhere - should it be /declare i int inner? I also seem to remember seeing a lot of /varset lines after /declares... is line 4 basically doing the same thing as /varset?


I didn't re-read the macro for accuracy and I didn't test it. There are bound to be errors like this in such a rush job.

Proper format:
/declare i int

Scope isn't needed in this simple macro but it's good practice to specify it. I'm pretty sure "outer" is the default if no scope is specified. Simple variables like i are traditionally inner scope (since you want to reuse them at several points in your macro). However, in practice, as your macro grows, there are times when you WANT to pass along the specific character (via i) to another subroutine. In that case, make the scope outer and choose a different, more descriptive name.

A default value will be 0 (for integers) if none is specified. You can specify a different value in the /declare without needing a /varset. /varsets immediately following a /declare is cumbersome and verbose and extra work but there are uses such as if you will override any default value with a value read in from an ini file. In this macro, any default value will be overwritten in the /for loop declaration.

Line 4 will change the value of variable i to 0 just as a /varset can but it isn't the same thing as a varset.

+ /for i 0 to ${Group.GroupSize}: this defines the variable "i" and specifically this line defines it by checking the current group size: if no group, 0 is returned so this script can be skipped for the next sub, if grouped 1 - 6 is returned and the variable "i" is defined as having that many... checks (better word here?) and moves to the /if qualifier

...

+ /next i: this tells the macro to check the remaining players defined by /for and heal if necessary


Better word here: Iteration. Loops iterate.

The "i" variable is defined in the /declare statement but initialized in the /for statement. The /for statement sets variable "i" to an initial value at the start of the for loop. If there is no group, Group.GroupSize=1. You are always in your own group even if no one else is in the group.

Macro Flow Control

/for loops work like this:
1. The variable ("i") is initialized
2. The contents of the for loop are executed - in this case, a single line. The contents of any /for loop are executed at least once.
3. When the /next line is reached, the variable is incremented/decremented. Increment by 1 is the default value but another value can be specified in the /for line.
4. The variable is tested against the end number (less than test).
5a. If the test fails, the /for loop is exited and the line after the /next line is run
5b. If the test passes, the variable is incremented/decremented (default is to increment by 1) and the loop is repeated

+ /if (${Group.Member[${i}].PctHPs < 70) /casting "name of heal spell" gem1 -targetid|${Group.Member[${i}].ID} -maxtries|4: this line tells the character to check group members health as defined by the above /for and if one returns HP <70 the character will cast the defined heal on the player reporting <70 via targetid, we also have maxtries to counteract fizzles


Close. The /if line checks a single player. That single player is specified by the value of i. A different iteration of the /for loop will have a different i so a different player is checked.

+ /return: defines the end of the routine


Defines the end of the subroutine named Main. Every Sub needs a /return.

The biggest struggle I have is finding valid strings: {Me.Buff}, {Target.ID}, {Group.GroupSize}, etc. Is there a list or breakdown anywhere? I've found the / commands on the wiki (invaluable for my BC hotkeys), and each plugin's page has some {string} lines, but I'm looking for something more overarching that lists them all, or at least the most commonly used.


Top Level Objects.
Thu May 08, 2014 7:02 pm
Senior Project Member
Top Level Objects! Yes, that's exactly what I was talking about!

That makes a lot of sense, I understand much better how that mac works now. I didn't have a chance to play last night, but I'm going to write something up and test it later. I think this macro should have my Cleric target my SK and heal if <= 70%.

Macro
More +

Sub Main

|Declare the main tank here
/declare Tank string Malistari
/varset Tank ${Tank}

|Declare spells here
/declare heal "Ancient: Hallowed Light"
/declare healGem int 2

:foreverloop
/target id ${Spawn[pc ${Tank}].ID}
/if (${Target.PctHPs}<=70 && ${Target.Type.Equal[PC]} && ${Target.Type.NotEqual[CORPSE]})
/call cast ${heal} gem${healGem}
/goto :foreverloop

/return
Fri May 09, 2014 2:16 pm
The /varset does nothing. The new value of Tank will be set to the old value of Tank. Malistari will be changed to Malistari. If you set the value in the /declare (Malistari) you don't need a /varset unless you want to change the variable to something else (Alulien).

The /call line will also do nothing. /call will try to call a new subroutine name "call" (notice the capitalization). But there is no other subroutine. No other subroutine in the macro and no subroutine included via an #include command. Your format indicates you want to use MQ2Cast_SpellRoutines.inc or Spell_Routines.inc.
Fri May 09, 2014 9:09 pm
Senior Project Member
Yes, I see. What you say is on point now that I go back and look at the sources I Frankenstein'd. Thank you for all your help thus far, Grumble, it has been incredibly helpful and considerate of my growing understanding of the code.

I got it working and then some! Is there a way I can make him sit after casting or stay sitting if he doesn't cast?

Macro
More +

Sub Main
:Main_Loop
/call TankHeal
/call MeHeal
/goto :Main_Loop
/return

Sub TankHeal
/target id ${Spawn[pc Malistari].ID}
/if (${Target.PctHPs} < 60) /casting "Ancient: Hallowed Light" gem2 -maxtries|3
/return

Sub MeHeal
/target id ${Spawn[pc Wrunken].ID}
/if (${Target.PctHPs} < 65) /casting "Pious Remedy" gem3 -maxtries|3
/return

I'm wondering if NetBots can be used to avoid bouncing targets so much? Not really sure if that makes a difference at all, but perhaps more efficient in some way? My Shaman seemed to... get behind? in a zone, not sure how else to describe it. He's just cycling through the entire group looking for different %s - works just fine, but was really weird how it saw mobs fighting that were long dead.

Also, I'm trying to do a group DA/Epic + group heal sub and they're 99% there: my Cleric will cast either his epic or DA, but I can't get the group heal "Word of Restoration" to go off after either. Of course, /echo shows that this is a perfectly valid line... Is there a way to mac this GrpHP subroutine "override" and cancel any spells I'm casting to execute these commands?

Macro
More +

Sub GrpHP
/declare i int local
/declare x int local
/for x 0 to ${Group.GroupSize}
/for i 0 to ${Group.GroupSize}
/if (${x} == ${i}) /next i
/if (${Group.Member[${i}].Distance}<=100 && ${Group.Member[${i}].PctHPs}<50 && ${Group.Member[${i}].Type.Equal[PC]} && ${Group.Member[${x}].Distance}<=100 && ${Group.Member[${x}].PctHPs}<50 && ${Group.Member[${x}].Type.Equal[PC]}) /call GrpHeal
/next i
/next x
/return

Sub GrpHeal
/if (${FindItem[Ancient Shield of the Divine].Timer}==0) /casting "Ancient Shield of the Divine" item
/if (${Me.AltAbilityReady[Divine Arbitration]} && !${FindItem[Ancient Shield of the Divine].Timer}==0) /aa act Divine Arbitration
/casting "Word of Restoration" gem4 -maxtries|3
/return
Sat May 10, 2014 3:14 pm
I can make him sit after casting or stay sitting if he doesn't cast?


Yes:
/if (!${Me.Casting.ID}) /sit

Lots of ways to do this. Rather, lots of ways to determine when it's time to sit and when it's not. The 1000 line macros have lots of checks involved, and for good reason...

This is one of those places where EQBC commands such as /stick won't always play nice with a macro. As written, that one liner could tell your /sticking cleric to sit when it should be dutifully following your tank around.

What macro line works for you will depend on you. You'll have to develop a consistent method of controlling your characters and tailor your EQBC commands and macros to suit. I encourage you to look at how other macros handle the /sit thing and how they are controlled. It doesn't have to be a cleric macro as the task affects all casters. There are several macros on our forums to look at.

I'm wondering if NetBots can be used to avoid bouncing targets so much? Not really sure if that makes a difference at all, but perhaps more efficient in some way? My Shaman seemed to... get behind? in a zone, not sure how else to describe it. He's just cycling through the entire group looking for different %s - works just fine, but was really weird how it saw mobs fighting that were long dead.


Yes. Netbots can avoid having to constantly /target. Likewise for the Group.Member[name] TLO.

/target isn't ideal because of the lag involved. It takes a while for the server to send the packet that updates the health of your target. This is done EVERYTIME you change targets, regardless if the data is also sent elsewhere (group member HP is sent consistently without targeting). It's laggy.

Also, I'm trying to do a group DA/Epic + group heal sub and they're 99% there: my Cleric will cast either his epic or DA, but I can't get the group heal "Word of Restoration" to go off after either. Of course, /echo shows that this is a perfectly valid line... Is there a way to mac this GrpHP subroutine "override" and cancel any spells I'm casting to execute these commands?


Your GroupHP sub takes 30 iterations to do what should only take 6. Loop through the group once. If a character is below 50, then increment a counting variable (which starts at 0) by 1. The loop takes 6 checks. At the end, if your counting variable is 2 (or 3 or 4 or whatever), then /call GrpHeal.

Word of Restoration: Is this meant to be a third option to epic and DA or is it meant to be cast whenever (and after) epic or DA is cast? If the latter, you need a /delay to wait until after casting epic or DA before attempting to cast Word of Restoration.

Interrupting spells is possible. It's easy to do but difficult to know when to do so. Do you interrupt a heal on your tank that's 1 second from finishing in order to cast a 4 second group heal? I don't advise interrupting a healing spell to cast a group heal. Ever. Especially not with 2 healers in the group.
Sun May 11, 2014 4:22 pm
Senior Project Member
Great info.

!${Me.Casting.ID} doesn't seem to be working for me - it returns NULL when /echo'd. Server thing with THF perhaps? I'm using /if (${Me.Standing}) /sit and it works for now as it won't interrupt a spell. And what you say about how things are used makes sense, I've already seen how my order of operations is important.

${NetBots[Group.Member[${i}].PctHPs} is doing the trick for grabbing HP for the healers.

I'm having trouble trying to clean up my group heal per your feedback. I have:


Macro
More +

Sub Main
:Main_Loop
        /call GrpHP
        /goto :Main_Loop
/return

Sub GrpHP
/declare i int inner
/declare check int inner 0
/for i 0 to ${Group.GroupSize}
{
        /if (${NetBots[Group.Member[${i}].PctHPs} < 65) /varset check 1
}
/if (${Check} >= 3) /call GrpHeal
/if (${i} < 5) /next i
/if (${Me.Standing}) /sit
/return

Sub GrpHeal
/if (${FindItem[Ancient Shield of the Divine].Timer}==0) /casting "Ancient Shield of the Divine" item
/if (${Me.AltAbilityReady[Divine Arbitration]} && !${FindItem[Ancient Shield of the Divine].Timer}==0) /aa act Divine Arbitration
/timed 5 /casting "Word of Restoration" gem4 -maxtries|2
/timed 40 /casting "Word of Restoration" gem4 -maxtries|2
/if (${Me.Standing}) /sit
/return


When I /echo and run the GrpHP sub I get:

/declare i int inner
/declare check int inner 0
/for i 0 to 6
/varset failed, variable 'check' not found
grpheal.mac@12 (GrpHP): /if ${NetBots[Group.Member[${i}].PctHPs} < 65) /varset check 1
grpheal.mac@3 (Main): /call GrpHP
/if (NULL >= 3) /call GrpHeal

I've checked the DataVars page page and can't seem to find anything wrong with my syntax.
Tue May 13, 2014 11:47 pm
Invalid /for loop syntax. See the Macro Flow Control page linked earlier.

The /if statement in the /for loop has several errors:
1. More [ than ].
2. Mixed use of NetBots and Group.Member when only one is needed (not an error but not a good practice).
3. /varset instead of /varcalc (varset guarantees check will always be 0 or 1).

check is declared but not evaluated while Check is evaluated but not declared. Undeclared variables always return NULL.
Wed May 14, 2014 1:00 am
Senior Project Member
Functioning now. The only thing that I can't figure out is when DA is being cast the chat window fills with 15-20 lines of "you can cast DA again in 3 minutes" - this only happens on the DA line and not with the epic (no recast not met messages). Any ideas why that might be? I'm confused because the 2 lines are practically identical.

Macro
More +

Sub Main
:Main_Loop
     /call GrpHP
     /goto :Main_Loop
/return

Sub GrpHP
/declare i int inner
/declare check int inner 0
/for i 0 to ${Group.GroupSize}
        /if (${Group.Member[${i}].PctHPs} < 65) /varcalc check ${check}+1
        /if (${check} >= 3) /call GrpHeal
        /if (${i} < 5) /next i
/return

Sub GrpHeal
/if (${FindItem[Ancient Shield of the Divine].Timer}==0) {
        /casting "Ancient Shield of the Divine" item
        /timed 5 /casting "Word of Restoration" gem4 -maxtries|2
        }
/if (${Me.AltAbilityReady[Divine Arbitration]} && !${FindItem[Ancient Shield of the Divine].Timer}==0) {
        /aa act Divine Arbitration
        /timed 30 /casting "Word of Restoration" gem4 -maxtries|2
        }
/return


The other thing is !${Me.Casting.ID} returns NULL - does this have any dependencies I might not have running or is there another way to achieve a spell casting check? I've looked at NetBots as well as character and spawn TLOs and have had no luck.

I'm going to spend some time questing and what not before I start working on a debuff routine for my Sham. I'm happy with the progress I've made and especially appreciate your patience as well as all of the carrots you've thrown, grumble.
Wed May 14, 2014 10:03 pm
The /for loop is still incorrect. "/next i" needs to be by itself on it's own line with nothing else on the line.

The only thing that I can't figure out is when DA is being cast the chat window fills with 15-20 lines of "you can cast DA again in 3 minutes" - this only happens on the DA line and not with the epic (no recast not met messages). Any ideas why that might be? I'm confused because the 2 lines are practically identical.


Count the number of error messages. Are they consistent?

Move the "/if (${check} >= 3) /call GrpHeal" line. Place is AFTER the "/next i" line.

Does the number of error messages change?

The other thing is !${Me.Casting.ID} returns NULL - does this have any dependencies I might not have running or is there another way to achieve a spell casting check? I've looked at NetBots as well as character and spawn TLOs and have had no luck.


Make a hotkey:
/echo ID=${Me.Casting.ID}

Cast a spell. Preferably one with a long cast time. Spam that hotkey before, during and after casting. You should see the correct spellID when casting.

There are no dependencies. It's vanilla MQ2 that provides this TLO.

"/echo ${Cast.Effect}" provides similar (spell name instead of ID) functionality if you have the MQ2Cast plugin loaded.
Thu May 15, 2014 5:58 pm
Senior Project Member
Goto page Previous  1, 2 Public Macros EQBC hotkeys
Reply