AssistBot

Post your completed (working) macros here. Only for macros using MQ2Data syntax!

Moderator: MacroQuest Developers

Zardoz0609
orc pawn
orc pawn
Posts: 10
Joined: Thu Apr 23, 2015 12:39 pm

AssistBot

Post by Zardoz0609 » Thu Apr 23, 2015 4:52 pm

Macroquest has quickly turned into one of my favorite hobbies. Anyhow, this is the code I use for my toons. I 3-box most of the time and tabbing window to window is just silly. I have a significantly more advanced code I use for my main toons, but I decided to build up a different group and refine the code a bit more.

I'm big on not declaring a million outer variables and I prefer to use .ini files if I want to use abilities or spells. All of my toons have their own class specific macro that includes one common macro list so you can simply plug and play the different functions as you see fit.

Here is the code. I update it almost every time I log in and it is a growing list. Hope everyone enjoys it and I am totally open to any changes or suggestions others have.


This is the Common.mac file - I do utilize the Spells.mac that can be found floating around if you go looking for it.

Edit - 25 Apr 2015 - I have added EQBC functionality, added a way to push the current spell list to the ini, added an automatic group buff function, and added a way to toggle on and off the automatic movement behind the target while fighting.

Edit - 27 Apr 2015 - Got rid of the need to map strafe keys, added a way to push a second "attacks" spell set, added a ranger-specific (can be modified for any bow/range wielding class) range attack function, added a caster range attack function, added casting while fiighting, added an auto tank mode to home in on the nearest npc and turn on attack (nothing fancy, careful where you use it, it's designed for open zones), added a stuck check that will simply bounce the toon off of the object if he gets stuck while following or heading to his attack target.

Edit - 29 Apr 2015 - Finally added some one-spell healing into the system. A simple "Save Your Heal!" into EQBC will push your ninth spell slot along with an 80% hp tolerance into the ini file. I added a way to push a different spell slot as well as load a different tolerance in if wanted. Simply type /bc "Save Your Heal! <Slot> <Tolerance>" Fixed a few minor other errors.

Edit - 30 Apr 2015 - Added the alternate advancement abilities to be both generic and tank-specific. Tweaked the healing system and the auto buff function. Fixed a few bugs.

Edit - 05 Sep 2016 - It has been a minute, but I have started playing again. I have made various bug fixes and had to fix a few of the issues with using a higher performance computer.

Code: Select all

#include Spells

#event Assist "<#1#> Assist me with >>> #2# <<<"
#event AutoFight "<#1#> Auto On!"
#event Buffs "<#1#> Buff Up!"
#event Moving "<#1#> Stop Moving!"
#event Ranged "<#1#> Keep Your Distance!"
#event MemHeal "<#*#> Save Your Heal! #1# #2#"
#event MemSpells "<#1#> Push #2#!"

Sub Variables

  /declare Leader int outer 1
  /declare AutoMode int outer 0
  /declare BackAttack int outer 1
  /declare GemCount int outer
  /declare HealSpell string outer ${Ini[Master.ini,"${Me}",HealSpell]}
  /declare HealGem int outer ${Ini[Master.ini,"${Me}",HealGem]}
  /declare HealRange int outer ${Ini[Master.ini,"${Me}",HealRange]}
  /declare HealTolerance string outer ${Ini[Master.ini,"${Me}",HealTolerance]}
  /declare MaxSpellRange int outer 100
  /declare RangedFight int outer 1

/return

|||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||

Sub Event_Assist

  /declare CurrentExp int ${Me.PctExp}
  /declare DifferenceExp float

  /if (${Leader} == 0 && ${String[${Target}].NotEqual[NULL]}) /bc Assist me with >>> ${Target.CleanName} <<<
  
  /if (${Me.Moving}) /keypress up

  /delay 2s

  :Kill
    /doevents Moving
    /doevents AutoFight
    /doevents Ranged

    /if (${Me.Pet.CleanName.NotEqual[NO PET]}) {
      /if (!${Me.Pet.Target.ID} && ${Target.Distance} < ${Target.MaxRangeTo}) {
	/if (${Me.Moving}) /keypress up
	/call TargetCheck
	/delay 1s
        /pet attack
      }
    }

    /if (${HealSpell.NotEqual[NULL]}) {
      /doevents MemHeal
      /call HealCheck
      /if (${Macro.Return.Arg[2,|]} && ${Me.PctMana} > 10) {
        /call HealCast ${Macro.Return.Arg[1,|]}
        /goto :Kill
      }
    }

    /if (${RangedFight} > 0)  {
      /if (!${Me.Combat}) /attack
      /call StayOnTarget
      /if (${Target.Distance} < ${Target.MaxRangeTo}) {
        /if (${Me.Class.CanCast} && ${Me.PctMana} > 10) {
          /if (${Me.Moving}) /keypress up
          /call CasterAttack
        } else {
          /call DoAbilities
          /if (${Group.MainTank.CleanName.Equal[${Me}]}) /call DoTankAbilities
        }
      }
    } else {
      /if (${Me.Class.Name.Equal[Ranger]}) {
        /call RangerAttack
      } else {
        /call CasterAttack
      }
    }

  /if (${Me.XTarget[1].PctHPs} > 0) /goto :Kill

  /keypress up

  /varcalc DifferenceExp ${Me.PctExp} - ${CurrentExp}

  /bc ${Me.PctExp} -- ${DifferenceExp}

  /doevents flush

  /delay 2s

/return

|||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||

Sub Event_AutoFight

  /call VarSwap ${AutoMode} AutoMode

/return

|||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||

Sub BeastlordSpells


/return

|||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||

Sub Event_Buffs

  /declare Count int
  /declare SpellCount int 

  /if (${Me.Class.CanCast}) {
    /squelch /target clear

    /call CountGems

    /target ${Me}
 
    /delay 1s

    /for SpellCount 1 to ${GemCount}
      /if (${${Me}BuffsTargetArray[${SpellCount}].Equal[Self]}) {
        /if (!${Me.Buff[${${Me}BuffsNameArray[${SpellCount}]}].ID} && ${${Me}BuffsNameArray[${SpellCount}].NotEqual[Feign Death]}) {
	  /delay 2s
          /call Cast "${${Me}BuffsNameArray[${SpellCount}]}" Gem${SpellCount}
        }
      }
    /next SpellCount

    /if (${Me.Pet.CleanName.NotEqual[NO PET]}) {
      /for SpellCount 1 to ${GemCount}
        /if (${${Me}BuffsTargetArray[${SpellCount}].Equal[Pet]}) {
          /target ${Me.Pet}
          /delay 1s
          /if (!${Target.Buff[${${Me}BuffsNameArray[${SpellCount}]}].ID}) {
            /call Cast "${${Me}BuffsNameArray[${SpellCount}]}" Gem${SpellCount}
          }
        }
      /next SpellCount
    }

    /for SpellCount 1 to ${GemCount}
      /if (${${Me}BuffsTargetArray[${SpellCount}].Equal[Group v1]} || ${${Me}BuffsTargetArray[${SpellCount}].Equal[Group v2]}) {
        /if (!${Me.Buff[${${Me}BuffsNameArray[${SpellCount}]}].ID}) {
	  /delay 2s
          /call Cast "${${Me}BuffsNameArray[${SpellCount}]}" Gem${SpellCount}
        }
      }
    /next SpellCount

    /for Count 0 to ${Group.Members}
      /target ${Group.Member[${Count}].CleanName}
      /delay 2s
      /for SpellCount 1 to ${GemCount}
        /if (${${Me}BuffsTypeArray[${SpellCount}].Equal[Beneficial]}) {
          /if (${${Me}BuffsTargetArray[${SpellCount}].Equal[Single]}) {
            /if (!${Target.Buff[${${Me}BuffsNameArray[${SpellCount}]}].ID} && ${${Me}BuffsNameArray[${SpellCount}].NotEqual[${HealSpell}]}) {
	      /delay 2s
              /call Cast "${${Me}BuffsNameArray[${SpellCount}]}" Gem${SpellCount}
            }
          }
        }
      /next SpellCount
    /next Count    
    /bc Buffs Done!
  }

/return

|||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||

Sub CasterAttack

  /declare Count int 1

  /call FindMaxSpellRange
  /call CountGems
  /call TargetCheck
  
  /if (${RangedFight} < 1) /call StayInRange ${MaxSpellRange}
  /if (${HealSpell.NotEqual[NULL]} && ${Me.PctMana} < 40) /return

  /if (${Target.Distance} < ${MaxSpellRange}) {
    /if (${Me.Moving}) /keypress up
    /for Count 1 to ${GemCount}
      /if (${${Me}AttacksTypeArray[${Count}].Equal[Detrimental]}) {
        /if (${${Me}AttacksDurationArray[${Count}]} > 0) {
          /if (!${Target.Buff[${${Me}AttacksNameArray[${Count}]}].ID}) {
            /if (${Me.SpellReady[${Count}]}) {
	      /delay 1s
	      /call Cast "${${Me}AttacksNameArray[${Count}]}" Gem${Count}
            }
          }
        } else {
          /if (${Me.SpellReady[${Count}]}) /call Cast "${${Me}AttacksNameArray[${Count}]}" Gem${Count}
        } 
      }
    /next Count
  }

/return

|||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||

Sub CheckStuck(PriorX, PriorY)

  /delay 1

  /if (${PriorX}==${Me.X} && ${PriorY}==${Me.Y} && ${Me.Moving}) {
    /keypress back hold
    /delay 1
    /keypress back
    /keypress strafe_left hold
    /delay 1
    /keypress strafe_left
    /keypress up
  }

/return

|||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||

Sub CheckTarget

  /if (${Target.Name.NotEqual[${Me.XTarget[1].Name}]})

|||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||

Sub CountGems

  /declare Count int 1

  :Next
    /if (${Me.Gem[${Count}].Name.NotEqual[NULL]}) {
      /varcalc Count ${Count} + 1
      /goto :Next
    }
  /varcalc Count ${Count} - 1
  /varset GemCount ${Count}

/return

|||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||

Sub DoAbilities

  /declare Count int

  /for Count 1 to ${${Me}AbilityArray.Size}
    /if (${Me.AbilityReady[${${Me}AbilityArray[${Count}]}]}) /doability ${${Me}AbilityArray[${Count}]}
  /next Count  

  /for Count 1 to ${${Me}AAArray.Size}
    /if (${Me.AltAbilityReady[${${Me}AAArray[${Count}]}]}) /alt act ${${Me}AAArray[${Count}]}
  /next Count

/return

|||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||

Sub DoTankAbilities

  /declare Count int

  /for Count 1 to ${${Me}TankAbilityArray.Size}
    /if (${Me.AbilityReady[${${Me}TankAbilityArray[${Count}]}]}) /doability ${${Me}TankAbilityArray[${Count}]}
  /next Count

  /for Count 1 to ${${Me}TankAAArray.Size}
    /if (${Me.AltAbilityReady[${${Me}TankAAArray[${Count}]}]}) {
      /if (${${Me}TankAATypeArray[${Count}].Equal[Multiple]}) {
        /if (${Me.XTarget} > 1) /alt act ${${Me}TankAAArray[${Count}]}
      } else {
        /alt act ${${Me}TankAAArray[${Count}]
      }
    }
  /next Count

/return

|||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||

Sub FindMaxSpellRange

  /declare Count int

  /for Count 1 to ${GemCount}
    /if (${${Me}AttacksTypeArray[${Count}].Equal[Detrimental]} && ${${Me}AttacksRangeArray[${Count}]} < ${MaxSpellRange}) /varset MaxSpellRange ${${Me}AttacksRangeArray[${Count}]}
  /next Count
    
/return

|||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||

Sub Follow

  /if (${Group.Leader.CleanName.Equal[${Me}]} || !${Group}) {
    /varset Leader 0
  } else {
    /varset Leader 1
  }

  /if (${Leader} > 0) {
    /if (${Group.Leader.Distance} > 10) {
      /if (${Group.Leader.HeadingTo.Degrees} != ${Me.Heading.Degrees}) /squelch /face fast ${Group.Leader}
      /keypress up hold
      /call CheckStuck ${Me.X} ${Me.Y}
    } else {
      /if (${Me.Moving}) /keypress up
      /if (${Group.Leader.Sitting} && !${Me.Sitting}) /sit
    }
  }

/return

|||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||

Sub GetBehind

  /declare TarHead int
  /declare MeHead int
  /declare NeutralHead int

  /varset TarHead ${Target.Heading.Degrees}
  /varset MeHead ${Me.Heading.Degrees}

  /if (${Me.XTarget[1].ID} > 0) {
    /if (${TarHead} < ${MeHead}) {
      /varcalc NeutralHead ${MeHead} - ${TarHead}
    } else {
      /varcalc NeutralHead 360 - ${TarHead} + ${MeHead}
    }

    /if (${NeutralHead} > 180 && ${NeutralHead} < 330) {
      /keypress strafe_left hold
      /delay 1
      /keypress strafe_left
    } else /if (${NeutralHead} < 180 && ${NeutralHead} > 30) {
      /keypress strafe_right hold
      /delay 1
      /keypress strafe_right
    }
  }  

/return

|||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||

Sub HealCast(Toon)

  /target ${Group.Member[${Toon}]}
  /delay 1s

  /if (${Target.Distance} > ${HealRange}) {
    /call StayInRange ${HealRange}
  } else {
    /if (${Me.Moving}) /keypress up
    /call Cast "${HealSpell}" Gem${HealGem}
  }

/return

|||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||

Sub HealCheck

  /declare Count int 0
  /declare LowHealth 0
  /declare CastRequired bool FALSE
  
  /for Count 0 to ${Group}
    /if (${Group.Member[${Count}].PctHPs} < ${HealTolerance} && !${Group.Member[${Count}].Dead}) {
      /if (${Group.Member[${Count}].PctHPs} < ${Group.Member[${LowHealth}].PctHPs}) {
        /varset LowHealth ${Count}
      }
      /varset CastRequired TRUE
    }
  /next Count

/return ${LowHealth}|${CastRequired}

|||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||

Sub LeaderAbilities

  /if (${Group} && (${Group.MainAssist.CleanName.NotEqual[${Me}]} || !${Group.MainAssist.ID})) /grouproles set ${Me} 2
  /if (${AutoMode} > 0) {
    /squelch /target npc radius 40
    /delay 1s (!${Target.ID})
    /if (!${Target.ID} || ${Target.Dead} || ${Target.DistanceZ} > 50) {
      /squelch /target npc los
      /delay 1s (!${Target.ID})
    }
    /attack on
  }
  /if (${Me.Combat} && ${Target.CleanName.NotEqual[NULL]}) {
    /call Event_Assist
  }

/return

|||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||

Sub LoadINI

  /call ReadINI Ability
  /call ReadINI AA
  /call ReadINI TankAbility
  /call ReadINI TankAA
  /call ReadINI TankAAType
  /call ReadINI BuffsName
  /call ReadINI BuffsType
  /call ReadINI BuffsTarget
  /call ReadINI BuffsDuration
  /call ReadINI BuffsRange
  /call ReadINI AttacksName
  /call ReadINI AttacksType
  /call ReadINI AttacksTarget
  /call ReadINI AttacksDuration
  /call ReadINI AttacksRange

/return

|||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||

Sub Event_MemHeal(Line,Gem,Tolerance)

  /declare SpellGem int 9
  /declare SpellTolerance int 80

  /if (${Gem}) /varset SpellGem ${Gem}
  /if (${Tolerance}) /varset SpellTolerance ${Tolerance}
  /if (!${Me.Class.DruidType} || !${Me.Class.ShamanType} || !${Me.Class.ClericType}) /return 

  /ini "Master.ini" "${Me}" "HealSpell" "${Me.Gem[${SpellGem}]}"
  /ini "Master.ini" "${Me}" "HealGem" "${SpellGem}"
  /ini "Master.ini" "${Me}" "HealTolerance" "${SpellTolerance}"
  /ini "Master.ini" "${Me}" "HealRange" "${Me.Gem[${SpellGem}].Range}"

  /varset HealSpell ${Me.Gem[${SpellGem}]}
  /varset HealGem ${SpellGem}
  /varset HealTolerance ${SpellTolerance}
  /varset HealRange ${Me.Gem[${SpellGem}].Range}

/return
  
|||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||

Sub Event_MemSpells(Line,Caller,List)

  /declare Count int

  /call CountGems

  /if (${Me.Class.CanCast}) {  
    /for Count 1 to ${GemCount}
      /ini "Master.ini" "${Me}" "${List}Name${Count}" "${Me.Gem[${Count}]}"
      /ini "Master.ini" "${Me}" "${List}Type${Count}" "${Me.Gem[${Count}].SpellType}"
      /ini "Master.ini" "${Me}" "${List}Target${Count}" "${Me.Gem[${Count}].TargetType}"
      /ini "Master.ini" "${Me}" "${List}Duration${Count}" "${Me.Gem[${Count}].Duration}"
      /ini "Master.ini" "${Me}" "${List}Range${Count}" "${Me.Gem[${Count}].Range}"
      /if (${${Me}${List}NameArray.Size} > 0 && ${GemCount} <= ${${Me}${List}NameArray.Size}) {
        /varset ${Me}${List}NameArray[${Count}] ${Me.Gem[${Count}]}
        /varset ${Me}${List}TypeArray[${Count}] ${Me.Gem[${Count}].SpellType}
        /varset ${Me}${List}TargetArray[${Count}] ${Me.Gem[${Count}].TargetType}
        /varset ${Me}${List}DurationArray[${Count}] ${Me.Gem[${Count}].Duration}
        /varset ${Me}${List}RangeArray[${Count}] ${Me.Gem[${Count}].Range}
      } else /if (${Count} == ${GemCount}) {
        /macro ${Macro}
      }
    /next Count
  }

/return

|||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||

Sub Event_Moving(Line,Type)

  /echo ${Line} ${Type}

  /call VarSwap ${BackAttack} BackAttack

/return
|||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||

Sub Plugins

  /plugin MQ2EQBC
  /bccmd connect

/return

|||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||

Sub Event_Ranged

  /if (${Me.Class.CanCast}) /call VarSwap ${RangedFight} RangedFight

/return

|||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||

Sub RangerAttack

  /declare MinRange int 40

  /if (${Leader} > 0) /call TargetCheck
  
  /call StayInRange ${InvSlot[Ammo].Item.Range} ${MinRange}
 
  /if (!${Me.AutoFire}) /autofire

/return

|||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||

Sub RangerSpells

/return

|||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||

Sub ReadINI(ArrayType)

  /declare nValues     int local  1
  /declare nArray      int local  0

  :CounterLoop
    /if (${String[${Ini[Master.ini,"${Me}",${ArrayType}${nValues}]}].Equal[null]}) {
      /varcalc nValues ${nValues}-1
      /goto :MakeArray
    }
    /varcalc nValues ${nValues}+1
  /goto :CounterLoop

  :MakeArray
    /if (!${nValues}) /return
    /if (${nValues} > 0) {
      /declare ${Me}${ArrayType}Array[${nValues}] string outer
    }

  /for nArray 1 to ${nValues}
        /varset ${Me}${ArrayType}Array[${nArray}] ${Ini[Master.ini,"${Me}",${ArrayType}${nArray}]}
  /next nArray

/return

|||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||

Sub StayInRange(MaxRange,MinRange)

  /if (${Target.ID}) /face fast 

  /if (${Target.Distance} > ${MaxRange}) {
    /keypress up hold
  } else /if (${Target.Distance} < ${MinRange}) {
    /keypress back hold
  } else {
    /keypress up
    /keypress back
  }

/return

|||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||

Sub StayOnTarget

  /declare Range int

  /if (${Leader} > 0) /call TargetCheck

  /if (${Target.ID} && !${Me.XTarget[1].Dead}) {
    /varcalc Range ${Target.MaxRangeTo}/2
    /if (${Target.HeadingTo.Degrees} != ${Me.Heading.Degrees}) /face fast
    /if (${Target.Distance} > ${Range}) {
      /keypress up hold
      /call CheckStuck ${Me.X} ${Me.Y}
    } else {
      /keypress up
      /if (${Me.PctAggro} < 100 && ${BackAttack} > 0) /call GetBehind
    }
  }

/return

|||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||

Sub TargetCheck

  /if (!${Target.ID} || ${Target.Dead} || ${Me.XTarget[1].ID}!=${Target.ID}) {
    /assist ${Group.Leader}
    /delay 1s
  }

/return

|||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||

Sub Tasks

  /doevents
  /call Follow
  /if (${Leader} < 1) {
    /call LeaderAbilities
  }

  /if (${Me.XTarget} < 1 && ${Me.Combat}) /attack off

/return

|||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||

Sub VarSwap(Variable, Name)

  /if (${Variable} > 0) {
    /varset Variable 0
  } else {
    /varset Variable 1
  }

  /varset ${Name} ${Variable}

/return

|||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
This is just an example of the main class macro I use. This will develop more as the characters level and more class-specific functionality comes in.

Code: Select all

#include Common

Sub Main

  /xtarget set 1 gat
  /call Variables
  /call Plugins
  /call LoadINI

  :Beast
    /call Tasks
  /goto :Beast

/return
This is just an example of the ini file. It takes in both normal abilities as well as tank-specific abilities if the character is set to Main Tank.

Code: Select all

[CharacterName]
Ability1=Kick
[OtherCharacterName]
Ability1=Kick
TankAbility1=Taunt
[OtherOtherCharacterName]
Ability1=Kick
Last edited by Zardoz0609 on Mon Sep 05, 2016 7:34 am, edited 12 times in total.

dewey2461
Contributing Member
Contributing Member
Posts: 1759
Joined: Sun Apr 17, 2005 1:53 am

Re: AssistBot

Post by dewey2461 » Thu Apr 23, 2015 5:27 pm

Zardoz0609 wrote:All of the characters are joined in a fellowship so I use /fs to pass commands ... I do utilize the Spells.mac that can be found floating around if you go looking for it.
Thanks for sharing your code. It looks very clean and pretty easy to follow. It would be nice if you posted your version of spells.mac or gave the link so its easier for someone else to duplicate your setup.

I would suggest you look into using MQ2EQBC. It gives you an easy to use chat channel that runs on your local machine/network. This means the commands don't travel to sony / daybreak and back. Its quicker and safer.

Zardoz0609
orc pawn
orc pawn
Posts: 10
Joined: Thu Apr 23, 2015 12:39 pm

Re: AssistBot

Post by Zardoz0609 » Thu Apr 23, 2015 5:41 pm

I had looked into EQBCS, I just haven't made it around to configuring it. On my main setup, I really only pass the assist command regularly. I have a group buffing function and a few ways to toggle on and off some of the other features, but they aren't really noticeable. The only noticeable thing in this particular code is the experience percentage that gets spit out at the end of every kill. Definitely, wouldn't be a bad idea to put that into a local chat server.

Here's the spells.mac I use.

viewtopic.php?t=7568

EqMule
Developer
Developer
Posts: 2697
Joined: Fri Jan 03, 2003 9:57 pm
Contact:

Re: AssistBot

Post by EqMule » Thu Apr 23, 2015 9:12 pm

I agree with Dewey it's very clean and easy to read, but you really need to use eqbc for the communication between toons or you will eventually get in trouble, all it takes is someone looking through your logs on the server side and they will see you are using a "third party tool" don't risk it ;)
My status o/
If you like MQ2 and would like to contribute, please do. My goal is 25 donations per month.
So far I've received Image donations for this month's patches.

Bitcoin: 1Aq8ackjQ4f7AUvbUL7BE6oPfT8PmNP4Zq
Krono: PM me.
I can always use characters for testing, PM me if you can donate one.

dewey2461
Contributing Member
Contributing Member
Posts: 1759
Joined: Sun Apr 17, 2005 1:53 am

Re: AssistBot

Post by dewey2461 » Thu Apr 23, 2015 9:28 pm

Zardoz0609 wrote: Here's the spells.mac I use.
viewtopic.php?t=7568
Looks like you saved "spell_routines.inc" as spell.mac which is why I was asking.

The version you link above is pretty old. Pete has a newer version that makes things a bit easier here: ( You need VIP access )

viewtopic.php?f=49&t=18629&start=15

Again thanks for sharing. Its always nice to see new blood come in and get excited about coding up new stuff.

Zardoz0609
orc pawn
orc pawn
Posts: 10
Joined: Thu Apr 23, 2015 12:39 pm

Re: AssistBot

Post by Zardoz0609 » Fri Apr 24, 2015 7:49 am

I changed it around a bit last night to run through the Irc client and temporarily use a public irc server (no one seems to use those any more... especially ones based in northern Canada ;) ). Perhaps, tonight, I will get it working with the BCS.

