All pastes #932158 Raw Edit

Stuff

public text v1 · immutable
·published 2008-03-07 15:18 UTC
rendered paste body
;----- *** GLOBAL ***
#define OB_IDLE 0
#define OB_ASSIST_IDLE 2000


;----- *** MAIN ***
#define OB_DEAD 1001
#define OB_TOON 1002
#define OB_NPC 1003
#define OB_ITEM 1004
#define OB_LOOT 1005
#define OB_QUEST 1006
#define OB_ROAM 1007

#define MAIN_STATE_START 1001
#define MAIN_STATE_END 1007

;----- *** ASSIST MODE ***
; no NPC or QUEST or ITEM, replace ROAM with ASSIST
#define OB_DEAD_ASSIST 2001
#define OB_TOON_ASSIST 2002
#define OB_LOOT_ASSIST 2003
#define OB_ASSIST 2004

#define ASSIST_STATE_START 2001
#define ASSIST_STATE_END 2004

;----- DEAD
#define OB_RELEASE 101
#define OB_DEADMOVE 102
#define OB_USE_SPIRITHEALER 103
#define OB_SPIRITHEALER 104
#define OB_SAFE_RES 105
#define OB_REVIVE_CORPSE 106
#define OB_DEAD_WAIT 107
#define OB_DEAD_FUCKED 108
#define OB_DEAD_MOREGOSSIP 109
#define OB_CLASS_DEAD 110

;----- TOON
#define OB_COMBAT_BUFF 201
#define OB_COMBAT 202
#define OB_COMBAT_IDLE 203
#define OB_BUFF 204
#define OB_REST 205
#define OB_MOVETO_PULL 206
#define OB_PULL_BUFF 207
#define OB_PULL 208
#define OB_PULL_WAIT 209
#define OB_CASTING 210
#define OB_CASTING_WAIT 211
#define OB_ACT_HUMAN 212
#define OB_COMBAT_CLASS_IDLE 213
#define OB_FLEE 214
#define OB_FLEE_WAIT 215

;----- NPC Sub State Name
#define OB_USE_NPC 301
#define OB_MOREGOSSIP 302
#define OB_TAKE_FLIGHT 303
#define OB_REPAIR 304
#define OB_SELL 305
#define OB_TRAINER 306
#define OB_AUCTION 307
#define OB_NPC_WAIT 308
#define OB_NPC_MOVE 309
#define OB_LOGOUT 310
#define OB_START_HEARTH 311
#define OB_HEARTHING 312
#define OB_RESTOCK 313
#define OB_MULE 314
#define OB_NPC_GETTING_READY 315
#define OB_HEARTH_GETTING_READY 316
#define OB_LEARN_FLIGHT 317

;----- TRADESKILL (in NPC and takes place b4 SELL)
#define OB_TRADESKILL_MAKE 320
#define OB_TRADESKILL_BUY 321
#define OB_TRADESKILL_MOVE 322
#define OB_TRADESKILL_WAIT 323

;----- LOOT
#define OB_USE_LOOT 401
#define OB_SKIN_CORPSE 402
#define OB_LOOT_CORPSE 403
#define OB_LOOT_HERB 404
#define OB_LOOT_ORE 405
#define OB_LOOTALL 406
#define OB_CLOSE_LOOT 407
#define OB_LOOT_WAIT 408
#define OB_LOOT_MOVE 409
#define OB_LOOT_GETTING_READY 410
#define OB_OPENING 411
#define OB_FISHING 412


;----- ITEM
#define OB_EQUIP_BAG 501
#define OB_EQUIP_GEAR 502
#define OB_EQUIP_WAIT 503

;----- QUEST
#define OB_QUEST_REWARD 510
#define OB_QUEST_NEEDGOSSIP 511
#define OB_QUEST_GOSSIP 512
#define OB_QUEST_CLOSEGOSSIP 513
#define OB_QUEST_NEEDNPC 514
#define OB_ITEM_BEGINSQUEST 515
#define OB_QUEST_NEEDOBJECT 516
#define OB_QUEST_HARVEST 517
#define OB_QUEST_WAIT 518

;----- ROAM
#define OB_MOUNT 601
#define OB_DISMOUNT 602
#define OB_LEVELUP 603
#define OB_NEED_PULL 604
#define OB_NEED_VENDOR 605
#define OB_NEED_TRAINER 606
#define OB_NEED_MAILBOX 607
#define OB_NEED_BANK 608
#define OB_NEED_AH 609
#define OB_NEED_FP 530
#define OB_MOVETO_MOB 610
#define OB_ROAMING 611
#define OB_ROAM_TO_NODE 612

#define OB_FISHING_EXTENSION Autofish
#define OB_FISHING_POLE Fishing Pole


