Page 1 of 1

Help on the macro I'm trying to make.

Posted: Wed Apr 30, 2014 5:42 am
by 1everdude
Hi everyone. Looks like this is a slow board, but hopefully someone will get around to this.
Anyways, I made a macro to farm Greater Lightstones from Willowisps in Jaggedpine on the EQEmu server I play on (they're essential for progression), but I'm completely new to this and there are a few things I have problems with. I want to try to set it up to check if the character is moving but isn't attacking, and start attacking, but I don't know how to make it check the entire time my character is moving, if that makes sense. It seems to only check once, rather than the whole time. Right now the macro does work, but doesn't do anything if the attack gets turned off. Any help would be greatly appreciated.

This is what I'm trying to use to get it to work

Code: Select all

/if (${Me.Moving} && !${Me.Combat}) {
/attack on
}
This is the whole macro.

Code: Select all

Sub Main
|The ancient willowisp is a custom mob on the server that kills pretty much everything.
|This will gate you and end the macro if it's up.
/declare LootSlot int local 1
:beginning
/varset LootSlot 1
/tar ancient
/if (${Target.CleanName.Equal[ancient willowisp]}) {
/stand
/delay 1s
/keypress 0
/goto :end
}
|This part targets a willowisp and sticks to it, or waits a minute and tries again.
|I use /attack on instead of /killthis so that I can keep my MQ2Melee settings the same
|but use casters with this macro, and have the attack stay on.
/tar will
/if (${Target.CleanName.Equal[a willowisp]}) {
/echo Targeting a willowisp.
/stick 5 uw
/attack on
} else {
/delay 60s
/echo No willowisp detected. Pausing 1 minute.
/goto :beginning
}
|This is what I'm having trouble with. I want it to check if I'm moving and not in combat, |and if so, /attack on
/if (${Me.Moving} && !${Me.Combat}) {
/attack on
}
|This section targets the dead willowisp, waits 2 seconds to get next to the body, and |opens the loot window
:attemptLoot
/tar will
/if (${Target.CleanName.Equal[a willowisp's corpse]}) {
/stick 1
/delay 2s
/loot
} 
|This checks if the loot window is open, and if not, tries again to open it.
/if (${Window[LootWnd].Open}) {
/goto :looting
} else {
/goto :attemptLoot
} 
|This loots the first item, bags it if it's a Greater Lightstone, but destroys it otherwise, |then goes on to the next item til the corpse is empty. Then it exits the window and starts |the macro over.
:looting
/itemnotify Loot${LootSlot} leftmouseup
/delay 1s
/if (${Cursor.Name.Equal[Greater Lightstone]}) {
/autoinv
} else {
/destroy
}
/varcalc LootSlot ${LootSlot}+1
/if (${Corpse.Items}==0) {
/keypress esc
/keypress esc
/keypress esc
/keypress esc
} else {
/goto :looting
}
/delay 3s
/goto :beginning
} else {
/goto :looting
:end
/return
I know that my code is absolutely hideous and probably horribly inefficient, but it works, as long as I don't hit a rock and have my combat forced off. I'm open to suggestions for improving it though!

Re: Help on the macro I'm trying to make.

Posted: Wed Apr 30, 2014 11:54 am
by Cr4zyb4rd
You're off to a really good start. My first and biggest piece of advice, which I can't stress enough, is to use tabs. Indenting sub-blocks of code isn't just being fussy, it makes dozens of common errors leap right out at you, especially in this type of situation where you're trying to debug the flow-control of the overall macro.

Here's what I end up with just from making that change

Code: Select all

Sub Main
	|The ancient willowisp is a custom mob on the server that kills pretty much everything.
	|This will gate you and end the macro if it's up.
	/declare LootSlot int local 1
:beginning
	/varset LootSlot 1
	/tar ancient
	/if (${Target.CleanName.Equal[ancient willowisp]}) {
		/stand
		/delay 1s
		/nomodkey /keypress 0
		/return
	}

	|This part targets a willowisp and sticks to it, or waits a minute and tries again.
	|I use /attack on instead of /killthis so that I can keep my MQ2Melee settings the same
	|but use casters with this macro, and have the attack stay on.
	/tar will
	/if (${Target.CleanName.Equal[a willowisp]}) {
		/echo Targeting a willowisp.
		/stick 5 uw
		/attack on
	} else {
		/delay 60s
		/echo No willowisp detected. Pausing 1 minute.
		/goto :beginning
	}

	|This is what I'm having trouble with. I want it to check if I'm moving and not in combat, |and if so, /attack on
	/if (${Me.Moving} && !${Me.Combat}) {
		/attack on
	}

	|This section targets the dead willowisp, waits 2 seconds to get next to the body, and |opens the loot window
:attemptLoot
	/tar will
	/if (${Target.CleanName.Equal[a willowisp's corpse]}) {
		/stick 1
		/delay 2s
		/loot
	} 

	|This checks if the loot window is open, and if not, tries again to open it.
	/if (!${Window[LootWnd].Open}) {
		/goto :attemptLoot
	} 

	|This loots the first item, bags it if it's a Greater Lightstone, but destroys it otherwise, |then goes on to the next item til the corpse is empty. Then it exits the window and starts |the macro over.
:looting
	/itemnotify Loot${LootSlot} leftmouseup
	/delay 1s
	/if (${Cursor.Name.Equal[Greater Lightstone]}) {
		/autoinv
	} else {
		/destroy
	}
	/varcalc LootSlot ${LootSlot}+1
	/if (${Corpse.Items}==0) {
		/nomodkey /keypress esc
		/nomodkey /keypress esc
		/nomodkey /keypress esc
		/nomodkey /keypress esc
	} else {
		/goto :looting
	}
	/delay 3s
	/goto :beginning
/return
Right away this makes the labels for your gotos pop out. From this I could see that you had a /goto :end when you could easily just /return and exit out of the entire subroutine. It also let me spot a few lines of "extra" code at the end (including a } with no match) that were never getting executed.

You also had a funny bit where you checked if the loot window was open, and if so jumped to :looting which was the very next statement anyway. I reversed the conditions of the /if so it only does one check instead of if/else.

In general more advanced programmers shy away from goto. It's punching a big old hole in the expected top-down flow of things and very easy to lose track of some piece of state information. Sometimes they can save you another line or two of code versus doing things "the right way" but such shortcuts often come back to bite you. I believe the only place you currently "need" to use them is creating complex /while loops because /while {stuff} doesn't handle embedded {} blocks.

Be very careful with destroy. You never check that the cursor is clear in the first place when you get to this part of the code, suppose you forget the macro's running or something and you're swapping gear around. All it takes is half a second to trash your Asspants of Flashdance and then how are you going to earn any tips?

Watch out for /keypress. There's almost always a way to do what you want directly with /cast, /doability &etc. If not be sure to preface it with /nomodkey so that if ctrl/shift/alt are pressed (while EQ is in the background, for example) they don't get passed along.

It's hard to say why your /attack on check is failing without seeing it in action, unless it's happening during the 60 second delay (this pauses all macro processing during this time and is probably a bit extreme. All I can guess is that you've lost your target or something.. why is attack turning off in the first place? You can set up individual INI settings for MQ2Melee so you should probably use that, but if not all I can suggest is building a proper melee function that checks if you still have a target &etc.

My next step would be to move the entire looting section into a subroutine since it seems fairly self-contained. Then you could just do a /call CheckLoot or whatever and make your main loop cleaner.

Re: Help on the macro I'm trying to make.

Posted: Wed Apr 30, 2014 2:16 pm
by 1everdude
Thank you so much for offering so much help. That's a lot more than I was expecting.
The reason the combat has been failing is because of my toons running into rocks and things and being forced to duck. If you have any ideas about other ways to solve that, I'm open to suggestions. I'm brand new to writing Macros and I'm still trying to work out what is or isn't possible.

Re: Help on the macro I'm trying to make.

Posted: Wed Apr 30, 2014 3:49 pm
by Cr4zyb4rd
1everdude wrote:Thank you so much for offering so much help. That's a lot more than I was expecting.
The reason the combat has been failing is because of my toons running into rocks and things and being forced to duck. If you have any ideas about other ways to solve that, I'm open to suggestions. I'm brand new to writing Macros and I'm still trying to work out what is or isn't possible.
There's actually a setting in the alt-o options menu for turning off that duck-when-bumping-into-scenery behavior, I wish I could remember the exact name of it but it currently escapes me. It won't stop you from getting stuck, but at least it won't crawl you even further underneath some object and disable your attacking/casting in the bargain.

Re: Help on the macro I'm trying to make.

Posted: Wed Apr 30, 2014 4:07 pm
by warlock45
Autoduck -quack quack- is the option =)

Might put in an event looking for "has hit you for" or some other text you get while being attacked. Then have the sub event check for standing (if still needed) then have it turn on attack.

Re: Help on the macro I'm trying to make.

Posted: Wed Apr 30, 2014 5:56 pm
by 1everdude
Thanks for everything guys. It's working pretty much perfectly now that I messed with the Stuck Logic for /stick a bit and turned autoduck off.