On another note, I put in some code to push each caster toons spell list to the ini file and I was putting in a buff function so someone can just tell the group to buff up.

This is just the ini push function

Code: Select all

Sub Event_MemBuffs

  /declare Count int 

  /call CountGems

  /if (${Me.Class.CanCast}) {  
    /for Count 1 to ${GemCount}
      /ini "Master.ini" "${Me}" "SpellName${Count}" "${Me.Gem[${Count}]}"
      /ini "Master.ini" "${Me}" "SpellType${Count}" "${Me.Gem[${Count}].SpellType}"
      /ini "Master.ini" "${Me}" "SpellTarget${Count}" "${Me.Gem[${Count}].TargetType}"
      /varset ${Me}SpellNameArray[${Count}] ${Me.Gem[${Count}]}
      /varset ${Me}SpellTypeArray[${Count}] ${Me.Gem[${Count}].SpellType}
      /varset ${Me}SpellTargetArray[${Count}] ${Me.Gem[${Count}].TargetType}
    /next Count
  }

/return
and the gem counter

Code: Select all

Sub CountGems

  /declare Count int 1

  :Next
    /if (${Me.Gem[${Count}].Name.NotEqual[NULL]}) {
      /varcalc Count + 1
      /goto :Next
    }
  /varcalc Count ${Count} - 1
  /varset GemCount ${Count}

