• IS THIS SITE UGLY? Click "RG3" at the very bottom-left of this page to change it. To dismiss this notice, click the X --->
  • You've been invited to attend the 2nd annual "EverQuest Software Awards"
Resource icon

Guide - Conditions and you. Coding tutorial information


Dec 29, 2017
So a lot of people I've noticed don't really understand conditions and how to compare something to something else. In order to understand conditions with comparisons we should first start with the basics of how MQ2 Interprets information. This is relevant for macros as a whole, and any "conditions". You might use for MQ2Melee holyshit/downshit or even KissAssist Conditions.

To start, you should probably understand an if statement.

/if (Condition) /dothis

That's saying that if the condition is true, then dothis.

So if I say
/if (${Me.Level}) /dothis
Then I'm saying if ${Me.Level} has a value other than 0 then I want to execute the slash command /dothis

You can also compare values in addition to the above example.

/if (${Me.Level} > 10) /echo I am over level 10

Where I'm saying if my level is greater than 10, then I want to echo (output to the mq2 window) a text that I am over level 10.

So what are some other ways that we can compare information? Well, first we need to understand the different types of information available to us.

Primarily we have numbers, and we have strings.

A number should be self explanatory. It's a number output, which is what you would get from ${Me.Level} or ${Me.PctHPs} where when used in a /echo it will output the related information. So if your level is 51 and your health is currently at 83% then /echo Level: ${Me.Level} Health: ${Me.PctHPs} will output

[MQ2] Level: 51 Health: 83

A string is a collection of characters in order, such as ${Me.Name} which will output your characters name. So if I did /echo Name: ${Me.Name} it would output

[MQ2] Name: Chatwiththisname

Depending on what type of output you get when you echo the information on what method you will use to compare the information. I'm going to start with all numbered values.
Integer: an integer is a whole number value. IE: 1, 2, 3, 4, 583, etc
Float: is a value with a decimal place in it. IE: 1.35, 3.14, 188.73

Floating point values are less common than integers, but you will often get them as returns when dealing with things like ${Target.Distance} where the distance is a mathematical calculation that you would have learned in Algebra when calculating the distance between two points on a Cartesian coordinate chart. The formula is irrelevant for the purpose of this tutorial.

Comparing Integers and Float uses comparators such as:
Greater Than: >
Less Than: <
Equal to: ==
Not Equal: !=
Less Than OR Equal: <=
Greater Than OR Equal: >=

