Edit 05/05:
fixed pause so it works in all cases
fixed /avoidadd <name>
fixed /avoidrem <name>
probably fixed the problem with using the wrong song index
Edit 05/06:
fixed the avoid list and targetting.
Code: Select all
| - chant.mac - By Raebis
| - Mob avoidance added by ml2517
| - MQ2Parmatized by dkaa
| - MQ2Datatized by dkaa
| - Obstacle avoidance by dkaa
|
| Version: REV5c(w/ avoidance mod) Jan 10 4:30pm
|
| This mac is used mostly for big open zones with not a lot of
| big hills (cause hills cause pain - unless you have levitate)
|
| Features:------------------------------------------------------------------------
|
| * Automatically selects high light blue, dark blue, or white mob
| * Runs to mob before targeting it (Stealth! No cross-zone targeting!)
| * Aggro/Add Detection: Automatically targets and kites aggroed mobs (adds)
| * Ignores greens and low light blues unless they are aggroed (adds)
| * Caster Detection: Automatically will switch target to aggroed casting mobs
| * Compatible with level 49 and level 6 selos
| * Auto Healing: If health gets low, it will automatically heal
| * Fleeing Mob Catcher: If mob runs away, macro keeps you in range!
| * Detects WMS (Warping Mob Syndrom) and gets a new target if a mob warps away!
| * NEW: Rubber Anchor: kites mobs closest to macro starting point - no wandering!
| * NEW: Mob avoidance by name. Add/Remove from the list on the fly. (See the description of use below)
| * NEW: Script pausing upon startup or during the script. (See the description of use below)
| ---------------------------------------------------------------------------------
|
| usage: chant.mac <DOTs/LVL6 Selos> <49selo> <radius> [<heal song>] [<pause on startup>]
|
|
| Usage Examples:
| -Scenario 1: If you are using...
| ...DOTs in Gems 4, 5, 6, and 7
| ...Level 49 Selo in Gem 2
| ...Radius of 55
| ...Hymn of Restoration in Gem 1
| ...If you wanted the script to start paused
| syntax: /mac chant 4567 2 55 1 1
|
| -Scenario 2: If you are using...
| ...DOTs in Gems 6 and 7
| ...Level 6 Selo in gem 3
| ...Radius of 80
| ...Hymn of Restoration in gem 8
| ...If you want the script to start un-paused
| syntax: /mac chant 673 0 80 8 0
|
|
| If <heal song> is defined then when health goes below ${Health}Min (default is 70%)
| it will replace the first song in <DOTs> with <heal song> until health is above
| ${Health}Max (default is 85%)
|
| If <pause on startup> is a 1 the script will pause upon startup so that you can add mobs to your avoid list.
| If <pause on startup> is a 0 the script will start immediately and go hunting.
| If you don't define <pause on startup> it assumes you want to immediately start hunting.
|
| If <selo> is 0 then the macro will not try to cast selos every 150 seconds
|
| Note about the rubber anchor:
| The macro will target the mob closest to the RubberAnchor (your /loc when first
| starting the macro)
|
| REV5b was Tested in EW for bout an hour
|
| Warning: You may wander from your starting point but after killing a mob, the
| next mob that the macro targets will be closest to your starting point
|
| Note: Rev information moved to the top
|
| -----------------------------------------------------------------------------------
|
| New Commands:
| -------------
| /avoidadd mobname
| /avoidrem mobname
| /pause
|
| Examples:
| ---------
| /avoidadd A Large Trout
| /avoidrem A Large Trout
| /pause
|
| When adding mobs to the avoidance list initially you can use the /echo pause command.
| This will pause the script but still allow you to target and add/remove the mobs you'd
| like to avoid/not avoid. You can also pause the script upon startup by using the pause parameter.
|
| The best way to use the avoid add command is to use a hotkey with this:
| /avoidadd $(Target.CleanName}
|
| The best way to use the avoid remove command is to use a hotkey with this:
| /avoidrem ${Target.CleanName}
|
| Then you simply run around the zone targeting mobs that you know you'd like to avoid and add/remove them
| to your avoidance list. The list is written to an INI file so you won't have to add them to the list
| the next time you play.
|
#event NeedTarget "You must first select a target for this spell!"
#event Exp "You gain "
#event Died "You have entered"
#event Caster " begins to cast a spell."
#event Tell "tells you"
#turbo 10
Sub Main(string DOTs,string Selos,int CRadius,string Health,int Paused)
/if (!${Defined[CRadius]}) {
/echo usage: chant.mac <DOTs, LVL6 Selos> <49selo> <radius> [<heal song>]
/return
}
/declare PauseFlag int outer
/if (${Defined[Paused]}) {
/if (${Paused}) {
/varset PauseFlag 1
} else {
/varset PauseFlag 0
}
} else {
/varset PauseFlag 0
}
/declare avoidadd string outer
/declare avoidrem string outer
/alias /pause /varcalc PauseFlag !${PauseFlag}
/alias /avoidadd /varset avoidadd
/alias /avoidrem /varset avoidrem
/declare CirR outer
/declare Songs[10] int outer
/declare nSongs int outer
/declare CurSong int outer
/declare PrevSong int outer
/declare Exper int outer
/declare AAExp int outer
/declare SongTimer timer outer
/declare SeloSong int outer
/declare HealSong int outer
/declare OrigSong int outer
/declare HealthMin outer
/declare HealthMax outer
/declare DBLevel outer
/declare TargetUpNext int outer
/declare RubberX int outer
/declare RubberY int outer
/declare AvoidList[50] string outer UNDEFINED-ARRAY-ELEMENT
/declare MyXLOC float outer
/declare MyYLOC float outer
/declare ObstCount int outer
/declare EachSong int local
/call AvoidINILoad
/varset PrevSong 0
/varset MyXLOC 0.0
/varset MyYLOC 0.0
/varset nSongs ${DOTs.Length}
/echo nSongs ${nSongs}
/echo DOTs ${DOTs}
/for EachSong 1 to ${nSongs}
/varset Songs[${EachSong}] ${DOTs.Mid[${EachSong},1]}
/echo Song ${EachSong}: ${Me.Gem[${Songs[${EachSong}]}].Name}
/next EachSong
/if (${Selos}!=0) {
/varset SeloSong ${Selos}
/echo Selo's: ${Me.Gem[${SeloSong}].Name}
} else {
/varset SeloSong 0
/echo Not using level 49 Selos.
}
/if (!${Defined[Health]}) {
/echo No HealSong. Please watch your health.
/varset HealSong 0
} else /if (${Health}!=0) {
/varset HealSong ${Health}
/echo Healsong: ${Me.Gem[${HealSong}].Name}
} else {
/echo No HealSong. Please watch your health.
/varset HealSong 0
}
/varset CirR ${CRadius}
/echo Radius: ${CirR}
/varset OrigSong ${Songs[1]}
/varset CurSong 1
/varset Exper ${Me.Exp}
/varset AAExp ${Me.AAExp}
/varset SongTimer 1
|/varset DBLevel $int($calc($calc($char(level)*.75)+1))
/varset DBLevel 35
/varset HealthMin 70
/varset HealthMax 85
/varset TargetUpNext 0
/varset RubberX ${Me.X}
/varset RubberY ${Me.Y}
/echo Rubber Anchor dropped at ${RubberX},${RubberY}
/if (${PauseFlag}==1) {
/echo Script [PAUSED] issue an "/pause" to unpause it.
}
:Loop
/if (${avoidadd.Length}) {
/echo ${avoidadd.Length} for ${avoidadd}
/call AvoidINIAdd "${avoidadd}"
/varset avoidadd
}
/if (${avoidrem.Length}) {
/echo ${avoidrem.Length} for ${avoidrem}
/call AvoidINIRemove "${avoidrem}"
/varset avoidrem
}
/if (${PauseFlag}==1) {
/delay 1
/doevents AddAvoid
/doevents RemoveAvoid
/goto :Loop
}
/if (${TargetUpNext}<=0) /if (!${Target.ID}) {
/call GetTarget
|/delay 2
}
/if (${TargetUpNext}>0) /if (${Target.ID}) {
/echo User Selected Target or Aggroed while running
/varset TargetUpNext 0
}
/if (${Target.Distance}>1000) /if (${Target.PctHPs}<=50) {
/echo Target Warped... Getting a new target; id was ${Target.ID}
/cleanup
/call GetTarget
/delay 2
}
/if (${HealSong}) /if (${Me.PctHPs}<${HealthMin}) {
/if (${Songs[1]}!=${HealSong}) {
/echo Healing On - Health: ${Me.PctHPs}% to ${HealthMax}%
/varset Songs[1] ${HealSong}
}
}
/if (${HealSong}) /if (${Me.PctHPs}>=${HealthMax}) {
/if (${Songs[1]}!=${OrigSong}) {
/echo Healing Off
/varset Songs[1] ${OrigSong}
}
}
|/delay 2
/if (${SeloSong}) /if (!${Me.Casting.ID}) /if (!${Me.Buff[$Me.Gem[${SeloSong}].Name].Duration}) /varset SongTimer 1
/if (${SongTimer}>0) /if (!${Me.Casting.ID}) /call SongFailed
/call Circ
/delay 1
/doevents
|/delay 1
/goto :Loop
/return
Sub Event_Timer(string TimerName)
/if (${String[${TimerName}].Equal[SongTimer]}) {
| ${Me.Buff[${Me.Gem[4]}].ID}
/if (${SeloSong}) /if (!${Me.Buff[${Me.Gem[${SeloSong}]}].ID}) {
/echo Selos not up!!!
/stopsong
/cast ${SeloSong}
/varset PrevSong 0
/varset SongTimer 30
/call Circ
/doevents
/return
}
| ${Me.Buff[${Me.Gem[4].Name}].Duration}<=6) {
/if (${SeloSong}) /if (${Me.Buff[${Me.Gem[${SeloSong}].Name}].Duration}<=6) {
/echo Selos about to die
/stopsong
/cast ${SeloSong}
/varset PrevSong 0
/varset SongTimer 30
/call Circ
/doevents
/return
}
/delay 2
/stopsong
/echo ${CurSong} casting ${Songs[${CurSong}]}
/cast ${Songs[${CurSong}]}
/varset PrevSong ${CurSong}
/varcalc CurSong ${CurSong}+1
/if (${CurSong}>${nSongs}) /varset CurSong 1
/varset SongTimer 30
/call Circ
/doevents
}
/return
Sub Circ
/declare CirX local
/declare CirY local
/call CheckObst
/if (${Target.ID}) {
/varset CirX ${Target.Y}
/varset CirY ${Target.X}
} else {
/if (${TargetUpNext}!=0) {
/varset CirX ${Spawn[ID ${TargetUpNext}].Y}
/varset CirY ${Spawn[ID ${TargetUpNext}].X}
/if (${Spawn[ID ${TargetUpNext}].Distance}<=${Math.Calc[${CirR}*2]}) {
/if (${Target.ID}) {
/if (${Target.ID}!=${TargetUpNext}) {
/target id ${TargetUpNext}
}
} else {
/target id ${TargetUpNext}
}
/varset TargetUpNext 0
}
}
}
/if (${Math.Distance[${CirX},${CirY}]}<${Math.Calc[${CirR}/2]}) {
/face heading ${Math.Calc[${Heading[${CirX},${CirY}].DegreesCCW}+180]}
} else {
/face heading ${Math.Calc[${Heading[${CirX},${CirY}].DegreesCCW}+${Math.Calc[90*${CirR}/${Math.Distance[${CirX},${CirY}]}]}]}
}
/return
Sub SongFailed
/if (!${PrevSong}) {
/varset SongTimer 1
/return
}
/varset CurSong ${PrevSong}
/varset SongTimer 1
/return
Sub Event_NeedTarget
/if (${TargetUpNext}<=0) /call GetTarget
/return
Sub Event_Died
/delay 10
/sit
/delay 10
/camp desktop
/return
Sub Event_Exp
/varset AAExp ${Math.Calc[${Me.AAExp}-${AAExp}]}
/varset Exper ${Math.Calc[${Me.Exp}-${Exper}]}
/echo EXP: ${Exper}:${Me.PctExp}% - AAXP: ${AAExp}:${Me.AAExp}% - ${Math.Calc[${Macro.RunTime}/60]} minutes
/varset Exper ${Me.Exp}
/varset AAExp ${Me.AAExp}
/if (${TargetUpNext}==0) /if (${Target.ID}==0) /call GetTarget
/return
Sub GetTarget
/declare LastMobID int local 0
/declare FirstMobID int local 0
/declare MobID int local 0
/declare SRadius int local
/varset MobID ${Spawn[npc radius ${Math.Calc[${CirR}*2]}].ID}
/varset FirstMobID ${MobID}
/echo MobID ${MobID}
:CheckAggrodMobs
/if (${MobID}!=0) {
/if (${Spawn[ID ${MobID}].Speed}>100) {
/call AvoidTargets ${MobID}
/if (${Macro.Return}==1) {
/target id ${MobID}
/echo Kiting aggro'd mob: ${Target.CleanName}
/return
}
}
/varset LastMobID ${MobID}
/varset MobID ${Spawn[npc id ${LastMobID} radius ${Math.Calc[${CirR}*2]} next].ID}
/if (${FirstMobID}==${MobID}) {
/goto :NoAggrodMobs
}
/goto :CheckAggrodMobs
:NoAggrodMobs
}
/echo no aggro'd mobs found
/varset MobID 0
/varset FirstMobID 0
/varset LastMobID 0
/alert clear 1
| a clear alert and noalert don't mix
/alert add 1 npc this_is_bogus
/for SRadius 100 to 10000 step 100
/if (${MobID}==0) {
/varset MobID ${Spawn[noalert 1 npc range ${DBLevel} ${Me.Level} loc ${RubberX} ${RubberY} radius ${SRadius}].ID}
/varset FirstMobID ${MobID}
} else {
/varset LastMobID ${MobID}
/varset MobID ${Spawn[noalert 1 npc range ${DBLevel} ${Me.Level} loc ${RubberX} ${RubberY} radius ${SRadius}].ID}
/if (${FirstMobID}==${MobID}) {
/next SRadius
}
}
/if (${MobID}!=0) {
/call AvoidTargets ${MobID}
/if (${Macro.Return}==1) {
/echo not avoiding ${Spawn[ID ${MobID}].CleanName}
/goto :Done
} else {
/alert add 1 npc ${Spawn[ID ${MobID}].CleanName}
}
}
/next SRadius
/varset MobID ${Spawn[npc]}
/echo No mobs found, action required!
/beep
/beep
/beep
/beep
:Done
/varset TargetUpNext ${MobID}
/echo Next: ${Spawn[ID ${MobID}].Level} ${Spawn[ID ${MobID}].CleanName} - Distance: ${Spawn[ID ${MobID}].Distance}
/return
|#############################################################################
Sub AvoidTargets(int TempMobID)
/declare Element int local 1
:AvoidCheckLoop
/if (${AvoidList[${Element}].Equal[UNDEFINED-ARRAY-ELEMENT]}) {
/return 1
}
/if (${AvoidList[${Element}].Equal[${Spawn[ID ${TempMobID}].CleanName}]}) {
/echo AVOIDING ${AvoidList[${Element}]}
/return 0
}
/varcalc Element ${Element}+1
/goto :AvoidCheckLoop
/return 1
|#############################################################################
Sub AvoidINIRemove(string RemoveName)
/declare TempElements local 0
/declare TempVar int local 0
/declare TempItem string local
:RemCheckLoop
/varset TempItem ${Ini[AvoidList.ini,Avoid,${TempVar},NOTFOUND]}
/if (${TempItem.Equal[NULL]}) {
| no file
/goto :RemFoundInArray
}
/if (${TempItem.Equal[NOTFOUND]}) {
/echo ${RemoveName} not in AvoidList.ini
/goto :RemFoundInArray
}
/if (${RemoveName.Equal[${TempItem}]}) {
/varset AvoidList[${Math.Calc[${TempVar}+1]}] Empty
/echo ${RemoveName} removed from AvoidList.ini
/ini AvoidList.ini Avoid ${TempVar} Empty
:VerifyRemoval
/if (!${Ini[AvoidList.ini,Avoid,${TempVar},NOTFOUND].Equal[Empty]}) {
/echo verify removal unsuccessful
/goto :VerifyRemoval
}
/goto :RemFoundInArray
}
/varcalc TempVar ${TempVar}+1
/goto :RemCheckLoop
:RemFoundInArray
/return
|#############################################################################
Sub AvoidINIAdd(string AddName)
/declare TempElements int local 0
/declare TempVar int local 1
/declare TempItem string local
/echo AvoidINIAdd ${AddName}
:AddCheckLoop
/varset TempItem ${Ini[AvoidList.ini,Avoid,${TempVar},NOTFOUND]}
/if (${TempItem.Equal[NULL]}) {
| no file
/goto :FoundInArray
}
/if (${TempItem.Equal[NOTFOUND]}) {
/varset AvoidList[${Math.Calc[${TempVar}+1]}] ${AddName}
/goto :AddItem
}
/if (${TempItem.Equal[${AddName}]}) {
/echo ${AddName} already in AvoidList.ini
/goto :FoundInArray
}
/if (${TempItem.Equal[Empty]}) {
/varset AvoidList[${Math.Calc[${TempVar}+1]}] ${AddName}
/goto :AddItem
}
/varcalc TempVar ${TempVar}+1
/goto :AddCheckLoop
:AddItem
/ini AvoidList.ini Avoid ${TempVar} "${AddName}"
:VerifyAdd
/if (!${Ini[AvoidList.ini,Avoid,${TempVar},NOTFOUND].Equal[${AddName}]}) {
/echo verify addition unsuccessful
/goto :VerifyAdd
}
/echo ${AddName} added to AvoidList.ini
:FoundInArray
/return
|#############################################################################
Sub AvoidINILoad
/declare TempItem string local
/declare AvoidItemNum int local 0
:LoadAvoidLoop
/varset TempItem ${Ini[AvoidList.ini,Avoid,${AvoidItemNum},NOTFOUND]}
/if (${TempItem.Equal[NULL]}) {
/goto :DoneLoading
}
/if (${TempItem.Equal[NOTFOUND]}) {
/goto :DoneLoading
}
| note: indexing starts at 1 not 0
/echo adding ${TempItem} to avoid list at ${Math.Calc[${AvoidItemNum}+1].Int}
/varset AvoidList[${Math.Calc[${AvoidItemNum}+1]}] ${TempItem}
/varcalc AvoidItemNum ${AvoidItemNum}+1
/goto :LoadAvoidLoop
:DoneLoading
/return
|#############################################################################
Sub Event_AddAvoid(string EvtText)
/if (${EvtText.Mid[6,10].Equal[avoid add ]}) {
/call AvoidINIAdd "${EvtText.Mid[16,${Math.Calc[${EvtText.Length}-16]}]}"
}
/return
Sub Event_RemoveAvoid(EvtText)
/if (${EvtText.Mid[6,13].Equal[avoid remove ]}) {
/call AvoidINIRemove "${EvtText.Mid[19,${Math.Calc[${EvtText.Length}-19]}]}"
}
/return
Sub Event_Caster(string CastText)
/declare CasterID int local
/varset CasterID ${Spawn[${CastText.Left[${Math.Calc[${String[${CastText}].Length}-24]}]}].ID}
/if (!${Spawn[ID ${CasterID}].Type.Equal[NPC]}) /return
/if (${Target.ID}==${CasterID}) /return
/if (${Spawn[ID ${CasterID}].Distance}<=${Math.Calc[${CirR}*2]}) {
/target id ${CasterID}
/echo Targeting Caster: ${Target.CleanName}
}
/return
Sub Event_Tell
/beep
/mp3 play
/return
sub CheckObst
/if (${MyXLOC}==${Me.X}) /if (${MyYLOC}==${Me.Y}) {
/echo STUCK!!!
/call HitObst 1
}
/varset MyXLOC ${Me.X}
/varset MyYLOC ${Me.Y}
/return
sub HitObst
/keypress up
/keypress down hold
/if (${Math.Rand[99]}>50) {
/delay 2
/keypress down
/keypress Right hold
/delay 2
/delay ${Param0}
/keypress Right
} else {
/delay 2
/keypress down
/keypress Left hold
/delay 2
/delay ${Param0}
/keypress Left
}
/keypress down
/keypress Right
/keypress Left
/keypress up
/keypress num_lock
/return



