Getting Started - Macro Creation - MMOBugs Wiki

Overview

Learn to code your own macros. Lets go over the anatomy of a macro.

 Events
 Reference Files
 Sub Main
 Declares
 Main Loop
 Calls
 /doevents
 Return to Main Loop
 /return
 Subs

Events

At the top of a macro you'll find your Events. The macro will monitor what is happening in EQ, and if it receives text that matches your Events, it will enact upon it at the next /doevents line. An Event looks like this:

 #Event Slowed		"#*#slows down#*#"

The Event is called "Slowed", the text watching for is "slows down". Using #*#, you dont have to write the entire line to watch for. Any text before and after "slows down" will be acceptable.


Included Reference Files

Many macros use other files for reference on how to do things. A common one is Spell_Routines.inc. This file adds commands to your macro that will allow you to do more complex things.

 #include Spell_Routines.inc


Sub Main

All macros need to have a Sub Main, where everything branches off of. Inside your Sub Main, you'll have all the things that you want to happen in your macro, and all the things that happen will eventually return here.

 Sub Main
 
 /return

Inside your Sub Main you can put Declares, your Main Loop, call other Sub's and basically keep it as simple or complex as you'd like. Simple is better :) More on these things below.

Declares

This section is probably the most confusing part of a macro, and a lot of playing around and asking questions in IRC are probably your strongest assests. Declares are written inside your Sub Main. A declare is a statement that is saying "Let something = X". For example

 /declare DeadCount 		int 		outer
 /declare MobsDead		int		outer	0

If you wanted to keep track of how many mobs died during the course of your macro, you would need to declare your DeadCount. This wont do it all by itself however, it ties into another part of your macro. At whatever point in your macro a mob dies, you would add

 /varcalc MobsDead ${MobsDead} + 1

Then, so you know how many mobs have died, you could insert an /echo (text that MQ sends to your MQ window that only you see that reports information back to you from the macro)

 /echo ${MobsDead} killed


Here's another example. Say you're doing an AFK macro, but you want your buddy to be able to join your character if he logs in when you're afk. But sometimes you dont want him to be able to. Here's where a declare comes in handy. You can change this without editing your macro every time you change your mind. Start with the declare

 /declare CanInvite		bool	outer	TRUE

Right now, the CanInvite is set to TRUE. For your buddy to activate it, you'll need an Event.

 #Event InviteMe		"#*#password#*#"

So, when your buddy sends you the password, it will activate the event at the next /doevent line. Here's the actual event sub

 Sub Event_InviteMe(Line, Player)
 	/if (${CanInvite} ) {
 		/dzadd ${Player}
 		/invite ${Player}	
 	} else {
 		/tell ${Player} inviting is currently off
 	}
 /return

Somewhere in your macro, you'll need something like this. I'll explain what each line means.

 Sub Event_InviteMe(Line, Player)

This line is where the macro will go after it hits your /doevent. When your buddy sends you the tell, the macro takes note that the password matches your event, and then stores that information until the next /doevent. When that happens, it takes action and goes to the event, in this case, InviteMe. The (Line, Player) keeps track of the name that sent the tell. This allows your buddy to log on different characters without you having to write an InviteMe event for every one of them.

 /if (${CanInvite} ) {

If CanInvite is TRUE, the macro will execute the commands inside the {} brackets. In this case, thats

 /dzadd ${Player}
 /invite ${Player}

So your buddy is invited. Then your macro skips down to /return and progresses from where it jumped off at the /doevents. However, if InviteMe was FALSE, this would happen

 } else {
     /tell ${Player} inviting is currently off
 }

You can change the TRUE and FALSE remotely with a second event. This allows you to do it within EQ without having to edit the macro itself at all.

 #Event YesInvite		"#*#different password#*#"

This event would link to a Sub for YesInvite

 Sub Event_YesInvite
 	/echo inviting now enabled
 	/varset CanInvite TRUE
 /return

Here's one last example for Declares for now. Say you want your macro to end if you ever leave the zone. This comes in handy for obvious reasons. Lets start with the declare

 /declare MyZone			string	outer	${Zone}

Then we can add 'checks' in our macro in various places (especially in loops) to make sure we're still in the same zone. Here's an example

 /if (!${Zone.Name.Equal[${MyZone}]}) {
 		/end
 }

We'll do more declares later

Main Loop

This is where the circle of a macro occurs that keeps it looping back upon itself. If you dont want a macro to go continuously, you'd obviously not have it. Here's what it will look like

 :Main_Loop
 
 All your junk
 /doevents
 /goto :Main_Loop

