xpbeast.mac - Tuna's automated beastlord XP gain

A forum for you to dump all the macros you create, allowing users to use, modify, and comment on your work.

Moderator: MacroQuest Developers

gillgian
orc pawn
orc pawn
Posts: 18
Joined: Tue Mar 16, 2004 3:09 pm

Post by gillgian » Tue Mar 23, 2004 12:27 pm

Thanks for sharing the script with use beastlords.

Tindal
orc pawn
orc pawn
Posts: 10
Joined: Thu Mar 18, 2004 11:45 am

Post by Tindal » Tue Mar 23, 2004 1:58 pm

Hey Kosodo, i don't suppose you would PM me the modified code for the mage?

El
a ghoul
a ghoul
Posts: 108
Joined: Mon Dec 29, 2003 12:34 pm

Post by El » Tue Mar 23, 2004 5:31 pm

I wouldn't mind getting that either, Kosodo.

kasodo
a lesser mummy
a lesser mummy
Posts: 64
Joined: Fri Feb 13, 2004 9:41 am

mage modified version

Post by kasodo » Tue Mar 23, 2004 9:59 pm

as of the recent patch this mac ctd's when it finshes buffing and searches for mobs to pull any ideas Tuna?

[40oz]
a hill giant
a hill giant
Posts: 156
Joined: Tue Nov 12, 2002 12:14 pm

Post by [40oz] » Wed Mar 24, 2004 2:06 am

That would have to do with offset and/or struct issues breaking commands the macro uses. Wait until MQ2 is stable.

Tindal
orc pawn
orc pawn
Posts: 10
Joined: Thu Mar 18, 2004 11:45 am

Post by Tindal » Wed Mar 24, 2004 10:29 pm

Has anyone been able to get this macro working with the new patch yet?

kasodo
a lesser mummy
a lesser mummy
Posts: 64
Joined: Fri Feb 13, 2004 9:41 am

some changes to my xpMage version

Post by kasodo » Wed Mar 24, 2004 10:48 pm

If you are interested in seeing my changes to the xpMage I modified from his bst script ill gladly send it to you works fully functional with all the EQW nerfs as well went ahead and modified his occutils as well with /keypress and no more /sendkey or /press

Tindal
orc pawn
orc pawn
Posts: 10
Joined: Thu Mar 18, 2004 11:45 am

Post by Tindal » Wed Mar 24, 2004 11:24 pm

I would be very grateful Kasodo.

Would you mind sharing what you altered in the script so it wouldn't CTD after the 3/23 patch?

BrainDozer
a lesser mummy
a lesser mummy
Posts: 45
Joined: Sun Aug 03, 2003 2:10 pm

Post by BrainDozer » Thu Mar 25, 2004 3:42 am

This script sure would be easy to modify to command a genbot bot.

kasodo
a lesser mummy
a lesser mummy
Posts: 64
Joined: Fri Feb 13, 2004 9:41 am

mage version and /sendkey /press fixes

Post by kasodo » Thu Mar 25, 2004 11:33 am

Soon as MQ is fixed again I will post my code for the mage version I did. Pretty much it pulls with Malo uses /pet hold til mob hits you then sends pet, backs up 50 units until mob is dead, loots, runs back to pull spot and pulls again

I didn't comment anything and you will have to check the start and safe locs etc etc.

It was geared towards a 65 mage with ER IV to pull non stop in FG. And yes BD I added some stuff to command a genbot bot for slows and stuff. I will comment those out so they can be seen but wont interfere with regular script.

Narces
a lesser mummy
a lesser mummy
Posts: 37
Joined: Thu Aug 07, 2003 7:50 am

Post by Narces » Thu Mar 25, 2004 1:55 pm

I see this being nothing but trouble. Its one thing to post a script on how to kill a mob, and its another to create one entirely automated to exp afk. Those of us with the capability to code something similar to this also know enough to avoid trouble, and we usually don't distro the code.

Its like giving a bunch of kids guns with live ammo. Sure, the safety is on it.. but how long until one of them figures out how to turn it off? Or maybe the safety fails and the gun goes off anyway? Who do you blame?

I'd hate to see someone get banned for AFK EXP'n... erm, wait no, I'd enjoy that.. but I would hate to see MQ getting unneeded attention from SOE because someone decided it would be cool to post something like this. This is a bad idea..