/return
The GemCount variable is just an outer that I plugged into the Variables function.

JudgeD
a snow griffon
a snow griffon
Posts: 354
Joined: Sat Aug 18, 2012 8:07 pm

Re: AssistBot

Post by JudgeD » Fri Apr 24, 2015 10:45 am

Would be nice to have .GemCount added to the Me TLO

Zardoz0609
orc pawn
orc pawn
Posts: 10
Joined: Thu Apr 23, 2015 12:39 pm

Re: AssistBot

Post by Zardoz0609 » Fri Apr 24, 2015 4:13 pm

Today's update allows for a simple "Buff Up!" Command and all of the caster-type buff the group and their own pet.

Code: Select all

Sub Event_Buffs

  /declare Count int
  /declare SpellCount int 

  /if (${Me.Class.CanCast}) {
    /call CountGems

    /target ${Me.CleanName}

    /for SpellCount 1 to ${GemCount}
      /if (${${Me}SpellTargetArray[${SpellCount}].Equal[Self]}) {
        /if (${String[${Me.Buff[${${Me}SpellNameArray[${SpellCount}]}]}].Equal[NULL]}) {
          /call Cast "${${Me}SpellNameArray[${SpellCount}]}" Gem${SpellCount}
        }
      }
    /next SpellCount

    /if (${Me.Pet.CleanName.NotEqual[NO PET]}) {
      /for SpellCount 1 to ${GemCount}
        /if (${${Me}SpellTargetArray[${SpellCount}].Equal[Pet]}) {
          /target ${Me.Pet}
          /delay 5
          /if (${String[${Target.Buff[${${Me}SpellNameArray[${SpellCount}]}]}].Equal[NULL]}) {
            /call Cast "${${Me}SpellNameArray[${SpellCount}]}" Gem${SpellCount}
          }
        }
      /next SpellCount
    }

    /for SpellCount 1 to ${GemCount}
      /if (${${Me}SpellTargetArray[${SpellCount}].Equal[Group v1]} || ${${Me}SpellTargetArray[${SpellCount}].Equal[Group v2]}) {
        /if (${String[${Me.Buff[${${Me}SpellNameArray[${SpellCount}]}]}].Equal[NULL]}) {
          /call Cast "${${Me}SpellNameArray[${SpellCount}]}" Gem${SpellCount}
        }
      }
    /next SpellCount

    /for Count 0 to ${Group.Members}
      /target ${Group.Member[${Count}].CleanName}
      /delay 5
      /for SpellCount 1 to ${GemCount}
        /if (${${Me}SpellTypeArray[${SpellCount}].Equal[Beneficial]}) {
          /if (${${Me}SpellTargetArray[${SpellCount}].Equal[Single]}) {
            /if (${String[${Target.Buff[${${Me}SpellNameArray[${SpellCount}]}]}].Equal[NULL]}) {
              /call Cast "${${Me}SpellNameArray[${SpellCount}]}" Gem${SpellCount}
            }
          }
        }
      /next SpellCount
    /next Count    
    /i say Buffs Done!
  }

