Macro Bot.mac Updates and Bug Fixes by [40oz]

Like Pete, I've quit playing the game and any coding I do is purely beneficial to the community. Sadly, I don't have near the skill in programming as Pete does, as I'm just now taking my first C++ class. I'd be happy to help with the code however I can, but without direction I'd be just as lost as any typical user. I've recently covered the topic of struct's and classes for C++.

Also an unfortunate/fortunate thing depending on how you look at it, my class on C++ isn't just about C++. It also covers unix, including compilation in Unix. So any source I create must work in both windows and Unix. As Unix is a new concept for me it has added an additional challenge to my coding. Something I make in C++ may work in VS but not in g++ compilation. So I have to go the extra mile to make sure everything is done correctly for cross platform compilation.

I have downloaded the GIT and pending any homework I have to complete this semester I will look over it. However, some more refined direction on what is needed to be done would be awesome as I can treat it as an assignment and research specific portions of coding to help me with anything I create/add to the functionality. I don't think I am reading to try and understand the monster that is MQ2Bot.cpp in its entirety.

~Chat
I knew zero C++ prior to creating mq2bot. Literally knowing anything is more than i had. I just looked at other plugins for reference and googled/asked htw. I still only know enough to write that specific plugin. i can plan out how i would like things to function but coding them is sometimes problematic because I dont always know what is going to cause issues/crashes. i've never used C++ outside of mq2.

I apologize this is a bit off topic, but this made me wonder, what language script language is used by mq2?

MQ2 macro's are their own language more or less. As all TLO's are declared variables referencing some memory index inside of EQ. When you type ${Me.PctHPs} you are telling the game to find you in EQ, then locate the health as predefined in the MQ2 source in some location.

${Group.Member[${i}].ID}

