• 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

Simple Farm Mob Macro

Nov 2, 2016
One thing I have come across rarely is that sometimes the macro gets stuck at a certain point. Probably more mesh related than anything.

Is there some way to either check if you have moved location within 60 seconds and if not then move to a known starting point?

By the way, sorry to the original poster for derailing his thread slightly!
Feb 20, 2018
I was looking for something like this and google turned up this post. I found this script to be great, my only complaint was that providing all those mob names on the command line. It's OK if you just have two or three targets, but I had 16.

So I modified this script to read an INI file that contained mobs to hunt based on the zone the script was invoked in. I have never tried to code a macro before, so I am probably not doing it the best way, but it "appears" to work.

Rich (BB code):
| Update to killbot.mac v1.4 - Use INI file rather than command line arguments
| killbot.mac by Rogue601  v1.4 - work in progress
| This macro is meant as a tutorial for myself and possibly others.
| I tried to keep it clean and OVER comment so others know what and why
| The point of this macro is to pick a list of mobs you want to farm.
| It's meant to be simple and not have ignorelists or files.
| Please don't afk with this and get in trouble.
| This requires that you are running MQ2Nav and have a valid mesh.
| used with Autoloot this is a very effecting macro for farming tradeskill materials
| I started this to farm bear skins. I've spent more time on it then I did on bearskins. LOL
| enjoy!  

| TODO - Add nav path distance to override radius

| -------------------------------------------------------------------------------------
| Sub Main
| -------------------------------------------------------------------------------------
Sub Main