So basically once this loop starts, it will do 'All your junk' and then hit the "/goto :Main_Loop" where it will return to the top and do it all over again. I reccommend keeping your Main Loop as simple as possible and to branch off from there with /call's and /doevents.


Call Subs

To do various things within your macro, you'll want to write them within Subs. You can /call Sub's from your Main Loop, or from other places within your macro. I'll use a Zonecheck Sub as an example. Whenever you want your macro to do a zonecheck, you can write

 /call Zonecheck

When your macro hits this line, it will deviate from where it was going and go to your Sub Zonecheck. Here's an example of Sub Zonecheck.

 Sub ZoneCheck
     /if (!${Zone.Name.Equal[${MyZone}]}) {
         /sit
         /camp
         /mqlog I logged off because i wasnt in the right zone!
         /end
     }
 /return

All sub's must end with a /return.

Anatomy of a Command Line

Commands are structured pretty simple, and once you've seen a few, you've seen them all. Commands are in the format of /if something.is.true { i'll do this } and the opposite, /if !something.is.true { i'll do this }. The exclamation mark means 'not'.

 /if (${Me.AbilityReady[backstab]} ) {
     /doability "backstab"
 }

Anatomically, the Command line is made up of these parts:

/if - Starting a Command Line

$Me.AbilityReady - The conditions. There are a lot of different conditions.

[backstab] - The Subject

{ /doability "backstab" } - What the command line would do if the Conditions and the Subject proved to be true.

Command Line Examples

 /if  ( ${Me.AltAbilityReady[Steadfast Servant]} ) {
     /alt activate 485
 }

In this example, it is saying if the Alt Ability [Steadfast Servant] is ready, it will execute the commands inside the {}.

 /if (${Target.CleanName.NotEqual[Fry]}) {
     /end
 }

In this example, if the target is not Fry, the macro will end.

 /if ( ${Me.Buff[Primal Guard].Duration.TotalSeconds} < 200) {
     /call Cast "Darkened Flowing Black Silk Sash" item
 }

In this example, the condition is ${Me.Buff_.duration.TotalSeconds} < 200. The Subject is [Primal Guard]. If your buff "Primal Guard" has less than 200 seconds on it, the /if will be TRUE and it will /call Cast "Darkened Flowing Black Silk Sash" item.

Conditions

 ${Me.AltAbilityReady[Steadfast Servant]}

Checks to see if your alt ability is ready

 ${Me.Buff[Aura of Rage].Duration.TotalSeconds} < 200

Checks to see if your Buff has less than 200 seconds left on it

 ${Me.PctHPs}

Checks to see what your current % hp are. Example: /if (${Me.PctHPs} < 20) { /call cast "Healing" gem1 }

 ${Me.PctMana}

Checks to see what your current % mana is. Example: /if (${Me.PctMana} < 20) { /sit }

 ${Me.State.NotEqual[SIT]}

Checks to see if you're sitting or not.

 ${Target.CleanName.Equal[Fry]}

Checks to see if you're targetting Fry

 ${Me.AbilityReady[backstab]}

Checks to see if backstab (or kick, or tail rake, or whatever you want) is ready

 ${Me.CombatAbilityReady[Duelist Discipline]}

Checks to see if your disc is up.

 ${Target.Fleeing}

If your target is running away, do something!

 ${Target.X} > 50

Checks to see if your target's X loc is over 50.

 !${Me.PetBuff[Fortitude]}

Checks to see if your pet is missing a buff

Ultimately there is unlimited different conditions, as you can determine your own using Declares. I'll stop here and add more if people think they should be included. In each compile there's macro's in the macro's folder thats provided that you can dissect and learn from. If you need something specific, check IRC and the Search button.

Joining Conditions

You can also have an /if command depend on multiple conditions. Here's an example

 /if (${Me.CombatAbilityReady[Stonewall Discipline]} && ${Me.PctHPs} < 80) {
     /disc Stonewall Discipline
 }

To join conditions, include both (or more) within the ( ) brackets and && between the conditions. This allows you even more control over the complexity of your macro. Here's another

 /if ( ${Me.PctHPs} < 20 && ${SpawnCount[npc radius 50]} > 30 ) {
     /fade
 }

I've been trained! Better /fade outta here!


Casting

Note: For these commands, make sure to have #include Spell_Routines.inc in your macro

 /call Cast "Spirit of the Puma" gem6

/call Cast is the command line you want to use to cast spells. The line will retrieve the spell from your spell book if it isnt memmed, and cast it completely before going on to the next command in your macro.

You can click an item with a command like this:

 /call Cast "Belt of Tidal Energy" item