:(

kasodo
a lesser mummy
a lesser mummy
Posts: 64
Joined: Fri Feb 13, 2004 9:41 am

Mage Version

Post by kasodo » Fri Mar 26, 2004 8:33 pm

Here is the modified version not commented well at all. I replaced the /sendkeys and /presses.

As for the post prior to this you overlook what this script "could" be used for. Say you have a high lvl BST and you want to powerlvl your younger chars... You group up with the bst set the macro going and then play your twink while the bst pulls and kills non stop.

Yes this could be used for the wrong reasons, then again so could MQ this code is perfectly safe to post here. Everytime you load up MQ you run the risk of getting caught.

Sorry it is kind of long....

Code: Select all

|--------------------------------------------------------------
| XPBEAST.MAC
| Author : Tuna
| UPDATED: 2004 Mar 17
| PURPOSE: Automate XP and Alt XP gain in any zone
|
| LONGEST RUN TIME: 6 days, 4 hours nonstop
|
| Bugs: 1: If someone buffs you with something which overwrites
|		one of your own, you will go OOM trying to put your
|		buff back on you.  Might incorporate the "buff timer"
|		logic I use in TPC macro to fix this.
|		2: Movement does not look perfect.  Someone watching
|		could detect it is a bot (assuming they watched for
|		a while).
|		3: Player keeps up buffs even when someone is near.
|		Ideally, beastlord should do *nothing* when a player
|		is near.
|		4: You will announce to the chat channel of choice
|		an XP gain twice per kill.
|		5: This script is VERY processor heavy.  You have
|		been warned!  A 1400mhz machine will drop to about
|		3 frames per second while running this.
|			
| Todo: * Randomize the run spot 
|		* Make a more natural "/face"
|		* Make a more natural run-to.
|		* Pull from multiple camps
|		* Get someone to paypal me for this shit
|--------------------------------------------------------------
#turbo
#include occutils.mac

#chat say

| Change this to wherever you XP
#define ZONE_TO_XP_IN		"Fungus Grove"
| You will also need to search for @@STARTINGLOCS and change
| those values.

| Minimum amount of mana you must have before starting a fight
#define manaMin_toAggro		80

| If bot is not sneaky, he'll pull even when people are near.
| You probably want a sneaky bot, so leave this set to 1.
#define BOT_IS_SNEAKY		0

| Secret phrase for inter-bot chat
#define CONST_SECRETPHRASE "sup :)"

| Change this to a private channel name.
#define CHANNEL_ANNOUNCE	"fraglerok"

| If REQUIRE_PET is 0, you will not summon pets and if the script
| is started without one, you will pull and kill without one.
#define REQUIRE_PET			1

| If nonzero, and you are alone in a group, this will /quit
| immediately.
#define REQUIRE_DUO_PARTNER		1

| If this is set to 1, you will summon food and drink approx once
| per every 2 fights.  Otherwise you will never summon food and
| drink.  I'd like to make this "smarter" by summoning a stack
| of food in response to "You are low on food" but I'm a bit
| lazy about this fix.
#define SUMMON_ORGANICS_AS_NEEDED 0

| Self-explanatory handling of adds:
#define KILL_ANYTHING_THIS_CLOSE_TO_ALLIES 35

| Name of mob killing.  Will not pull anything except this.
| Make sure you change this.  :-p
#define MOB_KILLING			"a small mushroom"

| If you are grouped with a necro, you will send "Medding"
| to the group every so many seconds if you are low on mana.
| This way he can fulfill his destiny as a necromancer and twitch you.
#define timeBetween_manaAnnounce	18s

| Max distance to pull.  I have an extended range item.
#define dist_maxPull 	220

| Spell to pull with.  This is only cast once.
| I use a shitty low level nuke because I only have a shitty
| low level extended range 2 item.  And I'm cheap.
#define sn_Pull		"Malosini"

| Spell to nuke target with.  Right now the bst does not
| need to nuke any, so this goes unused.
#define sn_Nuke		"Sun Vortex"

| Spell to slow target with.
| If you are level 65 and have Revenge you'll change this.
#define sn_Slow		""

| Spell to heal players with.
#define sn_HealPC	""

| Spell to DoT mobs with.
#define sn_DoT		""

| Primary pet heal.  Should be the largest, slowest heal you have.
#define sn_PetHeal	"Planar Renewal"

| Secondary pet heal.  Should take less mana than primary.
| Alternatively, you could put a player heal here but it
| may drain you of mana.  :p
#define sn_PetHeal2	"Planar Renewal"

| Pet proc spell.  Also make sure you change the event triggers
| in this macro to a matching value.
#define sn_PetProc	"Flameshield of Ro"

| Pet haste spell.
#define sn_PetHaste	"Burnout V"

| Pet summon spell.  Put your highest level warder here.
#define sn_PetSummon	"Ward of Xegony"

| Regen buff name.
#define sn_Regen	""


| ===================================================================
| EVENTS
| These events will force subroutines to be called (triggered)
| when they enter your logfile.
|
| VERY IMPORTANT BUG:
| If you have HitsMode set to "number only" for "Me getting hit"
| then this script will break.  Macroquest only sees "119" when
| a mob hits you for 119 in that case.  It needs to see "hits YOU for"
| instead of just the number.
|
|
| ALSO: Make sure you read over the events.  If you change your slow
| to the level 65 one, make sure you also update the SlowWoreOff
| event trigger text, etc.
| ===================================================================
|#event HitsGroupmate ""
|#event RegenRequest ""
|#event PetRegenWoreOff "Your pet's Flameshield of Ro spell has worn off"
#event SlowWoreOff "Your Malosini spell has worn off"
#event GainXP "You gain experience"
#event GainXPParty "You gain party experience"
#event PetIsTaunting "Taunting attacker, Master"
#event concheck " scowls at you"
|#event TargetSlowed ""
#event ImDead "You have been slain by"
#event INuked "staggers as the spirits of frost slam against"
#event YouHaveSlain "You have slain"
|#event PetHasSlain "has been slain by $pet(name)"
|#event PetNuking "$pet(name) begins to cast a spell"
#event WizTellsReady ""
#event ptDS "Your pet's Flameshield of Ro spell has worn off.
#event ptHaste "Your pet's Burnout V spell has worn off."

| You may want to add other HitsMe events for slashing, piercing,
| etc.
#event HitsMe	"bashes YOU for"
#event HitsMe	"kicks YOU for"
#event HitsMe	"hits YOU for"
| =====================================================================
| end events.  Begin MAIN routine
| =====================================================================


Sub Main
	/echo ============================================
	/echo XPBEAST v1.66 : 17 Mar 2004
	/echo *Requires* level 62 BeastLord
	/echo Also REQUIRES: /pet hold
	/echo You *will very likely* die without this AA.
	/echo This macro also assumes (but does not require)
	/echo your beastlord has PARAGON and SPIRIT FRENZY.
	/echo ============================================

	/call SetupGlobals
	/call OUGlobals
	/call AnotherSwapSpot 7
	/call AnotherSwapSpot 8
|	/call AnotherFriendlyPlayer 
|	/call AnotherFriendlyPlayer Yourotherbuddy
|	/call AnotherFriendlyPlayer Someguywhoalwaysxpsnearyou
|	/call AnotherFriendlyPlayer Acultfollower
|	/call AnotherFriendlyPlayer SycophantNumberTwo

	/call AlsoNeedBuff "Shield of Maelin"
|	/call AlsoNeedBuff "Regrowth"
|	/call AlsoNeedBuff "Infusion of Spirit"
	/call AlsoNeedBuff "Xegony's Phantasmal Guard"
|	/call AlsoNeedBuff "Talisman of Jasinth"
|	/call AlsoNeedBuff "Spiritual Vigor"
|	/call AlsoNeedBuff "Celerity"
|	/call AlsoNeedBuff "Stamina"

	| --------
	| Clear out any sticky keys from other macros or players
	| --------
	/keypress CLEAR_TARGET
	/keypress CLEAR_TARGET
	/keypress CLEAR_TARGET
|	/press alt 
|	/press shift 
|	/press ctrl 

	| --------
	| Run to start location
	| --------
	/call InitSounds
	/call PlaySound "init"
	/call RunHomeIfNeeded

	| --------
	| I feel this loop is faily self-explanatory.  If you have questions
	| about the function names or the bot states, just poke through
	| this macro.  All functions are documented.
	| 
	| If they are not in this macro, check the include file(s)
	| --------
	:Loop
| /call NoisyDebug
		/call StopMovingIfMoving
		/call DuoHealer
		/call HateListChecker
		/if "@botState"=="KILL" {
			/call StateChecker
			/call GetTarget
			/call RefreshSpells
			/call PetCleric
			/call BattlePercents
			/call CombatRangeHandler
		}
		/if "@botState"=="LOOT" {
			/call LootCorpses
		}
		/if "@botState"=="WAIT" {
			/call RunHomeIfNeeded
|			/call ParagonWhenNeeded
|			/call SitStand
			/call PetSummoner
			/call StateChecker
			/call BotWait
			/call RefreshSpells
			/call PetCleric
|			/call QuenchOrganics
		}
		/doevents
	/goto :Loop
/return

Sub LootCorpses
	/if n @t_LootTimerWindow<=0 {
		/varset botState "WAIT"
		/return
	}
	/keypress CLEAR_TARGET
	/target npc corpse "MOB_KILLING" radius 50
	/if "$target()"=="TRUE" {
		/if n $target(distance)<50 {
			/call AutoRunToLoc $target(x) $target(y) "STOPATDEST" "CAREFUL"
			/call SimpleLootAll
		}
	}
/return

Sub CombatRangeHandler
	/declare dist3d local
	/if "$char(casting)"=="TRUE" /return
	/if "$target()"=="FALSE" {
		/call CombatDone
		/return
	}
	/if @isGettingHit==0 {
		/call CombatDone
		/return
	}
      /if @bstassist==1 {
|            /gsay assist
|            /delay 4s
|            /gsay slow
|            /varset bstassist 0
      }
	/if "$spawn(@isFighting,type)"!="NPC" {
		/call CombatDone
		/return
	}
	/if n $target(id)==$char(pet) /return
	/if n $target(id)==$char(id) /return
	/if n $group(1)>0 {
		/if n $target(id)==$group(1) /return
	}

	/stand
	/face fast 
|	/doability "Slam" 

	/varset dist3d $distance($target(y),$target(x),$target(z))

	/if n @dist3d>=@FastRange /call Fastmove 
	/if n @dist3d>@RangeMax {
	  /keypress FORWARD hold 
	}
      /keypress FORWARD 
	/if n @dist3d<@RangeMin {
	  /keypress BACK hold 
	}
      /keypress BACK 
	/face fast 
/return


sub CombatDone
	/call StopMovingIfMoving
/return

Sub Fastmove 
	/declare dist3d local
	/varset MyXLOC $char(x) 
	/varset MyYLOC $char(y) 
	/if "$target()"=="FALSE" {
		/keypress FORWARD
		/if "$combat"=="TRUE" { 
			/attack off 
			/return 
		}
	}
	/if "$spawn(@isFighting,type)"!="NPC" {
		/call CombatDone
		/return
	}
	/stand
	/face fast 
	/varset dist3d $distance($target(y),$target(x),$target(z))
	/if n @dist3d>@FastRange { 
		/keypress FORWARD hold
	}
	/if n @dist3d<=@FastRange { 
		/keypress FORWARD
		/return 
	}
/return 

Sub SitStand
	/if n @isFighting==0 {
		/if n $char(hp,pct)<90 {
		/if n $char(mana,pct)<90 {
			/if "$char(state)"=="STAND" /sit
		}
		}
	} else {
		/if "$char(state)"=="SIT" /stand
	}
/return

Sub HateListChecker
	/declare a local
	/if n @hateList_count>0 {
		/for a 1 to @hateList_count
			/if n @hateList(@a)>0 {
			/if "$spawn(@hateList(@a))"=="FALSE" {
				/echo Removing missing spawn # @hateList(@a) from hatelist
				/varset hateList(@a) 0
			} else {
					/if "$spawn(@hateList(@a),state)"=="DEAD" {
						/echo Oh.  It's a corpse.  Lolz.
						/varset hateList(@a) 0
					} else {
						/if n @isFighting!=@hateList(@a) {
							/echo Yes - it's around and $spawn(@hateList(@a),distance) away.  KILL IT!
							/target ID @hateList(@a)
							/call OfficiallyAggro
						}
					}
				}
			}
		/next a
	}
/return
Sub SetupGlobals
	/declare t_LoopDelay_CheckForNewSpawns timer
	/declare t_LootTimerWindow	timer
	/declare t_SpiritFrenzy		timer
	/varset t_SpiritFrenzy 0
	/declare t_DelayAfterFindingNearbyPC timer
	/varset t_DelayAfterFindingNearbyPC 0

	/declare FriendlyPlayers	array
	/declare ID_TARGET_NEXT 	global
	/declare ID_DUO				global
	/declare fAAXPStarted		global
	/declare QuitASAP 			global
	/declare isGettingHit		global
	/declare tempCount			global
	/declare alertSound			global
	/declare isFighting			global
	/declare needsSlow			global
	/declare needsNuke			global
	/declare needsDoT			global
	/declare petHasAggro		global
	/declare petNeedsRegen		global
	/declare wizNeedsRegen		global
	/declare idTemp				global
	/declare idPetEating		global
	/declare doingBattlePercents global
	/declare botState			global
	/declare xpStart			global
	/declare totalKills			global
	/declare deadTarget			global

	/declare nukesThisFight		global
	/declare maxNukesPerFight 	global
	/declare buffFound			global
	/declare mobDist_petAttack	global
      /declare bstassist            global
	/declare t_ParagonTimer		timer
      /declare petDS global
      /declare petHaste global
      /varset petDS 0
      /varset petHaste 0
	/varset t_ParagonTimer		0

	/declare t_CommandLag		timer
	| -------------- Buff tracking -------------------

	| -------------- AutoRunning -------------------
	/declare		iLastSpot	global
	/declare		iMaxLocs	global
	/declare		arX			array
	/declare		arY			array

	| @@STARTINGLOCS 
	| Spot 0 is normal pull spot
	/varset		arX(0) 63.87
	/varset		arY(0) 53.37

	| Spot 1 is another safe spot
	/varset		arX(1) 73
	/varset		arY(1) 107
	| Spot 2 is another safe spot...etc.
	/varset		iLastSpot	0
	/varset		iMaxLocs	1

	| Combat movement vars
	/declare ObstCount global 
	/declare MyXLOC global 
	/declare MyYLOC global 
	/declare RangeMax global 
	/declare RangeMin global 
	/declare FastRange global 


	/varset RangeMax 40
	/varset RangeMin 30
	/varset FastRange 40
	| -------------- /AutoRunning -------------------
	/varset		QuitASAP 0
	| -------------- Target Picking -------------------
	/declare Pull_NpcCount global
	/declare RadiusFromSpawnCenter global
	/declare MobList array
	/declare hateList_count	global
	/declare hateList		array
	/varset hateList_count 0
	| -------------- </Target Picking> -------------------

	| ------ Group mana notifications -----------
	/declare t_AnnounceMana	timer
	/varset t_LootTimerWindow 0
	/varset t_LoopDelay_CheckForNewSpawns 0


	/varset isGettingHit		0
	/varset buffFound 			0
	/varset doingBattlePercents 1
	/varset xpStart	$int($char(exp))
	/varset isFighting 0
	/varset alertSound	0
	/varset	deadTarget	0
	/varset needsSlow	0
	/varset needsDoT	0
	/varset needsNuke	0
	/varset maxNukesPerFight 1
	/varset idPetEating 0
	/varset petHasAggro 0
	/varset	petNeedsRegen 0
	/varset	wizNeedsRegen 0
	/varset botState "WAIT"
	/varset totalKills	0
	/varset mobDist_petAttack	110
      /varset bstassist        0
	/varset fAAXPStarted $char(aa,exp)

|	/keypress alt 
|	/keypress shift 
|	/keypress ctrl 
	/keypress CLEAR_TARGET
	/if n $group(1)!=0 {
		/echo DUO partner seems to be $target(name,clean), id $target(id)
		/varset ID_DUO $group(1)
	} else {
		/echo We seem to be solo.  No one in group.
		/varset ID_DUO 0
	}

/return

| If getting hit, runs around.
Sub ChickenWithHeadCutOff
	/if n @isGettingHit==0 /return
	/varcalc iLastSpot	@iLastSpot+1
	| Don't go to spot #0, that is starting spot.
	/if n @iLastSpot>@iMaxLocs /varset iLastSpot 1
	/varset isGettingHit 0
	/stand
	/call AutoRunToLoc @arX(@iLastSpot) @arY(@iLastSpot) "STOPATDEST" "CAREFUL"
	/face id $target(id)
	/keypress CENTERVIEW
/return

Sub StateChecker
	/if n @QuitASAP!=0 {
		/chat #CHANNEL_ANNOUNCE	Need to go for a little bit.
|		/quit
	}
	/call AlertIfLowHP

	/if "$zone"!="ZONE_TO_XP_IN" {
		/chat #CHANNEL_ANNOUNCE Huh... not in ZONE_TO_XP_IN
		/varset	QuitASAP 1
		/delay 5
|		/quit
	}
	/if "$gm"=="TRUE" {
		/chat #CHANNEL_ANNOUNCE Oh nos!  Black helicopters!
		/varset	QuitASAP 1
		/delay 20s         
|		/quit
	}
	/if n $group(1)==0 {
		/if n REQUIRE_DUO_PARTNER!=0 {
			/chat #CHANNEL_ANNOUNCE Duo... duo... Bueller... Bueller... 
			/varset	QuitASAP 1
			/delay 5
|			/quit
		}
	}
	/if n @t_AnnounceMana<=0 {
		/varset t_AnnounceMana timeBetween_manaAnnounce
		/if n $char(mana,pct)<90 {
			/if n $group(1)>0 {
				/if "$spawn($group(1),class)"=="Necromancer" {
					/gsay Medding
				} else {
					/if "$spawn($group(2),class)"=="Necromancer" /gsay Medding
				}
			}
		}
	}


	/if n @deadTarget!=0	/call TargetIsDead
	| ----------------------------------
	| Pet has not aggro'd anything and we are not fighting.
	| Once here, you're basically safely medding up.
	| ----------------------------------
	/if n @petHasAggro==0 {
		/if n @isFighting==0 {
			/if n $char(mana,pct)<manaMin_toAggro {
				/varset botState "WAIT"
				/return
			}
			/if n $char(hp,pct)<90 {
				/varset botState "WAIT"
				/return
			}
			/if "$target()"=="TRUE" {
				/if "$target(type)"=="NPC" {
					/if "$target(state)"=="DEAD" {
						/call TargetIsDead
						/return
					}
				}
			}
		}
	}

	/if n @petHasAggro==1 {
		/if "@botState"!="KILL" {
			/echo Pet has aggro? setting botState to kill
			/varset botState "KILL"
			/return
		}
	}
	/if n @isFighting!=0 {
		/if "@botState"!="KILL" {
			/echo  Fighting id @isFighting -- setting botState to kill
			/varset botState "KILL"
			/return
		}
	}

	/if "@botState"!="KILL" {
		/if n $char(mana,pct)<manaMin_toAggro /return
		/if n $char(hp,pct)<90 /return

		/if n REQUIRE_PET!=0 {
			/if n $char(pet)>0 {
				/if n $spawn($char(pet),hp,pct)<75 {
					/echo  Fullmana, fullhp - but pet still hurt
					/call SureCast "sn_PetHeal2"
					/return
				}
			}
		}
		/echo Fullmana, fullhp - setting botstate to kill
		/varset botState "KILL"
	}
/return

Sub BotWait
	/if "$char(state)"=="STAND" {
		/if n $char(hp,pct)<90 /sit
	}
	/if "$char(state)"=="STAND" {
		/if n $char(mana,pct)<90 /sit
	}
	| ------------ Heal ---------------
|	/if n $char(hp,pct)<90 {
|		/if n $char(mana,pct)>20 {
|			/press esc
|			/press f1
|			/call SureCast "sn_HealPC"
|		}
|	}
/return

Sub BattlePercents
	/if n @doingBattlePercents==0 /return
	/if n @isFighting<=0 /return

	/if n $target(hp,pct)<80 {
		/if n @t_SpiritFrenzy<=0 {
|			/alt activate 127
			/varset t_SpiritFrenzy 12m
		}
	}
	
	/call TargetByID @isFighting
	/if "$target()"=="FALSE" /return

	/if n $target(hp,pct)<7 {
		/return
	}
	/if n @needsDoT!=0 {
		/call TargetByID @needsDoT
		/varset needsDoT 0
|		/call SureCast "sn_DoT"
	}
	/if n $target(hp,pct)<70 {
		/if n @nukesThisFight<@maxNukesPerFight {
			/varset needsNuke 1
			/return
		}
	}

/return

Sub PetSummoner
	| If you don't require a pet, and don't have a pet, return early.
	/if n REQUIRE_PET==0 {
		/if n $char(pet)==0 /return
	}
	| However, if you're here it means you do require a pet.
	/if n $char(pet)==0 {
		/echo No pet, and we require one.  Pulling it up.
		/call SureCast "sn_PetSummon"
	}
/return

Sub PetCleric
	| If you don't require a pet, and don't have a pet, return early.
	/if n REQUIRE_PET==0 {
		/if n $char(pet)==0 /return
	}
	
	| Save old target ID
	/if $target(id)>0 {
		/varset idTemp $target(id)
	} else {
		/varset idTemp 0
	}

	| Stay within 90 units of pet
	/call MoveToPetHealDistance

	| If pet needs healed
	/if n $spawn($char(pet),hp,pct)<55 {
		/varset doingBattlePercents 0
		/call SureCast "sn_PetHeal"
	} else {
		/varset doingBattlePercents 1
	}
	/if n @isFighting==0 {
		/if n $spawn($char(pet),hp,pct)<75 {
			/call SureCast "sn_PetHeal2"
		}
	}

	/if n @idTemp>0 {
		/if n $target(id)!=@idTemp {
			/echo Just healed pet now returning to prev target, @idTemp ($spawn(@idTemp,name,clean))
			/call TargetByID @idTemp
		}
	}
/return

Sub RefreshSpells
	| ----- Combat spells -----
	/if n @isFighting>0 {
		/if n @needsSlow>0 {
|			/call TargetByID @needsSlow
|			/if n $target(hp,pct)<98 /call SureCast "sn_Slow"
		}
		/if n @needsNuke!=0 {
			/if n $target(hp,pct)<70 {
				/varadd nukesThisFight 1
				/call SureCast "sn_Nuke"
				/varset needsNuke 0
			}
		}
	} else {
		/call RefreshBuffList_Downtime
	}
/return

Sub GetTarget
	/declare	l0	local
	/if n @isFighting>0 {
		/if n $target(id)!=@isFighting {
			/call TargetByID @isFighting
			/echo target: We weren't on @isFighting but it is what we're fighting so, like, fuqit.
		}
		/return
	}
	/if n @petHasAggro==1 {
		/if "$target()"=="FALSE" {
			/echo  You have no target but your pet has aggro.  Way to go, Vanderhar.
			/call AssistPet
		} else {
			/echo  Pet has aggro, I have a target.  Not picking new target.
		}
		/return
	}
	| --- If low mana, low hp, duo partner is low hp, pet has low hp... abort!
	/if n $char(hp,pct)<100 /return
	/if n $char(mana,pct)<manaMin_toAggro /return
	/if n REQUIRE_PET!=0 {
		/if n $char(pet)!=0 {
			/if $spawn(char(pet),hp,pct)<100 /return
		}
	}
	
	
	| Don't pull if partner is hurt
	/if n $group(1)>0 {
		/keypress CLEAR_TARGET
		/if n $spawn(@ID_DUO,hp,pct)<25 {
			/echo $spawn(@ID_DUO,name,clean) is pretty hurt - not pulling.
			/return
		}
	}

	| Don't pull if someone is near
	/if n BOT_IS_SNEAKY!=0 {
		/if n @t_DelayAfterFindingNearbyPC>0 {
			/return
		}
		/if n $group(1)>0 {
			/keypress CLEAR_TARGET
			/target PC radius 300 notid @ID_DUO
			/if "$target()"=="TRUE" {
				/call IsPlayerFriendly $target(name)
				/if n $return==0 {
					/varset t_DelayAfterFindingNearbyPC 18s
					/echo Stranger, $target(name,clean), is within 300 units.. not pulling mobs.
					/return
				}
			}

		} else {
			/keypress CLEAR_TARGET
			/target PC radius 300
			/if "$target()"=="TRUE" {
				/call IsPlayerFriendly $target(name)
				/if n $return==0 {
					/varset t_DelayAfterFindingNearbyPC 18s
					/echo $target(name,clean) is within 300 units.. not pulling mobs.
					/return
				} else {
					/echo $target(name,clean) is within 300 units.. but friendly.  Hi.
				}
			}
		}
	}
	/keypress CLEAR_TARGET
	| -------- Any NPC killable -----------
	/call RunHomeIfNeeded
	
	| Return early if loop still being delayed.
	| This is one way I am trying to combat the
	| hellish processor hogging MQ does if your
	| script is too intense.
	/if n @t_LoopDelay_CheckForNewSpawns>0 /return
	/varset t_LoopDelay_CheckForNewSpawns 5

	/call PickMobToPull
	/if n @ID_TARGET_NEXT==0 /return
	/if "$spawn(@ID_TARGET_NEXT,type)"!="NPC" /return

	/call TargetByID @ID_TARGET_NEXT
	/echo Okay.  PickMobToPull has us targetting $target(name), $target(id)
	/stand
	/face

	/if "$target()"=="TRUE" {
		| Make sure the new target:
		|	1) is not me
		|	2) is not the pet
		|	3) is not a dead thing
		/if n $target(id)==$char(pet) {
			/echo Oh cool.  You targetted your pet to kill.  WTG.
			/return
		}
		/if n $target(id)==$char(id) {
			/echo Oh cool.  You targetted yourself to kill.  WTG.
			/return
		}
		/if "$target(state)"=="DEAD" {
			/echo Oh cool.  You targetted a corpse to attack.  WTG.
			/return
		}
		/call OfficiallyAggro
	}
