|- Chanthunter.mac
#Chat tell
#Event Tell "#*#tells you, '#*#"
#Event NeedTarget "You must first select a target for this spell!"
#Event OORTarget "Your target is out of range, get closer!"
#Event OORCorpse "You are too far away to loot that corpse."
#Event Died "Returning to home point, please wait..."
#Event LevelUp "#*#Welcome to Level#*#"
#Event Exp "You gain #*#experience!!"
#Event AAPoint "You have gained an ability point!#*#"
#Event Caster "#*#begins to cast a spell."
#Event Selos "You slow down."
#Event Aggro "#*# YOU for #*# points of damage."
#Event Aggro "#*# tries to hit YOU, #*#"
|#############################################################################
Sub Main()
/declare ScriptName string outer ABE
/declare vKiteRadius int outer ${Ini[${ScriptName}.ini,${Zone.ShortName},KiteRadius]}
/declare vKiteRadiusReset int outer ${Ini[${ScriptName}.ini,${Zone.ShortName},KiteRadiusReset]}
/declare vMaxKiteRadius int outer ${Ini[${ScriptName}.ini,${Zone.ShortName},MaxHuntRadius]}
/declare tMinTargetZ int outer -400
/declare tMaxTargetZ int outer 400
/declare tNextTargetID int outer 0
/declare tSnareTarget int outer 0
/declare vFailMax int outer 3
/declare vFailCount int outer 0
/declare tInvalidTargetID int outer 0
/declare locMyX int outer 0
/declare locMyY int outer 0
/declare tmSongTimer timer outer 1
/declare SkipCamp2 int outer 1
|==========================================================================
| Experience Tracking
|==========================================================================
/declare expAAStart float outer ${Me.PctAAExp}
/declare expAATotal float outer 0
/declare expStart float outer ${Me.PctExp}
/declare expTotal float outer 0
|==========================================================================
| Automatically camp out at a certain time (24hr format)
|==========================================================================
/declare AutoCamp int outer 0
/declare AutoCampHR int outer 4
/declare AutoCampMIN int outer 30
|==========================================================================
| Personal status variables
|==========================================================================
/declare meDead int outer 0
/declare meAFK int outer 1
/declare HealthMin outer 79
/declare HealthMax outer 95
/declare HealthON int outer 0
|==========================================================================
| Startup Anchor (pull-to) point
|==========================================================================
/declare AnchorX float outer
/declare AnchorY float outer
/varset AnchorX ${Ini[${ScriptName}.ini,${Zone.ShortName},AnchorX]}
/varset AnchorY ${Ini[${ScriptName}.ini,${Zone.ShortName},AnchorY]}
/popup Welcome to ${ScriptName}
/echo ${ScriptName}: Startup Anchor dropped at ${AnchorX},${AnchorY}
|/loadspells "Kiting"
|==========================================================================
| Edit this accordingly
|==========================================================================
/lootnodrop never
:Loop
/call GMCheck
/if (${Me.PctHPs}<18) {
/i say ${Time.Time12} - Camping to avoid death! (Current HP: ${Me.PctHPs}%)
/i say Current Location: ${Me.X}X ${Me.Y}Y
/keypress INSTANT_CAMP
}
/if (${meDead}) {
/camp desktop
/mqlog I died, wtf. Camping to save rez timer
}
/if (${tNextTargetID}<=0) /if (!${Target.ID}) {
/call AcquireTarget
}
/if (${tNextTargetID}>0) /if (${Target.ID}&&${Target.Type.Equal[NPC]}) {
|/echo ${ScriptName}: User Selected Target or Aggro'd while running
/varset tNextTargetID 0
}
/if (${Target.Distance}>${vMaxKiteRadius}) {
/if ( (${tNextTargetID}==0)&&(${Target.PctHPs}<7) ) {
/echo tNextTargetID: ${tNextTargetID}
/echo ${ScriptName}: Handling runner...
|/circle off
|/stick behind
}
|------------------------------------------------------------
| Runner or target warped, let him go
|------------------------------------------------------------
/if (${tNextTargetID}>0) {
/echo ${ScriptName}: Target Warped or beyond MaxRadius, getting a new target; old id was ${Target.ID}
/varset tInvalidTargetID ${Target.ID}
/call ResetSub
/call AcquireTarget
}
}
|------------------------------------------------------------
| snare song if mob hp under 21%
|------------------------------------------------------------
/if ((${Bool[${Ini[${ScriptName}.ini,${Zone.ShortName},SnareRunner]}]})&&(${Target.PctHPs}<(${Ini[${ScriptName}.ini,${Zone.ShortName},SnarePercent,1]}))&&(${Target.Type.Equal[NPC]}) ) {
/if (!${tSnareTarget}) {
/twist 3 4 5 6
/echo ${ScriptName}: Snaring...
/varset tSnareTarget 1
}
}
/if ( (${Me.PctHPs}<${HealthMin}) || (${Me.PctHPs}<${HealthMax}) ) {
/if ( (!${HealthON}) && (${Me.Buff[Cantata of Replenishment].Duration}<3) ) {
/echo ${ScriptName}: Healing ON: ${Me.PctHPs} to ${HealthMax}
/squelch /twist 1
/varset HealthON 1
}
}
/if (${Me.PctHPs}>=${HealthMax}) {
/if (${HealthON}) {
/echo ${ScriptName}: Healing OFF
/varset HealthON 0
}
/if ( (${Twist.List}==1)&&(${Target.ID}) ) {
/twist 4 5 6 7
}
}
/doevents
| Put your Selo's equivalent here...
/if (!${Me.Buff[$Me.Gem[2].Name].Duration}) /varset tmSongTimer 1
/goto :Loop
/return
|--------------------------------------------------------------------------------
|SUB: Loots mob and saves items found in ${ScriptName}.ini
|--------------------------------------------------------------------------------
Sub QuickLoot
/echo ${ScriptName}: Checking for corpses to cleanup
/squelch /target npc corpse radius ${Int[${vMaxKiteRadius}]}
/if (${Target.Type.Equal[Corpse]}) {
/echo ${ScriptName}: Looting corpse...
/call MoveToLoc ${Target.Y} ${Target.X}
/loot
/delay 5
/if (!${Corpse.Items}) {
/notify LootWnd DoneButton leftmouseup
/return
} else {
/declare LootSlot int local
/declare ItemNotFound int local -1
/declare KeepLootItem int local 0
/declare CorpseItemCount int local 0
/varset CorpseItemCount ${Corpse.Items}
/for LootSlot 1 to ${CorpseItemCount}
/itemnotify loot${LootSlot} leftmouseup
/delay 5
/varset KeepLootItem ${Ini[${ScriptName}.ini,LootList,${Cursor.Name},${ItemNotFound}]}
/delay 5
/if (${KeepLootItem}==${ItemNotFound}) {
/ini "${ScriptName}.ini" "LootList" "${Cursor.Name}" "1"
/varset KeepLootItem 1
}
/if (${KeepLootItem}==1) {
:InventoryItem
/autoinventory
/if (${Cursor.ID}) /goto:InventoryItem
} else {
|TODO: check to make sure you're not destroying your own gear!
/if (${Cursor.ID}) {
/echo ${ScriptName}: DESTROYING a ${Cursor.Name}... (inventory full?)
/destroy
/delay 5
}
}
/next LootSlot
/notify LootWnd DoneButton leftmouseup
}
/delay 2
/doevents
}
/call CheckAnchor
/return
|-----------------------------------------------------------------------------
|SUB: Acquire Target
|-----------------------------------------------------------------------------
Sub AcquireTarget
/declare RV_CurrentRadius int local
/declare RV_TargetSub int local
/declare iCamp2 int local
:Acquire
|-------------------------------------------------------------------------
| Check mobs inside current radius then increase by 50 until vMaxKiteRadius
|-------------------------------------------------------------------------
/for RV_CurrentRadius 10 to ${vMaxKiteRadius} step 20
/squelch /mapfilter CastRadius ${RV_CurrentRadius}
/squelch /target radius ${RV_CurrentRadius} notid ${tInvalidTargetID} npc
/if ( ${Target.Type.Equal[NPC]} ) {
/varset tSnareTarget 0
/circle on ${vKiteRadius} ${AnchorY} ${AnchorX}
/if (${Me.Speed}==0) {
/keypress num_lock
}
/if (${Int[${Target.Z}]}<${tMinTargetZ}) {
/echo ${ScriptName}: Mob is BELOW Min Z Range, picking another...
/varset tInvalidTargetID ${Target.ID}
/call ResetSub
/goto :Acquire
}
/if (${Int[${Target.Z}]}>${tMaxTargetZ}) {
/echo ${ScriptName}: Mob is ABOVE Min Z Range, picking another...
/varset tInvalidTargetID ${Target.ID}
/call ResetSub
/goto :Acquire
}
/if (${String[${Target.ConColor}].Equal["GREEN"]}) {
/if (${Target.Speed}>0) {
/echo ${ScriptName}: Green con in radius, clearing it..
} else {
/varset tInvalidTargetID ${Target.ID}
/call ResetSub
/goto :Acquire
}
}
/if (${String[${Target.ConColor}].Equal["RED"]}) {
/varset tInvalidTargetID ${Target.ID}
/call ResetSub
/goto :Acquire
}
/varset RV_CurrentRadius 10
/varset vFailCount 0
/popup Acquired ${Target.CleanName} at range ${Int[${Target.Distance}]}
/if (!${Twist.Twisting}&&(${Target.ID})) {
/twist 4 5 6 7
}
/if ( (${Twist.Twisting}==1)&&(${Target.ID}) ) {
/twist 4 5 6 7
}
/return
}
/delay 5
/next RV_CurrentRadius
/if (!${Target.ID}) {
/varcalc vFailCount ${vFailCount}+1
|/echo ${ScriptName}: Failed to Acquire Target in Range ${vMaxKiteRadius} ${vFailCount} Time(s)
/doevents chat
/call CheckAnchor
| Stop auto-running
/if (${Me.Speed}>0) {
/keypress num_lock
/keypress forward
/keypress back
}
/if (${vFailCount}>=${vFailMax}) {
/if (${Twist.Twisting}) {
/twist off
}
|/circle off
/call CheckAnchor
/call QuickLoot
/echo ${ScriptName}: Checking Autologoff...
/if (${AutoCamp}) {
/call CheckAnchor
| Time.Hour is returned in 24hr format
/if ( (${Time.Hour}>=${AutoCampHR}) && (${Time.Minute}>=${AutoCampMIN}) ) {
|/echo ${ScriptName}: Alarm Clock: Camping at ${Time.Time24}
/i say Alarm Clock: Camping at ${Time.Time24}
|/echo ${ScriptName}: Current Location: ${Me.X}X ${Me.Y}Y
/varset AutoCamp 0
|/echo ${ScriptName}: remember to change camp time HR~
/camp
/delay 30s
/return
} else {
/echo ${ScriptName}: Not time to Autologoff
}
}
|/echo ${ScriptName}: Waiting for Respawns...
/varset vFailCount 0
/echo ${ScriptName}: Idling...
/doevents
/delay 10s
}
/goto :Acquire
}
/return
|-----------------------------------------------------------------------------
|SUB: MoveToLoc
| This simply moves the player to within 1 unit of
| the requested location, while avoiding obstacles
|-----------------------------------------------------------------------------
Sub MoveToLoc(MoveToY, MoveToX)
/if (${MoveToY}==NULL) {
/echo ${ScriptName}: MoveToLoc Y location is NULL, not moving
/return
}
/if (${MoveToX}==NULL) {
/echo ${ScriptName}: MoveToLoc X location is NULL, not moving
/return
}
|/echo ${ScriptName}: Moving to Location: ${MoveToY}, ${MoveToX}.
|/echo ${ScriptName}: Distance: ${Math.Distance[${Me.Y},${Me.X}:${MoveToY},${MoveToX}]}
/declare FailureTimer timer local 0
/declare running int local
/declare MaxSpeed int local
/declare StopDistance int local
/declare distanceNow float local
/declare distanceBefore float local
/declare distanceModifier int local
/varset running 0
/declare distanceTimer timer 15
/varset distanceBefore ${Math.Distance[${Me.Y},${Me.X}:${MoveToY},${MoveToX}]}
/varset distanceModifier 1
/varset MaxSpeed 0
:moveToLocation
/if (${Me.Speed}>=${MaxSpeed}) /varset MaxSpeed ${Me.Speed}
/if (${MaxSpeed}<=166) {
/varset StopDistance 3
} else {
/varset StopDistance 10
}
/face fast nolook loc ${MoveToY},${MoveToX}
/if (${Math.Distance[${Me.Y},${Me.X}:${MoveToY},${MoveToX}]}<${StopDistance}) {
/keypress forward
/return
}
/if (${distanceTimer}==0) {
/if (${Me.Sneaking}) {
/varset distanceModifier 2
} else {
/varset distanceModifier 1
}
/varset distanceNow ${Math.Distance[${Me.Y},${Me.X}:${MoveToY},${MoveToX}]}
/if (${Math.Calc[${distanceBefore}-${distanceNow}]}<${Math.Calc[10/${distanceModifier}]}) {
/if (${FailureTimer}==0) {
/varset FailureTimer 600
}
/call HitObstacle
}
/varset distanceBefore ${Math.Distance[${Me.Y},${Me.X}:${MoveToY},${MoveToX}]}
/varset distanceTimer 15
}
/if (${running}==0) {
/keypress forward
/if (${Math.Distance[${Me.Y},${Me.X}:${MoveToY},${MoveToX}]}>${StopDistance}) {
/varset running 1
/keypress forward hold
}
} else {
/if (${Math.Distance[${Me.Y},${Me.X}:${MoveToY},${MoveToX}]}<${StopDistance}) {
/varset running 0
/keypress forward
}
}
/goto :moveToLocation
/return
|--------------------------------------------------------------------------------
|SUB: CheckObstacle
| Checks to see if we may have bumped into something that is stopping us
|--------------------------------------------------------------------------------
Sub CheckObstacle
/varset locMyX ${Me.X}
/varset locMyY ${Me.Y}
/if (${locMyX}==${Me.X} && ${locMyY}==${Me.Y}) {
/call HitObstacle
}
/return
|--------------------------------------------------------------------------------
|SUB: Hit Obstacle (Obstacle Avoidance)
|--------------------------------------------------------------------------------
Sub HitObstacle
/echo ${ScriptName}: Obstacle hit, moving around it...
/keypress forward
/keypress back hold
/delay 2
/keypress back
/if (${Math.Rand[100]}+1>50) {
/keypress strafe_right hold
} else {
/keypress strafe_left hold
}
/delay 3
/keypress strafe_right
/keypress strafe_left
/keypress forward hold
/return
|--------------------------------------------------------------------------------
|SUB: Reset Targeting variables
|--------------------------------------------------------------------------------
Sub ResetSub
/keypress esc
/keypress esc
/keypress esc
/varset vFailCount 0
/return
|--------------------------------------------------------------------------------
|SUB: CheckAnchor
|--------------------------------------------------------------------------------
Sub CheckAnchor
| Standing on anchor point?
/if ( ${Math.Distance[${Me.Y},${Me.X}:${AnchorY},${AnchorX}]}==0 ) /return
| Outside vMaxKiteRadius?
/if ( ${Math.Distance[${Me.Y},${Me.X}:${AnchorY},${AnchorX}]} > ${Math.Calc[${vMaxKiteRadius}*1.25]} ) {
/echo ${ScriptName}: Outside MaxRadius
/call MoveToLoc ${AnchorY} ${AnchorX}
}
/if ( ${Math.Distance[${Me.Y},${Me.X}:${AnchorY},${AnchorX}]} > 5 ) {
/call MoveToLoc ${AnchorY} ${AnchorX}
}
/return
|--------------------------------------------------------------------------------
|SUB: Check for adds
|--------------------------------------------------------------------------------
Sub CheckAdds
/varset tNextTargetID ${Spawn[npc loc ${Me.X} ${Me.Y} radius ${Math.Calc[${vKiteRadius}*1.50]}].ID}
/if (${tNextTargetID}==0) /if (${Target.ID}==0) {
/echo ${ScriptName}: Checking for adds...
/varset tNextTargetID ${Spawn[npc loc ${Me.X} ${Me.Y} radius ${Math.Calc[${vKiteRadius}*1.25]}].ID}
/target ${Spawn[${tNextTargetID}]}
/echo ${ScriptName}: UPNEXT: ${tNextTargetID} ID: ${Target.ID}
/if (${tNextTargetID}==0) /if (!${Target.ID}) {
/if (${Twist.Twisting}) {
/twist off
}
/if (${Me.Speed}>0) {
/keypress num_lock
/keypress forward
/keypress back
}
/call QuickLoot
}
} else {
/call AcquireTarget
}
/return
|--------------------------------------------------------------------------------
|SUB: GM Check
|--------------------------------------------------------------------------------
Sub GMCheck
/if (${Spawn[gm].ID}) {
/beep
/beep
/beep
/mqlog ${Time.Time12} - GM has entered the zone, ending the macro.
/mqlog Current Location: ${Me.X}X ${Me.Y}Y
/endmacro
}
/return
|--------------------------------------------------------------------------------
|SUB: Stops auto-running, sits, and camps out
|--------------------------------------------------------------------------------
Sub Camp
/if (${Me.Speed}>0) {
/keypress num_lock
}
/call CheckAnchor
/sit
/delay 5s
/camp
/return
|################################################################################
|
| EVENT HANDLERS
|
|################################################################################
|--------------------------------------------------------------------------------
|EVENT SUB: Handles when a casting mob was encountered within your area
| and retargets accordingly
|--------------------------------------------------------------------------------
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[${vKiteRadius}*2]}) {
/target id ${CasterID}
/echo ${ScriptName}: Targeting Caster: ${Target.CleanName}
}
/return
|--------------------------------------------------------------------------------
|EVENT SUB: No target in que, get a new one
|--------------------------------------------------------------------------------
Sub Event_NeedTarget
/if (${tNextTargetID}==0) /if (${Target.ID}==0) {
/echo ${ScriptName}: Need a target...
/varset tNextTargetID ${Spawn[npc loc ${Me.X} ${Me.Y} radius ${vKiteRadius}].ID}
} else {
/call AcquireTarget
}
/return
|--------------------------------------------------------------------------------
|EVENT SUB: Got hit, make sure you're moving
|--------------------------------------------------------------------------------
Sub Event_Aggro
/echo Aggro event triggered
/if (${Me.Speed}==0) {
/keypress num_lock
}
/return
|--------------------------------------------------------------------------------
|EVENT SUB: Target Out of Range
|--------------------------------------------------------------------------------
Sub Event_OORTarget
/if (${Target.Distance}<${vMaxKiteRadius}) {
|
| Only chase if hps within reasonable range
|
/if ( (${Me.PctHPs}>${HealthMin})&&(${Target.PctHPs}<50) ) {
/echo ${ScriptName}: Chasing...
/call MoveToLoc ${Target.Y} ${Target.X}
/stick behind
}
/if ( (${Me.PctHPs}>${HealthMin})&&(${Target.PctHPs}>50) ) {
/echo ${ScriptName}: Pulling...
/call MoveToLoc ${Target.Y} ${Target.X}
/call MoveToLoc ${AnchorY} ${AnchorX}
/echo ${ScriptName}: Speed Check after pull...
/keypress num_lock
}
}
/return
|--------------------------------------------------------------------------------
|EVENT SUB: Corpse Out of Range
|--------------------------------------------------------------------------------
Sub Event_OORCorpse
/if (${Target.Type.Equal[Corpse]}) {
/face
/call MoveToLoc ${Target.Y} ${Target.X}
/call QuickLoot
}
/return
|--------------------------------------------------------------------------------
|EVENT SUB: You died, sit and camp
|--------------------------------------------------------------------------------
Sub Event_Died
/beep
/beep
/varset meDead 1
/return
|--------------------------------------------------------------------------------
|EVENT SUB: Level up (aka "DING")
|--------------------------------------------------------------------------------
Sub Event_LevelUp
/varset LevelFlag 1
/mqlog Level'd up to: ${Me.Level} at ${Time.Time12} - ${Time.Date}
/varset expTotal 0
/varset expAATotal 0
/return
|--------------------------------------------------------------------------------
|EVENT SUB: Update exp timer and counter, then get next target
|--------------------------------------------------------------------------------
Sub Event_Exp
/varcalc expTotal ${Me.PctExp}-${expStart}
/varcalc expAATotal ${Me.PctAAExp}-${expAAStart}
/call CheckAdds
/return
|--------------------------------------------------------------------------------
|EVENT SUB: Timer handlers for songs (recast, etc)
|--------------------------------------------------------------------------------
Sub Event_Timer(string TimerName)
/if (${String[${TimerName}].Equal[tmSongTimer]}) {
|------------------------------------------------------------------------
|Refresh SeloSong if it's fading & we're outside
|------------------------------------------------------------------------
/if (${Me.Buff[${Me.Gem[2].Name}].Duration}<=6) /if (!${Zone.Type}==1) {
/squelch /twist once 2
/varset tmSongTimer 30
/delay 5s
/doevents
/return
}
|/echo ${ScriptName}: Timer Fired: ${TimerName} - ${Time.Time12}
}
/return
|--------------------------------------------------------------------------------
|EVENT SUB: Refresh selo's if it wears off
|--------------------------------------------------------------------------------
Sub Event_Selos
/if (${Me.Buff[${Me.Gem[2].Name}].Duration}<=6) {
/squelch /twist once 2
/return
}
/return
|--------------------------------------------------------------------------------
|EVENT SUB: what to do when you get a tell
|--------------------------------------------------------------------------------
Sub Event_ChatTell(string line,string chatSender,string chatText)
/call Event_Chat "tell" "${chatSender}" "${chatText}"
/return
|--------------------------------------------------------------------------------
|EVENT SUB: handle incoming tells and relay
|--------------------------------------------------------------------------------
Sub Event_Chat(string ChatType,string ChatSender,string ChatText)
/if (${ChatType.Equal[TELL]}) {
/if (${Spawn[npc ${ChatSender} radius 100].ID}) /return
}
/return