• IS THIS SITE UGLY? Click "RG3" at the very bottom-left of this page to change it. To dismiss this notice, click the X --->
Resource icon

Guide - Conditions and you. Coding tutorial information

Joined
Dec 29, 2017
Likes
984
RedCents
4,170¢
#1
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.

Strings
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:


Find
Length
Compare
CompareCS
Equal
NotEqual
EqualCS
NotEqualCS


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.
CompareCS
EqualCS
NotEqualCS

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.

Operands
&& 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.
https://www.macroquest2.com/wiki/index.php/Top-Level_Objects

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.

[datatype]
Member#=nameOfMember

IE: The string datatype is as follows.

[string]
Member1=Arg
Member2=Mid
Member3=Left
Member4=Right
Member5=Find
Member6=Length
Member7=Upper
Member8=Lower
Member9=Compare
Member10=CompareCS
Member11=Equal
Member12=NotEqual
Member13=EqualCS
Member14=NotEqualCS
Member15=Count
Member16=Token
Member17=Replace

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.

${Me.Name.Find[Chat]}
${Me.Name.Arg[1,|]}
${Me.Name.Length}

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.

 

Attachments

Last edited:
Joined
Dec 29, 2017
Likes
984
RedCents
4,170¢
#4
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.
 
Joined
Apr 15, 2017
Likes
72
RedCents
421¢
#5
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
 
Joined
Mar 2, 2019
Likes
0
RedCents
#7
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
[{()}]
 

Sicprofundus

#Can'tStop #Won'tStop
Moderator
Joined
May 5, 2016
Likes
1,117
RedCents
5,267¢
#8
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
example
[group]
member6=MainTank
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
 

Attachments

Joined
Dec 29, 2017
Likes
984
RedCents
4,170¢
#9
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.

IE:
Code:
/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.

Code:
/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

Code:
/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.

IE:
Code:
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.
    }
/return
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.
 
Joined
May 16, 2019
Likes
10
RedCents
101¢
#10
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!
 
Top