/return

Sub CheckForBuff
	/varset buffFound 0
	/for tempCount 1 to 15
        /if "$char(buff,@tempCount)"~~"@Param0" {
			/varset buffFound 1
			/return
		}
	/next l0 
/return


| ------------------------------------------
| QuenchOrganics
| Summons one food and one drink, placing them
| in your autoinventory.
| ------------------------------------------
Sub QuenchOrganics
	/if n SUMMON_ORGANICS_AS_NEEDED==0 /return
	/if n $char(mana,pct)<100 /return
	/autoinventory
	/delay 10
	/call SureCast "Summon Drink"
	/autoinventory
	/delay 10
	/call SureCast "Summon Food"
	/autoinventory
/return

| -------------------------------------------------
| Cycles through the buffs and places them on
| you and your partner (if you have one)
| Will also refresh pet buffs and any special buffs
| such as wizard-regen.  There was a time I never
| placed regen on myself, only on wizard.
| -------------------------------------------------
Sub RefreshBuffList_Downtime
	/declare	l0	local
	/declare	l1	local
	/declare	c	local

	/if n @wizNeedsRegen!=0 {
		/if n $group(1)>0 {
			/call TargetByID $group(1)
|			/call SureCast "sn_Regen"
			/varset wizNeedsRegen 0
		}
	}
	/if n @petDS!=0 {
            /target id $char(pet)
		/call SureCast "sn_PetProc"
            /varset petDS 0
 |           /g sn Yekan's Quickening
 |           /g sn Spirit of Vermin
	}
	/if n @petHaste!=0 {
		/call SureCast "sn_PetHaste"
            /varset petHaste 0
	}