/return
I don't really like using the String to run the logic, however, I couldn't find another way to go about it as the .Buff is basically a lookup that returns a NULL with no actual object type associated. In other words, if the buff is present on the character/target, then using ${Target.Buff[WhateverBuff].Name.NotEqual[NULL]} works just fine if WhateverBuff is currently on the character. However, if the buff is not present it simply comes back as NULL instead of False. I also tried to use /if (!${Target.Buff[WhateverBuff]}). That works fine if the buff is not on the character, however, if the buff is on the character the if statement gets mad simply because it's a lookup that can only return a false or null value.

Anyhow, it works just fine if you have gone into macroquest and reenabled the string function. If anyone has a good way to rework this, I am more than happy to change it around because using string like that is a forced coding.

EqMule
Developer
Developer
Posts: 2697
Joined: Fri Jan 03, 2003 9:57 pm
Contact:

Re: AssistBot

Post by EqMule » Fri Apr 24, 2015 4:36 pm

You can

Code: Select all

/if (${Bool[${Target.Buff[somebuff].ID}]}==TRUE) 
to force a Boolean that always returns true or false...
My status o/
If you like MQ2 and would like to contribute, please do. My goal is 25 donations per month.
So far I've received Image donations for this month's patches.

Bitcoin: 1Aq8ackjQ4f7AUvbUL7BE6oPfT8PmNP4Zq
Krono: PM me.
I can always use characters for testing, PM me if you can donate one.