| COMMENT : Declare variables to save data to work with
| COMMENT : to set a variable use the /varset command example: /varset searchRadius 10000
| COMMENT : to use the variable in code  ${searchRadius}

    /if (2 > ${Macro.Params}) {
        /echo Usage: /mac killbot radius ini_file
        /echo Example : /mac killbot 10000 farm.ini
        /echo Note: There is no anchor, radius is from your current location after a kill.

    /declare debugOn                     bool     outer FALSE    
    /declare iniFilename                 string     outer ${Param1}
    /declare activeMobID                     string    outer 0
    /declare searchRadius                     int     outer ${Param0}    
    /declare searchRadiusZ                     int     outer 500  
    | ----------------------------------------------------------------------------
    | farmMobList - Build a mob list array
    | ----------------------------------------------------------------------------    

    | COMMENT : The INI file containing the mobs we want to hunt has been
    | COMMENT : provided. Each section in the file contains the zone shortname,
    | COMMENT : followed by a k,v pair of mobname, integer. If the integer is one, 
    | COMMENT : we want to hunt the mob. Anything else, we do not.

    | COMMENT : Declare some variables we will need to interpret the file. First 
    | COMMENT : determine the current zone shortname.
    /declare mobCount                             int     local   0
    /declare x                                    int     local   0
    /declare currentZoneName                      string  local
    /varset currentZoneName ${Zone[${Zone.ID}].ShortName}
    | COMMENT : Now load the entries corresponding to that zone from the INI file. 
    | COMMENT : There is no way to know ahead of time what is in there, and INI 
    | COMMENT : merely returns a string, not an array. So it is necessary to first 
    | COMMENT : parse that string and count how many mobs we need to hunt.
    /echo Loading ${currentZoneName} from ${iniFilename}
    /echo ${Ini[${iniFilename}]}
    /declare mobList                             string local 
    /varset mobList ${Ini[${iniFilename},${currentZoneName}]}
    /declare mobListCount                        int local 0
    /declare mobType                             string local
    /declare mobTruth                            string local
    | COMMENT : The total number of pipe characters in the returned string. The 
    | COMMENT : maximum number of mobs is that plus one (it is a separator).
    /varset mobListCount ${Math.Calc[${mobList.Count[|]} + 1]}
    /echo INI contained a maximum of ${mobListCount} entries in this section.
    | COMMENT : Iterate through that list, checking that each entry is non-NULL, 
    | COMMENT : and then check if the value is '1'. Count only entries that meet 
    | COMMENT : both criteria.
    /for x 1 to ${Math.Calc[${mobListCount}+1]}
        /varset mobType ${mobList.Arg[${x},|]}
        /varset mobTruth ${Ini[${iniFilename},${currentZoneName},${mobType}]}
        /if (${mobType.NotEqual[NULL]} && ${mobTruth.NotEqual[NULL]})    {    
            /if (${mobTruth.Equal[1]}) {                                
                /varcalc mobCount ${mobCount} + 1
    /next x
    /echo Found ${mobCount} mobs to hunt in this zone.
    | COMMENT: Allocate the findMobList array, sized to match the number of target 
    | COMMENT: mobs determined above. 
    /declare findMobList[${mobCount}]      string  outer
    /declare y                                    int     local   1
    | COMMENT: Now go back through the list, adding mobs to findMobList much as was 
    | COMMENT: done during the sizing step.
    /for x 1 to ${Math.Calc[${mobListCount}+1]}
        /varset mobType ${mobList.Arg[${x},|]}
        /varset mobTruth ${Ini[${iniFilename},${currentZoneName},${mobType}]}
        /if (${mobType.NotEqual[NULL]} && ${mobTruth.NotEqual[NULL]})    {                
            /if (${mobTruth.Equal[1]}) {                    
                /varset findMobList[${y}] ${mobType}
                /varcalc y ${y} + 1
    /next x        

    | COMMENT : if debug is on we'll display the list
        /if (!${debugOn}) {
        /echo Welcome to Killbot!, Received ${findMobList.Size} mob names to hunt.
        /for x 1 to ${findMobList.Size}
            /echo ${x}. ${findMobList[${x}]}  
        /next x

    | ----------------------------------------------------------------------------
    | Initialize - Set some defaults and clear the xtarget list    
    | ----------------------------------------------------------------------------    
    /if (${debugOn}) /echo DEBUG: Initilizing MobList, xTar and Nav Mesh
    /xtar remove
    /nav reload
    | ----------------------------------------------------------------------------
    | Main Loop - This is where the magic happens. 
    |        1.  Agroed: If we are agroed deal with that first
    |        2. FindMob: Find the type of mob name you are looking for
    |        3.  NavMob: Navigate to the mob using MQ2Nav
    |        4. KillMob: Kill the Mob using MQ2Melee    
    | ----------------------------------------------------------------------------
         | -----------------------------------------------------------------------------------
        | 1. AGROED : If I don't have an activeMobID, but I have an Xtar that means
        |       I have been agroed.  Let's make that my active target and skip the findMob
                /if (${activeMobID}==0 && ${Me.XTarget[1].ID}) {
                    /if (${debugOn}) /echo DEBUG: Agroed: activeMobID: ${activeMobID} Xtar: ${Me.XTarget[1].ID}
                    /varset activeMobID ${Me.XTarget[1].ID}
        | ----------------------------------------------------------------------
        | 2. FindMob : activeMobID NO then Findone or wait
        |     Here we check for an activeMobID or if we have agro in Xtarget[1]
        |    If we do NOT then we need to call FindMob
        | -------------------------------------------------------------------------
        } else /if (${activeMobID}==0 && !${Me.XTarget[1].ID}) {
                /if (${debugOn}) /echo DEBUG: gotoloopfindmob: No Active Target.
                /varset activeMobID 0
                /call FindMob
        | --------------------------------------------------------------------------------
        | 3. NavMob: If we have an activeMobID and it's located further then 30 then Navigate
        |         If we have an Xtar because of agro lets stop nav and switch
        | ---------------------------------------------------------------------------------  
        } else /if (${Spawn[id ${activeMobID}].ID} && ${Spawn[${activeMobID}].Distance} > 30) {
            /if (${activeMobID} == ${Me.XTarget[1].ID} || !${Me.XTarget[1].ID}) {
                /call NavMob    
            } else {
                /squelch /nav stop
                /varset activeMobID ${Me.XTarget[1].ID}    

        | ----------------------------------------------------------
        | 4. KillMob : If everything worked we are near the activeMobID
        | ----------------------------------------------------------              
        } else {
                /call KillMob    

           | COMMENT : the mainloop runs every 10 seconds. Change this to spead it up or slow it down.
           /delay 10
    /goto :mainloop


| -------------------------------------------------------------------------------------
| OnExit - Things it does when you type /endmac
| -------------------------------------------------------------------------------------
    /setchattitle MQ2
    /squelch /nav stop
    /stick off

| -------------------------------------------------------------------------------------
| Sub FindMob - Locate a Mob in the radius you specified
| -------------------------------------------------------------------------------------
Sub FindMob
    | COMMENT : Simple radius search. This will be replaced with a NAV search eventually
    | REMOVED : old simple one parameter search 
    | REMOVED : /varset activeMobID ${NearestSpawn[npc targetable radius ${searchRadius} zradius ${searchRadiusZ} "${farmMobList}"].ID}

    /declare closestMobID                     int    local 0
    /declare closestMobDistance                float    local 99999
    /declare checkMobID                    int    local 0
    /declare checkMobDistance                float    local 0
    /declare x                        int    local 0    
    | COMMENT : Lets find which of our mobs is closest and set it as the activeMobID
    | COMMENT : We set the initial value of closestMobDistance to 99999 to guarantee the first
    | COMMENT : mob checked would be chosen by default.
    | COMMENT : We run a for loop on each mob name in the list and check it against the current one.
    /for x 1 to ${findMobList.Size} 
        /varset checkMobID ${NearestSpawn[npc targetable radius ${searchRadius} zradius ${searchRadiusZ} "${findMobList[${x}]}"].ID}
        /varset checkMobDistance ${Spawn[${checkMobID}].Distance}
        /if (${closestMobDistance} > ${checkMobDistance} && ${checkMobID} > 0)    {
            /varset closestMobID ${checkMobID}
            /varset closestMobDistance ${checkMobDistance}
    /if (${debugOn}) /echo DEBUG: FindMob:"${findMobList[${x}]}" closestMobID:${closestMobID} closestMobDistance:${closestMobDistance} checkMobID:${checkMobID} checkMobDistance:${checkMobDistance} 
    /next x

    | COMMENT : Only change the activeMobID if we actually found something
    | NOTE : You can do if statements in one line if there is only one command. 
    /if (${closestMobID} > 0) /varset activeMobID ${closestMobID}
    /if (${debugOn}) /echo DEBUG: FindMob: radius ${searchRadius} zradius ${searchRadiusZ} "${farmMobList}"
    /if (!${activeMobID}) {
        /setchattitle Scanning for Targets
        /echo FindMob: Nothing Found waiting 5 seconds. 
        /delay 50

| -------------------------------------------------------------------------------------
| Sub NavMob - Navigate using MQ2Nav 
| -------------------------------------------------------------------------------------
Sub NavMob
    | COMMENT : Once activeMobID is set we use MQ2Nav to get there.
    /if (${debugOn}) /echo DEBUG: NavMob: Tracking "${Spawn[${activeMobID}].CleanName}" ID: ${activeMobID} Distance: ${Spawn[${activeMobID}].Distance}
    /setchattitle Tracking ${Spawn[${activeMobID}].CleanName}
    /squelch /nav id ${activeMobID}   | COMMENT: squelch removes the output of the nav spam


| -------------------------------------------------------------------------------------
| Sub KillMob - Target and Kill
| -------------------------------------------------------------------------------------
Sub KillMob
    | COMMENT : This is the kill code. It's only reachable if activeMobID is set and it's close range

    /if (${debugOn}) /echo DEBUG: Killbot: Killing a ${Spawn[${activeMobID}].CleanName} ID: ${activeMobID}
    /target id ${activeMobID}
    /if (${Target.ID} && ${Target.Type.Equal[NPC]}) {
        | COMMENT : Turn off Nav and activate MQ2Melee's /stick and /killthis
        /squelch /nav stop
        /stick 8 uw
        /setchattitle Killing ${Target.CleanName}
        /if (${Target.ID} && ${Me.Combat} && ${Target.Type.Equal[npc]}) {
            /delay 10
            /if (${debugOn}) /echo DEBUG: KillMob: Combat Loop
            /goto :gotoloopkeepfighting            

    } else { 
        /varset activeMobID 0 
    /if (${Target.Type.Equal[corpse]}) {
        /if (${debugOn}) /echo DEBUG: KillMob: Clearing Corpse Target
        /squelch /target clear
        /varset activeMobID 0
Here's a sample INI file, in case you ever want to farm defiant in Steamfont... (4000+ kills, no robe, I suffer for my lost causes). The invocation here might look something like:

Rich (BB code):
 /mac killbot 1000 farm.ini
And the example file:
Rich (BB code):