|	/if n $char(buff,"Spiritual Light")<=0 {
|            /g snt Spiritual Light on Karieanne
|	}
|	/if n $pet(buff,"Deftness")<=0 {
|		/call TargetByID $char(pet)
|		/call SureCast "Deftness"
|	}

	| Sometimes I duo with a cleric.  Eh.  I don't buff him.
	/if "$spawn($group(1),class)"!="Cleric" {
		
		| Also don't buff any partner below level 46.
		/if n $spawn($group(1),level)>=65 {
			/call DUO_CastAllNeededBuffs
		} else {
			/call CastAllNeededBuffs
		}
	} else {
		/call CastAllNeededBuffs
	}
/return

| ----------------------------------------------------------------------
| ParagonWhenNeeded
| If Mana is less than 80, this will use the Paragon ability and reset its
| script timer to 15 minutes.
| ----------------------------------------------------------------------
Sub ParagonWhenNeeded
|	/if n $char(mana,pct)>=80 /return
|	/if n @t_ParagonTimer>0 /return
|	/if "$char(state)"=="SIT" /stand
|	/alt activate 128
|	/delay 7s
|	/varset t_ParagonTimer	15m
/return

| ----------------------------------------------------------------------
| OfficiallyAggro()
| PURPOSE: Plays "Pop!" noise and marks a target for killing.
| Casts the pull spell (whatever sn_Pull is defined as) and if
| this bot is grouped with anyone, sends a /tell to the groupmate
| with secretphrase and incoming target ID.
| ----------------------------------------------------------------------
Sub OfficiallyAggro
	/echo  NEW KILL TARGET: $target(name) id $target(id) level $target(level)
	/call AddHate $target(id)
	/varset isFighting $target(id)
|	/varset needsSlow $target(id)
	| /varset needsDoT $target(id)
	/call PlaySound "spawn"

	/call SureCast "sn_Pull"
	/if "$return"=="CANNOTSEE" {
		/call RemoveHate $target(id)
		/echo I can't see $target(name,clean).. uh... resetting
		/varset petHasAggro	0
		/varset isFighting	0
		/varset	deadTarget	0
		/varset nukesThisFight 0
		/varset botState "WAIT"
		/return
	}
	/pet hold

	/if n $group(1)>0 {
		 /gsay Incoming $target(name,clean)
		|/tell $spawn(@ID_DUO,name,clean) CONST_SECRETPHRASE 0000$target(id)
	}
/return


| ---------------------------------------------------------------------
| TargetIsDead
| PURPOSE: Updates killing statistics and puts bot in a WAIT state
|
| TRIGGER: Called in response to a "slain" death message.  This will
| also be called when players die.
| ---------------------------------------------------------------------
Sub TargetIsDead

	/keypress CLEAR_TARGET
	/keypress CLEAR_TARGET
	/keypress CLEAR_TARGET

	/varset petHasAggro	0
	/varset isFighting	0
	/varset	deadTarget	0
	/varset nukesThisFight 0
      /varset bstassist      0
	/varset botState "WAIT"
/return

| ----------------------------------------------
| PURPOSE: If you are not near the home base,
| this macro will stand and run there.
| If you *are* near home base, the macro returns
| early.
| ----------------------------------------------
Sub RunHomeIfNeeded
	/if n $distance(@arY(0),@arX(0))<=10 /return
	/stand
	/call AutoRunToLoc @arX(0) @arY(0) "STOPATDEST" "CAREFUL"
	/face heading 143
	/keypress CLEAR_TARGET
	/keypress CENTERVIEW
/return

| ----------------------------------------------
| This is called when a target you are slowing
| is near enough to melee range for your EQ client
| to see the trigger text.  IE "loses its fighting edge"
| or whatever.  Once triggered, it zeros the
| "needsSlow" variable.
| Eventually this macro will keep an array of all
| targets who need slowed, but for now this assumes
| you are fighting one thing at a time.
| ----------------------------------------------
Sub Event_TargetSlowed
	/varset needsSlow 0
/return

| ----------------------------------------------------------------------
| Assists pet and if the pet is targeting something other than
| itself, it is aggro'd.
| I've had a lot of trouble with this function and it seems very,
| very buggy.  /assist in EQ is worrisome and unreliable.
| So what I've done is added "AddRadiusToHate" for the pet.  If the
| pet is within 35 units (or whatever 'KILL_ANYTHING_THIS_CLOSE_TO_ALLIES'
| is set to) of any mobs, those mobs are added to the hatelist.
| ----------------------------------------------------------------------
Sub AssistPet
	| Target the pet and assist it
	/call TargetByID $char(pet)
	/echo Targetting pet to assist it
	/call AddRadiusToHate KILL_ANYTHING_THIS_CLOSE_TO_ALLIES $target(x) $target(y)
	/assist

	| Wait for shitty EQ /assist code to catch up
	/delay 15
	/echo  Pet seems to be attacking $target(name) (id $target(id))

	| If the thing the pet is attacking is alive
	/if n $target(id)!=$char(pet) {
		| @@FIX: Sometimes there are living mobs named "Soandso the Undying Corpse"
		| or "a muddy corpse" or "a shambling corpse".  This needs better
		| checking. @@TODO probably something like /if "$target(state)"!="DEAD"
		/if "$target(name)"!~"corpse" {
			/if n $target(hp,pct)>0 {
				/echo  Assisting pet on $target(name,clean)
				/varset petHasAggro 1
				/varset isFighting $target(id)
				/return
			} else {
        			/keypress CLEAR_TARGET
			}
		}
	}
	| Else the stupid shit IS attacking a corpse
	/varset isFighting 0
	/varset petHasAggro 0