SwiftyMUSE
Developer
Developer
Posts: 1205
Joined: Tue Sep 23, 2003 10:52 pm

Re: AssistBot

Post by SwiftyMUSE » Fri Apr 24, 2015 4:59 pm

EqMule wrote:You can

Code: Select all

/if (${Bool[${Target.Buff[somebuff].ID}]}==TRUE) 
to force a Boolean that always returns true or false...
or,

Code: Select all

/if (${Target.Buff[somebuff].ID})
PayPal: Donate to SwiftyMUSE
Bitcoin: 1LuQ6YcEAWxF3fm9yWMiro4K582je7364V
Krono: PM me

dont_know_at_all wrote:Gee, if only there was a way to correctly report a crash...

EqMule
Developer
Developer
Posts: 2697
Joined: Fri Jan 03, 2003 9:57 pm
Contact:

Re: AssistBot

Post by EqMule » Fri Apr 24, 2015 6:31 pm

Won't that just return the string "NULL" if the target doesn't have the buff?
My status o/
If you like MQ2 and would like to contribute, please do. My goal is 25 donations per month.
So far I've received Image donations for this month's patches.

Bitcoin: 1Aq8ackjQ4f7AUvbUL7BE6oPfT8PmNP4Zq
Krono: PM me.
I can always use characters for testing, PM me if you can donate one.