You'll notice that the Not Equal comparators shows an exclamation point "!". This was not a mistake. This means NOT in all programming languages I've personally dealt with (that doesn't necessarily mean all).

So I'll give examples and then explain each of the above options.

/if (${Me.Level} > 10) /echo I'm higher than level 10
I should hope this shows that if my level is higher than 10 (not including 10) then I should issue the slash command.

/if (${Me.Level} < 10) /echo I'm lower than level 10
If my level is lower than level 10 (not including 10) then I should issue the slash command.

/if (${Me.Level} == 50) /echo I am level 50
If my level is EXACTLY 50, issue the slash command.

/if (${Me.Level} != 50) /echo I am not level 50
if my level is ANYTHING EXCEPT 50, issue the slash command.

/if (${Me.Level} <= 20) /echo I am lower than level 21.
If my level is Less than OR EQUAL to 20 (20 included) then issue the slash command

/if (${Me.Level} >= 20) /echo I am higher than level 19.
If my level is Greater than OR EQUAL to 20 (20 included) then issue the slash command

These comparisons also work when using Floating point values. /if (${Target.Distance} < 200) /casting "Fervid Renewal"
Distance is almost assuredly going to be a floating point number if you do a /echo ${Target.Distance}, but it compares the same way. If the distance is 199.99 or less then it would return a valid comparison and issue the slash command, which in this case would be to cast a heal spell.

So I mentioned strings earlier because I wanted to make sure we understand that these are definitively vastly different from numbers. If you try to use comparators we used on numbers earlier, then you'll find yourself getting errors for unparsable in calculations, non-numeric encountered. For example.

/if (${Me.Name} > ${Target.Name}) /echo I'm greater than my target.

so let us say eqmule is my target. the output would be something like.

Unparsable in Calculation: 'C'
Failed to parse /if condition '(Chatwiththisname > eqmule)', non-numeric encountered

If you are using this as a holyflag, downflag or condition in KISS then it would spam it so much you'd see nothing but this on your screen whenever it tried to parse the information.

The correct way to check is using a member of the string datatype would be to use one of the following:


The above are pulled from my data.ini (which I will attach to this post) and are for use with the string datatype.

/if (${Me.Name.Find[Chatwith]}) /echo I found Chatwith in ${Me.Name}.
If I find a substring inside of the string with the text in the [SquareBrackets] then issue the slash command

/if (${Me.Name.Length}) /echo My name has a length of ${Me.Name.Length} characters.
If the string has character count greater than zero, then issue the slash command.

/if (${Me.Name.Compare[eqmule]} == 0) /echo I keep MQ2 running for everyone.
If my name is eqmule regardless of character case then issue the slash command. IE: EqMuLe is considered the same as eqmule
/if (${Me.Name.Equal[eqmule]}) /echo I keep MQ2 running for everyone.
If my name is equal to eqmule regardless of character case, issue the slash command.

/if (${Me.Name.NotEqual[eqmule]}) /echo I'm not eqmule.
If my name is NOT equal to eqmule regardless of character case, issue the slash command.

You also have some case-sensitive options.

Which are used as shown in the example above, but are case sensitive. IE: /if (${Me.Name.EqualCS[ChAtWiThThIsNaMe]}) /echo I am ChAtWiThThIsNaMe

That would return false because it is case sensitive.

Operands and you.
Well, now that we know the difference in comparing information from a string and comparing information from a number. What if I need to check multiple things in a single condition?

So much like the comparators you need a way to say things like "AND" and "OR" when checking some conditions. IE: I need to make sure I am in range of casting a spell, and I need to make sure I have enough mana to cast it, but I also don't want to be moving, or already casting, or do it when I'm invisible. So....how do I do that?!

Okay, so we'll start with going about this on a single line because a user will typically need to put this all into a single line for a condition, holyshit, or downshit.

&& means AND
|| means OR

/if (${Target.Distance} < 200 && ${Me.CurrentMana} > 2774 && !${Me.Moving} && !${Me.Casting.ID} && !${Me.Invis}) /casting "Fervid Renewal"

So above I've looked at the spell information in-game for Fervid Renewal and got the Spell name, the spell range, and the mana it requires to cast. Then I've used the information to decide if I should cast it.

Fervid Renewal
Range: 200
Mana: 2774

${Me.Casting.ID} would return the ID of the spell I was currently casting if I was casting a spell. Which would result in returning a value greater than 0. IE: 43241 is the ID of Fervid Renewal.
If I am invisible, then ${Me.Invis} would return TRUE, and if I was moving then ${Me.Moving} would return TRUE.

So if you did an echo for all this information. It could look something like.

[MQ2] 12.05 < 200 && 130331 > 2774 && !FALSE && !NULL && !TRUE

This is how the information is evaluated by MQ2 to decide if it should execute the slash command following the issue statement.

So the distance is 12.05 < 200, so that would pass the test.
My mana is 130331 > 2774, so that would pass the test
I'm moving would be FALSE. But since I put "!" at the beginning, if you recall, that means NOT. So I'm saying if this is NOT TRUE then it's TRUE (double negative??). So this one passes.
${Me.Casting.ID} returned !NULL, which means I was not casting a spell, but since I used "!" not I'm saying if I'm NOT CASTING a spell then it passes. So this one passes.
${Me.Invis} returned !TRUE Which means I was invisible, but I only want it to pass if I'm NOT invisible because I used "!" at the start. Since !TRUE means it failed, the entire conditional statement fails the test and is not used.

Next is the || OR Operand. This means THIS OR THIS needs to be true in order for me to do something.

/if (${Target.Named} || ${Me.PctHPs} < 30) /disc Stout Defense

Which means I want to use my Stout Defense disc anytime I have a named targeted OR my HPs is below 30%. So in this case, only one of the two conditions needs to pass in order for it to be true. So unless both fail to pass the checks, then it will issue the slash command.

Okay, so all this is good information. But how do I do the ${Me.StatGoesHere.MuchoPigSelf.SuperPunch[SomeStuffHere]}

the short answer is that there is a WIKI for all the TLO's.

Each one of those will tell you what it has access to and the members of that datatype.

For Example. ${Me} is a TLO https://www.macroquest2.com/wiki/index.php/TLO:Me

Here it shows you Access to Types

Where it will list all the types you have access to members of.

Additionally, I've managed to create a simple macro that pulls all the members of a datatype and outputs them to an INI file. To my knowledge, this works on all builds of MQ2, IE: UF, RoF, RoF2, etc. I'll provide a copy of the macro and a copy of the INI from the last live run I did.

The information is in the following format.


IE: The string datatype is as follows.


So anything that is a string can use those as a member.

An example is ${Me.Name} is a string of characters. I can use any of the above members with that string.


How to use each of the members will likely be something that you'll want to check examples of on the WIKI.

Please keep in mind that I may have some information in the data.ini that is not available on the WIKI. That's because the WIKI is a user run series of pages where individuals like yourself add information to it to make it more complete. If you learn something that isn't available on the wiki and can find the time to update the Wiki, please do so!

Please feel free to ask questions in this thread if you are having trouble understanding. Please understand that TLO's and their Members are case sensitive. IE: ${Me.Name} is not the same as ${me.name}

As always, I can be found on discord https://discord.gg/GUeSzr9 for additional assistance, but your thanks on my posts help keep me subbed and active in game. I also do custom coded macros for a fee and accept donations.

Video was made from my live stream going over basically the same information that is found here.



Last edited:


Dec 29, 2017
I added a youtube video to the bottom of this tutorial that goes over more or less the same things in the original text based tutorial on conditions. Hopefully for those that aren't a fan of text based tutorials the video will allow you the opportunity to understand conditions.


Well-known member
Apr 15, 2017
fantastic thank you for this it really helped me understand thing more tho I probably will end up watching this video another 40 or 50 times
Mar 2, 2019
Really like the tutorial both text and video.
Been a long time since I have done any programming if Commodore Pet BASIC counts, but was wondering if there is any convention to the use of the various bracket sets


MQ2 Diplomat
May 5, 2016
Really like the tutorial both text and video.
Been a long time since I have done any programming if Commodore Pet BASIC counts, but was wondering if there is any convention to the use of the various bracket sets
This is a great question!

I can only speak from a non-coding background from my experience using these in macros and conditions etc

{} curly brackets/braces are used when using TLO/Variables - example /if (${Me.Class.ShortName.Find[CLR]}) /dismount - you could /echo and see the ${Me.Class.ShortName} for example and it would spit out what your class shortname is
[] regular brackets are used when doing something like a find or a bool --- example /if (${Me.Class.ShortName.Find[CLR]}) /dismount
() parentheticals are used for things like doing an /if and then providing parameters for that if before providing what it should do if that is met --- example /if (${Me.Class.ShortName.Find[CLR]}) /dismount

That is my rudimentary understanding of those - I look forward to hearing a more in-depth explaination!

I've attached my Data.ini --- this has whatever TLOs were available to me when I ran the data.mac that @ChatWithThisName created

you can see the header names and then what tlo is available under that
so I can /echo ${Group.MainTank} and it will give me the name of whatever character is assigned as the main tank

From a non-coding background one of the biggest challenges was asking "Where do you find the curly bracket some-words curly bracket things?" --- that was only a couple months ago lol

Welcome btw @Katiekaboom



Dec 29, 2017
Suppose in a way there is. But it's hard for me to explain it. But I'll give it a shot and see how it comes out as far as readability.

So as mentioned by @Sicprofundus TLO (Top level objects) and Variables are always surrounded by ${ and } with the variable name is in the middle. This only applies to when you are trying to use the variable to get the value, not when declaring, or setting the value, unless you're trying to calculate the value using it's current value.

/declare i int outer 1
/varset i 20
/varcalc i ${i}+1
/echo i is now ${i}
So above I've declare a variable called "i" as an outer variable and set it to 1 on initialization. (No brackets are used for this)
On the next line I've set the variable "i" to the value of 20 (But didn't need to use the brackets)
Next I used a "/varcalc" which means to conduct a mathmatic operation on a variable. then I tell it which variable (in this case it's "i") and then I used the variable itself, and added 1. This would be the same as saying i++ in something like c++
then I echo that "i" (no brackets because I want the actual letter) is now ${i} (brackets! because I want the current value of "i")

Now for the square brackets we can think of it as a parameter of some functions member. That parameter could be an index (number) or a string of characters. An example would be searching a string to find a word as explained in the tutorial.

/declare myString string outer The Text I want to search
/if (${myString.Find[Text]}) /echo ${myString}
So above I've declared a string, and I've initialized it as the text "The Text I want to search"
Then I did an if statement where I said if I find inside of the variable "myString" the text "Text" then echo the entire string.
In this case, the variable is myString and I'm using a member of the "String" datatype to search it for a specific sub string of characters in the middle of the string. when I use the member of string "Find" I must then tell it what to find. So I'm to use the square brackets to put that information, much like a parameter I'd pass to a function, because essentially that's what it is. But I still have to close the variable afterwords, so I put the closing } after.