/return



| -----------------------------
| Unused right now except for space saver.
| In future may put Eliza code back in here.
| -----------------------------
Sub Event_Chat
	/echo  You got a @Param0 from @Param1: @Param2
/return

| -----------------------------
| Called in response to your nuke landing.
| -----------------------------
Sub Event_INuked
	/varset needsNuke 0
/return

| -----------------------------
| Another placeholder.  Eventually will
| be used in occutils for landmine, pulling
| and other checks.  For instance if a
| target goes from scowling to indifferent
| yet you are not invis and are not feigned
| you can bet it is charmed
| -----------------------------
Sub Event_ConCheck
	/echo  He be scowling I guess
/return

| -----------------------------
| Cases where my targets die.
| -----------------------------
|Sub Event_PetHasSlain
|	/call TargetIsDead
|/return

Sub Event_YouHaveSlain
	/call TargetIsDead
/return


| -----------------------------
| GainXP and GainXPParty should do the exact same thing.
| I don't want to push another function call
| on the stack (though how much processing time does
| that really take in MQ anyway?)
| -----------------------------
Sub Event_GainXP
	/declare aaXPGained local
	/varcalc aaXPGained $char(aa,exp)-@fAAXPStarted
	/echo @totalKills kills.  XP: $char(exp) -- AAXP: $char(aa,exp)% and $char(aa,points) unspent.
	/chat #CHANNEL_ANNOUNCE @totalKills, $char(exp), $char(aa,exp), $char(aa,points)

	/varset t_LootTimerWindow	5s
	/varset t_CommandLag		5s
	/varadd totalKills			1
	/varset deadTarget			1
	/varset petHasAggro 		0
      /varset isGettingHit          0
	/varset botState 			"LOOT"
      /varset bstassist             0
	/call RemoveDeadSpawnsFromHateList
/return
Sub Event_GainXPParty
	/declare aaXPGained local
	/varcalc aaXPGained $char(aa,exp)-@fAAXPStarted
	/echo @totalKills kills.  XP: $char(exp) -- AAXP: $char(aa,exp)% and $char(aa,points) unspent.
	/chat #CHANNEL_ANNOUNCE @totalKills, $char(exp), $char(aa,exp), $char(aa,points)

	/varset t_LootTimerWindow	5s
	/varset t_CommandLag		5s
	/varadd totalKills			1
	/varset deadTarget			1
	/varset petHasAggro 		0
      /varset isGettingHit          0
	/varset botState			"LOOT"
      /varset bstassist             0
	/call RemoveDeadSpawnsFromHateList
/return


| -----------------------------
| Called every time you see "Taunting attacker, Master"
| Normally this is ignored, but if you are in a wait
| or loot state it could indicate 1 of 4 things:
|	1) This script is a piece of shit
|	2) Someone trained you
|	3) You pulled adds because you picked a shitty place to XP
|	4) All the above
| -----------------------------
Sub Event_PetIsTaunting
	| ---
	| Who cares if pet is taunting if we already have a target?
	/if n @petHasAggro!=0 /return
	/if "@botState"=="KILL" /return

	| ---
	| Always wait a couple seconds after "you gain experience!!"
	| before acknowledging a pettaunt.  For some reason commands
	| seem a bit laggy in MQ2.  Pets last taunt msg could have been
	| 5 to 20 seconds ago and this event still fires after xp gain.
	/if n @t_CommandLag>0 /return


	/varset botState "KILL"
	/varset petHasAggro 1
	/keypress CLEAR_TARGET
	/call AssistPet
	/if "$target(name,clean)"=="MOB_KILLING" {
		/call OfficiallyAggro
	} else {
		/echo I can't figure out what the fuck $target(name) is.  Ignoring.
	}
/return

| -----------------------------------------------------
| See Event_PetIsTaunting for description of what PetNuking
| does also.
| -----------------------------------------------------
|Sub Event_PetNuking
|	| Oh nos - our pet is aggro'd while we were medding.
|	/if "@botState"!="KILL" {
|		/echo  Oh boy - pet is aggro'd on something.
|		/call AssistPet
|		/if "$target(name,clean)"=="MOB_KILLING" {
|			/call OfficiallyAggro
|		} else {
|			/echo I can't figure out what the fuck $target(name) is.  Ignoring.
|		}
|		/return
|	}
|/return

| --------------------------------------------------------
Sub Event_ptDS
   /varset petDS 1
/return

Sub Event_ptHaste
   /varset petHaste 1
/return

| -----------------------------------------------------
| Event_ImDead is called when you are slain.
| You'll see this from time to time.  Shit happens.
| Overall I've gone from level 60 with 3aa to level 62
| with 63aa so I can safely say the script is worth
| a death here and there.
| -----------------------------------------------------
Sub Event_ImDead
	/varset QuitASAP 1
/return

| -----------------------------------------------------
| NoisyDebug
| Dumps stuff into mq2chatwnd
| -----------------------------------------------------
Sub NoisyDebug
	/echo  @botState : fight @isFighting Slow[@needsSlow] Pet: Aggro @petHasAggro tSpawn @t_LoopDelay_CheckForNewSpawns tLoot @t_LootTimerWindow tFrenzy @t_SpiritFrenzy
/return

| -----------------------------------------------
| Readies the MP3 player for playing.
| @@TODO add "downtime ambience" and maybe "battle ambience"
| so you know what state the bot is in without having
| to look at the screen.
| -----------------------------------------------
sub InitSounds 
|  /mp3 clear 
|  /mp3 add c:\mp3\eqbots\pop.wav
|  /mp3 add c:\mp3\eqbots\init.wav
|  /mp3 add c:\mp3\eqbots\battle.mp3
/return 


| -----------------------------------------------
| Plays a song from the in-game mp3 player.
| -----------------------------------------------
sub PlaySound 
  /if @Param0=="spawn" { 
    /mp3 play 1
    /delay 2
    /mp3 stop 
  } else /if @Param0=="tell" { 
    | /mp3 play 2 
    | /delay 2s 
    | /mp3 stop 
  } else /if @Param0=="init" { 
    /mp3 play 2
    /delay 1s 
    /mp3 stop 
  } else /if @Param0=="alert" { 
    /mp3 play 3 
  }
  
/return 

| ---------------------------------------
| AlertIfLowHP
|
| Under the right conditions:
| 1) Plays a loud, obnoxious MP3
| 2) Moves to your groupmate and begs for an evac
| 3) Turns off loud music
| ---------------------------------------
sub AlertIfLowHP
	/if n $char(mana,pct)<15 {
		/if n $char(hp,pct)<30 {
			/if n $group(1)>0 {
				/gsay hot shit - evac!
				/target id $group(1)
				/call MoveToTarget
			}
		}
	}
	/if n $char(hp,pct)<30 {
		/if n @alertSound==0 {
|			/call PlaySound "alert"
			/varset alertSound 1
		}
	}
	/if n $char(hp,pct)>=90 {
		/if n @alertSound==1 {
|			/mp3 stop
			/varset alertSound 0
		}
	}
/return

| ---------------------------------------
| QueryWizardForReady
| Queries duo partner for readiness.
| Currently unused.
| ---------------------------------------
sub QueryWizardForReady
	| If timer has expired, as wiz again
	/if n @t_wizReady<=0 {
		/tell $spawn($group(1),name) are you ready?
		/varset t_wizReady 10
	}
/return

| ---------------------------------------
| Heals your partner if needed.
| Returns to previous target if you had one.
| ---------------------------------------
sub DuoHealer
	/if n $group(1)==0 /return

	/declare prevTarget	local
	/if "$target()"=="TRUE" {
		/varset	prevTarget $target(id)
	} else {
		/varset	prevTarget 0
	}

	/if n $group(1)>0 {
|		/if n $spawn($group(1),hp,pct)<60 {
|			/echo Healing injured player
|			/call TargetByID $group(1)
|			/call SureCast "sn_HealPC"
|			/if n @prevTarget!=0 /call TargetByID @prevTarget
|		}
	}
/return

| ------------------------------------------------
| Summons a horse, if you have one and it is in
| your ammo slot.
| @@NOTE: Make the fuck sure you don't own
| a DROGMOR and have "Summon Horse" listed in
| your bufflist.  Instead change that buff to
| read "Summon Drogmor"
| ------------------------------------------------
sub SummonHorse
	/stand
	/cast item "$equip(ammo,name)"
	/delay 45
/return

| ------------------------------------------------
| This event is called when your slow wears off.
| Note that if you have the bst epic or have
| someone helpful nearby slowing mobs for you
| then you will go OOM trying to re-slow your
| target.
|
| You can probably fix this by putting a "time
| until needs reslowed" timer in the code.
| ------------------------------------------------
sub Event_SlowWoreOff
	/varset	needsSlow @isFighting