objectdef oState inherits oBase
{
	variable int CurrentState = OB_IDLE
	variable int CurrentSubState = OB_IDLE
	
	variable string MovingToLoc = "FALSE"
	variable int JustRes = ${LavishScript.RunningTime}
	variable int FindSpot = ${LavishScript.RunningTime}
	
	variable int LagTime = 10000
	
	; logout settings
	variable bool LogoutOnTimer = FALSE
	variable int LogOutIn = 0
	variable int LogOutInMS = 0
	variable bool LogOutOnLevel = FALSE
	variable int LogOutLevel = 0
	variable int LastLogoutChange = 0
	
	; ends hotspot iteration by iterating to next valid location
	variable int Location_Failed_Count = 0
	variable int Location_Failed_Timer = 0
		
	;Mail
	variable int MailClickable = ${LavishScript.RunningTime}	

	variable int DEADState_Wait_Until = 0
	variable int DEADState_Release_Wait_Until_Timeout = 10
	variable int DEADState_Interact_Wait_Until_Timeout = 4

	variable int ITEMState_Equip_Wait_Until = 0
	variable int ITEMState_Equip_Wait_Until_Timeout = 2

	variable int TOONState_Pull_Wait_Until = 0
	variable int TOONState_Pull_Wait_Until_Timeout = 4
	variable int TOONState_Casting_Wait_Until = 0
	variable int TOONState_Casting_Until_Timeout = 2
	
	variable int LOOTState_Loot_Wait_Until = 0
	variable int LOOTState_Loot_Wait_Until_Timeout = 1
	variable int LOOTState_Loot_Wait_After_Until_Timeout = 2
	
	variable int LOOTState_Skip_Scans = 0
	variable int LOOTState_Skip_Scans_Timeout = 10
	
	variable int TOONState_Flee_Wait_Until = 0
	variable int TOONState_Last_Flee_Time = 0

	variable int LOOTState_Loot_Fishing_Until = 0
	variable int LOOTState_Loot_Fishing_Timeout = 30
	variable string MainHandBeforeFishing = NULL
	variable string OffHandBeforeFishing = NULL
	
	
	variable int NPCState_NPC_Wait_Until = 0
	variable int NPCState_Hearthstone_Wait_Until_Timeout = 10
	variable int NPCState_Use_Wait_Until_Timeout = 10
	variable int NPCState_Interact_Wait_Until_Timeout = 2

	variable int QUESTstate_Wait_Until = 0
	variable int QUESTstate_Wait_Until_Timeout = 4
	variable int QUESTstate_Harvest_Wait_Until_Timeout = 10
	

	member RestockMerchant()
	{
		switch ${POI.Type}
		{
			case AMMO
			case FOOD
			case WATER
			case ARROW
				return TRUE
				break
		}
		if ${POI.Name.Equal[${Inventory.FoodMerch}]}
		{
			return TRUE
		}
		if ${POI.Name.Equal[${Inventory.DrinkMerch}]}
		{
			return TRUE
		}
		if ${POI.Name.Equal[${Inventory.AmmoMerch}]}
		{
			return TRUE
		}
		return FALSE
	}

	method Initialize()
	{

	}

	method ShutDown()
	{

	}

	member StateName(int StateNumber)
	{
		switch ${StateNumber}
		{		
			;----- GLOBAL State Name
			case OB_IDLE 
				return "IDLE"
			case OB_ASSIST_IDLE
				return "ASSIST IDLE"

			;----- MAIN State Name
			case OB_DEAD 
				return "DEAD"
			case OB_TOON 
				return "TOON"
			case OB_NPC 
				return "NPC"
			case OB_ITEM 
				return "ITEM"
			case OB_LOOT 
				return "LOOT"
			case OB_QUEST 
				return "QUEST"			
			case OB_ROAM 
				return "ROAM"
			case OB_DEAD_WAIT
				return "DEAD WAITING"
			case OB_DEAD_MOREGOSSIP
				return "MOREGOSSIP"

			;----- ASSIST State Name
			case OB_DEAD_ASSIST
				return "DEAD"				
			case OB_TOON_ASSIST
				return "TOON"				
			case OB_LOOT_ASSIST
				return "LOOT_ASSIST"				
			case OB_ASSIST
				return "ASSIST"
			
			;----- DEAD Sub State Name
			case OB_RELEASE
				return "RELEASE"
			case OB_DEADMOVE
				return "MOVING"
			case OB_SPIRITHEALER
				return "SPIRIT HEALER"
			case OB_SAFE_RES
				return "SAFE RES"
			case OB_REVIVE_CORPSE
				return "REVIVE CORPSE"
			case OB_DEAD_FUCKED
				return "MISSING PATH WE ARE FUCKED"
			case OB_CLASS_DEAD
				return "ROUTINE OVERRIDE"

			;----- ROAM Sub State Name
			case OB_LEVELUP
				return "LEVEL UP"
			case OB_NEED_VENDOR
				return "VENDOR"
			case OB_NEED_TRAINER
				return "TRAINER"
			case OB_NEED_MAILBOX
				return "MAILBOX"
			case OB_NEED_BANK
				return "BANK"
			case OB_NEED_AH
				return "AH"
			case OB_NEED_FP
				return "FLIGHT PATH"
			case OB_MOUNT
				return "MOUNT"
			case OB_DISMOUNT
				return "DISMOUNT"
			case OB_MOVETO_MOB
				return "MOVETO_MOB"
			case OB_ROAMING
				return "ROAMING"
			case OB_NEED_INNKEEPER
				return "INNKEEPER"
			case OB_MULE
				return "MAIL MULE"
			case OB_NPC_GETTING_READY
				return "GETTING READY"
			case OB_ROAM_TO_NODE
				return "ROAM TO NODE"

			;----- TOON Sub State Name
			case OB_COMBAT_BUFF
				return "COMBAT BUFF"
			case OB_COMBAT
				return "COMBAT"
			case OB_COMBAT_IDLE
				return "COMBAT_IDLE"
			case OB_COMBAT_CLASS_IDLE
				return "CLASS_IDLE"
			case OB_BUFF
				return "BUFF"
			case OB_REST
				return "REST"
			case OB_MOVETO_PULL
				return "MOVETO_PULL"
			case OB_PULL_BUFF
				return "PULL BUFF"
			case OB_PULL
				return "PULL"
			case OB_PULL_WAIT
				return "PULL WAIT"
			case OB_CASTING
				return "CASTING"
			case OB_CASTING_WAIT
				return "CASTING WAIT"
			case OB_ACT_HUMAN
				return "ACT HUMAN"
			case OB_FLEE
				return "RUN LIKE A GIRL"
			case OB_FLEE_WAIT
				return "POST FLEE WAIT"
			
			;----- LOOT Sub State Name
			case OB_SKIN_CORPSE
				return "SKINNING"
			case OB_LOOT_CORPSE
				return "LOOTING"
			case OB_LOOT_HERB
				return "HERBING"
			case OB_LOOT_ORE
				return "MINING"
			case OB_USE_LOOT
				return "USE"
			case OB_LOOTALL
				return "LOOT ALL"
			case OB_CLOSE_LOOT
				return "CLOSING LOOT"
			case OB_LOOT_WAIT
				return "WAIT FOR LOOT"
			case OB_LOOT_MOVE
				return "MOVE TO LOOT"
			case OB_LOOT_GETTING_READY		
				return "GETTING READY"
			case OB_OPENING
				return "OPENING"
			case OB_FISHING
				return "FISHING"
				
			;----- NPC Sub State Name
			case OB_MOREGOSSIP
				return "TALK TO NPC"
			case OB_TAKE_FLIGHT
				return "FLIGHT MASTER"
			case OB_LEARN_FLIGHT
				return "LEARN FLIGHT"
			case OB_REPAIR
				return "REPAIR"
			case OB_SELL
				return "SELL"
			case OB_TRAINER
				return "TRAINER"
			case OB_AUCTION
				return "AUCTION"
			case OB_NPC_WAIT
				return "NPC WAIT"
			case OB_NPC_MOVE
				return "NPC MOVE"
			case OB_START_HEARTH
				return "Invoke Hearthstone"
			case OB_HEARTHING
				return "Hearthing"
			case OB_RESTOCK
				return "RESTOCK FOOD"
			case OB_HEARTH_GETTING_READY
				return "HEARTH GETTING READY"

			;----- TRADESKILL
			case OB_TRADESKILL_MAKE
				return "TRADESKILL_MAKE"	
			case OB_TRADESKILL_BUY
				return "TRADESKILL_BUY"
			case OB_TRADESKILL_MOVE
				return "TRADESKILL_MOVE"
			case OB_TRADESKILL_WAIT
				return "TRADESKILL_WAIT"
			
			;----- ITEM Sub State Name
			case OB_EQUIP_BAG
				return "Equip Bag"
			case OB_EQUIP_GEAR
				return "Equip Gear"
			case OB_EQUIP_WAIT
				return "Equip Wait"

			;----- QUEST Sub State Name			
			case OB_QUEST_NEEDOBJECT
				return "QUEST_OBJECT"
			case OB_QUEST_HARVEST
				return "QUEST_HARVEST"
			case OB_QUEST_NEEDGOSSIP
				return "NEED_QUEST"
			case OB_QUEST_GOSSIP
				return "QUEST_GOSSIP"
			case OB_QUEST_CLOSEGOSSIP
				return "CLOSE_QUESTS"
			case OB_QUEST_NEEDNPC
				return "MOVETO_QUESTGIVER"
			case OB_ITEM_BEGINSQUEST
				return "ITEM_STARTQUEST"
			case OB_QUEST_REWARD
				return "QUEST_REWARD"	
			case OB_QUEST_WAIT
				return "QUEST_WAIT"
		}	
		return "UNKNOWN:" ${StateNumber}
	}
		
	method Pulse()
	{
		variable int TempState 
		variable int i
		
		if !${UIElement[chkAssistMode@Overview@Pages@openbot].Checked}
		{		
			for (i:Set[MAIN_STATE_START];${i}<= MAIN_STATE_END;i:Inc)
			{
				TempState:Set[${This.${This.StateName[${i}]}State}]
				if ${TempState} != OB_IDLE
				{
					This.CurrentState:Set[${i}]
					This.CurrentSubState:Set[${TempState}]
					;This:Debug[${This.StateName[${This.CurrentState}]} ${This.StateName[${This.CurrentSubState}]}]
					This:${This.StateName[${This.CurrentState}]}Pulse
					return
				}
			}
		}
		else
		{
			if ${State.ManualOverride}
			{
				This.CurrentState:Set[OB_ASSIST]
				This.CurrentSubState:Set[OB_ASSIST_IDLE]
				This:Output[User Control Detected.]
				This:${This.StateName[${This.CurrentState}]}Pulse		
				return
			}			
			for (i:Set[ASSIST_STATE_START];${i}<= ASSIST_STATE_END;i:Inc)
			{
				TempState:Set[${This.${This.StateName[${i}]}State}]
				if ${TempState} != OB_IDLE
				{
					This.CurrentState:Set[${i}]
					This.CurrentSubState:Set[${TempState}]
					;This:Debug[${This.StateName[${This.CurrentState}]} ${This.StateName[${This.CurrentSubState}]}]
					This:${This.StateName[${This.CurrentState}]}Pulse
					return
				}
			}		
		}
	}

	;----------
	;----- DEAD Sub State
	;----------

	member DEADState()
	{
		/* wait for death lag */
		if ${LavishScript.RunningTime} <= ${DEADState_Wait_Until}
		{
			return OB_DEAD_WAIT
		}
		
		/* when we are dead, but not yet a ghost -- allow for routine hooking here */
		if ${Me.Dead}
		{
			if ${Class.NeedDead}
			{
				return OB_CLASS_DEAD
			}
			This.DEADState_Wait_Until:Set[${Math.Calc[${LavishScript.RunningTime}+(${This.DEADState_Release_Wait_Until_Timeout} * ${Bot.GlobalCooldown})]}]
			return OB_RELEASE
		}

		/* ok -- we died and releaseed -- now what? */
		if ${Me.Ghost}
		{
			if ${Math.Calc[${LavishScript.RunningTime} - ${This.JustRes}]} >= ${LagTime}
			{
				/* check corpse before Spirit Healer */
				if ${POI.Type.Equal[CORPSE]}
				{
					if ${Navigator.SafeToRes}
					{
						return OB_REVIVE_CORPSE
					}
					else
					{
						if ${Math.Distance[${Me.Location},${Me.Corpse}]} < 40
						{
							return OB_SAFE_RES
						}
						else
						{
							return OB_DEADMOVE
						}	
					}
				}
				elseif !${POI.NeedSpiritHealer}
				{
					/* only set corpse if we dont need Spirit Healer */
					/* and only need Spirit Healer based on corpse counter */
					if ${POI.Set[${Me.Corpse.X}:${Me.Corpse.Y}:${Me.Corpse.Z}:-1:"Corpse of ${Me.Name}":CORPSE:${Me.FactionGroup.Upper}:${Me.Level}]}
					{
						return OB_DEADMOVE
					}	
				}
				
				if ${POI.Type.Equal[SPIRITHEALER]} && !${UIElement[chkAssistMode@Overview@Pages@openbot].Checked}
				{
					if ${POI.InUseRange}
					{
						if ${WoWScript[StaticPopup1:IsVisible()]}
						{
							This.DEADState_Wait_Until:Set[${Math.Calc[${LavishScript.RunningTime}+(${This.DEADState_Interact_Wait_Until_Timeout} * ${Bot.GlobalCooldown})]}]
							return OB_SPIRITHEALER
						}
						else
						{
							if ${WoWScript[GetGossipOptions()](exists)}
							{
								return OB_DEAD_MOREGOSSIP
							}
							else
							{
								This.DEADState_Wait_Until:Set[${Math.Calc[${LavishScript.RunningTime}+(${This.DEADState_Interact_Wait_Until_Timeout} * ${Bot.GlobalCooldown})]}]
								return OB_USE_SPIRITHEALER
							}
						}
					}
					else
					{
						return OB_DEADMOVE
					}
				}
				else					
				{
					if ${POI.SetNearestPOI[SPIRITHEALER]} && !${UIElement[chkAssistMode@Overview@Pages@openbot].Checked}
					{
						return OB_DEADMOVE
					}
					elseif ${POI.Set[${Me.Corpse.X}:${Me.Corpse.Y}:${Me.Corpse.Z}:-1:"Corpse of ${Me.Name}":CORPSE:${Me.FactionGroup.Upper}:${Me.Level}]}
					{
						return OB_DEADMOVE
					}
					else
					{
						This:Output[No way to Corpse and to Spirithealer. Not enough Mapping data.]
						return OB_DEAD_FUCKED
					}	
				}
			}
			else
			{
				return OB_DEAD_WAIT
			}
		}					
		return OB_IDLE
	}

	method DEADPulse()
	{
		switch ${This.CurrentSubState}
		{
			case OB_CLASS_DEAD
			Class:DeadPulse
			break
			
			case OB_RELEASE
			if ${UIElement[chkDeathSoundOn@Config@Pages@openbot].Checked}
			{
				This:PlaySound["Inform"]
			}				
			Navigator:ClearPath
			move -stop
			This.JustRes:Set[${LavishScript.RunningTime}]
			WoWScript RepopMe()
			if ${LavishScript.RunningTime} <= ${Math.Calc[${POI.LastRetrieveCorpseTime} + ${POI.CorpseCampTimeout}]} && !${UIElement[chkAssistMode@Overview@Pages@openbot].Checked}
			{
				POI.CorpseCampCount:Inc
				This:Output[Corpse Camp Counter ${POI.CorpseCampCount} of ${Config.GetSlider[sldCorpseCamped]}]
				if ${POI.CorpseCampCount} >= ${Config.GetSlider[sldCorpseCamped]} 
				{
					This:Output[Corpse Camped -> Try Spritithealer]
					This:Output[Trying luck at next Grind Spot]
					Grind:NextHotspot
					POI.NeedSpiritHealer:Set[TRUE]
					POI.CorpseCampCount:Set[0]
				}
			}
			else
			{
				POI.CorpseCampCount:Set[0]
			}
			Grind.RepopCount:Inc
			break

			case OB_DEAD_MOREGOSSIP
			WoWScript SelectGossipOption(1)
			break
			
			case OB_SPIRITHEALER
			WoWScript "AcceptXPLoss()"
			break

			case OB_USE_SPIRITHEALER
			Navigator:ClearPath
			move -stop
			POI:Use
			break

			case OB_DEADMOVE
			MovingToLoc:Set["TRUE"]
			if !${Navigator.IsMovingToCurrentPOI}
			{
				Navigator:MoveToCurrentPOI
			}
			break

			case OB_SAFE_RES
			Navigator:ClearPath
			FindSpot:Set[${LavishScript.RunningTime}]
			MovingToLoc:Set["TRUE"]
			Navigator:MoveToLoc[${Navigator.FindSafeSpot}]
			break

			case OB_REVIVE_CORPSE
			Navigator:ClearPath
			Navigator.ForceRes:Set[FALSE]
			Navigator.ResSpot:Set[0]
			WoWScript RetrieveCorpse()
			MovingToLoc:Set["TRUE"]
			MovingToLoc:Set["FALSE"]
			POI.LastRetrieveCorpseTime:Set[${LavishScript.RunningTime}]
			break
		}
	}

	;----------
	;----- TOON Sub State
	;----------
	member TOONState()
	{	
		if ${Flee.NeedToRun}
		{
			return OB_FLEE
		}
		
		if ${Me.InCombat} && !${Mount.IsMounted}
		{
			/* first lets deal with our POI and Target */
			if ${Toon.ValidTarget[${Target.GUID}]} && ${Target.PctHPs} > 0
			{
				if ${POI.GUID.NotEqual[${Target.GUID}]}
				{
					if !${POI.Set[${Target.X}:${Target.Y}:${Target.Z}:${Target.GUID}:${Target.Name}:MOB:FACTION_NEUTRAL:${Target.Level},TRUE]}
					{
						This:Debug[Error: Can not set POI to Target]	
					}
				}
			}
			elseif ${Me.InCombat} && ${Toon.ValidTarget[${Targeting.TargetCollection.Get[1]}]} && ${Object[${Targeting.TargetCollection.Get[1]}].PctHPs} > 0
			{
				Toon:NeedTarget
				if !${POI.Set[${Object[${Targeting.TargetCollection.Get[1]}].X}:${Object[${Targeting.TargetCollection.Get[1]}].Y}:${Object[${Targeting.TargetCollection.Get[1]}].Z}:${Object[${Targeting.TargetCollection.Get[1]}].GUID}:${Object[${Targeting.TargetCollection.Get[1]}].Name}:MOB:FACTION_NEUTRAL:${Object[${Targeting.TargetCollection.Get[1]}].Level},TRUE]}
				{
					This:Debug[Error: Can not set POI to AGGRO Target]	
					Toon:NeedTarget  
				}
			}
			
			/* then if we have a target, lets do combat */
			if ${Target(exists)}
			{
				if ${Class.NeedCombatBuff}
				{
					return OB_COMBAT_BUFF
				}
				else
				{
					return OB_COMBAT
				}					
			}
			else
			{	
				/* we have no target, so lets idle */
				if ${Class.NeedCombatIdle}
				{
					return OB_COMBAT_CLASS_IDLE
				}
				return OB_COMBAT_IDLE
			}
		}

		if ${Class.NeedRest}
		{
			return OB_REST
		}

		if ${Class.NeedBuff} &&  (0 < ${Toon.SafeSpotRange})
		{
			if !${Mount.IsMounted} && 0 < ${Toon.SafeSpotRange}
			{
			return OB_BUFF
			}
		}		
		
		if ${Toon.PullableTarget} && !${Mount.IsMounted}
		{
			if ${POI.Set[${Object[${Targeting.TargetCollection.Get[1]}].X}:${Object[${Targeting.TargetCollection.Get[1]}].Y}:${Object[${Targeting.TargetCollection.Get[1]}].Z}:${Object[${Targeting.TargetCollection.Get[1]}].GUID}:${Object[${Targeting.TargetCollection.Get[1]}].Name}:MOB:FACTION_NEUTRAL:${Object[${Targeting.TargetCollection.Get[1]}].Level},FALSE]}
			{	
				if ${Object[${Targeting.TargetCollection.Get[1]}].Distance} > ${Toon.PullRange} && !${Me.Casting}
				{
					return OB_MOVETO_PULL
				}
				else
				{
					if ${Class.NeedPullBuff}
					{
						return OB_PULL_BUFF
					}
					else
					{
						return OB_PULL
					}
				}
			}
			else
			{
				This:Output["Error: Can not set POI to PULL Target"]			
			}
		}

		/* catch all casting check - takes place after combat and pull so it wont interfere with combat casting */
		/* we have waits already defined for skinning and such in LOOT */
		if ${Toon.Casting}
		{
			return OB_CASTING
		}

		if ${LavishScript.RunningTime} <= ${This.TOONState_Casting_Wait_Until}
		{
			return OB_CASTING_WAIT
		}		
		
		if ${Human.NeedAction} && ${Human.ActionDelay} < ${LavishScript.RunningTime} && !${UIElement[chkAssistMode@Overview@Pages@openbot].Checked}
		{
			return OB_ACT_HUMAN
		}
		
		if ${LavishScript.RunningTime} <= ${This.TOONState_Flee_Wait_Until} || ${Math.Calc[${LavishScript.RunningTime}-${This.TOONState_Last_Flee_Time}]} < 1500
		{
			return OB_FLEE_WAIT
		}
		return OB_IDLE
	}

	method TOONPulse()
	{
		if ${Script[OB_FISHING_EXTENSION](exists)} 
		{
			This:EndFishing
		}
		
		switch ${This.CurrentSubState}
		{
			case OB_FLEE
			if ${Class.HookFlee}
			{
				Class:FleePulse
			}
			Flee:MoveToFlee
			This.TOONState_Last_Flee_Time:Set[${LavishScript.RunningTime}]
			break
			
			case OB_FLEE_WAIT
			if ${Math.Calc[${LavishScript.RunningTime}-${This.TOONState_Last_Flee_Time}]} < 1500
			{
				Flee:MoveToFlee				
				This.TOONState_Flee_Wait_Until:Set[${This.InMilliseconds[${Math.Rand[450]}]}]
				This:Output["Should be safe, but getting a bit farther away."]					
				return
			}
			if ${Movement.Speed}
			{
				Navigator:MoveToLoc[${Me.X},${Me.Y},${Me.Z}]
				move -stop
			}
			This:Output["Waiting a moment after FLEE."]				
			break
			
			case OB_COMBAT_BUFF
			Mount:Dismount
			Class:CombatBuffPulse
			break

			case OB_COMBAT
			Mount:Dismount
			Navigator:ClearPath
			Class:AttackPulse
			break

			case OB_COMBAT_IDLE
			move -stop
			This:Output["Idle in combat."]
			break
			
			case OB_COMBAT_CLASS_IDLE
			Class:CombatIdle
			break
			
			case OB_BUFF
			Mount:Dismount
			Navigator:ClearPath
			Class:BuffPulse
			break

			case OB_REST
			Mount:Dismount
			Navigator:ClearPath
			Class:RestPulse
			break

			case OB_MOVETO_PULL
			Mount:Dismount	
			Toon:NeedTarget		
			if !${Navigator.IsMovingToCurrentPOI}
			{
				Navigator:MoveToCurrentPOI
			}
			break
			
			case OB_PULL_BUFF
			Mount:Dismount
			Navigator:ClearPath
			Class:PullBuffPulse
			break

			case OB_PULL
			Navigator:ClearPath
			Toon:NeedTarget
			Class:PullPulse
			break
					
			case OB_CASTING
			This.TOONState_Casting_Wait_Until:Set[${Math.Calc[${LavishScript.RunningTime}+(${This.TOONState_Casting_Until_Timeout} * ${Bot.GlobalCooldown})]}]
			move -stop
			break
			
			case OB_CASTING_WAIT
			move -stop
			break
			
			case OB_ACT_HUMAN
			Human:Pulse
			break			
		}
	}

		
	;----------
	;----- LOOT Sub State
	;----------
	member LOOTState()
	{
		variable guidlist list
		variable int Index
		variable bool Found = FALSE
		variable int bltimer
		
		if ${Script[OB_FISHING_EXTENSION](exists)} && ${LavishScript.RunningTime} <= ${This.LOOTState_Loot_Fishing_Until} && (${Item[-inventory,"OB_FISHING_POLE"](exists)} || ${Me.Equip[16].Name.Equal["OB_FISHING_POLE"]})
		{
			This:StartFishing
			return OB_FISHING
		}
		else
		{
			This:EndFishing
		}
		
		if ${Me(unit).Casting.Name.Token[1," "].Equal[Skinning]}
		{
			This.LOOTState_Loot_Wait_Until:Set[${Math.Calc[${LavishScript.RunningTime}+(${This.LOOTState_Loot_Wait_Until_Timeout} * ${Bot.GlobalCooldown})]}]
			return OB_SKIN_CORPSE
		}
		if ${Me(unit).Casting.Name.Token[1," "].Equal[Herbalism]}
		{
			This.LOOTState_Loot_Wait_Until:Set[${Math.Calc[${LavishScript.RunningTime}+(${This.LOOTState_Loot_Wait_Until_Timeout} * ${Bot.GlobalCooldown})]}]
			return OB_LOOT_HERB
		}
		if ${Me(unit).Casting.Name.Token[1," "].Equal[Mining]}
		{
			This.LOOTState_Loot_Wait_Until:Set[${Math.Calc[${LavishScript.RunningTime}+(${This.LOOTState_Loot_Wait_Until_Timeout} * ${Bot.GlobalCooldown})]}]
			return OB_LOOT_ORE
		}				
		if ${Me(unit).Casting.Name.Token[1," "].Equal[Opening]}
		{
			This.LOOTState_Loot_Wait_Until:Set[${Math.Calc[${LavishScript.RunningTime}+(${This.LOOTState_Loot_Wait_Until_Timeout} * ${Bot.GlobalCooldown})]}]
			return OB_OPENING
		}

		if ${LavishScript.RunningTime} <= ${This.LOOTState_Loot_Wait_Until}
		{
			return OB_LOOT_WAIT
		}

		if ${LootWindow(exists)}
		{
			if ${LootWindow.Count} > 0 && (${Inventory.FreeSlots} > 0)
			{
				This.LOOTState_Loot_Wait_Until:Set[${Math.Calc[${LavishScript.RunningTime}+(${This.LOOTState_Loot_Wait_After_Until_Timeout} * ${Bot.GlobalCooldown})]}]
				This.LOOTState_Skip_Scans:Set[0]
				return OB_LOOTALL
			}
			else
			{
				This.LOOTState_Loot_Wait_Until:Set[${Math.Calc[${LavishScript.RunningTime}+(${This.LOOTState_Loot_Wait_After_Until_Timeout} * ${Bot.GlobalCooldown})]}]
				This.LOOTState_Skip_Scans:Set[0]
				return OB_CLOSE_LOOT
			}
		}

		if ${LavishScript.RunningTime} >= ${LOOTState_Skip_Scans} || ${UIElement[chkAssistMode@Overview@Pages@openbot].Checked}
		{
			
			This.LOOTState_Skip_Scans:Set[${Math.Calc[${LavishScript.RunningTime}+(${This.LOOTState_Skip_Scans_Timeout} * ${Bot.GlobalCooldown})]}]

			if (${Inventory.FreeSlots} > 0) && ${UIElement[chkLoot@Config@InvPages@Inventory@Pages@openbot].Checked}
			{
				list:Clear
				list:Search[-units,-dead,-nearest]
				Index:Set[0]
				if ${list.Count} > 0
				{
					while ${list.GUID[${Index:Inc}](exists)} && !${Found}
					{
						if ${Unit[${list.GUID[${Index}]}].Lootable}
						{
							if ${POI.Set[${Unit[${list.GUID[${Index}]}].X}:${Unit[${list.GUID[${Index}]}].Y}:${Unit[${list.GUID[${Index}]}].Z}:${list.GUID[${Index}]}:${Unit[${list.GUID[${Index}]}].Name}:LOOT:FACTION_NEUTRAL:${Unit[${list.GUID[${Index}]}].Level}]}
							{
								Found:Set[TRUE]
							}
						}
						if ${Unit[${list.GUID[${Index}]}].Skinnable} && ${Toon.HasSkill[SKILL_SKINNING]} && (${Item[-inventory,"Skinning Knife"](exists)} || ${Item[-inventory,"Finkle's Skinner"](exists)}  || ${Item[-inventory,"Zulian Slicer"](exists)} )
						{
							if ${POI.Set[${Unit[${list.GUID[${Index}]}].X}:${Unit[${list.GUID[${Index}]}].Y}:${Unit[${list.GUID[${Index}]}].Z}:${list.GUID[${Index}]}:${Unit[${list.GUID[${Index}]}].Name}:SKILL_SKINNING:FACTION_NEUTRAL:${Unit[${list.GUID[${Index}]}].Level}]}
							{
								Found:Set[TRUE]
							}
						}
					}
				}
			}

			if !${Found} && ${Toon.HasSkill[SKILL_HERBALISM]} && (${Inventory.FreeSlots} > 0) && ${UIElement[chkGather@Config@InvPages@Inventory@Pages@openbot].Checked}
			{
				list:Clear
				list:Search[-gameobjects,-herb,-usable,-unlocked,-nearest]
				Index:Set[0]
				while ${list.GUID[${Index:Inc}](exists)} && !${Found}
				{
					if ${Toon.SkillLevel[Herbalism]} >= ${OBDB.GetLevel[${Object[${list.GUID[${Index}]}].Name}]} 
					{
						if ${POI.Set[${Object[${list.GUID[${Index}]}].X}:${Object[${list.GUID[${Index}]}].Y}:${Object[${list.GUID[${Index}]}].Z}:${list.GUID[${Index}]}:${Object[${list.GUID[${Index}]}].Name}:SKILL_HERBALISM:FACTION_NEUTRAL:${Object[${list.GUID[${Index}]}].Level}]}
						{
							Found:Set[TRUE]
						}
					}
					else
					{
						This:Output[do Not want ${Object[${list.GUID[${Index}]}].Name} level to high.]
					}
				}
			}
			if !${Found} && ${Toon.HasSkill[SKILL_MINING]} && ${Item[-inventory,"Mining Pick"](exists)} && (${Inventory.FreeSlots} > 0) && ${UIElement[chkGather@Config@InvPages@Inventory@Pages@openbot].Checked}
			{
				list:Clear
				list:Search[-gameobjects,-mine,-usable,-unlocked,-nearest]
				Index:Set[0]
				while ${list.GUID[${Index:Inc}](exists)} && !${Found}
				{
					if ${Toon.SkillLevel[Mining]} >= ${OBDB.GetLevel[${Object[${list.GUID[${Index}]}].Name}]} 
					{
						if ${POI.Set[${Object[${list.GUID[${Index}]}].X}:${Object[${list.GUID[${Index}]}].Y}:${Object[${list.GUID[${Index}]}].Z}:${list.GUID[${Index}]}:${Object[${list.GUID[${Index}]}].Name}:SKILL_MINING:FACTION_NEUTRAL:${Object[${list.GUID[${Index}]}].Level}]}
						{
							Found:Set[TRUE]
						}
					}
					else
					{
						This:Output[do Not want ${Object[${list.GUID[${Index}]}].Name} level to high.]
					}
				}
			}
			/* quest objects */
			if !${Found} && (${Inventory.FreeSlots} > 0) && ${UIElement[chkHarvestQuests@Config@InvPages@Inventory@Pages@openbot].Checked}
			{
				list:Clear
				list:Search[-gameobjects, -nearest, -chest, -unlocked, -usable]
				Index:Set[0]
				while ${list.GUID[${Index:Inc}](exists)} && !${Found}
				{
					if ${POI.Set[${Object[${list.GUID[${Index}]}].X}:${Object[${list.GUID[${Index}]}].Y}:${Object[${list.GUID[${Index}]}].Z}:${list.GUID[${Index}]}:${Object[${list.GUID[${Index}]}].Name}:QUESTOBJECT:FACTION_NEUTRAL:${Object[${list.GUID[${Index}]}].Level}]}
					{
						Found:Set[TRUE]
					}
				}
			}
		}
		
		
		if ${POI.MetaType.Equal[LOOT]}
		{
			if ${Toon.DetectAdds[${POI.GUID}]}
			{
				This:Output[Detected too many adds next to ${POI.Name}. Blacklisting it with GUID for 1 Hour.]
				GlobalBlacklist:Insert[${POI.GUID},3600000]
				POI:Clear
				This.LOOTState_Skip_Scans:Set[0]
				return OB_LOOT_WAIT
			}
			else
			{
				if ${POI.IsBlacklisted} || !${Object[${POI.GUID}](exists)}
				{
					POI:Clear
					This.LOOTState_Skip_Scans:Set[0]
					return OB_LOOT_WAIT
				}
				else
				{
					if ${POI.InUseRange}
					{
						if (${POI.Type.Equal[LOOT]} && !${Unit[${POI.GUID}].CanLoot})
						{
							POI:Clear
							This.LOOTState_Skip_Scans:Set[0]
							return OB_LOOT_WAIT							
						}
						if ${Movement.Speed} || ${Me.Sitting}
						{
							return OB_LOOT_GETTING_READY
						}
						else
						{
							This.LOOTState_Loot_Wait_Until:Set[${Math.Calc[${LavishScript.RunningTime}+(${This.LOOTState_Loot_Wait_Until_Timeout} * ${Bot.GlobalCooldown})]}]
							return OB_USE_LOOT
						}
					}
					else
					{
						return OB_LOOT_MOVE		
					}
				}
			}
		}
	
		return OB_IDLE	
	}

	method LOOTPulse()
	{
		switch ${This.CurrentSubState}
		{
			case OB_LOOT_MOVE
			if !${Navigator.IsMovingToCurrentPOI}
			{
				Navigator:MoveToCurrentPOI
			}
			break
			
			case OB_LOOT_GETTING_READY
			Toon:Standup
			if ${Movement.Speed}
			{
				Navigator:ClearPath
				move -stop
			}
			break
			
			case OB_USE_LOOT
			POI:Use
			break

			case OB_SKIN_CORPSE
			This:Output["OOOO a skinable corpse, gimmie!!"]
			POI.LastUse:Set[${LavishScript.RunningTime}]
			break

			case OB_LOOT_HERB
			This:Output["OOOO a Herb, gimmie!!"]
			POI.LastUse:Set[${LavishScript.RunningTime}]
			break

			case OB_LOOT_ORE
			This:Output["OOOO an ore deposit, gimmie!!!"]
			POI.LastUse:Set[${LavishScript.RunningTime}]
			break

			case OB_OPENING
			This:Output["OOOO something to open, gimmie!!!"]
			POI.LastUse:Set[${LavishScript.RunningTime}]
			break


			case OB_LOOTALL
			Mount:Dismount
			Navigator:ClearPath
			move -stop
			Toon:Standup
			POI:LootAll
			Grind.LootCount:Inc
			break

			case OB_CLOSE_LOOT
			WoWScript CloseLoot()
			POI:Clear
			break
		}
	}

	;----------
	;----- NPC Sub State
	;----------
	member NPCState()
	{

		if ${Me(unit).Casting.Name.Token[1," "].Equal["Hearthstone"]}
		{
			This.NPCState_NPC_Wait_Until:Set[${Math.Calc[${LavishScript.RunningTime}+(${This.NPCState_Hearthstone_Wait_Until_Timeout} * ${Bot.GlobalCooldown})]}]
			return OB_HEARTHING
		}
		
		if ${LavishScript.RunningTime} <= ${NPCState_NPC_Wait_Until}
		{
			return OB_NPC_WAIT
		}

		if ${POI.NeedLogout} || (${UIElement[chkLogOutOnLevel@Logout@Pages@OpenBot].Checked} && ${UIElement[sldLogOutLevel@Logout@Pages@OpenBot].Value(exists)} && ${Me.Level} >= ${UIElement[sldLogOutLevel@Logout@Pages@OpenBot].Value}) || (${UIElement[chkLogoutOnTimer@Logout@Pages@OpenBot].Checked} && ${UIElement[sldLogOutIn@Logout@Pages@OpenBot].Value(exists)} && ${Math.Calc[${${Script.RunningTime}.RunningTime}/60000]} >= ${UIElement[sldLogOutIn@Logout@Pages@OpenBot].Value})
		{
			if ${Item[Hearthstone](exists)} && ${Me.Action[Hearthstone].Usable}
			{
				if ${Movement.Speed} || ${Me.Sitting}
				{
					return OB_HEARTH_GETTING_READY
				}
				else
				{
					This.NPCState_NPC_Wait_Until:Set[${Math.Calc[${LavishScript.RunningTime}+(${This.NPCState_Hearthstone_Wait_Until_Timeout} * ${Bot.GlobalCooldown})]}]
					return OB_START_HEARTH 
				}
			}
			
			if ${POI.Type.Equal[INNKEEPER]} && !${POI.IsBlacklisted}
			{
				if ${POI.InUseRange}
				{
					return OB_LOGOUT
				}
				else
				{
					return OB_NPC_MOVE
				}
			}
			else
			{
				if ${POI.SetNearestPOI[INNKEEPER]}
				{
					return OB_NPC_MOVE
				}
				else
				{
					This:Output[Not enough mapping data to get to an Innkeeper, logging out here!]
					return OB_LOGOUT
				}
			}
		}	
		
		if ${Me.Flying}
		{
			return OB_TAKE_FLIGHT
		}
		
		if ${FlightPlan.TakeFlightMaster} 
		{
			if ${POI.Type.Equal[FLIGHTMASTER]} && !${POI.IsBlacklisted}
			{
				if ${POI.InUseRange}
				{
					if ${WoWScript[TaxiFrame:IsVisible()]}
					{
						return OB_TAKE_FLIGHT					
					}
					else
					{
						if ${WoWScript[GetGossipOptions()](exists)}
						{
							This.NPCState_NPC_Wait_Until:Set[${Math.Calc[${LavishScript.RunningTime}+(${This.NPCState_Interact_Wait_Until_Timeout} * ${Bot.GlobalCooldown})]}]
							return OB_MOREGOSSIP
						}
						if ${Movement.Speed} || ${Me.Sitting}
						{
							return OB_NPC_GETTING_READY
						}
						else
						{
							This.NPCState_NPC_Wait_Until:Set[${Math.Calc[${LavishScript.RunningTime}+(${This.NPCState_Interact_Wait_Until_Timeout} * ${Bot.GlobalCooldown})]}]
							return OB_USE_NPC
						}						
					}
				}
				return OB_NPC_MOVE
			}
			elseif ${FlightPlan.SetFlightPOI}
			{
					return OB_TAKE_FLIGHT
			}
			FlightPlan.NeedFlight:Set[FALSE]
		}

		if ${FlightPlan.LearnFlightMaster}
		{
			if !${Config.GetCheckbox[chkLearnFM]}
			{
				FlightPlan.LearnFlightMaster:Set[FALSE]
				FlightPlan.LearnFM:Set["0:0:0:0:0:0:0:0"]					
			}
			elseif ${POI.Type.Equal[FLIGHTMASTER]} && !${POI.IsBlacklisted}
			{
				if ${POI.InUseRange}
				{
					if ${WoWScript[TaxiFrame:IsVisible()]}
					{
						return OB_LEARN_FLIGHT					
					}
					else
					{
						if ${WoWScript[GetGossipOptions()](exists)}
						{
							This.NPCState_NPC_Wait_Until:Set[${Math.Calc[${LavishScript.RunningTime}+(${This.NPCState_Interact_Wait_Until_Timeout} * ${Bot.GlobalCooldown})]}]
							return OB_MOREGOSSIP
						}
						if ${Movement.Speed} || ${Me.Sitting}
						{
							return OB_NPC_GETTING_READY
						}
						else
						{
							This.NPCState_NPC_Wait_Until:Set[${Math.Calc[${LavishScript.RunningTime}+(${This.NPCState_Interact_Wait_Until_Timeout} * ${Bot.GlobalCooldown})]}]
							return OB_USE_NPC
						}						
					}
				}
				return OB_NPC_MOVE
			}
			elseif ${POI.Set[${FlightPlan.LearnFM}]}
			{
					return OB_LEARN_FLIGHT
			}
		}
		
		if ${POI.NeedRepair}
		{
			if ${POI.Type.Equal[REPAIR]} && !${POI.IsBlacklisted}
			{
				if ${POI.InUseRange}
				{
					if ${WoWScript[MerchantFrame:IsVisible()]}
					{
						This.NPCState_NPC_Wait_Until:Set[${Math.Calc[${LavishScript.RunningTime}+(${This.NPCState_Interact_Wait_Until_Timeout} * ${Bot.GlobalCooldown})]}]
						return OB_REPAIR
					}
					else
					{
						if ${WoWScript[GetGossipOptions()](exists)}
						{
							This.NPCState_NPC_Wait_Until:Set[${Math.Calc[${LavishScript.RunningTime}+(${This.NPCState_Interact_Wait_Until_Timeout} * ${Bot.GlobalCooldown})]}]
							return OB_MOREGOSSIP
						}
						else
						{
							if ${Movement.Speed} || ${Me.Sitting}
							{
								return OB_NPC_GETTING_READY
							}
							else
							{
								This.NPCState_NPC_Wait_Until:Set[${Math.Calc[${LavishScript.RunningTime}+(${This.NPCState_Interact_Wait_Until_Timeout} * ${Bot.GlobalCooldown})]}]
								return OB_USE_NPC
							}
						}
			 		}
			 	}
			 	else
			 	{
					return OB_NPC_MOVE
			 	}
			}
			else
			{
				if ${POI.SetNearestPOI[REPAIR]}
				{
					return OB_NPC_MOVE
				}
				else
				{
					This:Output[Not enough mapping data to REPAIR POI !]
					;no return here try other NPC
				}
			}
		}
		
		if ${POI.NeedTradeSkill}
		{
			/* Tradeskills.NeedTradeSkill should determine when tradeskills should start and stop */
			if ${Tradeskills.NeedTradeSkill}
			{
					if ${Tradeskills.NeedMake}
					{
						return OB_TRADESKILL_MAKE
					}
					elseif ${Tradeskills.NeedBuy}
					{
						return OB_TRADESKILL_BUY
					}
					elseif ${Tradeskills.NeedTradePOI}
					{
						/* set POI here */
						return OB_TRADESKILL_MOVE
					}
					elseif ${Tradeskills.NeedWait}
					{
						return OB_TRADESKILL_WAIT
					}
			}
			POI.NeedTradeSkill:Set[FALSE] 
		}
			
		if ${POI.NeedSell}
		{
			if ${POI.Type.Equal[SELL]} && !${POI.IsBlacklisted}
			{
				if ${WoWScript[MerchantFrame:IsVisible()]}
				{
					This.NPCState_NPC_Wait_Until:Set[${Math.Calc[${LavishScript.RunningTime}+(${This.NPCState_Interact_Wait_Until_Timeout} * ${Bot.GlobalCooldown})]}]
					return OB_SELL
				}
				else
				{
			 		if ${POI.InUseRange}
			 		{
						if ${WoWScript[GetGossipOptions()](exists)}
						{
							This.NPCState_NPC_Wait_Until:Set[${Math.Calc[${LavishScript.RunningTime}+(${This.NPCState_Interact_Wait_Until_Timeout} * ${Bot.GlobalCooldown})]}]
							return OB_MOREGOSSIP
						}
						else
						{
							This.NPCState_NPC_Wait_Until:Set[${Math.Calc[${LavishScript.RunningTime}+(${This.NPCState_Interact_Wait_Until_Timeout} * ${Bot.GlobalCooldown})]}]
							return OB_USE_NPC
						}
			 		}
			 		else
			 		{
						return OB_NPC_MOVE
			 		}
			 	}
			}
			else
			{
				if ${POI.SetNearestPOI[SELL]}
				{
					return OB_NPC_MOVE
				}
				else
				{
					This:Output[Not enough mapping data to SELL POI !]
					;no return here try other NPC
				}
			}
		}
		
		if ${POI.NeedRestock}
		{
			if ${Inventory.FreeSlots} > 0
			{
				if ${This.RestockMerchant} &&  !${POI.IsBlacklisted}
				{
					if ${POI.InUseRange}
					{
						if ${WoWScript[MerchantFrame:IsVisible()]} 
						{
							This.NPCState_NPC_Wait_Until:Set[${Math.Calc[${LavishScript.RunningTime}+(${This.NPCState_Interact_Wait_Until_Timeout} * ${Bot.GlobalCooldown})]}]
							return OB_RESTOCK
						}
						else
						{
							if ${WoWScript[GetGossipOptions()](exists)}
							{
								This.NPCState_NPC_Wait_Until:Set[${Math.Calc[${LavishScript.RunningTime}+(${This.NPCState_Interact_Wait_Until_Timeout} * ${Bot.GlobalCooldown})]}]
								return OB_MOREGOSSIP
							}
							else
							{
								This.NPCState_NPC_Wait_Until:Set[${Math.Calc[${LavishScript.RunningTime}+(${This.NPCState_Interact_Wait_Until_Timeout} * ${Bot.GlobalCooldown})]}]
								return OB_USE_NPC
							}
						}
					}
					else
					{
							return OB_NPC_MOVE
					}
				}
				else
				{
					if ${Inventory.NeedRestock[1].Equal[FOOT]} && ${Inventory.FoodMerch.NotEqual[""]} && ${POI.SetPOINamed[${Inventory.FoodMerch}]}
					{
						return OB_NPC_MOVE
					}
					elseif ${Inventory.NeedRestock[1].Equal[WATER]} && ${Inventory.DrinkMerch.NotEqual[""]} && ${POI.SetPOINamed[${Inventory.DrinkdMerch}]}
					{
						return OB_NPC_MOVE
					}
					elseif (${Inventory.NeedRestock[1].Equal[AMMO]} || ${Inventory.NeedRestock[1].Equal[ARROW]}) && ${Inventory.AmmoMerch.NotEqual[""]} && ${POI.SetPOINamed[${Inventory.AmmoMerch}]}
					{
						return OB_NPC_MOVE
					}
					elseif ${POI.SetNearestPOI[${Inventory.NeedRestock[1]}]}
					{
						return OB_NPC_MOVE
					}
					else
					{
						This:Output[Not enough mapping data to RESTOCK POI !]
						;no return here try other NPC
					}
				}
			}
			else
			{
				POI.NeedRestock:Set[FALSE]
			}
		}
		
		if ${POI.NeedMailbox}
		{
			if ${POI.Type.Equal[MAILBOX]} && !${POI.IsBlacklisted}
			{
				if ${POI.InUseRange}
				{
					if ${WoWScript[MailFrame:IsVisible()]}
					{
						This.NPCState_NPC_Wait_Until:Set[${Math.Calc[${LavishScript.RunningTime}+(${This.NPCState_Interact_Wait_Until_Timeout} * ${Bot.GlobalCooldown})]}]
						return OB_MULE
					}
					else
					{
						This.NPCState_NPC_Wait_Until:Set[${Math.Calc[${LavishScript.RunningTime}+(${This.NPCState_Interact_Wait_Until_Timeout} * ${Bot.GlobalCooldown})]}]
						return OB_USE_NPC
					}
				}
				else
				{
					return OB_NPC_MOVE
				}
			}
			else
			{
				if ${POI.SetNearestPOI[MAILBOX]}
				{
					return OB_NPC_MOVE
				}
				else
				{
					This:Output[Not enough mapping data to MAILBOX POI !]
					;no return here try other NPC
					POI.NeedMailbox:Set[FALSE]

				}
			}
		}

		if ${POI.NeedClassTrainer}
		{
			if ${POI.Type.Equal[${Me.Class}_TRAINER]} && !${POI.IsBlacklisted}
			{
				if ${POI.InUseRange}
				{
					if ${This.VisibleFrame[ClassTrainerFrame]}
					{
						This.NPCState_NPC_Wait_Until:Set[${Math.Calc[${LavishScript.RunningTime}+(${This.NPCState_Interact_Wait_Until_Timeout} * ${Bot.GlobalCooldown})]}]
						return OB_TRAINER
					}
					else
					{
						if ${WoWScript[GetGossipOptions()](exists)}
						{
							This.NPCState_NPC_Wait_Until:Set[${Math.Calc[${LavishScript.RunningTime}+(${This.NPCState_Interact_Wait_Until_Timeout} * ${Bot.GlobalCooldown})]}]
							return OB_MOREGOSSIP
						}
						else
						{
							This.NPCState_NPC_Wait_Until:Set[${Math.Calc[${LavishScript.RunningTime}+(${This.NPCState_Interact_Wait_Until_Timeout} * ${Bot.GlobalCooldown})]}]
							return OB_USE_NPC
						}
					}
				}
				else
				{
					if !${WoWScript["GetContainerItemCooldown(${Item[Hearthstone].Bag.Number}, ${Item[Hearthstone].Slot})", 2]}
					{
					Move -stop
					Item[Hearthstone]:Use
					Bot.ForcedStateWait:Set[${This.InTenths[100]}]
					}
					return OB_NPC_MOVE
				}
			}
			else
			{
				if ${POI.SetNearestPOI[${Me.Class}_TRAINER]}
				{
						if !${WoWScript["GetContainerItemCooldown(${Item[Hearthstone].Bag.Number}, ${Item[Hearthstone].Slot})", 2]}
						{
						Move -stop
						Item[Hearthstone]:Use
						Bot.ForcedStateWait:Set[${This.InTenths[100]}]
						}
					return OB_NPC_MOVE
				}
				else
				{
					This:Output[Not enough mapping data to CLASSTRAINER, aborting trainer run !]
					;no return here try other NPC
					POI.NeedClassTrainer:Set[FALSE]
				}
			}
		}
		
		
		;THIS IS A SOURCE OF ROAM LAG - ATTEMPTED REWRITE	
		if !${POI.IgnoreSkinningTrainer} && ${Toon.HasSkill[SKILL_SKINNING]}
		{
			if (${Toon.SkillLevel[SKILL_SKINNING]}==${Toon.SkillMaxLevel[SKILL_SKINNING]}) && (${Toon.SkillLevel[SKILL_SKINNING]}<${Bot.SkillLvlCap})
			{
				if ${POI.Type.Equal["Skinning_TRAINER"]} && !${POI.IsBlacklisted}
				{
					if ${POI.InUseRange}
					{
						if ${This.VisibleFrame[ClassTrainerFrame]}
						{
							This.NPCState_NPC_Wait_Until:Set[${Math.Calc[${LavishScript.RunningTime}+(${This.NPCState_Interact_Wait_Until_Timeout} * ${Bot.GlobalCooldown})]}]
							return OB_TRAINER
						}
						else
						{
							if ${WoWScript[GetGossipOptions()](exists)}
							{
								This.NPCState_NPC_Wait_Until:Set[${Math.Calc[${LavishScript.RunningTime}+(${This.NPCState_Interact_Wait_Until_Timeout} * ${Bot.GlobalCooldown})]}]
								return OB_MOREGOSSIP
							}
							else
							{
								This.NPCState_NPC_Wait_Until:Set[${Math.Calc[${LavishScript.RunningTime}+(${This.NPCState_Interact_Wait_Until_Timeout} * ${Bot.GlobalCooldown})]}]
								return OB_USE_NPC
							}
						}
					}
					else
					{
						return OB_NPC_MOVE
					}
				}
				else
				{
					if !${POI.Type.Equal["FLIGHTMASTER"]}
					{
						if ${POI.SetNearestPOI["Skinning_TRAINER",${Math.Calc[1 + ${Toon.SkillLevel[SKILL_SKINNING]}]}]}
						{
							return OB_NPC_MOVE
						}
						else
						{
							This:Output[Not enough mapping data to Skinning Trainer that can train me, aborting trainer run !]
							POI.IgnoreSkinningTrainer:Set[TRUE]
							;no return here try other NPC
						}
					}
				}
			}			
		}
		
		
		if !${POI.IgnoreHerbalismTrainer} && ${Toon.HasSkill[SKILL_HERBALISM]} 
		{
			if (${Toon.SkillLevel[SKILL_HERBALISM]}==${Toon.SkillMaxLevel[SKILL_HERBALISM]}) && (${Toon.SkillLevel[SKILL_HERBALISM]}<${Bot.SkillLvlCap})
			{
				if ${POI.Type.Equal["Herbalism_TRAINER"]} && !${POI.IsBlacklisted}
				{
					if ${POI.InUseRange}
					{
						if ${This.VisibleFrame[ClassTrainerFrame]}
						{
							This.NPCState_NPC_Wait_Until:Set[${Math.Calc[${LavishScript.RunningTime}+(${This.NPCState_Interact_Wait_Until_Timeout} * ${Bot.GlobalCooldown})]}]
							return OB_TRAINER
						}
						else
						{
							if ${WoWScript[GetGossipOptions()](exists)}
							{
								This.NPCState_NPC_Wait_Until:Set[${Math.Calc[${LavishScript.RunningTime}+(${This.NPCState_Interact_Wait_Until_Timeout} * ${Bot.GlobalCooldown})]}]
								return OB_MOREGOSSIP
							}
							else
							{
								This.NPCState_NPC_Wait_Until:Set[${Math.Calc[${LavishScript.RunningTime}+(${This.NPCState_Interact_Wait_Until_Timeout} * ${Bot.GlobalCooldown})]}]
								return OB_USE_NPC
							}
						}
					}
					else
					{
						return OB_NPC_MOVE
					}
				}
				else
				{
					if !${POI.Type.Equal["FLIGHTMASTER"]}
					{
						if ${POI.SetNearestPOI["Herbalism_TRAINER",${Math.Calc[1 + ${Toon.SkillLevel[SKILL_HERBALISM]}]}]}
						{
							return OB_NPC_MOVE
						}
						else
						{
							This:Output[Not enough mapping data to Herbalism Trainer that can train me, aborting trainer run !]
							POI.IgnoreHerbalismTrainer:Set[TRUE]
							;no return here try other NPC
						}
					}
				}
			}
		}
		
		if !${POI.IgnoreMiningTrainer} && ${Toon.HasSkill[SKILL_MINING]}
		{
			if (${Toon.SkillLevel[SKILL_MINING]}==${Toon.SkillMaxLevel[SKILL_MINING]}) && (${Toon.SkillLevel[SKILL_MINING]}<${Bot.SkillLvlCap})
			{
				if ${POI.Type.Equal["Mining_TRAINER"]} && !${POI.IsBlacklisted}
				{
					if ${POI.InUseRange}
					{
						if ${This.VisibleFrame[ClassTrainerFrame]}
						{
							This.NPCState_NPC_Wait_Until:Set[${Math.Calc[${LavishScript.RunningTime}+(${This.NPCState_Interact_Wait_Until_Timeout} * ${Bot.GlobalCooldown})]}]
							return OB_TRAINER
						}
						else
						{
							if ${WoWScript[GetGossipOptions()](exists)}
							{
								This.NPCState_NPC_Wait_Until:Set[${Math.Calc[${LavishScript.RunningTime}+(${This.NPCState_Interact_Wait_Until_Timeout} * ${Bot.GlobalCooldown})]}]
								return OB_MOREGOSSIP
							}
							else
							{
								This.NPCState_NPC_Wait_Until:Set[${Math.Calc[${LavishScript.RunningTime}+(${This.NPCState_Interact_Wait_Until_Timeout} * ${Bot.GlobalCooldown})]}]
								return OB_USE_NPC
							}
						}
					}
					else
					{
						return OB_NPC_MOVE
					}
				}
				else
				{
					if !${POI.Type.Equal["FLIGHTMASTER"]}
					{					
						if ${POI.SetNearestPOI["Mining_TRAINER",${Math.Calc[1 + ${Toon.SkillLevel[SKILL_MINING]}]}]}
						{
							return OB_NPC_MOVE
						}
						else
						{
							This:Output[Not enough mapping data to Mining Trainer that can train me, aborting trainer run !]
							POI.IgnoreMiningTrainer:Set[TRUE]
							;no return here try other NPC
						}
					}
				}
			}
		}
		return OB_IDLE
	}

	method NPCPulse()
	{
		switch ${This.CurrentSubState}
		{
			case OB_NPC_GETTING_READY
			Toon:Standup
			if ${Movement.Speed}
			{
				Navigator:ClearPath
				move -stop
			}
			break
			
			case OB_RESTOCK
			variable iterator iter
			Inventory.RestockList:GetIterator[iter]
			iter:First
			
			This:Debug["RESTOCK?: ${Inventory.NeedRestock}"]
		 	if !${Inventory.NeedRestock}
	 		{
	 			This:Output["Done Restocking"]
	 			POI:Clear
	 			POI.NeedRestock:Set[FALSE]
	 			break
	 		}

			while ${iter.IsValid}
	 		{
	 			This:Debug["MAX: ${iter.Value.Max} STACK: ${Inventory.StackCount[${iter.Key}]} DIS: ${iter.Value.Disabled}"]
	 			if ${iter.Value.Max} > ${Inventory.StackCount[${iter.Key}]} && !${iter.Value.Disabled}
	 			{
	 				if ${Inventory.BuyItem[${iter.Key}]}
	 				{
	 					This:Debug["Buying ${iter.Key}"]
	 					This.NPCState_NPC_Wait_Until:Set[${Math.Calc[${LavishScript.RunningTime}+(${This.NPCState_Interact_Wait_Until_Timeout} * ${Bot.GlobalCooldown})]}]
	 					break
	 				}
	 				elseif ${LNavGroup[${iter.Value.myType}].Contains[${POI.Name}]}
	 				{
	 					iter.Value.Disable:Set[TRUE]
	 				}
	 			}
	 			iter:Next
	 		}
				break
			
			
			case OB_HEARTH_GETTING_READY
			Toon:Standup
			if ${Movement.Speed}
			{
				Navigator:ClearPath
				move -stop
			}
			break
			
			case OB_START_HEARTH 
			Item[Hearthstone]:Use
			break
			
			case OB_NPC_MOVE				
			Human.StopOnFollow_Override:Set[${This.InSeconds[300]}]				
			if ${Mount.NeedMount}
			{
				Grind.CurrentGrind.CurrentHotspot:Set[1]				
				Mount:Mount
				return
			}
			if ${POI.Distance} <= ${Mount.DismountDistance} && ${Mount.IsMounted}
			{
				Mount:Dismount
			}				
			if !${Navigator.IsMovingToCurrentPOI}
			{
				Navigator:MoveToCurrentPOI
			}
			break
			
			case OB_TAKE_FLIGHT
			if !${Me.Flying}
			{
				This:Output["Taking Flightpath to ${FlightPlan.FlightNode[${FlightPlan.DestinationFM}]}"]
			}
			if ${WoWScript[TaxiFrame:IsVisible()]}
			{			
				if ${FlightPlan.NeedRefresh}
				{
					FlightPlan:Refresh
					FlightPlan.NeedRefresh:Set[FALSE]
					return
				}
				if ${FlightPlan.NeedFlight}
				{
					if ${FlightPlan.GetNodeSlot[${FlightPlan.DestinationFM}]} > 0
					{
						WoWScript TakeTaxiNode(${FlightPlan.GetNodeSlot[${FlightPlan.DestinationFM}]})
						FlightPlan.NeedFlight:Set[FALSE]
						FlightPlan.DestinationFM:Set[NULL]
						FlightPlan.LastFlight:Set[${LavishScript.RunningTime}]						
						return
					}
				}
			}
			break
				
			case OB_LEARN_FLIGHT
			if ${WoWScript[TaxiFrame:IsVisible()]}
			{			
				if ${FlightPlan.NeedRefresh}
				{
					FlightPlan:Refresh
					FlightPlan.NeedRefresh:Set[FALSE]
					FlightPlan.LearnFlightMaster:Set[FALSE]
					FlightPlan.LearnFM:Set["0:0:0:0:0:0:0:0"]					
					return
				}
			}				
			break
			
			case OB_USE_NPC
			Mount:Dismount
			Toon:Standup
			Navigator:ClearPath
			move -stop
			POI:Use
			break
			
			case OB_LOGOUT
			if ${UIElement[chkErrorSoundOn@Config@Pages@openbot].Checked}
			{
				This:PlaySound["Stop"]
			}				
			This:Debug["OB_LOGOUT, Have a good day"]
			Navigator:ClearPath
			move -stop
			WoWScript Logout()
			endscript openbot
			break
			
			case OB_MOREGOSSIP
			;TODO: use event GOSSIP_SHOW and title1, gossip1 = GetGossipOptions()
			;see http://www.wowwiki.com/API_GetGossipOptions
			variable int gcheck=1
			variable int copt=0
			while ${WoWScript[GetGossipOptions(),${gcheck}](exists)}
			{
				;This:Output[${WoWScript[GetGossipOptions(),${gcheck}]}]
				if ${WoWScript[GetGossipOptions(),${gcheck}].NotEqual["binder"]} && ${WoWScript[GetGossipOptions(),${gcheck}].NotEqual["gossip"]}
				{	
					copt:Inc
				}
				if ${WoWScript[GetGossipOptions(),${gcheck}].Find["browse your goods"]}!=NULL
				{
					This:Output["Selecting: ${gcheck} ${WoWScript[GetGossipOptions(),${gcheck}]}"]
					WoWScript SelectGossipOption(${copt})
					break
				}
				gcheck:Inc
			}
			WoWScript SelectGossipOption(1)
			break

			case OB_REPAIR
			WoWScript RepairAllItems()
			POI.NeedRepair:Set[FALSE]
			if ${Object[${Inventory.GetSlot[Sell]}](exists)}
			{
				POI.NeedSell:Set[TRUE]
			}
			break
			
			case OB_SELL
			This:Output[Checking ${Sell}]
	 		if ${Object[${Inventory.GetSlot[Sell]}](exists)}
 			{
 				Object[${Inventory.GetSlot[Sell]}]:Use
 			}
			else
			{
				This:Output[Done Selling]
				POI.NeedSell:Set[FALSE]
 				if ${Object[${Inventory.GetSlot[Mule]}](exists)} && ${Me.Coinage} >= 30
				{
					POI.NeedMailbox:Set[TRUE]
				}
			}
			break

			case OB_TRAINER
			WoWScript SetTrainerServiceTypeFilter("available",1)
			WoWScript SetTrainerServiceTypeFilter("unavailable",0)
			WoWScript SetTrainerServiceTypeFilter("used",0)

			if ${WoWScript[GetNumTrainerServices()]}>0
			{
				if ${WoWScript[GetTrainerServiceCost(${WoWScript[GetTrainerSelectionIndex()]})]} <= ${Me.Coinage}
				{
					WoWScript BuyTrainerService(${WoWScript[GetTrainerSelectionIndex()]})
				}
				else
				{
					if ${POI.Type.Equal[${Me.Class}_TRAINER]}
					{
						POI.NeedClassTrainer:Set[FALSE]
						This:Output[Not enough money for ${Me.Class} Trainer, skipping Training !]
					}
					if ${POI.Type.Equal["Skinning_TRAINER"]}
					{
						POI.IgnoreSkinningTrainer:Set[TRUE]
						This:Output[Not enough money for Skinning Trainer, skipping Training !]
					}
					if ${POI.Type.Equal["Herbalism_TRAINER"]}
					{
						POI.IgnoreHerbalismTrainer:Set[TRUE]
						This:Output[Not enough money for Herbalism Trainer, skipping Training !]
					}
					if ${POI.Type.Equal["Mining_TRAINER"]}
					{
						POI.IgnoreMiningTrainer:Set[TRUE]
						This:Output[Not enough money for Mining Trainer, skipping Training !]
					}
				}
			}
			else
			{
				if ${POI.Type.Equal[${Me.Class}_TRAINER]}
				{
					POI.NeedClassTrainer:Set[FALSE]
				}
			}
			break

			case OB_MULE
	 		if ${Object[${Inventory.GetSlot[Mule,"-notsoulbound"]}](exists)} && ${Me.Coinage} >= 30
			{
		 		if ${WoWScript[GetSendMailItem(),3]}
				{
					WoWScript SendMail(\"${UIElement[tenMuleChar@Config@InvPages@Inventory@Pages@OpenBot].Text}\"\, \"${Object[${Inventory.GetSlot[Mule,"-notsoulbound"]}].Name}\"\, \"\")
				}
				else
				{
					if ${WoWScript[CursorHasItem()]}
					{
						WoWScript ClickSendMailItemButton()
					}
					else
					{
						Item[${Inventory.GetSlot[Mule,"-notsoulbound"]}]:PickUp
					}
				}
			}
			else
			{
				POI.NeedMailbox:Set[FALSE]
			}
			break
			
			case OB_TRADESKILL_MAKE
			Tradeskills:MakeTradeSkill
			break
			
			case OB_TRADESKILL_BUY
			Tradeskills:BuyTradeSkill
			break
			
			case OB_TRADESKILL_MOVE
			Tradeskills:NeedTradePOI
			break
			
			case OB_TRADESKILL_WAIT 
			This:Debug[Waiting in Tradeskill]
			break
		}
	}

	;----------
	;----- ITEM Sub State
	;----------
	member ITEMState()
	{
  		if ${LavishScript.RunningTime} <= ${This.ITEMState_Equip_Wait_Until}
  		{
				return OB_EQUIP_WAIT
  		}
			if ${Autoequip.DismissBindPopUp}
			{
				This.ITEMState_Equip_Wait_Until:Set[${Math.Calc[${LavishScript.RunningTime}+(${This.ITEMState_Equip_Wait_Until_Timeout} * ${Bot.GlobalCooldown})]}]
				return OB_EQUIP_WAIT				
			}		
			if ${Autoequip.NeedEQ} && !${Me.Equip[16].Name.Equal["OB_FISHING_POLE"]}
			{
				if ${Autoequip.EquipGear}
				{
					This.ITEMState_Equip_Wait_Until:Set[${Math.Calc[${LavishScript.RunningTime}+(${This.ITEMState_Equip_Wait_Until_Timeout} * ${Bot.GlobalCooldown})]}]
					return OB_EQUIP_WAIT
				}
				elseif ${Autoequip.EquipBag}
				{
					This.ITEMState_Equip_Wait_Until:Set[${Math.Calc[${LavishScript.RunningTime}+(${This.ITEMState_Equip_Wait_Until_Timeout} * ${Bot.GlobalCooldown})]}]
					return OB_EQUIP_WAIT
				}
				else
				{
					Autoequip.NeedEQ:Set[FALSE]
				}
			}
		return OB_IDLE
	}

	method ITEMPulse()
	{
		switch ${This.CurrentSubState}
		{
			case OB_EQUIP_WAIT
			break
		}
	}


	;----------
	;----- QUEST Sub State
	;----	
	member QUESTState()
	{
		/* wait between brief wait between quest states */
  		if ${LavishScript.RunningTime} <= ${This.QUESTstate_Wait_Until}
  		{
			return OB_QUEST_WAIT
  		}
		/* if not waiting, do */
				if ${Questgiver.ChooseReward}
				{
					This.QUESTstate_Wait_Until:Set[${Math.Calc[${LavishScript.RunningTime}+(${This.QUESTstate_Wait_Until_Timeout} * ${Bot.GlobalCooldown})]}]
					return OB_QUEST_REWARD
				}	
				/* need questgiver */
				if ${Questgiver.SetQuestGiverPOI}
				{
					Questgiver:ClearMerchantFrames
					if ${POI.InUseRange}
					{
						if !${Questgiver.GossipVisible} 
						{	
							This.QUESTstate_Wait_Until:Set[${Math.Calc[${LavishScript.RunningTime}+(${This.QUESTstate_Wait_Until_Timeout} * ${Bot.GlobalCooldown})]}]							
							return OB_QUEST_NEEDGOSSIP
						}
						if ${Questgiver.NeedGossip}
						{	
							This.QUESTstate_Wait_Until:Set[${Math.Calc[${LavishScript.RunningTime}+(${This.QUESTstate_Wait_Until_Timeout} * ${Bot.GlobalCooldown})]}]							
							return OB_QUEST_GOSSIP
						}
						return OB_QUEST_CLOSEGOSSIP
					}
					else
					{
						return OB_QUEST_NEEDNPC
					}
				}
				/* an item begins a quest */
				if ${Questgiver.ItemStartQuest}
				{
					This.QUESTstate_Wait_Until:Set[${Math.Calc[${LavishScript.RunningTime}+(${This.QUESTstate_Wait_Until_Timeout} * ${Bot.GlobalCooldown})]}]					
					return OB_ITEM_BEGINSQUEST
				}
		return OB_IDLE		
	}


	method QUESTPulse()
	{
		switch ${This.CurrentSubState}
		{
			case OB_QUEST_WAIT
			{
				return
			}
			case OB_QUEST_REWARD
			{
				Questgiver:GetReward
			}
			
			case OB_QUEST_NEEDOBJECT
			{
				if !${Navigator.IsMovingToCurrentPOI}
				{
					Navigator:MoveToCurrentPOI
				}	
				return
			}		
			case OB_QUEST_HARVEST
			{
				POI:Use
				return
			}
			case OB_QUEST_NEEDGOSSIP
			{
				Target ${POI.GUID}
				POI:Use
				return
			}
			case OB_QUEST_GOSSIP
			{
				Questgiver:GossipPulse
				return
			}	
			case OB_QUEST_CLOSEGOSSIP
			{
				WoWScript CloseGossip()
				if ${WoWScript[QuestFrame:IsVisible()]}
				{
					WoWScript "QuestFrame:Hide()"
				}
				return
			}	
			case OB_QUEST_NEEDNPC
			{
				Target ${POI.GUID}
				if !${Navigator.IsMovingToCurrentPOI}
				{
					Navigator:MoveToCurrentPOI
				}		
				return
			}
			case OB_ITEM_BEGINSQUEST
			{
				Questgiver:BeginItemQuest
			}
		}	
	}		
		
	
	;----------
	;----- ROAM Sub State
	;----------
	member ROAMState()
	{
		if !${Me.Dead} && !${Me.Ghost} && ${Mount.NeedMount}
		{
			return OB_MOUNT
		}

		if !${Me.Dead} && !${Me.Ghost} && ${POI.Distance} <= ${Mount.DismountDistance} && ${Mount.IsMounted}
		{
			return OB_DISMOUNT
		}
		
		if ${Me.Level} != ${Toon.Level}
		{
			return OB_LEVELUP
		}
			
		/* conditionals for moving to mob should be defined in Toon.MoveToMob */
		if ${Toon.MoveToMob} && !${Mount.IsMounted}
		{
			if ${POI.Type.Equal[MOB]} && ${POI.GUID.Equal[${Targeting.TargetCollection.Get[1]}]} 
			{
				return OB_MOVETO_MOB				
			}			
			elseif ${POI.Set[${Object[${Targeting.TargetCollection.Get[1]}].X}:${Object[${Targeting.TargetCollection.Get[1]}].Y}:${Object[${Targeting.TargetCollection.Get[1]}].Z}:${Object[${Targeting.TargetCollection.Get[1]}].GUID}:${Object[${Targeting.TargetCollection.Get[1]}].Name}:MOB:FACTION_NEUTRAL:${Object[${Targeting.TargetCollection.Get[1]}].Level},FALSE]}
			{	
				return OB_MOVETO_MOB
			}
		}
		
		;REWRITTEN TO REDUCE ROAM LAG
		variable bool canMine = FALSE
		variable bool canHerb = FALSE
		if ${Toon.HasSkill[Herbalism]} || ${Toon.HasSkill[Mining]}
		{
			if ${Toon.HasSkill[Herbalism]} && ${UIElement[chkRoamHerb@Config@InvPages@Inventory@Pages@openbot].Checked}
			{
				canHerb:Set[TRUE]
			}
			
			if ${Item[-inventory,"Mining Pick"](exists)} && ${Toon.HasSkill[Mining]} && ${UIElement[chkRoamMine@Config@InvPages@Inventory@Pages@openbot].Checked}
			{
				canMine:Set[TRUE]
			}
			if ${canHerb} && ${canMine}
			{
				if ${POI.SetNearestPOI[MINING,1,${Toon.SkillLevel[Mining]}]}
				{
					;If there is a Herb Node Nearer or same Distance then we prefer to roam there
					if ${POI.SetNearestPOI[HERBALISM,1,${Toon.SkillLevel[Herbalism]},${POI.Distance}]}
					{
						return OB_ROAM_TO_NODE
					}
					return OB_ROAM_TO_NODE
				}
				else
				{
					if ${POI.SetNearestPOI[HERBALISM,1,${Toon.SkillLevel[Herbalism]}]}
					{
						return OB_ROAM_TO_NODE
					}
				}			
			}
			elseif ${canMine}
			{
				if ${POI.SetNearestPOI[MINING,1,${Toon.SkillLevel[Mining]}]}
				{
					return OB_ROAM_TO_NODE
				}
			}
			elseif ${canHerb}
			{
				if ${POI.SetNearestPOI[HERBALISM,1,${Toon.SkillLevel[Herbalism]}]}
				{
					return OB_ROAM_TO_NODE
				}
			}
		}

		if ${Grind.ChangeLocation}
		{
			This:Debug[Changing Location]
		}

		/* only attempt to set a hotspot poi if poi is not current hotspot*/
		if ${POI.Name.NotEqual[${Grind.HotSpotName}]} || (${POI.X} != ${Grind.X} || ${POI.Y} != ${Grind.Y} || ${POI.Z} != ${Grind.Z})
		{
			This:Debug["Setting POI to ${Grind.HotSpotName}"]
			if !${POI.Set[${Grind.X}:${Grind.Y}:${Grind.Z}:${Grind.HotSpotName}:${Grind.HotSpotName}:HOTSPOT:FACTION_NEUTRAL:0]}
			{
				if ${Config.GetCheckbox[chkTakeFMToGrind]}
				{
					if ${FlightPlan.FlyToPoint[${Grind.X},${Grind.Y},${Grind.Z}]}
					{
						if ${FlightPlan.SetFlightPOI}
						{
							return OB_ROAMING
						}
					}
				}
				/* if we loop 25 times within 2 minutes, location is bad */
				if ${This.Location_Failed_Count:Inc} > 25 && ${This.Location_Failed_Timer} > ${LavishScript.RunningTime}
				{
					if ${UIElement[chkErrorSoundOn@Config@Pages@openbot].Checked}
					{
						This:PlaySound["Stop"]
					}
					This:Output["ERROR: LOCATION FAILED. NO CONNECTIONS TO ANY HOTSPOT. FORCING LOCATION CHANGE"]
					Grind:LoadBestLocationSet[TRUE]
					This.Location_Failed_Count:Set[0]
					This.Location_Failed_Timer:Set[0]
					return OB_IDLE
				}
				if ${This.Location_Failed_Timer} < ${LavishScript.RunningTime}
				{
					This.Location_Failed_Timer:Set[${This.Location_Failed_Timer}+120000]
				}
				/* first try iterating through hotspots */
				This:Output["Error: Not enough mapping data to ${Grind.HotSpotName}. Iterating to Next Hotspot"]
				Grind:NextHotspot
				return OB_IDLE
			}
		}
			
		if ${POI.Type.Equal[HOTSPOT]} && ${POI.Name.Token[1,"@"].Upper.Equal[FISHING]}
		{
			if ${Script[OB_FISHING_EXTENSION](exists)} &&  (${Item[-inventory,"OB_FISHING_POLE"](exists)} || ${Me.Equip[16].Name.Equal["OB_FISHING_POLE"]})
			{
				if ${POI.Distance} <= ${Navigator.GetPercision} 
				{
					This:Output[Reached Fishing Hotspot start OB_FISHING_EXTENSION now.]	
					This.LOOTState_Loot_Fishing_Until:Set[${Math.Calc[${LavishScript.RunningTime}+(${This.LOOTState_Loot_Fishing_Timeout} * ${Bot.GlobalCooldown})]}]
				}
			}
			else
			{
				This:Output[Need OB_FISHING_EXTENSION loaded and OB_FISHING_POLE in Inventory to Fish ! Skipping Fishing Hotspot.]	
				This:NextHotspot
			}
		}
		
		/* dont check POI distance for iterating Grind unless POI is Hotspot */
		if ${POI.Type.Equal[HOTSPOT]} && ${POI.Distance} <= ${Math.Calc[${Navigator.GetPercision}+${POI.RandomDistanceModifier}]} && ${POI.Name.Token[1,"@"].Upper.NotEqual[FISHING]}
		{
			This:Output[Reached Current Hotspot. Random switch distance was: ${POI.Distance}]
			This:NextHotspot
		}
		
		;Never Idle during GRIND ;)
		return OB_ROAMING
	}
	
	method ROAMPulse()
	{
		switch ${This.CurrentSubState}
		{
			case OB_MOUNT
			Mount:Mount
			break

			case OB_DISMOUNT
			Mount:Dismount
			break

			case OB_LEVELUP
			This:Output[Gratz we Leveled up! New Level is ${Me.Level}.]
			This:Output[Checking Profile and doing Trainer run.]
			Toon.Level:Set[${Me.Level}]
			Grind:LoadBestLocationSet[FALSE]
			if ${Math.Calc[${Me.Level}%4]} == 0
			{
				POI.NeedClassTrainer:Set[TRUE]
			}
			break
			
			case OB_MOVETO_MOB
			Mount:Dismount
			Toon:NeedTarget			
			if !${Navigator.IsMovingToCurrentPOI}
			{
				Navigator:MoveToCurrentPOI
			}
			break
			
			case OB_ROAMING
			if !${Navigator.IsMovingToCurrentPOI}
			{
				Navigator:MoveToCurrentPOI
			}
			break
		}
	}

	method NextHotspot()
	{
			if ${Grind.RandomizeHotSpots}
			{
				Grind:RandomHotSpot
				This:Output[Next Random HotSpot is ${Grind.HotSpotName}.]
			}
			else
			{
				Grind:NextHotspot
				This:Output[Next HotSpot is ${Grind.HotSpotName}.]			
			}
			POI.RandomDistanceModifier:Set[${Math.Rand[10]}]
			This:Output[Next Distance Modifier is: ${POI.RandomDistanceModifier}]	
	}
	
	method EndFishing()
	{
		if !${Script[OB_FISHING_EXTENSION].Paused}
		{
			Script[OB_FISHING_EXTENSION]:Pause
		}
		if ${Me.Equip[16].Name.Equal["OB_FISHING_POLE"]}
		{
			if ${Item[-inventory,"${MainHandBeforeFishing}"](exists)}
			{
				Item[-inventory,"${MainHandBeforeFishing}"]:Use	
				MainHandBeforeFishing:Set[NULL]
			}
			if ${Item[-inventory,"${OffHandBeforeFishing}"](exists)}
			{
				Item[-inventory,"${OffHandBeforeFishing}"]:Use	
				MainHandBeforeFishing:Set[NULL]
			}
		}
	}

	method StartFishing()
	{
		Navigator:FaceHeading[${Grind.Hd}]
		if !${Me.Equip[16].Name.Equal["OB_FISHING_POLE"]}
		{
			MainHandBeforeFishing:Set[${Me.Equip[16].Name}]
			OffHandBeforeFishing:Set[${Me.Equip[17].Name}]
			Item[-inventory,"OB_FISHING_POLE"]:Use
		}
		if ${Script[OB_FISHING_EXTENSION].Paused}
		{
			Script[OB_FISHING_EXTENSION]:Resume
		}
	}	
	
	; ------ ASSIST MODE
	member ASSISTState()
	{
		if ${State.NeedAssist[${Target.GUID}]}
		{
			if ${State.HaveAssistPath[${Target.GUID}]}
			{
				if ${Target.Distance} < ${Toon.PullRange}
				{
					if ${Class.NeedPullBuff}
					{
						return OB_PULL_BUFF
					}
					else
					{
						return OB_PULL
					}
				}
				else
				{
					return OB_MOVETO_MOB
				}
			}
			else
			{
				This:Output[Need Path to Mob.]
			}
		}
		return OB_ASSIST_IDLE
	}

	method ASSISTPulse()
	{
		switch ${This.CurrentSubState}
		{
			case OB_PULL
			Class:PullPulse
			break
			
			case OB_PULL_BUFF
			Class:PullBuffPulse
			break
			
			case OB_ASSIST_IDLE
			POI.myobjectstring:Set["0:0:0:0:0:0:0:0:0"]	
			Navigator:ClearPath
			break
			
			case OB_MOVETO_MOB
			Navigator:MoveToMob[${Target.GUID}]	
			break
		}
	}	
	
	member NeedAssist(string MobGUID)
	{	
		variable objectref TargetMob
		TargetMob:Set[${MobGUID}]
		
		if ${Mount.IsMounted}
		{
			return FALSE
		}
		
		if !${TargetMob(exists)} || ${TargetMob.Name.Equal[NULL]} 
		{
			return FALSE
		}	
		
		if (${MobGUID.Equal[${Me.GUID}]} || ${TargetMob.Dead})
		{
			return FALSE
		}
		if !${TargetMob.Attackable}
		{
			return FALSE							
		}
		return TRUE
	}

	member HaveAssistPath(string GUID)
	{
		variable float mobDistance
		variable objectref theMob = ${GUID}
		variable int moveDirectly = ${Toon.PullRange}
		
		mobDistance:Set[${Math.Distance[${Me.X},${Me.Y},${Me.Z},${theMob.X},${theMob.Y},${theMob.Z}]}]		
		if ${moveDirectly} < 40
		{
			moveDirectly:Set[40]
		}		
		if ${mobDistance} < ${moveDirectly} && !${Me.IsPathObstructed[${theMob.X},${theMob.Y},${Math.Calc[${theMob.Z}+0.6]}]}
		{
			return TRUE
		}
		elseif ${Navigator.AvailablePath[${theMob.X},${theMob.Y},${theMob.Z}]}
		{
			return TRUE
		}
		return FALSE	
	}	
	
	member LOOT_ASSISTState()
	{
		if (${State.NeedAssist[${Target.GUID}]} && ${State.HaveAssistPath[${Target.GUID}]}) || ${Mount.IsMounted}
		{
			return OB_IDLE
		}
		return ${This.LOOTState}
	}
	
	method LOOT_ASSISTPulse()
	{
		This:LOOTPulse
	}
	
	member ManualOverride()
	{
		if ${WoWScript[IsMouseButtonDown("LeftButton")]} && ${WoWScript[IsMouseButtonDown("RightButton")]}
		{
			return TRUE
		}
		return FALSE
	}
}