Group is a TLO, one of the members of that TLO Struct/Class is Member[] which is an Array of information. In this case I'm moving through a for loop, and I've /declared i int local 0 and the range of ${i} is to ${Group} which returns an int according to the size of the group, which is drawn from some predefined memory location from EQ. Then Group.Member[#].ID gets a specific ID from the predefined memory in EQ etc etc etc.....

So the main program is created using C++, and the scripting language that is defined within MQ2 is an API (Application Program Interface) for creating macros.

To the best of my knowledge ${variable} is used in Javascript. Which would make sense because macro's are an API for scripting. Additionally, the $ is found in Unix. I'm sure there are other languages that use the Bash that i'm unaware of or have no experience with.

Obviously my response is all speculation. I don't know that is isn't based on a specific language. Suppose nobody but the original creators/collaborators would know unless informed by the latter
 
Last edited:
Fixing most of the issues seem trivial but i cannot fix sub spellload2 variable issues so 40oz or pete will have to look at that.
 
MQ2 macro's are their own language more or less. As all TLO's are declared variables referencing some memory index inside of EQ. When you type ${Me.PctHPs} you are telling the game to find you in EQ, then locate the health as predefined in the MQ2 source in some location.

${Group.Member[${i}].ID}

Group is a TLO, one of the members of that TLO Struct/Class is Member[] which is an Array of information. In this case I'm moving through a for loop, and I've /declared i int local 0 and the range of ${i} is to ${Group} which returns an int according to the size of the group, which is drawn from some predefined memory location from EQ. Then Group.Member[#].ID gets a specific ID from the predefined memory in EQ etc etc etc.....

So the main program is created using C++, and the scripting language that is defined within MQ2 is an API (Application Program Interface) for creating macros.

To the best of my knowledge ${variable} is used in Javascript. Which would make sense because macro's are an API for scripting. Additionally, the $ is found in Unix. I'm sure there are other languages that use the Bash that i'm unaware of or have no experience with.

Obviously my response is all speculation. I don't know that is isn't based on a specific language. Suppose nobody but the original creators/collaborators would know unless informed by the latter

Here's why I asked. I retired from programming many years ago. To give you an idea of how long ago, Fortran was the only language used on that multi-year project. Both Pascal and BASIC were before that. Since then, I've dabbled with C++ / Visual C. I've often looked for guides on programming that offer more than you can learn looking over someone else's scripts. Learning from the scripts others have created can only give you situational "education," at best. I liken it to playing a cleric but only healing, rezing and buffing, instead of learning the proper times to summon your hammer pets, mark the target for reverse DS, stunning, nuking while healing, rezing and buffing. That's why I'm hoping to find some good sources for instruction. If functions in Javascript also work for mq2 macros, there's a ton of great info out there.

After receiving some good advice I received on this board (just a few months ago), I started playing with mq2melee. THANK YOU!!! I'm still learning things that should and shouldn't and can and can't be done with mq2melee, but I love it, and that's because I've found lots of good details to learn from.
 
MQ2 macro's are their own language more or less. As all TLO's are declared variables referencing some memory index inside of EQ. When you type ${Me.PctHPs} you are telling the game to find you in EQ, then locate the health as predefined in the MQ2 source in some location.

${Group.Member[${i}].ID}

Group is a TLO, one of the members of that TLO Struct/Class is Member[] which is an Array of information. In this case I'm moving through a for loop, and I've /declared i int local 0 and the range of ${i} is to ${Group} which returns an int according to the size of the group, which is drawn from some predefined memory location from EQ. Then Group.Member[#].ID gets a specific ID from the predefined memory in EQ etc etc etc.....

So the main program is created using C++, and the scripting language that is defined within MQ2 is an API (Application Program Interface) for creating macros.

To the best of my knowledge ${variable} is used in Javascript. Which would make sense because macro's are an API for scripting. Additionally, the $ is found in Unix. I'm sure there are other languages that use the Bash that i'm unaware of or have no experience with.

Obviously my response is all speculation. I don't know that is isn't based on a specific language. Suppose nobody but the original creators/collaborators would know unless informed by the latter

Here's why I asked. I retired from programming many years ago. To give you an idea of how long ago, Fortran was the only language used on that multi-year project. Both Pascal and BASIC were before that. Since then, I've dabbled with C++ / Visual C. I've often looked for guides on programming that offer more than you can learn looking over someone else's scripts. Learning from the scripts others have created can only give you situational "education," at best. I liken it to playing a cleric but only healing, rezing and buffing, instead of learning the proper times to summon your hammer pets, mark the target for reverse DS, stunning, nuking while healing, rezing and buffing. That's why I'm hoping to find some good sources for instruction. If functions in Javascript also work for mq2 macros, there's a ton of great info out there.

After receiving some good advice I received on this board (just a few months ago), I started playing with mq2melee. THANK YOU!!! I'm still learning things that should and shouldn't and can and can't be done with mq2melee, but I love it, and that's because I've found lots of good details to learn from.


Template for a post to respond that I need to collect links to multiple posts for. I'll be back!

I'm back, **** TLO builder ****
The above is a link to a "TLO Builder" spreadsheet/app created by PeteSampras that is more or less correct. I've recently gained access to it and plan to fix some things (if I can) such as the recent change to Aura's TLO. It hasn't been updated since 2015, but I've been using it with almost no issues to create perfectly written syntax. It gives you a visual of everything you can do with a specific TLO. Some things most people don't even know about. Like ${Me.MaxRange} returns the max range from your character a target can be for you to connect a melee hit as a double, IE: 19.22 Many many many more options that you can't find without a lot of digging on the partially outdated MQ2 Wiki page.

and then, **** Learn to program with the books I use in college. ****

is the link to programming books I'm currently using for Java and C++ in College for courses in searchable PDF Format. Zip files include some assignments for class and some solutions for the C++, my first post includes recommended free IDE Software links for use in both languages. It's also a great place to learn some situations for basic programming.

Overall for MQ2 the ultimate location for information to do with it of course would be the WIKI. At least for the locations that are kept updated. **** MacroQuest Wiki ****

Also, if you're unaware. Macroquest is maintained on Macroquest.com and you can donate to them (as they do it for donations only) at *** MacroQuest2 *** For your donation, you'll also be granted access to the VIP Forums on Macroquest2's webiste. MQ2 Source is OPEN, thus you can see how it's made and even make your own changes/Plugins. Just as Pete said, he just picked it up and learned from others. The source is available from Macroquest2 or here at MMOBugs.com either one.

Hope this helps :)
 
Last edited:
Fixing most of the issues seem trivial but i cannot fix sub spellload2 variable issues so 40oz or pete will have to look at that.

Can you post what you have so far?

I've got the declares fixed, but haven't had time to dig in further. I can take a look if I can see where you're starting from and you describe what's happening.

Thanks!
 
Guessing this isn't gonna happen before the EQ patch tonight?
 
I just got with William12 to combine forces. I don't know that it will from my end, I'm swamped in RL, it's just bad timing. If this was happening in two weeks, no problem. But now is just bad. I'm doing what I can during downtime. Hopefully we will get something to post to beta in the next day or so.
 
So, I'm working on fixing this up for you guys, spent about 2 hours or so instead of packing like I need to be doing. I've run in to a problem that I think is related to a bug in For Loops. Please eyeball me. Here's the problematic code:

Code:
	/for i 1 to 3
		/call Debug 3 "i: ${i} || MakeList${i}.Count[|]: ${MakeList${i}.Count[|]}"
		/for x 1 to ${MakeList${i}.Count[|]}
			/call Debug 3 "x: ${x} || Ini Value: ${Ini[MyIni,${MakeList${i}.Arg[${x},|]},${MakeList${i}.Arg[${x},|]}Total]}"
			/if (!${Ini[MyIni,${MakeList${i}.Arg[${x},|]},${MakeList${i}.Arg[${x},|]}Total]}) /next x
			/for y 1 to ${Ini[MyIni,${MakeList${i}.Arg[${x},|]},${MakeList${i}.Arg[${x},|]}Total]}
				/if (!${Ini[MyIni,${MakeList${i}.Arg[${x},|]},${MakeList${i}.Arg[${x},|]}Total]}) /next x
				/if (${Ini[MyIni,${MakeList${i}.Arg[${x},|]},${MakeList${i}.Arg[${x},|]}Use${y}]}) {
					/if (${i}==1) {
						/if (!${Defined[${MakeList${i}.Arg[${x},|]}UseAtMobPctHP]}) /declare ${MakeList${i}.Arg[${x},|]}UseAtMobPctHP string outer
						/if (!${Defined[${MakeList${i}.Arg[${x},|]}StopAtMobPctHP]}) /declare ${MakeList${i}.Arg[${x},|]}StopAtMobPctHP string outer
						/varset ${MakeList${i}.Arg[${x},|]}UseAtMobPctHP ${${MakeList${i}.Arg[${x},|]}UseAtMobPctHP} ${Ini[MyIni,${MakeList${i}.Arg[${x},|]},${MakeList${i}.Arg[${x},|]}UseAtMobPctHP${y}]}
						/varset ${MakeList${i}.Arg[${x},|]}StopAtMobPctHP ${${MakeList${i}.Arg[${x},|]}StopAtMobPctHP} ${Ini[MyIni,${MakeList${i}.Arg[${x},|]},${MakeList${i}.Arg[${x},|]}StopAtMobPctHP${y}]}
					}
					/if (${i}==2) {
						/if (!${Defined[${MakeList${i}.Arg[${x},|]}UseAtMyHP]}) /declare ${MakeList${i}.Arg[${x},|]}UseAtMyHP string outer
						/varset ${MakeList${i}.Arg[${x},|]}UseAtMyHP ${${MakeList${i}.Arg[${x},|]}UseAtMyHP} ${Ini[MyIni,${MakeList${i}.Arg[${x},|]},${MakeList${i}.Arg[${x},|]}UseAtMyHP${y}]}
					}
					/if (${i}==3) {
						/if (!${Defined[${MakeList${i}.Arg[${x},|]}UseAt]}) /declare ${MakeList${i}.Arg[${x},|]}UseAt string outer
						/if (!${Defined[${MakeList${i}.Arg[${x},|]}StopAt]}) /declare ${MakeList${i}.Arg[${x},|]}StopAt string outer
						/varset ${MakeList${i}.Arg[${x},|]}UseAt ${${MakeList${i}.Arg[${x},|]}UseAt} ${Ini[MyIni,${MakeList${i}.Arg[${x},|]},${MakeList${i}.Arg[${x},|]}UseAt${y}]}
						/varset ${MakeList${i}.Arg[${x},|]}StopAt ${${MakeList${i}.Arg[${x},|]}StopAt} ${Ini[MyIni,${MakeList${i}.Arg[${x},|]},${MakeList${i}.Arg[${x},|]}StopAt${y}]}
					}
					/if (${i}==4) {
						/if (!${Defined[${MakeList${i}.Arg[${x},|]}SpellIcon]}) /declare ${MakeList${i}.Arg[${x},|]}SpellIcon string outer
						/varset ${MakeList${i}.Arg[${x},|]}SpellIcon ${${MakeList${i}.Arg[${x},|]}SpellIcon}${${MakeList.Arg[${x},|]}SpellIcon{y}}
					}
				}
			/next y
		/next x
	/next i

This is in Sub MakeList. It's 3 nested for loops.

The problem is, i never increments. I'm not sure why this would have changed from before until now, but it's where I'm stuck. It ends up being an infinite loop.

I can show you some debug output from a character who only had Buffs and Self Buff sectiosn enabled in the INI, everything else had Totals set to 0.

Code:
[2017/09/19 21:30:44] [MQ2] DBG3: In Sub MakeList
[2017/09/19 21:30:44] [MQ2] DBG3: i: 1 || MakeList1.Count[|]: 6
[2017/09/19 21:30:44] [MQ2] DBG3: x: 1 || Ini Value: NULL
[2017/09/19 21:30:44] [MQ2] DBG3: x: 2 || Ini Value: 0
[2017/09/19 21:30:44] [MQ2] DBG3: x: 3 || Ini Value: 0
[2017/09/19 21:30:44] [MQ2] DBG3: x: 4 || Ini Value: 0
[2017/09/19 21:30:44] [MQ2] DBG3: x: 5 || Ini Value: NULL
[2017/09/19 21:30:44] [MQ2] DBG3: x: 6 || Ini Value: NULL
[2017/09/19 21:30:44] [MQ2] DBG3: i: 1 || MakeList1.Count[|]: 6
[2017/09/19 21:30:44] [MQ2] DBG3: x: 1 || Ini Value: NULL
[2017/09/19 21:30:44] [MQ2] DBG3: x: 2 || Ini Value: 0
[2017/09/19 21:30:44] [MQ2] DBG3: x: 3 || Ini Value: 0
[2017/09/19 21:30:44] [MQ2] DBG3: x: 4 || Ini Value: 0
[2017/09/19 21:30:44] [MQ2] DBG3: x: 5 || Ini Value: NULL
[2017/09/19 21:30:44] [MQ2] DBG3: x: 6 || Ini Value: NULL
[2017/09/19 21:30:44] [MQ2] DBG3: i: 1 || MakeList1.Count[|]: 6
[2017/09/19 21:30:44] [MQ2] DBG3: x: 1 || Ini Value: NULL
[2017/09/19 21:30:44] [MQ2] DBG3: x: 2 || Ini Value: 0
[2017/09/19 21:30:44] [MQ2] DBG3: x: 3 || Ini Value: 0
[2017/09/19 21:30:44] [MQ2] DBG3: x: 4 || Ini Value: 0
[2017/09/19 21:30:44] [MQ2] DBG3: x: 5 || Ini Value: NULL
[2017/09/19 21:30:44] [MQ2] DBG3: x: 6 || Ini Value: NULL

So, following the code logic, i is 1, it loops through x's, after it gets to the max x, it goes back to i being 1?

It'll short circuit the y for loop when the Ini Value it's looking at comes back NULL, doing a next X there, which will be happening on value 6 for x, as seen in the log. But then since X runs out, it doesn't seem to follow with a next i.

edit: Confirmed. Changing the code so there's only one /next x fixed the infinite loop

Code:
	/for i 1 to 3
		/call Debug 3 "i: ${i} || MakeList${i}.Count[|]: ${MakeList${i}.Count[|]}"
		/for x 1 to ${MakeList${i}.Count[|]}
			/call Debug 3 "x: ${x} || Ini Value: ${Ini[MyIni,${MakeList${i}.Arg[${x},|]},${MakeList${i}.Arg[${x},|]}Total]}"
			/if (${Ini[MyIni,${MakeList${i}.Arg[${x},|]},${MakeList${i}.Arg[${x},|]}Total]}) {
				/for y 1 to ${Ini[MyIni,${MakeList${i}.Arg[${x},|]},${MakeList${i}.Arg[${x},|]}Total]}
					/if (!${Ini[MyIni,${MakeList${i}.Arg[${x},|]},${MakeList${i}.Arg[${x},|]}Total]}) /next x
					/if (${Ini[MyIni,${MakeList${i}.Arg[${x},|]},${MakeList${i}.Arg[${x},|]}Use${y}]}) {
						/if (${i}==1) {
							/if (!${Defined[${MakeList${i}.Arg[${x},|]}UseAtMobPctHP]}) /declare ${MakeList${i}.Arg[${x},|]}UseAtMobPctHP string outer
							/if (!${Defined[${MakeList${i}.Arg[${x},|]}StopAtMobPctHP]}) /declare ${MakeList${i}.Arg[${x},|]}StopAtMobPctHP string outer
							/varset ${MakeList${i}.Arg[${x},|]}UseAtMobPctHP ${${MakeList${i}.Arg[${x},|]}UseAtMobPctHP} ${Ini[MyIni,${MakeList${i}.Arg[${x},|]},${MakeList${i}.Arg[${x},|]}UseAtMobPctHP${y}]}
							/varset ${MakeList${i}.Arg[${x},|]}StopAtMobPctHP ${${MakeList${i}.Arg[${x},|]}StopAtMobPctHP} ${Ini[MyIni,${MakeList${i}.Arg[${x},|]},${MakeList${i}.Arg[${x},|]}StopAtMobPctHP${y}]}
						}
						/if (${i}==2) {
							/if (!${Defined[${MakeList${i}.Arg[${x},|]}UseAtMyHP]}) /declare ${MakeList${i}.Arg[${x},|]}UseAtMyHP string outer
							/varset ${MakeList${i}.Arg[${x},|]}UseAtMyHP ${${MakeList${i}.Arg[${x},|]}UseAtMyHP} ${Ini[MyIni,${MakeList${i}.Arg[${x},|]},${MakeList${i}.Arg[${x},|]}UseAtMyHP${y}]}
						}
						/if (${i}==3) {
							/if (!${Defined[${MakeList${i}.Arg[${x},|]}UseAt]}) /declare ${MakeList${i}.Arg[${x},|]}UseAt string outer
							/if (!${Defined[${MakeList${i}.Arg[${x},|]}StopAt]}) /declare ${MakeList${i}.Arg[${x},|]}StopAt string outer
							/varset ${MakeList${i}.Arg[${x},|]}UseAt ${${MakeList${i}.Arg[${x},|]}UseAt} ${Ini[MyIni,${MakeList${i}.Arg[${x},|]},${MakeList${i}.Arg[${x},|]}UseAt${y}]}
							/varset ${MakeList${i}.Arg[${x},|]}StopAt ${${MakeList${i}.Arg[${x},|]}StopAt} ${Ini[MyIni,${MakeList${i}.Arg[${x},|]},${MakeList${i}.Arg[${x},|]}StopAt${y}]}
						}
						/if (${i}==4) {
							/if (!${Defined[${MakeList${i}.Arg[${x},|]}SpellIcon]}) /declare ${MakeList${i}.Arg[${x},|]}SpellIcon string outer
							/varset ${MakeList${i}.Arg[${x},|]}SpellIcon ${${MakeList${i}.Arg[${x},|]}SpellIcon}${${MakeList.Arg[${x},|]}SpellIcon{y}}
						}
					}
				/next y
			}
		/next x
	/next i

htw / eqmule - any idea if what WAS there, with an /if conditional calling a /next x should have worked as a short circuit before the recent patches, but broke sometime with the recent changes?
 
Last edited:
There was a MQ2 release put out yesterday to fix an infinite loop bug. Were you using that version? (We updated about 24 hours ago)
 
There was a MQ2 release put out yesterday to fix an infinite loop bug. Were you using that version? (We updated about 24 hours ago)

I downloaded MQ2 today, so should have been.

That said.

I HAVE A BETA VERSION. Release notes. It is attached to this post. Requires a new spell_routines.inc as well.

Code:
 ** 2017-09-19 - 40oz
 **   - First round of fixes for the new variable handling in MQ2 Core
 **     - THESE ARE NOT COMPLETE CHANGES TO MAKE IT WORK
 **     - Only basic functionality was tested with SelfBuff alone.
 **     - Will need error reports for other broken sections with INIs to test against.

This is working with a basic ini file that only self buffs at the moment. I haven't tested all sections and loading of all INI section types. I need specific error reports with example INIs for each section (Dot, Buff, Heal, etc.). Please grab the text out of your MQ2ChatWnd log in the MQ2\Logs folder so I can see exactly what the error is.

At this point it should be pretty easy for anyone to fix. If you contribute changes that fix something, please upload it in a post on this thread as an attachment. If you're going to fix something, make sure you've grabbed the newest here. I will try to keep up, but I'm getting on a plane to Japan in 2 days and I haven't finished packing the house I'm renting out yet, so I may be out of time for this until I'm in Japan.

I'll try to fix broken sections as they come in, but I can make no promises on my time at the moment. If other folks incorporate changes, I'll be in charge of merging them if someone else doesn't whenever I have time. Once we are happy with the updates, I'll update the top post.
 

Attachments

  • bot40.mac
    480.2 KB · Views: 15
  • Spell_routines.inc
    67.2 KB · Views: 16
Last edited:
So, I'm working on fixing this up for you guys, spent about 2 hours or so instead of packing like I need to be doing. I've run in to a problem that I think is related to a bug in For Loops. Please eyeball me. Here's the problematic code: .....

htw / eqmule - any idea if what WAS there, with an /if conditional calling a /next x should have worked as a short circuit before the recent patches, but broke sometime with the recent changes?

3rd line /for x 1 to ${MakeList${i}.Count[|]} inside the count, instead of a variable it's using | which is odd. Not sure if that was intended. I see it used in multiple locations through out the code provided. Thus it appears to be intentional. Just not familiar with it's purpose. .Count[] I assume is supposed to be passed an index location, but what does the use of | get you?
 
Last edited:
So, I'm working on fixing this up for you guys, spent about 2 hours or so instead of packing like I need to be doing. I've run in to a problem that I think is related to a bug in For Loops. Please eyeball me. Here's the problematic code: .....

htw / eqmule - any idea if what WAS there, with an /if conditional calling a /next x should have worked as a short circuit before the recent patches, but broke sometime with the recent changes?

3rd line /for x 1 to ${MakeList${i}.Count[|]} inside the count, instead of a variable it's using | which is odd. Not sure if that was intended. I see it used in multiple locations through out the code provided. Thus it appears to be intentional. Just not familiar with it's purpose. .Count[] I assume is supposed to be passed an index location, but what does the use of | get you?

It counts the number of the given character in the string. So it's counting how many items to iterate over as the string is pipe separated.
 
So, I'm working on fixing this up for you guys, spent about 2 hours or so instead of packing like I need to be doing. I've run in to a problem that I think is related to a bug in For Loops. Please eyeball me. Here's the problematic code: .....

htw / eqmule - any idea if what WAS there, with an /if conditional calling a /next x should have worked as a short circuit before the recent patches, but broke sometime with the recent changes?

3rd line /for x 1 to ${MakeList${i}.Count[|]} inside the count, instead of a variable it's using | which is odd. Not sure if that was intended. I see it used in multiple locations through out the code provided. Thus it appears to be intentional. Just not familiar with it's purpose. .Count[] I assume is supposed to be passed an index location, but what does the use of | get you?

It counts the number of the given character in the string. So it's counting how many items to iterate over as the string is pipe separated.

Ok, thanks for that information.

Additionally, the following

Lines 364, 1347, 3816, 3837, 7269-(EchoSub), 7560 - need ending quotation
7269 is /call ${EchoSub} everything else is /call Debug

Being you're trying to get feedback, I'm unsure if this will cause issues with those using debug.

Note sure what you're using for editing code. I'm using notepad++ with custom language defined. I've exported that and attached it. You should be able to import my language file via the "Define your language" under the languages drop down at the bottom. It helps me catch the problems. You'll still have to change global background to a dark color I believe for this scheme to make sense. I've included a screenshot of what it looks like. I use darker scheme because staring at a bunch of white all the time gives me a headache.
 

Attachments

  • notepad++_.mac_language.xml
    5.5 KB · Views: 6
  • MQ2Lang.bmp
    4.1 MB · Views: 10
Last edited:
Few things so far....

* It currently thinks that PCs on your xtarget list are adds

* It buffs toons over and over at the moment, regardless of weather they already have the buff or not.

* It debuffs mobs over and over, even with a successful cast.

* Eventually it gives an error "Subroutine 34904 wasn't found" when attempting to cast auras
Spell_Routines.inc@676

* Error: /next without matching /for
@ 5397 (ClickyNuke)


EDIT: Regarding the buffs and debuffs, its not checking conditions on other stuff too..... other one i noticed is MTbuff with check for more then 3 adds, it fires as soon as MA gets a target, even if only 1 mob on xtarget (could be related to PCs on xtarget being counted as adds)
 
So, I'm working on fixing this up for you guys, spent about 2 hours or so instead of packing like I need to be doing. I've run in to a problem that I think is related to a bug in For Loops. Please eyeball me. Here's the problematic code:

Code:
	/for i 1 to 3
		/call Debug 3 "i: ${i} || MakeList${i}.Count[|]: ${MakeList${i}.Count[|]}"
		/for x 1 to ${MakeList${i}.Count[|]}
			/call Debug 3 "x: ${x} || Ini Value: ${Ini[MyIni,${MakeList${i}.Arg[${x},|]},${MakeList${i}.Arg[${x},|]}Total]}"
			/if (!${Ini[MyIni,${MakeList${i}.Arg[${x},|]},${MakeList${i}.Arg[${x},|]}Total]}) /next x
			/for y 1 to ${Ini[MyIni,${MakeList${i}.Arg[${x},|]},${MakeList${i}.Arg[${x},|]}Total]}
				/if (!${Ini[MyIni,${MakeList${i}.Arg[${x},|]},${MakeList${i}.Arg[${x},|]}Total]}) /next x
				/if (${Ini[MyIni,${MakeList${i}.Arg[${x},|]},${MakeList${i}.Arg[${x},|]}Use${y}]}) {
					/if (${i}==1) {
						/if (!${Defined[${MakeList${i}.Arg[${x},|]}UseAtMobPctHP]}) /declare ${MakeList${i}.Arg[${x},|]}UseAtMobPctHP string outer
						/if (!${Defined[${MakeList${i}.Arg[${x},|]}StopAtMobPctHP]}) /declare ${MakeList${i}.Arg[${x},|]}StopAtMobPctHP string outer
						/varset ${MakeList${i}.Arg[${x},|]}UseAtMobPctHP ${${MakeList${i}.Arg[${x},|]}UseAtMobPctHP} ${Ini[MyIni,${MakeList${i}.Arg[${x},|]},${MakeList${i}.Arg[${x},|]}UseAtMobPctHP${y}]}
						/varset ${MakeList${i}.Arg[${x},|]}StopAtMobPctHP ${${MakeList${i}.Arg[${x},|]}StopAtMobPctHP} ${Ini[MyIni,${MakeList${i}.Arg[${x},|]},${MakeList${i}.Arg[${x},|]}StopAtMobPctHP${y}]}
					}
					/if (${i}==2) {
						/if (!${Defined[${MakeList${i}.Arg[${x},|]}UseAtMyHP]}) /declare ${MakeList${i}.Arg[${x},|]}UseAtMyHP string outer
						/varset ${MakeList${i}.Arg[${x},|]}UseAtMyHP ${${MakeList${i}.Arg[${x},|]}UseAtMyHP} ${Ini[MyIni,${MakeList${i}.Arg[${x},|]},${MakeList${i}.Arg[${x},|]}UseAtMyHP${y}]}
					}
					/if (${i}==3) {
						/if (!${Defined[${MakeList${i}.Arg[${x},|]}UseAt]}) /declare ${MakeList${i}.Arg[${x},|]}UseAt string outer
						/if (!${Defined[${MakeList${i}.Arg[${x},|]}StopAt]}) /declare ${MakeList${i}.Arg[${x},|]}StopAt string outer
						/varset ${MakeList${i}.Arg[${x},|]}UseAt ${${MakeList${i}.Arg[${x},|]}UseAt} ${Ini[MyIni,${MakeList${i}.Arg[${x},|]},${MakeList${i}.Arg[${x},|]}UseAt${y}]}
						/varset ${MakeList${i}.Arg[${x},|]}StopAt ${${MakeList${i}.Arg[${x},|]}StopAt} ${Ini[MyIni,${MakeList${i}.Arg[${x},|]},${MakeList${i}.Arg[${x},|]}StopAt${y}]}
					}
					/if (${i}==4) {
						/if (!${Defined[${MakeList${i}.Arg[${x},|]}SpellIcon]}) /declare ${MakeList${i}.Arg[${x},|]}SpellIcon string outer
						/varset ${MakeList${i}.Arg[${x},|]}SpellIcon ${${MakeList${i}.Arg[${x},|]}SpellIcon}${${MakeList.Arg[${x},|]}SpellIcon{y}}
					}
				}
			/next y
		/next x
	/next i

This is in Sub MakeList. It's 3 nested for loops.

The problem is, i never increments. I'm not sure why this would have changed from before until now, but it's where I'm stuck. It ends up being an infinite loop.

I can show you some debug output from a character who only had Buffs and Self Buff sectiosn enabled in the INI, everything else had Totals set to 0.

Code:
[2017/09/19 21:30:44] [MQ2] DBG3: In Sub MakeList
[2017/09/19 21:30:44] [MQ2] DBG3: i: 1 || MakeList1.Count[|]: 6
[2017/09/19 21:30:44] [MQ2] DBG3: x: 1 || Ini Value: NULL
[2017/09/19 21:30:44] [MQ2] DBG3: x: 2 || Ini Value: 0
[2017/09/19 21:30:44] [MQ2] DBG3: x: 3 || Ini Value: 0
[2017/09/19 21:30:44] [MQ2] DBG3: x: 4 || Ini Value: 0
[2017/09/19 21:30:44] [MQ2] DBG3: x: 5 || Ini Value: NULL
[2017/09/19 21:30:44] [MQ2] DBG3: x: 6 || Ini Value: NULL
[2017/09/19 21:30:44] [MQ2] DBG3: i: 1 || MakeList1.Count[|]: 6
[2017/09/19 21:30:44] [MQ2] DBG3: x: 1 || Ini Value: NULL
[2017/09/19 21:30:44] [MQ2] DBG3: x: 2 || Ini Value: 0
[2017/09/19 21:30:44] [MQ2] DBG3: x: 3 || Ini Value: 0
[2017/09/19 21:30:44] [MQ2] DBG3: x: 4 || Ini Value: 0
[2017/09/19 21:30:44] [MQ2] DBG3: x: 5 || Ini Value: NULL
[2017/09/19 21:30:44] [MQ2] DBG3: x: 6 || Ini Value: NULL
[2017/09/19 21:30:44] [MQ2] DBG3: i: 1 || MakeList1.Count[|]: 6
[2017/09/19 21:30:44] [MQ2] DBG3: x: 1 || Ini Value: NULL
[2017/09/19 21:30:44] [MQ2] DBG3: x: 2 || Ini Value: 0
[2017/09/19 21:30:44] [MQ2] DBG3: x: 3 || Ini Value: 0
[2017/09/19 21:30:44] [MQ2] DBG3: x: 4 || Ini Value: 0
[2017/09/19 21:30:44] [MQ2] DBG3: x: 5 || Ini Value: NULL
[2017/09/19 21:30:44] [MQ2] DBG3: x: 6 || Ini Value: NULL

So, following the code logic, i is 1, it loops through x's, after it gets to the max x, it goes back to i being 1?

It'll short circuit the y for loop when the Ini Value it's looking at comes back NULL, doing a next X there, which will be happening on value 6 for x, as seen in the log. But then since X runs out, it doesn't seem to follow with a next i.

edit: Confirmed. Changing the code so there's only one /next x fixed the infinite loop

Code:
	/for i 1 to 3
		/call Debug 3 "i: ${i} || MakeList${i}.Count[|]: ${MakeList${i}.Count[|]}"
		/for x 1 to ${MakeList${i}.Count[|]}
			/call Debug 3 "x: ${x} || Ini Value: ${Ini[MyIni,${MakeList${i}.Arg[${x},|]},${MakeList${i}.Arg[${x},|]}Total]}"
			/if (${Ini[MyIni,${MakeList${i}.Arg[${x},|]},${MakeList${i}.Arg[${x},|]}Total]}) {
				/for y 1 to ${Ini[MyIni,${MakeList${i}.Arg[${x},|]},${MakeList${i}.Arg[${x},|]}Total]}
					/if (!${Ini[MyIni,${MakeList${i}.Arg[${x},|]},${MakeList${i}.Arg[${x},|]}Total]}) /next x
					/if (${Ini[MyIni,${MakeList${i}.Arg[${x},|]},${MakeList${i}.Arg[${x},|]}Use${y}]}) {
						/if (${i}==1) {
							/if (!${Defined[${MakeList${i}.Arg[${x},|]}UseAtMobPctHP]}) /declare ${MakeList${i}.Arg[${x},|]}UseAtMobPctHP string outer
							/if (!${Defined[${MakeList${i}.Arg[${x},|]}StopAtMobPctHP]}) /declare ${MakeList${i}.Arg[${x},|]}StopAtMobPctHP string outer
							/varset ${MakeList${i}.Arg[${x},|]}UseAtMobPctHP ${${MakeList${i}.Arg[${x},|]}UseAtMobPctHP} ${Ini[MyIni,${MakeList${i}.Arg[${x},|]},${MakeList${i}.Arg[${x},|]}UseAtMobPctHP${y}]}
							/varset ${MakeList${i}.Arg[${x},|]}StopAtMobPctHP ${${MakeList${i}.Arg[${x},|]}StopAtMobPctHP} ${Ini[MyIni,${MakeList${i}.Arg[${x},|]},${MakeList${i}.Arg[${x},|]}StopAtMobPctHP${y}]}
						}
						/if (${i}==2) {
							/if (!${Defined[${MakeList${i}.Arg[${x},|]}UseAtMyHP]}) /declare ${MakeList${i}.Arg[${x},|]}UseAtMyHP string outer
							/varset ${MakeList${i}.Arg[${x},|]}UseAtMyHP ${${MakeList${i}.Arg[${x},|]}UseAtMyHP} ${Ini[MyIni,${MakeList${i}.Arg[${x},|]},${MakeList${i}.Arg[${x},|]}UseAtMyHP${y}]}
						}
						/if (${i}==3) {
							/if (!${Defined[${MakeList${i}.Arg[${x},|]}UseAt]}) /declare ${MakeList${i}.Arg[${x},|]}UseAt string outer
							/if (!${Defined[${MakeList${i}.Arg[${x},|]}StopAt]}) /declare ${MakeList${i}.Arg[${x},|]}StopAt string outer
							/varset ${MakeList${i}.Arg[${x},|]}UseAt ${${MakeList${i}.Arg[${x},|]}UseAt} ${Ini[MyIni,${MakeList${i}.Arg[${x},|]},${MakeList${i}.Arg[${x},|]}UseAt${y}]}
							/varset ${MakeList${i}.Arg[${x},|]}StopAt ${${MakeList${i}.Arg[${x},|]}StopAt} ${Ini[MyIni,${MakeList${i}.Arg[${x},|]},${MakeList${i}.Arg[${x},|]}StopAt${y}]}
						}
						/if (${i}==4) {
							/if (!${Defined[${MakeList${i}.Arg[${x},|]}SpellIcon]}) /declare ${MakeList${i}.Arg[${x},|]}SpellIcon string outer
							/varset ${MakeList${i}.Arg[${x},|]}SpellIcon ${${MakeList${i}.Arg[${x},|]}SpellIcon}${${MakeList.Arg[${x},|]}SpellIcon{y}}
						}
					}
				/next y
			}
		/next x
	/next i

htw / eqmule - any idea if what WAS there, with an /if conditional calling a /next x should have worked as a short circuit before the recent patches, but broke sometime with the recent changes?

So the way for and next works is that if you have a /for x it will consider the FIRST /next x it finds the END of the loop.

That's why a /for loop should ONLY have ONE matching /next

In your case you should therefore replace ALL the /next x INSIDE your for loop with /continue which will locate the one and ONLY /next x OUTSIDE of it and "goto" it...

/next has been misused like this for years, it was overdue for a "nerf" use /continue when you need to skip to the next iteration, and /break if you need to break out altogether.
 
Last edited:
So the way for and next works is that if you have a /for x it will consider the FIRST /next x it finds the END of the loop.

That's why a /for loop should ONLY have ONE matching /next

In your case you should therefore replace ALL the /next x INSIDE your for loop with /continue which will locate the one and ONLY /next x OUTSIDE of it and "goto" it...

/next has been misused like this for years, it was overdue for a "nerf" use /continue when you need to skip to the next iteration, and /break if you need to break out altogether.


Is this a recent change? If so I'm pretty sure there are places I'm guilty of it as well. I didn't even know /continue existed lol. There are some places I know I use /goto to skip to the end of the routine, but pretty sure there are places where I just used /next in an if as well.

I'm curious if this is a recent change, what is the benefit to the change? Is it another performance improvement thing? I think such a change is going to break my bots even worse than the undeclared variables did lol. Going to take a lot longer to find all the places and fix at least :(
 
So the way for and next works is that if you have a /for x it will consider the FIRST /next x it finds the END of the loop.

That's why a /for loop should ONLY have ONE matching /next

In your case you should therefore replace ALL the /next x INSIDE your for loop with /continue which will locate the one and ONLY /next x OUTSIDE of it and "goto" it...

/next has been misused like this for years, it was overdue for a "nerf" use /continue when you need to skip to the next iteration, and /break if you need to break out altogether.

I'm glad you clarified that. I had tried to use this same method to make a for loop with multiple chances of /next x and it didn't work, so I opted to strong arm it with my own incrementing in an if loop which used a /goto is some condition wasn't yet met (basically a while loop). Will make future development easier. As a side note, are while loops supported?
 
So the way for and next works is that if you have a /for x it will consider the FIRST /next x it finds the END of the loop.

That's why a /for loop should ONLY have ONE matching /next

In your case you should therefore replace ALL the /next x INSIDE your for loop with /continue which will locate the one and ONLY /next x OUTSIDE of it and "goto" it...

/next has been misused like this for years, it was overdue for a "nerf" use /continue when you need to skip to the next iteration, and /break if you need to break out altogether.


Is this a recent change? If so I'm pretty sure there are places I'm guilty of it as well. I didn't even know /continue existed lol. There are some places I know I use /goto to skip to the end of the routine, but pretty sure there are places where I just used /next in an if as well.

I'm curious if this is a recent change, what is the benefit to the change? Is it another performance improvement thing? I think such a change is going to break my bots even worse than the undeclared variables did lol. Going to take a lot longer to find all the places and fix at least :(

Dev~ if it is recent, it's not from the recent patches that I'm aware of. It has never functioned properly for me using multiple /next

I brute forced my way through most code simply on the basis that my for loops wouldn't function in the manner shown in that code.

For the typical flow of code it doesn't really make sense because you expect it would only evaluate that /next x if it entered the /if () {/next} so at least we understand why we would all think it should work like that. But /break and /continue are just as well.
 
Last edited:
I think the main issue is with:

Code:
Sub IniLoad(ininame,var,vartype,sec,default)
	/call Debug 3 "In Sub IniLoad"
	/if (!${Defined[${var}]} && (!${default.Length}||${default.Equal[NULL]})) /declare ${var} ${vartype} outer ${Ini[${ininame},${sec},${var}]}
	/if (!${Defined[${var}]} && (${default.Length} && ${default.NotEqual[NULL]})) /declare ${var} ${vartype} outer ${Ini[${ininame},${sec},${var},${default}]}
	/if (${vartype.Equal[string]}) {
		/if (!${${var}.Length}||${${var}.Equal[NULL]}) /mmoini "${ininame}" "${sec}" "${var}"
	}
	/if (${vartype.Equal[string]}) {
			/if (${${var}.Length} && !${${var}.Equal[NULL]}) /mmoini "${ininame}" "${sec}" "${var}" "${${var}}"
	}
	/if (${vartype.Equal[int]}||${vartype.Equal[float]}) /mmoini "${ininame}" "${sec}" "${var}" "${${var}}"
	/if (${vartype.Equal[bool]}) {
		/if (!${${var}}) /mmoini "${ininame}" "${sec}" "${var}" "FALSE"
	} 
	/if (${vartype.Equal[bool]}) {
		/if (${${var}}) /mmoini "${ininame}" "${sec}" "${var}" "TRUE"
	}
	/varset ${var} ${Ini[${ininame},${sec},${var}]}
	/call Debug 3 "Leaving Sub IniLoad"
/return

Creating lots of variables that are wrong/undeclared, but I don't know how to fix that.

I also think that line 5085, currently:
Code:
/if (${XHealTotal} && !${Me.XTarget[${x}].TargetType.Equal[Auto Hater]} && ${Select[${Spawn[id ${Me.XTarget[${x}].ID}].Type},pet,pc,mercenary]} && ${Me.XTarget[${x}].ID} && ${Range.Between[1,${InterruptToXHealAt}:${Spawn[${Me.XTarget[${x}].ID}].PctHPs}]} && ${OptionsCheck.Find[XHeal]}) {

Should be:
Code:
/if (${XHealTotal} && !${Me.XTarget[${z}].TargetType.Equal[Auto Hater]} && ${Select[${Spawn[id ${Me.XTarget[${z}].ID}].Type},pet,pc,mercenary]} && ${Me.XTarget[${z}].ID} && ${Range.Between[1,${InterruptToXHealAt}:${Spawn[${Me.XTarget[${z}].ID}].PctHPs}]} && ${OptionsCheck.Find[XHeal]}) {

(could be wrong, but there is no loop over "x" in that sub, so I think it should be "z")

And as per eqmules post, the loop 40oz posted:
Code:
/for i 1 to 3
		/call Debug 3 "i: ${i} || MakeList${i}.Count[|]: ${MakeList${i}.Count[|]}"
		/for x 1 to ${MakeList${i}.Count[|]}
			/call Debug 3 "x: ${x} || Ini Value: ${Ini[MyIni,${MakeList${i}.Arg[${x},|]},${MakeList${i}.Arg[${x},|]}Total]}"
			/if (${Ini[MyIni,${MakeList${i}.Arg[${x},|]},${MakeList${i}.Arg[${x},|]}Total]}) {
				/for y 1 to ${Ini[MyIni,${MakeList${i}.Arg[${x},|]},${MakeList${i}.Arg[${x},|]}Total]}
					/if (!${Ini[MyIni,${MakeList${i}.Arg[${x},|]},${MakeList${i}.Arg[${x},|]}Total]}) /next x
					/if (${Ini[MyIni,${MakeList${i}.Arg[${x},|]},${MakeList${i}.Arg[${x},|]}Use${y}]}) {
						/if (${i}==1) {
							/if (!${Defined[${MakeList${i}.Arg[${x},|]}UseAtMobPctHP]}) /declare ${MakeList${i}.Arg[${x},|]}UseAtMobPctHP string outer
							/if (!${Defined[${MakeList${i}.Arg[${x},|]}StopAtMobPctHP]}) /declare ${MakeList${i}.Arg[${x},|]}StopAtMobPctHP string outer
							/varset ${MakeList${i}.Arg[${x},|]}UseAtMobPctHP ${${MakeList${i}.Arg[${x},|]}UseAtMobPctHP} ${Ini[MyIni,${MakeList${i}.Arg[${x},|]},${MakeList${i}.Arg[${x},|]}UseAtMobPctHP${y}]}
							/varset ${MakeList${i}.Arg[${x},|]}StopAtMobPctHP ${${MakeList${i}.Arg[${x},|]}StopAtMobPctHP} ${Ini[MyIni,${MakeList${i}.Arg[${x},|]},${MakeList${i}.Arg[${x},|]}StopAtMobPctHP${y}]}
						}
						/if (${i}==2) {
							/if (!${Defined[${MakeList${i}.Arg[${x},|]}UseAtMyHP]}) /declare ${MakeList${i}.Arg[${x},|]}UseAtMyHP string outer
							/varset ${MakeList${i}.Arg[${x},|]}UseAtMyHP ${${MakeList${i}.Arg[${x},|]}UseAtMyHP} ${Ini[MyIni,${MakeList${i}.Arg[${x},|]},${MakeList${i}.Arg[${x},|]}UseAtMyHP${y}]}
						}
						/if (${i}==3) {
							/if (!${Defined[${MakeList${i}.Arg[${x},|]}UseAt]}) /declare ${MakeList${i}.Arg[${x},|]}UseAt string outer
							/if (!${Defined[${MakeList${i}.Arg[${x},|]}StopAt]}) /declare ${MakeList${i}.Arg[${x},|]}StopAt string outer
							/varset ${MakeList${i}.Arg[${x},|]}UseAt ${${MakeList${i}.Arg[${x},|]}UseAt} ${Ini[MyIni,${MakeList${i}.Arg[${x},|]},${MakeList${i}.Arg[${x},|]}UseAt${y}]}
							/varset ${MakeList${i}.Arg[${x},|]}StopAt ${${MakeList${i}.Arg[${x},|]}StopAt} ${Ini[MyIni,${MakeList${i}.Arg[${x},|]},${MakeList${i}.Arg[${x},|]}StopAt${y}]}
						}
						/if (${i}==4) {
							/if (!${Defined[${MakeList${i}.Arg[${x},|]}SpellIcon]}) /declare ${MakeList${i}.Arg[${x},|]}SpellIcon string outer
							/varset ${MakeList${i}.Arg[${x},|]}SpellIcon ${${MakeList${i}.Arg[${x},|]}SpellIcon}${${MakeList.Arg[${x},|]}SpellIcon{y}}
						}
					}
				/next y
			}
		/next x
	/next i

Still has 2 "/next x" lines...... so maybe it should be:
Code:
	/for i 1 to 3
		/call Debug 3 "i: ${i} || MakeList${i}.Count[|]: ${MakeList${i}.Count[|]}"
		/for x 1 to ${MakeList${i}.Count[|]}
			/call Debug 3 "x: ${x} || Ini Value: ${Ini[MyIni,${MakeList${i}.Arg[${x},|]},${MakeList${i}.Arg[${x},|]}Total]}"
			/if (!${Ini[MyIni,${MakeList${i}.Arg[${x},|]},${MakeList${i}.Arg[${x},|]}Total]}) /continue
			/for y 1 to ${Ini[MyIni,${MakeList${i}.Arg[${x},|]},${MakeList${i}.Arg[${x},|]}Total]}
				/if (!${Ini[MyIni,${MakeList${i}.Arg[${x},|]},${MakeList${i}.Arg[${x},|]}Total]}) /continue
				/if (${Ini[MyIni,${MakeList${i}.Arg[${x},|]},${MakeList${i}.Arg[${x},|]}Use${y}]}) {
					/if (${i}==1) {
						/if (!${Defined[${MakeList${i}.Arg[${x},|]}UseAtMobPctHP]}) /declare ${MakeList${i}.Arg[${x},|]}UseAtMobPctHP string outer
						/if (!${Defined[${MakeList${i}.Arg[${x},|]}StopAtMobPctHP]}) /declare ${MakeList${i}.Arg[${x},|]}StopAtMobPctHP string outer
						/varset ${MakeList${i}.Arg[${x},|]}UseAtMobPctHP ${${MakeList${i}.Arg[${x},|]}UseAtMobPctHP} ${Ini[MyIni,${MakeList${i}.Arg[${x},|]},${MakeList${i}.Arg[${x},|]}UseAtMobPctHP${y}]}
						/varset ${MakeList${i}.Arg[${x},|]}StopAtMobPctHP ${${MakeList${i}.Arg[${x},|]}StopAtMobPctHP} ${Ini[MyIni,${MakeList${i}.Arg[${x},|]},${MakeList${i}.Arg[${x},|]}StopAtMobPctHP${y}]}
					}
					/if (${i}==2) {
						/if (!${Defined[${MakeList${i}.Arg[${x},|]}UseAtMyHP]}) /declare ${MakeList${i}.Arg[${x},|]}UseAtMyHP string outer
						/varset ${MakeList${i}.Arg[${x},|]}UseAtMyHP ${${MakeList${i}.Arg[${x},|]}UseAtMyHP} ${Ini[MyIni,${MakeList${i}.Arg[${x},|]},${MakeList${i}.Arg[${x},|]}UseAtMyHP${y}]}
					}
					/if (${i}==3) {
						/if (!${Defined[${MakeList${i}.Arg[${x},|]}UseAt]}) /declare ${MakeList${i}.Arg[${x},|]}UseAt string outer
						/if (!${Defined[${MakeList${i}.Arg[${x},|]}StopAt]}) /declare ${MakeList${i}.Arg[${x},|]}StopAt string outer
						/varset ${MakeList${i}.Arg[${x},|]}UseAt ${${MakeList${i}.Arg[${x},|]}UseAt} ${Ini[MyIni,${MakeList${i}.Arg[${x},|]},${MakeList${i}.Arg[${x},|]}UseAt${y}]}
						/varset ${MakeList${i}.Arg[${x},|]}StopAt ${${MakeList${i}.Arg[${x},|]}StopAt} ${Ini[MyIni,${MakeList${i}.Arg[${x},|]},${MakeList${i}.Arg[${x},|]}StopAt${y}]}
					}
					/if (${i}==4) {
						/if (!${Defined[${MakeList${i}.Arg[${x},|]}SpellIcon]}) /declare ${MakeList${i}.Arg[${x},|]}SpellIcon string outer
						/varset ${MakeList${i}.Arg[${x},|]}SpellIcon ${${MakeList${i}.Arg[${x},|]}SpellIcon}${${MakeList.Arg[${x},|]}SpellIcon{y}}
					}
				}
			/next y
		/next x
	/next i
 
/continue is a performance improvement and works in both /for and /while loops, nested or single.

Also my OCD alarm goes off when I see /next being used as a goto improperly, so that was reason enough to change it. The change is recent and was basically pushed through by eqholic but I agree with it. It will make macros look prettier and the logic easier to follow.