PeteSampras
a snow griffon
a snow griffon
Posts: 322
Joined: Sat Dec 15, 2007 8:56 pm

Re: AssistBot

Post by PeteSampras » Fri Apr 24, 2015 7:52 pm

but NULL is set up to return as 0. it is still FALSE.

Zardoz0609
orc pawn
orc pawn
Posts: 10
Joined: Thu Apr 23, 2015 12:39 pm

Re: AssistBot

Post by Zardoz0609 » Fri Apr 24, 2015 8:06 pm

Tested both. Both work!

I ended up going with the /if (!${Target.Buff[Whatever].ID})

EqMule
Developer
Developer
Posts: 2697
Joined: Fri Jan 03, 2003 9:57 pm
Contact:

Re: AssistBot

Post by EqMule » Fri Apr 24, 2015 9:16 pm

NULL is 0 in c/c++ but in MacroQuest it's a stringtype "NULL" we might be faking that in the /if command I wouldn't know haven't really looked at it, I just know I've seen the problem with trying to parse fake NULL as a Booltype when it's not...

Maybe I'm wrong, whatever, glad you solved it.
My status o/
If you like MQ2 and would like to contribute, please do. My goal is 25 donations per month.
So far I've received Image donations for this month's patches.

Bitcoin: 1Aq8ackjQ4f7AUvbUL7BE6oPfT8PmNP4Zq
Krono: PM me.
I can always use characters for testing, PM me if you can donate one.

demonstar55
a snow griffon
a snow griffon
Posts: 314
Joined: Fri Nov 28, 2008 6:31 am

Re: AssistBot

Post by demonstar55 » Fri Apr 24, 2015 9:44 pm

EqMule wrote:NULL is 0 in c/c++ but in MacroQuest it's a stringtype "NULL" we might be faking that in the /if command I wouldn't know haven't really looked at it, I just know I've seen the problem with trying to parse fake NULL as a Booltype when it's not...

Maybe I'm wrong, whatever, glad you solved it.

Code: Select all

NULL
is handled specially, however

Code: Select all

null
Null
NULl ...
aren't