To give another example of the square brackets. You could say

/if (${Group.Member[1].PctHPs} > 10) /echo Well, they aren't dead at least.
In this case I'm using a TLO, "Group" and I'm accessing the "Member" function within it, and checking at index 1 (this is the first person in the party window and not yourself as you are index 0 in this case). Now that I have access to the information for the group member at index 1, I ask for their HPs by accessing the Spawn member PctHPs, then I close the }.

That's a little more complicated to explain, but I'll give it a go. The "Group" TLO accesses group members, then you say which member (In this case it's group member 1) and that returns a "Spawn" for that character, which is a struct populated with all the publicly available information about the character, Such as their HPs, their Mana, if they are sitting, their location, etc. In this case I only wanted to access that Spawns Health percentage.

I hope that one made some sense. More information about TLO's, their members, and how they are used can be found at the wiki for MQ2 https://macroquest2.com/wiki/index.php/TLO
Those are the TLO's available with core MQ2, and some plugins may add more while they are loaded, but going over all of them would be quite the task, so you're stuck checking the wiki.

So now on to hopefully the easiest to explain. The ( parentheses ) are used for three situations.
1. To pre-define parameters for a subroutine.
2. To start and stop a group of conditions for an if statement.
3. to group conditions together in groups.

Sub Main(string FirstParam, int SecondParam, bool ThirdParam)
    /if (${FirstParam.Length}) /echo A param was passed to FirstParam and it was ${FirstParam}
    /if (${SecondParam}) /echo A param was passed to SecondParam and it was ${SecondParam}
    /if (${ThirdParam}) /echo A param was passed to ThirdParam and it was ${ThirdParam}
    /if (${FirstParam.NotEqual[NULL]} && (${SecondParam} > 0 || ${ThirdParam})) {
        /echo FirstParam was not NULL and either SecondParam is greater than 0 or ThirdParam was true.
So above I created Sub Main, and I gave it 3 predefined parameters, the first is a string, the second an int, the third a bool. Then I checked to see if they all had values passed to them and if they did I echo'd their values.
Next I used the ( ) to check a group of conditions, that has another group of conditions in it. So in the above it should evaluate from the inner most parentheses and work outwards. So it would evaluate (${SecondParam} > 0 || ${ThirdParam}) first. and determine if that is true or not. Then it will check ${FirstParam.NotEqual[NULL]} to see it was true. If they are both passing values it would echo the string of text to the MQ2 Window. Otherwise it would do nothing and hit the /return, which in a Sub Main is the end of a macro, so the macro would end.

Hope that makes some sense.
May 16, 2019
Really great post! Even though I still have a lot to learn this post has given me a much better understanding on how the code works. Nice work!
Mar 2, 2019
I'm still a complete noob when it comes to scripting, however recently some things have gotten so annoying have found ways to eliminate the frustration of having the SK decide to redo self buffs JUST as I initiate agro manually (And the buffs were UP and still had several hours remaining), or having the cleric rebuffing Assurance every 5 minutes and getting stuck in a loop chain casting Assurance on NULL, And for crying out loud STOP dropping invis to self buff and initiating a wipe . . .
Conditionsals . ..

For the SK:

Buffs1=Dark Lord's Unity (Beza)|Cond29

Cond29=!${Me.Buff[${Spell[Shroud of the Krellnakor].RankName}].ID} &&
!${Me.Buff[${Spell[Mental Fright].RankName}].ID} &&
!${Me.Buff[${Spell[Drape of the Magmaforeged].RankName}].ID} &&
!${Me.Buff[${Spell[Remoreseless Demeanor].RankName}].ID} &&
!${Me.Buff[${Spell[Helot Skin].RankName}].ID} &&
!${Me.Buff[${Spell[Helot Covenant].RankName}].ID} &&
!${Me.Buff[${Spell[Icebone Skeletal Form].RankName}].ID} &&
!${Me.Buff[${Spell[Call of Nightfall].RankName}].ID} && !${Me.Invis} && !${Me.Moving}

Buffs3=Unified Hand of Assurance|Dual|Assurance|Cond11

Cond11=!${Me.Buff[${Spell[Assurance].RankName}].ID} &&
!${Me.Buff[${Spell[Benediction of Sanctity].RankName}].ID} && !${Me.Invis} && !${Me.Moving}

I realize this may not be pretty, may not even be the correct version conditionals, but it has seems to make me stop screaming at the AI for doing stupid stuff at the most inopportune times.
These conditionals I have created based on other examples from other ini files and seem to be working,
Now if I could just stop the cleric from Spam casting Yaulp while mounted . . .And stop trying to summon a mount while in a dungeon, editing the ini file to Remark the buff line or remove the Remark bar is getting a bit old already
Cant seem to figure out how to get ${Zone.Type} into a working conditional (as in ${Zone.Type} is NOT 0, 3, or 4 (indoor dungeon, dungeon city, and indoor city) THEN summon the mount)


Dec 29, 2017
${Zone.Type}==1 || ${Zone.Type} == 2
to say only do it if it's 1 or 2. I'm assuming 1 or 2 is outside because you appear to list just about every other number :-P.

if we need to exclude those values then we might need something like

Cond0=${Zone.Type} != 0 && ${Zone.Type} != 3 && ${Zone.Type} != 4
Where we are saying if the Zone.Type isn't 0, and it isn't 3, and it isn't 4. NOT to be confused with This, or this, thIs. Because when you think about it and you're using || which means "OR" then you might say it the way it reads and think that's what you should type. When you use || it means if any of these checks pass individually, where-as with && (AND) you are saying all the checks have to pass.

or if you're wanting to be fancy.

So those are two slightly more complicated things nested inside of one another. First we have the ${If, which is to say ${If[ThisIsTrue,thensayTRUE, otherwisesayFALSE]} then we use the ${Select nested inside of it to say ${Select[CompareThis,toThis,andThis]}, Select is not limited to only checking two things. You can check as many things as you like. if it matches any of them it will return the index of the one it found it at, or 0 if it didn't. Since 0 is considered false, then if it doesn't match one it would technically return false. So when we nest them, I say ${Select[${Zone.Type},0,3,4]} inside of the ${If. Lets say the Zone.Type in this case is 3, then the Select statement would return a 2, because it was the second thing it found. Since any non-zero number is true, then it would return a true value to the if statement, so it we took the resulting value and placed it into the if statement it would look like ${If[2,0,1]} and that's saying that if it returns a match for the select statement, then return a 0, which is false. So if it's indoor dungeon, dungeon city, or indoor city then fail the check and don't use the mount. If however the ${Select[${Zone.Type},0,3,4]} DIDN'T find a match. Then it would be 0 and the if statement would look like ${If[0,0,1]} and it would return the 1 because it was false.

I realize that this might be a lot to take in based on what little I've explained at this point. But that's technically the easiest way to type it. However the easiest way to understand it would be the first two.
Mar 2, 2019
Yes, this was the coding that I was missing.
Based on the examples of TRUE and FALSE checks I was able to find in conditionals elsewhere !${Zone.Type}==0 was echoing 1==0 and I could not figure out how to phrase it to a TRUE or FALSE

Cond0=${Zone.Type} != 0 && ${Zone.Type} != 3 && ${Zone.Type} != 4
and adding in the Invis and moving check
Cond10=${Zone.Type}!=0 && ${Zone.Type}!=3 && ${Zone.Type}!=4 && !${Me.Invis} && !${Me.Moving}
and now this is echoing 1!=0 && 1!=3 && 1!=4 && !FALSE && !FALSE
so the zone check is coming back with what should result as a TRUE but not echoing a TRUE, and achieves the desired result IF
Buffs12=Black Ornate Silken Bridle|Cond10
but completely breaks with
Buffs12=Black Ornate Silken Bridle|Mount|Cond10

It so far has not been critical but watching the AI continue to try to summon a mount while moving through knowledge after spawning at bind trying to return to corpses is rather annoying
Last edited:
Mar 2, 2019
You would think an /mqp would work, but I actually want the cleric to start popping off heals when moving around through possible agro mobs, just dont want him to drop invis for rebuffing something that is still up . . . if the SK is invis and all the other toons are invis and autofollowing as i am moving . .. if something sees Invis pops it and initiates agro, the SK responds, and has heals at the ready .. . . but moving around in an area and ending up in battle because one of the toons 1) doesnt check for movement, 2) doesnt check for invis and 3) doesnt check if the buffs are still up . . . THEN Drops invis to cast a buff that didnt need to be rebuffed anyways and initiates agro . . .Absolutely infuriating
Oct 7, 2015
Somewhere I saw a post regarding how to nest conditionals in KissAssist but I can't find it now. For readability I was hoping to build a logical string.

Cond3=Cond1 && Cond2

But I can't get it to work so I assume my syntax is wrong.
Oct 7, 2015
Aug 13, 2018
Curious. I understand what's going on there, just surprised you'd need to reference the array identifier. I guess I just assumed that they were treated as variables, but guess it makes sense that it's read into an array. Glad you found a solution that works!


Dec 29, 2017
Well the conditions are stored in an Array. So in order to access the information for the conditions as saved to the variable, you'd need to access the array at the index of the condition.
Mar 2, 2019
Much as I enjoy elegance and minimal coding (and absolutely abhor the ever-expanding use or the memory because programmers cant figure out how to utilize packets of code repeatedly and instead just copy and paste it wherever needed) .. .
I can see where making a set of conditionals that is constantly checking other conditions . . . to some extent will get to be cumbersome and difficult to unravel later when trying to troubleshoot