/return

| ------------------------------------------------
| If you regen your pet (why bother?) this will
| tell the bufflist refresher to put regen
| on your pet again.  This is called when
| your pets regen wears off.
| ------------------------------------------------
sub Event_PetRegenWoreOff
	/varset	petNeedsRegen 1
/return

| ------------------------------------------------
| If you get an "ow" tell from your partner
| then this function is called.
| Yes, it's insecure but it works for now.
| Note that if you anger me irl and haven't read
| this comment I'll probably exploit this to your
| utter dismay.
| ------------------------------------------------
sub Event_HitsGroupmate
	/if n $group(1)!=0 {
		/call AddRadiusToHate KILL_ANYTHING_THIS_CLOSE_TO_ALLIES $spawn($group(1),x) $spawn($group(1),y)
	}
	/if n $spawn($group(1),pet)!=0 {
		/call AddRadiusToHate KILL_ANYTHING_THIS_CLOSE_TO_ALLIES $spawn($spawn($group(1),pet),x) $spawn($spawn($group(1),pet),y)
	}
/return

| ------------------------------------------------
| Called *every* time a mob hits you.
| This is a big pig of a function to have occur
| so often.
| ------------------------------------------------
sub Event_HitsMe
	/varset isGettingHit	1
|      /varset bstassist       1
	/if "$combat"=="FALSE" {
		/call AddRadiusToHate 35 $char(x) $char(y)
		/attack off
		/pet attack
	}
/return

| ------------------------------------------------
| Your parter sends you a regen request and this
| function is triggered.  You will regen him
| when time and mana permits.
| ------------------------------------------------
sub Event_RegenRequest
	/varset wizNeedsRegen	1
/return

| --------------------------------------------------------------------
| Radius-from-center pulling code
| This picks a mob sitting so-many units from a loc you designate.
| This is pretty solid code.
| --------------------------------------------------------------------
Sub PickMobToPull
	/declare a local

	/varset RadiusFromSpawnCenter 400
	/varset ID_TARGET_NEXT 0

	/call Populate_MobList

	/if n @Pull_NpcCount>0 {
	    /for a 1 to @Pull_NpcCount
			/echo Checking $spawn(@MobList(@a),x) x $spawn(@MobList(@a),y) y 
			/if "$spawn(@MobList(@a),name,clean)"=="MOB_KILLING" {
				/if n $spawn(@MobList(@a),distance)<dist_maxPull {
					/echo finalTarget is @MobList(@a) now ($spawn(@MobList(@a),name,clean))
					/varset ID_TARGET_NEXT @MobList(@a)
					/call TargetByID @ID_TARGET_NEXT
					/return
				} else {
					/echo $spawn(@MobList(@a),name) too far to pull ($spawn(@MobList(@a),distance))
				}
			}
			/delay 5
		/next a
		/echo None found - sorry.
	}
/return

| --------------------------------------------------
| Subroutine of PickMobToPull
| This does the meat of finding a mob to pull.
| @@FIX add zradius check
| @@FIX move the hardcoded locs up to the top.
| @@FIX add anti-killsteal code
| --------------------------------------------------
Sub Populate_MobList
	/declare npcid local
	/declare firstnpcid local
	/declare lastnpcid local
	/varset npcid 0
	/varset firstnpcid 0
	/varset lastnpcid 0
	/varset Pull_NpcCount 0

	| Note that 666,777 is the loc of the CENTER of the circle from which
	| you want to PULL MOBS.  You'll need to adjust this depending on your
	| zone and camp.
	/varset npcid $searchspawn(npc,loc:-30:30,radius:@RadiusFromSpawnCenter)
	:Loop
	/if n @npcid==@firstnpcid {
	   /return
	} else {
	   /if n @Pull_NpcCount==0 /varset firstnpcid @npcid
	   /varset lastnpcid @npcid
	   /varset npcid $searchspawn(npc,loc:-30:30,id:@lastnpcid,radius:@RadiusFromSpawnCenter,next)
		/if "$spawn(@lastnpcid,name,clean)"=="MOB_KILLING" {
			/echo Adding $spawn(@lastnpcid,name,clean) (@lastnpcid) to MobList
			/if n @lastnpcid!=0 /varadd Pull_NpcCount 1
			/if n @lastnpcid!=0 /varset MobList(@Pull_NpcCount) @lastnpcid
		}
	}
	/goto :Loop
/return


| end xpbeast.mac

Code: Select all

| ----------------------------------------------------------------------
| occutils.mac
| AUTHORS: Tuna
|
| PURPOSE: Useful routines which I put in a lot of scripts.
|			This one isn't as well commented as the other scripts.
|			Enjoy!
|
|			http://www.vigormortis.net
|
| I took the corpse looting code from someone in the forums.  Also
| took but heavily modified the autorun code.
|
| UPDATED: 2004 Mar 17
| ----------------------------------------------------------------------


#define CONST_SECRETPHRASE	"j3jf39jaljp"
#event SecretCommands		"j3jf39jaljp""

| Let's stay within this many units of the pet.
#define gPetHealRange 	85

#event SeatedCaster "You must be standing"
#event CastFizzle "Your spell fizzles!"
#event CastBegin "You begin casting"
#event SpellNotOnPC "That spell can not affect this target PC"
#event CannotSeeTarget "You cannot see your target"
#event TooFar "Your target is out of range, get closer!"
#event NoTargetHuh "You must first select a target for this spell!"
#event TooDistracted "You are too distracted to cast a spell now!"
#event HandsFull "You can't hold the book open with your hands full."

#event concheckNOTKOS " regards you amiably"
#event concheckNOTKOS " regards you indifferently -- "
#event concheckNOTKOS " glowers at you dubiously -- "
#event concheckKOS " glares at you threateningly -- "
#event concheckKOS " scowls at you, ready to attack -- "

sub Event_concheckKOS
	/varset gLastConsiderVal "KOS"
/return

sub Event_concheckNOTKOS
	/varset gLastConsiderVal "NOTKOS"
/return

sub Event_HandsFull
	/chat #elarvus $cursor(name) huh...
	/autoinventory
/return


| ==================================================
| MemIfNeeed
| Usage:
| /call MemIfNeeded "Super SpellName" [slot number]
|
| /call MemIfNeeded "Root"
| /call MemIfNeeded "Complete Heal"
| ==================================================
Sub AnotherSwapSpot
	/varcalc SwapSlotCount @SwapSlotCount+1
	/varset ar_SwapSlot(@SwapSlotCount) @Param0
	/echo Swap slot choice #@SwapSlotCount is gem #@ar_SwapSlot(@SwapSlotCount)
	/if n @SwapLastUsed<1 /varset SwapLastUsed 1
/return
Sub AnotherFriendlyPlayer
	/varcalc FriendlyPlayerSlotCount @FriendlyPlayerSlotCount+1
	/varset ar_FriendlyPlayerSlot(@FriendlyPlayerSlotCount) @Param0
	/echo FriendlyPlayer #@FriendlyPlayerSlotCount is #@ar_FriendlyPlayerSlot(@FriendlyPlayerSlotCount)
/return
Sub IsPlayerFriendly
	/declare c local
	/for c 1 to @FriendlyPlayerSlotCount
		/if "@ar_FriendlyPlayerSlot(@c)"=="@Param0" {
			/return 1
		}
	/next c
/return 0


Sub MemIfNeeded
	/declare	c	local
	/if n @SwapSlotCount<=0 {
		/echo You need to "/call AnotherSwapSpot 1" and replace 1 with a swap gem slot.
		/return
	}
	/for c 1 to 8
		/if "$char(gem,@c)"=="@Param0" {
			| /echo  Don't need to mem $char(gem,@c)
			/goto :MIN_NoMem
		}
	/next c
	/echo Memming @Param0 in gem @ar_SwapSlot(@SwapLastUsed) 
	/mem @ar_SwapSlot(@SwapLastUsed) "@Param0"

	/varcalc SwapLastUsed @SwapLastUsed+1
	/if n @SwapLastUsed>@SwapSlotCount /varset SwapLastUsed 1
	/delay 6s
	:MIN_NoMem
/return




Sub SureCastNoWait
	/declare	postCast	local
	/echo SureCast(@Param0)
	/call MemIfNeeded "@Param0"

	| --------------------------------------
	/if "$char(state)"=="SIT" /stand
	/varset castState "TRYING"
	/cast "@Param0"
	:CastLoop
		/delay 4
		/if "@castState"=="SUCCESS" /goto :DoneCasting
		/if "@castState"=="NOHOLD" /goto :DoneCasting
		/cast "@Param0"
		/doevents
		/goto :CastLoop
	:DoneCasting
	/varset postCast $int($calc($spell("@Param0",casttime)*10+10))
/return