Casting with Declares

Sometimes it is much easier to edit just the top of a macro instead of searching through it and editting the entire thing. A good example is with Declares, since when new expansions are released, spells come out that are virtually identical to the old one, but the macro needs to be editted with the new name.

 /declare FocusSpell 	        string	outer	Talisman of Wunshi

Now, instead of all the spots in the macro where you need to cast "Talisman of Wunshi", you can simply put [FocusSpell]

 /if ( ${Me.Buff[${FocusSpell}].Duration.TotalSeconds} < 200) {
     /echo Need focus refresh
     /call cast ${FocusSpell} gem2
 }

Other Commands

Always remember that commands that work in EQ work in macro's. So /attack on would work. MQ commands also work, and your macro's can feed off of the plugins that you have loaded. A very common plugin is mq2moveutils. You can include in your macro with /stick commands etc.

/target npc radius 200

/delay 2 /delay 2s /delay 2m

/keypress d

/target ${Me}

/alt activate 47

Structure

Every macro has to have a set structure. The way MQ 'looks' at a macro is essentially with one 'eye' that is running up and down the page. It starts off at the top and then goes down from there, being sent off on errends, and coming back from them. If you want your macro to use the new Sub that you put in, you'll have to send the 'eye' there at some point, it wont find it on its own. Lets take a quick look at a fully written Main Loop.

:Main_Loop

	/call BuffCheck
	/call GetTarget
	/call Kill
	/doevents
   	
	/goto :Main_Loop

In this case, there is three seperate Sub's that the main loop calls. BuffCheck, GetTarget, and Kill. As well, /doevents may also link to many other Event Subs as well. But lets say we wanted to add our ZoneCheck sub to our Main Loop. First, we add /call ZoneCheck to the Main Loop

:Main_Loop

	/call BuffCheck
             /call Zonecheck
	/call GetTarget
	/call Kill
	/doevents
   	
	/goto :Main_Loop

Then we add the ZoneCheck Sub to our Macro

Sub ZoneCheck
/if (${Zone.Name.NotEqual[${MyZone}]}) {
/sit
/camp
/mqlog I logged off because i wasnt in the right zone!
/end
}
/return 

Now, the 'eye' will hit /call ZoneCheck, skip down to Sub ZoneCheck, go through the commands, and hit the /return line. At this point, it will return to the Main loop where it left off and start on /call GetTarget


Varsets

Varsets are simply Variables that can be Setfor TRUE or FALSE. This allows you to do many differant things, but i'll go through some examples, and you should be able to figure them out from there.

Lets say you want your character to load a mob with DoTs. It only makes sense to cast a new DoT when the old one fades, you dont want your character to spam the mob with DoTs when they havent ran their course yet. We start with the Declares.

             /declare DoTaSpell		string	outer	"Blood of Yoppa"
	/declare DoTbSpell		string	outer	"Bane"
	/declare DoTcSpell		string	outer	"Breath of Ultor"

             /declare NeedDotA		bool		outer	FALSE
	/declare NeedDotB		bool		outer	FALSE
	/declare NeedDotC		bool		outer	FALSE

Then we go down to the part of the macro where you're killing the npc. This will be just before the Killing Loop.

             /varset NeedDotA TRUE
	/varset NeedDotB TRUE
             /varset NeedDotC TRUE

Now you've told your macro that you Need to cast DotA,B,and C on the Mob. In this case, thats Blood of Yoppa, Bane, and Breath of Ultor. So lets add the command line to actually cast the DoTs.

/if ( (${Target.PctHPs} > 10) && (${NeedDotA}) ) {
		/call cast ${DoTaSpell}	gem1
		/if (${Macro.Return.Equal["CAST_SUCCESS"]} ) {
			/varset NeedDotA FALSE
		}
	}

So now the macro will cast DotA on the mob as long as it has more than 10%hp, it will double check to see if the cast was a success, and then it will /varset NeedDotA FALSE, telling itself that the mob doesnt need the DoT anymore. We just need to add one more thing - an Event that tells the macro when to set the varset back to TRUE

#Event DoTAOff		"#*#|${DoTaSpell}|#*#worn off#*#"
Sub Event_DoTAOff
         /echo DoTAOff
	/varset NeedDotA TRUE	
/return

So now, when the macro recieves the fading text, it will go to Sub Event_YoppaOff at the next /doevents, and /varset NeedDotA TRUE. Then it will hit the /return, and go back to your Killing Sub, and when it hits the casting line, it will recast the DoT

Thanks and Credit go to JimJohnson and PeteSampras for thier efforts and fixing syntax and other coding advice