| ==================================================
| SureCast
| The amazing action-blocking function which will
| not let the rest of your routines run until, by
| god, some outcome occurs from your spellcasting.
|
| Usage:
|
| /call SureCast "spellname"
| If the spell is not memmed, it will mem the spell in
| the swap slot.
| ==================================================
Sub SureCast
	/declare	postCast		local
	/declare	t_CastTimeout	local
	/echo SureCast @Param0
	/if "$char(ismoving)"=="TRUE" {
		/echo You're moving and you want me to cast?
		/keypress FORWARD
	}
	/if "$defined(Param0)"=="FALSE" {
		| /echo @Param0 is $defined(Param0)
		/return
	}
	/if "@Param0"=="NULL" {
		/return
	}

	/if n $spell("@Param0",level)>$char(level) {
		/echo Eh... @Param0 is $spell("@Param0",level) .. I can't mem it.
		/return
	}
	/if n $spell("@Param0",level)<1 {
		/echo Eh... @Param0 is $spell("@Param0",level) .. I can't mem it.
		/return
	}

	/if "$target()"=="TRUE" {
		/varset SureCast_target $target(id)
	} else {
		/varset SureCast_target 0
	}


	| --------------------------------------
	/if "$char(state)"=="SIT" /stand
	/varset castState		"TRYING"
	/varset t_CastTimeout	20s
	:CastLoop
		/call MemIfNeeded "@Param0"
		/delay 2
		| ---
		| First: If something fucks up and you cannot
		| complete the spell for whatever reason, 
		| give up after so many seconds and just go on
		| with your life.
		| ---
		/if n @t_CastTimeout<=0 /goto :DoneCasting
		/if "@castState"=="SUCCESS" /goto :DoneCasting
		/if "@castState"=="TOOFAR" /goto :DoneCasting
		/if "@castState"=="NOHOLD" /goto :DoneCasting
		/if "@castState"=="CANNOTSEE" /goto :DoneCasting
		/if "@castState"=="NOTARGET" /goto :DoneCasting
		/cast "@Param0"
		/doevents
		/goto :CastLoop
	:DoneCasting
	/varset SureCast_target 0
	/varset postCast $int($calc($spell("@Param0",casttime)*10+10))
	/delay @postCast
/return "@castState"



Sub Event_SeatedCaster
	/stand
/return
Sub Event_TooFar
	/varset castState "TOOFAR"
/return
Sub Event_CastFizzle
	/varset castState "ERROR"
/return
sub Event_SpellNotOnPC
	/varset castState "NOHOLD"
/return
Sub Event_NotTakeHold
	/varset castState "NOHOLD"
/return
Sub Event_CannotSeeTarget
	/varset castState "CANNOTSEE"
/return
Sub Event_CastBegin
	| Good enough for now
	| Will have to fix later to deal with not taking hold, resists, etc
	/varset castState "SUCCESS"
/return

Sub Event_TooDistracted
	/keypress CLEAR_TARGET
/return

| --------------------
| Event for:
| "You must first select a target for this spell!
| --------------------
Sub Event_NoTargetHuh
	/echo No target, huh?  Last target of a spell was @SureCast_target
	/if n @SureCast_target!=0 {
		/if n $spawn(@SureCast_target)>0 {
			/echo Retargeting $spawn(@SureCast_target,name,clean) ... 
			/call TargetByID @SureCast_target
		} else {
			/varset castState "NOTARGET"
		}
	}
/return




| ===================================================================
| Autorun( stopornot, changeWhenStuck )
|
| Sort-of blocking function.
| /doevents happens while autorunning
| Will return if stuck
|
| AutoRunToLoc X Y "STOPATDEST" "CARELESS"
| AutoRunToLoc X Y "NOSTOP" "CAREFUL"
| ===================================================================
sub AutoRunToLoc
	/declare	l1	local
	/declare	l2	local
	/declare	distLastCheck local
    /declare	gThreshold local 
    /declare	doStopRunningWhenDone local 
	/declare	isCareful local

    /varset gThreshold 14
	/varset l2 @Param0
	/varset l1 @Param1
	/varset doStopRunningWhenDone @Param2
	/varset isCareful @Param3
	/if n $distance(@l1,@l2)<@gThreshold /return
	/varset t_StuckTimeout	2s

    /face loc @l1, @l2 

	/if "$char(state)"!="STAND" /stand
    /call AutoRun 1 
	/echo Running to @l2 X, @l1 Y ( @doStopRunningWhenDone, @isCareful )
    
	/echo $distance(@l1,@l2) 
	/varset distLastCheck $distance(@l1,@l2) 
	
	:MainLoop2 
		/delay 1
		/face loc @l1, @l2 
		/doevents

		| Update loc every 3 seconds
		/call isRooted
		/if n $return==0 {
			/if n @t_StuckTimeout<=0 {
				/varset t_StuckTimeout 3s

				| -----------------
				| If we appear stuck, return.  Calling procedure
				| should pick a new spot and re-call.
				| Only do this if "careful" mode, though.
				| When in careless mode, just pick a random dir and
				| run there for a sec or two.
				| Careful = meant for running through dungeons and specific paths
				| Careless = meant for running through Dawnshroud and other
				| wide places where you might just be stuck on a rock, but in
				| general you don't care if you aggro extra mobs.
				| -----------------
				/if n $distance(@l1,@l2)==@distLastCheck {
					/if n @gPausingForAggro==0 {
						/if "@isCareful"=="CAREFUL" {
							/echo Appear to be stuck... facing random heading and returning!
							/face heading $rand(360)
							/return
						} else {
							/echo Appear to be stuck... being careful and just waiting.
							| @@TODO : Put the MineField Navigator code in here ^_^
						}
					}
				}
				/varset distLastCheck $distance(@l1,@l2)
			}
		} else {
			/echo I'm rooted... not bothering with safe/careful checking
		}

	| End mainLoop
	/if n $distance(@l1,@l2)>@gThreshold /goto :MainLoop2 

	/if "@doStopRunningWhenDone"=="STOPATDEST" {
		/call AutoRun 0 
		/echo Destination reached - stopping
	} else {
		/echo Destination reached - not stopping
	}
/return


sub MoveToPetHealDistance
	| Return early (don't even face or target it) if pet in range
	/if n $spawn($char(pet),distance)<gPetHealRange /return

	/face loc $spawn($char(pet),y),$spawn($char(pet),x)

	/echo  Running to pet .. he's $spawn($char(pet),distance) away
    /call AutoRun 1 
	
	:MoveToPetLoop
		/face loc $spawn($char(pet),y),$spawn($char(pet),x)
		/if n $spawn($char(pet),distance)>gPetHealRange /goto :MoveToPetLoop
	/call AutoRun 0 

	/echo  Pet is in heal range again
/return

sub MoveToTarget
	| Return early (don't even face it) if pet in range
	/if n $target(distance)<40 /return
	/face 
	/echo  Running to $target(name,clean)... 
    	/call AutoRun 1 
	:MoveToTargetLoop
		/face 
		/if n $target(distance)>40 /goto :MoveToTargetLoop
	/call AutoRun 0 
	/echo  I'm near $target(name,clean) now
/return

Sub AutoRun 
   /if n @Param0==1 {
		/if n $char(speed)<=0 {
			/keypress FORWARD hold
		}
		/return
	}
	/if n @Param0==0 {
		/if n $char(speed)>0 {
			/keypress FORWARD
		}
		/return
	}
/return 

Sub CheckForBuff
	/declare	l local
	/for l 1 to 15
		| Return if this buff is on
		/if "$char(buff,@l)"=="@Param0" /return 1
	/next l
/return 0


| Expects mob ID as parameter
| Values gLastConsiderVal will be set to:
|	"KOS"
|	"NOTKOS"
|	"PENDING"
|	"NONE"
Sub DoConsider
	/declare idTemp local
	/if n $target(id)>0 {
		/varset idTemp $target(id)
	} else {
		/varset idTemp 0
	}
	/varset gLastConsiderVal "PENDING"
	/call TargetByID @Param0
	/consider
	/delay 15
	/doevents concheckKOS
	/doevents concheckNOTKOS
	/if n @idTemp>0 /call TargetByID @idTemp
/return

Sub OUGlobals
	/declare gLastConsiderVal	global
	/declare gPausingForAggro	global
	/declare t_StuckTimeout		timer
	/declare SureCast_target  	global
	/declare castState			global

	/declare ar_SwapSlot		array
	/declare SwapSlotCount		global
	/declare SwapLastUsed		global

	/declare ar_FriendlyPlayerSlot		array
	/declare FriendlyPlayerSlotCount	global

	/declare BuffList		array
	/declare BuffCount		global

	/varset gPausingForAggro	0
	/varset  SureCast_target	0
	/varset  BuffCount			0
	/varset  SwapSlotCount		0
	/varset  SwapLastUsed		0
	/varset  FriendlyPlayerSlotCount	0
	/varset gLastConsiderVal	"amiable"
	/call InitHateList
/return

Sub TargetByID
	/if n @Param0==0 {
	/keypress CLEAR_TARGET
      /return
	}
	/if n $target(id)==@Param0 /return

	| /echo TargetByID(@Param0) -- $spawn(@Param0,name,clean) $spawn(@Param0,distance) away
	/target id @Param0
/return

Sub AlsoNeedBuff
	/varcalc BuffCount $int(@BuffCount+1)
	/varset BuffList(@BuffCount) "@Param0"
	/echo BuffList(@BuffCount) is @Param0
/return

Sub CastAllNeededBuffs
	/declare l0 local
	/declare l1 local
	/for l0 1 to @BuffCount
|		 /echo  Checking if you have #@l0: @BuffList(@l0) ... 
		/for l1 1 to 15
			| Skip if this buff is on
			/if "$char(buff,@l1)"~~"@BuffList(@l0)" {
				/goto :RBD_DontNeedIt
			}
		/next l1
		| -------------- Special Cases ---------------
		/if "@BuffList(@l0)"~~"Summon Horse" {
			/call SummonHorse
		} else {
			| /echo  @BuffList(@l0) is a normal buff.  Targetting self.
			/call TargetByID $char(id)
		}
		| -----------------------------
		/if "@BuffList(@l0)"!~"Summon Horse" {
			/call SureCast "@BuffList(@l0)"
		}
		:RBD_DontNeedIt
	/next l0
/return

| -------------------------------------------
| This is like the occutils CastAllNeededBuffs
| The difference is, this function also casts
| each buff on your duo partner.
| -------------------------------------------
Sub DUO_CastAllNeededBuffs
	/declare l0 local
	/declare l1 local
	/for l0 1 to @BuffCount
		| /echo  Checking if you have #@l0: @BuffList(@l0) ... 
		/for l1 1 to 15
			| Skip if this buff is on
			/if "$char(buff,@l1)"~~"@BuffList(@l0)" {
				/goto :DRBD_DontNeedIt
			}
		/next l1
		| -------------- Special Cases ---------------
		/if "@BuffList(@l0)"~~"Summon Horse" {
			/call SummonHorse
		} else {
			| /echo @BuffList(@l0) is a normal buff.  Targetting self.
			/call TargetByID $char(id)
			/call SureCast "@BuffList(@l0)"
			/if n $group(1)>0 {
				| @@TODO Find out $spell("Name",xxxxx) to determine if
				| spell is self-only, group, or what.
				| Otherwise you'll blow all your mana casting group spells
				| once per member of the group.
				/if "@BuffList(@l0)"!="Alacrity" {
				/if "@BuffList(@l0)"!="Talisman of Jasinth" {
				/if "@BuffList(@l0)"!="Spiritual Purity" {
				/if "@BuffList(@l0)"!="Spiritual Dominion" {
				/if "@BuffList(@l0)"!="Shield of the Arcane" {
				/if "@BuffList(@l0)"!="Force Shield" {
				/if "@BuffList(@l0)"!="Instrument of Nife" {
					/call TargetByID $group(1)
					/call SureCast "@BuffList(@l0)"
				}}}}}}}
			}
		}
		:DRBD_DontNeedIt
	/next l0
/return


| --------------------------------------------------
| AddRadiustoHate(radius,x,y)
| --------------------------------------------------
Sub AddRadiusToHate
	/declare npcid local
	/declare firstnpcid local
	/declare lastnpcid local
	/declare radiusSearch	local
	/varset npcid 0
	/varset firstnpcid 0
	/varset lastnpcid 0
	/varset radiusSearch @Param0


	/varset npcid $searchspawn(npc,loc:@Param1:@Param2,radius:@radiusSearch)

	:AddRadiusLoop
		/delay 1
		/if n @npcid==@firstnpcid {
			/return
		} else {
			/varset lastnpcid @npcid
			/varset npcid $searchspawn(npc,loc:@Param1:@Param2,id:@lastnpcid,radius:@radiusSearch,next)
			/if n @lastnpcid!=0 {
				/call AddHate @lastnpcid
			}
		}
	/goto :AddRadiusLoop
/return

| Param0: (required) ID of mob to hate
| Param1: (optional) How much to hate it:
|	0		ignore this mob for now, but leave it on hateList
|	1		do *not* attack if this mob is not KOS
|	2		attack this mob as soon as you can
|	>2		vals higher than 2 indicate a higher hate value.
|			Every time your pet gets a "hate 00398493 more" it will
|			add 1 to the hate for that mob.
|
Sub AddHate
	/declare newSlot local
	/declare a local
	/declare newamt local
	/varset newSlot 0

/echo addhate(@Param0, @Param1)
	/if n @hateList_count>0 {
		/for a 1 to @hateList_count
			/if n @hateList(@a)==0 {
				/if n @newSlot==0 /varset newSlot @a
			}
			/if n @hateList(@a)==@Param0 {
				/if n @Param1>0 {
					/varcalc newamt @hateListRating(@a)+@Param1
					/varset hateListRating(@a) @newamt
					/echo Increasing hate for $spawn(@Param0,name,clean) to @hateListRating(@a)
				} else {
					/echo $spawn(@Param0,name,clean) ID @Param0 already on list in spot @a
				}
				/return 0
			}
		/next a
	}
	/if n @newSlot==0 {
		/varcalc hateList_count @hateList_count+1
		/varset newSlot @hateList_count
	}
	/varset a $int(@newSlot)
	/echo hateList(@a) = ID @Param0, $spawn(@Param0,name,clean), $spawn(@Param0,distance) away moving at $spawn(@Param0,speed)
	/varset hateList(@a) @Param0
	/if n @Param1>0 {
		/varset hateListRating(@a) @Param1
		/echo Setting initial hate rating for $spawn(@Param0,name,clean) to @hateListRating(@a)
	}
	/return 1
/return

Sub RemoveHate
	/declare a local
	/if n @hateList_count>0 {
		/for a 1 to @hateList_count
			/if n @hateList(@a)==@Param0 {
				/echo Removing @Param0 from hatelist
				/varset hateList(@a) 0
				/varset hateListRating(@a) 0
				/return
			}
		/next a
	}
/return

Sub InitHateList
	/declare hateList_count	global
	/declare hateList		array
	/declare hateListRating	array
	/declare a local

	/for a 1 to 72
		/varset hateList(@a) 0
		/varset hateListRating(@a) 0
	/next a
	/varset hateList_count 0
/return

Sub RemoveDeadSpawnsFromHateList
	/declare a local
	/if n @hateList_count>0 {
		/for a 1 to @hateList_count
			/if "$spawn(@hateList(@a))"=="FALSE" {
				/echo Removing missing spawn # @hateList(@a) from hatelist
				/varset hateList(@a) 0
				/varset hateListRating(@a) 0
			} else {
				/if "$spawn(@hateList(@a),state)"=="DEAD" {
					/echo Removing dead spawn from #@a in hateList
					/varset hateList(@a) 0
					/varset hateListRating(@a) 0
				} else {
					/if n @isFighting!=@hateList(@a) {
						/echo hateList(@a) = $spawn(@hateList(@a),name,clean), $spawn(@hateList(@a),distance) units away. Inc!
						/call TargetByID @hateList(@a)
						/if n $char(pet)>0 /pet attack
						/call OfficiallyAggro
					}
				}
			}
		/next a
	}

/return
sub SimpleLootAll
	/declare LootSlot local
	/varset LootSlot 0
	/lootn never
	/loot
	/delay 2s
|**
	:lootloop
		/if n @LootSlot>=9 /goto :doneloot
		/click left corpse @LootSlot
		/delay 1s
		/if "$cursor()"!="TRUE" /goto :doneloot
		:lootChecker
		/autoinventory
		/delay 1s
		/varadd LootSlot 1
		/goto :lootloop
	:doneloot
**|
/echo /click left corpse is still broken - using hardcoded numbers
	/click right 34 192
	/delay 5
	/click right 80 190
	/delay 5
	/click right 42 234
	/delay 5
	/click right 76 238
	/delay 5
	/click right 22 276
	/delay 5
	/click right 86 278
	/delay 5
	/click right 50 324
	/delay 5
	/lootn always
	/keypress CLOSE_TOP_WINDOW
	/keypress CLOSE_TOP_WINDOW
	/keypress CLOSE_TOP_WINDOW
	/delay 1s
/return

| -------------------------------------------------------------------
| RecastBuff
| PARAMETERS:
|	Param0: Should be some name like "Haste", "Crack" or "Regen"
|	Param1: Player name to rebuff
|
|	If you call this function with "Haste" as a parameter,
| It will assume @sn_Haste and @t_Haste exist.  It expects
| @sn_Haste to name a valid spell your character can cast,
| and it expects @t_Haste to be a valid, global timer.
| -------------------------------------------------------------------
sub RecastBuff
	/declare c local
	/declare timerVal	local
	/declare spellName	local

	/varset spellName "@sn_@Param0"
	/varset timerVal @t_@Param0

|	/echo Recasting buff for @Param0 ... currently @spellName
|	/echo Timer variable ( t_@Param0 ) has val @timerVal

	/if n @timerVal<=0 {
		/target PC "@Param1"
		/call SureCast "@spellName"

		/varcalc c $spell("@spellName",duration)*CHAR_BUFF_EXTENSION
		/varcalc c @c*10
		/varset t_@Param0 $int(@c)

		| Now recalc jus

Tindal
orc pawn
orc pawn
Posts: 10
Joined: Thu Mar 18, 2004 11:45 am

Post by Tindal » Sat Mar 27, 2004 6:48 pm

thanks alot Kasodo

Wylker
a lesser mummy
a lesser mummy
Posts: 42
Joined: Tue Feb 10, 2004 5:32 pm

Post by Wylker » Sun Mar 28, 2004 12:16 pm

can you please repost occutils.mac? the link does not work for me for some reason...and the posted one is cut off at the end

wylker
Last edited by Wylker on Mon Mar 29, 2004 12:59 am, edited 1 time in total.

apollo5145
orc pawn
orc pawn
Posts: 26
Joined: Wed Feb 25, 2004 8:14 pm

Post by apollo5145 » Sun Mar 28, 2004 12:23 pm

I'd love a copy of the mage one too if ya dont mind :)