Botpack
Class Bot

source: e:\games\UnrealTournament\Botpack\Classes\Bot.uc
Core.Object
   |
   +--Engine.Actor
      |
      +--Engine.Pawn
         |
         +--Botpack.Bot
Direct Known Subclasses:HumanBotPlus, SkaarjBot

class Bot
extends Engine.Pawn

//============================================================================= // Bot. //=============================================================================
Variables
 float Accuracy
           used during movement between pathnodes
 AlternatePath AlternatePath
           used by game AI for team games with bases
 AmbushPoint AmbushSpot
           used during movement between pathnodes
 float BaseAlertness
           used by game AI for team games with bases
 NavigationPoint BlockedPath
           used by game AI for team games with bases
 float CampTime
           used during movement between pathnodes
 float CampingRate
           used during movement between pathnodes
 string DefaultPackage
           used by game AI for team games with bases
 string DefaultSkinName
           used by game AI for team games with bases
 Weapon EnemyDropped
           used during movement between pathnodes
 int FaceSkin
           used by game AI for team games with bases
 class FavoriteWeapon
           used during movement between pathnodes
 int FixedSkin
           used by game AI for team games with bases
 string GoalString
           used by game AI for team games with bases
 RoamTarget, ImpactTarget
           used by game AI for team games with bases
 float LastAttractCheck
           used during movement between pathnodes
 float LastCampCheck
           used during movement between pathnodes
 float LastInvFind
           used during movement between pathnodes
 name LastPainAnim
           used during movement between pathnodes
 Translocator MyTranslocator
           used by game AI for team games with bases
 name NextAnim
           used in states with multiple, sequenced animations
 Pawn OldEnemy
           used in states with multiple, sequenced animations
 int OldMessageID
           used during movement between pathnodes
 name OldMessageType
           used during movement between pathnodes
 float PointDied
           used during movement between pathnodes
 float Rating
           used by game AI for team games with bases
 vector RealLastSeenPos
           used by game AI for team games with bases
 StatusDoll, StatusBelt
           used by game AI for team games with bases
 PlayerPawn SupportingPlayer
           used by game AI for team games with bases
 float TacticalOffset
           used by game AI for team games with bases
 int TeamSkin1
           used by game AI for team games with bases
 int TeamSkin2
           used by game AI for team games with bases
 string VoicePackMetaClass
           used by game AI for team games with bases
 vector WanderDir
           used during movement between pathnodes
 bool bTacticalDir
           used during movement between pathnodes
 bool bVerbose
           for debugging

States
FindAir, Dying, GameEnded, VictoryDance, RangedAttack, FallingState, ImpactJumping, TakeHit, StakeOut, Hunting, TacticalMove, Charging, Fallback, Retreating, Attacking, Acquisition, Wandering, Roaming, Hold, Holding, StartUp

Function Summary
 bool AddInventory(Inventory NewItem)
 rotator AdjustAim(float projSpeed, vector projStart, int aimerror, bool leadTarget, bool warnTarget)
     
/*
AdjustAim()
Returns a rotation which is the direction the bot should aim - after introducing the appropriate aiming error
*/
 float AdjustDesireFor(Inventory Inv)
 bool AdjustHitLocation(out vector, vector TraceDir)
     
/* Adjust hit location - adjusts the hit location in for pawns, and returns
true if it was really a hit, and false if not (for ducking, etc.)
*/
 rotator AdjustToss(float projSpeed, vector projStart, int aimerror, bool leadTarget, bool warnTarget)
     
/*
Adjust the aim at target.  
	- add aim error
	- adjust up or down if barrier
*/
 float AssessThreat(Pawn NewThreat)
 eAttitude AttitudeTo(Pawn Other)
 void BigJump(Actor JumpDest)
 void BotVoiceMessage(name messagetype, byte messageID, Pawn Sender)
 void Bump(Actor Other)
 void CallForHelp()
 bool CanFireAtEnemy()
 bool CanImpactJump()
 bool CanStakeOut()
     
// Can Stake Out - check if I can see my current Destination point, and so can enemy
 void ChangedWeapon()
 bool CheckBumpAttack(Pawn Other)
 bool CheckFutureSight(float deltatime)
     
// check for line of sight to target deltatime from now.
 bool CloseToPointMan(Pawn Other)
     
// CloseToPointMan - called if orders are 'follow' to check if close enough to point man
 bool DeferTo(Bot Other)
 void EnemyAcquired()
 bool FaceDestination(float F)
 void Falling()
 void FastInAir()
 void FearThisSpot(Actor aSpot)
 bool FindAmbushSpot()
 bool FindBestPathToward(Actor desired, bool bClearPaths)
     
/* FindBestPathToward() assumes the desired destination is not directly reachable, 
given the creature's intelligence, it tries to set Destination to the location of the 
best waypoint, and returns true if successful
*/
 void FireWeapon()
 void Gasp()
 float GetRating()
 bool Gibbed(name damageType)
 void GiveUpTactical(bool bNoCharge)
 void HaltFiring()
 void HearNoise(float Loudness, Actor NoiseMaker)
 void HearPickup(Pawn Other)
 void ImpactJump(Actor JumpDest)
 void InitRating()
 void InitializeSkill(float InSkill)
 void JumpOffPawn()
 void JumpOutOfWater(vector jumpDir)
 string KillMessage(name damageType, Pawn Other)
 void Killed(Pawn Killer, Pawn Other, name damageType)
 void LongFall()
 void MaybeTaunt(Pawn Other)
 bool NearWall(float walldist)
     
/* NearWall() returns true if there is a nearby barrier at eyeheight, and
changes Focus to a suggested value
*/
 bool NeedToTurn(vector targ)
 void PainTimer()
 bool PickLocalInventory(float MaxDist, float MinDistraction)
 void PlayChallenge()
 void PlayCombatMove()
 void PlayDeathHit(float Damage, vector HitLocation, name damageType, vector Momentum)
 void PlayDodge(bool bDuckLeft)
 void PlayDyingSound()
 void PlayFiring()
 void PlayFlip()
 
simulated
PlayFootStep()
 void PlayGutHit(float tweentime)
     
/* Default location specific take hits  - make sure pain frames are named right */
 void PlayHeadHit(float tweentime)
 void PlayHit(float Damage, vector HitLocation, name damageType, vector Momentum)
     
//**********************************************************************
 void PlayHitAnim(vector HitLocation, float Damage)
 void PlayLeftHit(float tweentime)
 void PlayLookAround()
 void PlayMeleeAttack()
 void PlayMovingAttack()
 void PlayOutOfWater()
 void PlayRangedAttack()
 void PlayRightHit(float tweentime)
 void PlayTakeHitSound(int damage, name damageType, int Mult)
 void PlayWaving()
 
simulated
PostBeginPlay()
 void PreBeginPlay()
 void PreSetMovement()
 void ReSetSkill()
 float RelativeStrength(Pawn Other)
     
/* RelativeStrength()
returns a value indicating the relative strength of other
0.0 = equal to self
> 0 stronger than self
< 0 weaker than self

Since the result will be compared to the creature's aggressiveness, it should be
on the same order of magnitude (-1 to 1)

Assess based on health and weapon
*/
 void SeePlayer(Actor SeenPlayer)
 void SendGlobalMessage(PlayerReplicationInfo Recipient, name MessageType, byte MessageID, float Wait)
 void SendTeamMessage(PlayerReplicationInfo Recipient, name MessageType, byte MessageID, float Wait)
 void SetAlertness(float NewAlertness)
     
/*
SetAlertness()
Change creature's alertness, and appropriately modify attributes used by engine for determining
seeing and hearing.
SeePlayer() is affected by PeripheralVision, and also by SightRadius and the target's visibility
HearNoise() is affected by HearingThreshold
*/
 bool SetEnemy(Pawn NewEnemy)
 void SetFall()
 void SetMovementPhysics()
     
//=============================================================================
 void SetOrders(name NewOrders, Pawn OrderGiver, optional bool)
 void SetPeripheralVision()
 void ShootTarget(Actor NewTarget)
 Carcass SpawnCarcass()
 void SpawnGibbedCarcass()
 void SpecialFire()
     
// ASMD combo move
 void StartMatch()
 void StopFiring()
 float StrafeAdjust()
 bool StrafeFromDamage(vector momentum, float Damage, name DamageType, bool bFindDest)
 bool SwitchToBestWeapon()
 void TranslocateToTarget(Actor Destn)
 void Trigger(Actor Other, Pawn EventInstigator)
 void TryToDuck(vector duckDir, bool bReversed)
 bool TryToward(Inventory Inv, float Weight)
 void UnderLift(Mover M)
     
// Mover has notifies pawn that pawn is underneath it
 void WarnTarget(Pawn shooter, float projSpeed, vector FireDir)
 void WhatToDoNext(name LikelyState, name LikelyLabel)
 void YellAt(Pawn Moron)
 void ZoneChange(ZoneInfo newZone)


State FindAir Function Summary
 void SetMultiSkin(Actor SkinActor, string SkinName, string FaceName, byte TeamNum)
 void GetMultiSkin(Actor SkinActor, out string, out string)
     
/* Skin Stuff */
 void PickDestination(bool bNoCharge)
     
/* PickDestination()
*/
 void EnemyNotVisible()
 void Timer()
 void AnimEnd()
 void HitWall(vector HitNormal, Actor Wall)
 void TakeDamage(int Damage, Pawn instigatedBy, Vector hitlocation, Vector momentum, name damageType)
 void HeadZoneChange(ZoneInfo newHeadZone)


State Dying Function Summary
 void BeginState()
 void TakeDamage(int Damage, Pawn instigatedBy, Vector hitlocation, Vector momentum, name damageType)
 void ReStartPlayer()


State GameEnded Function Summary
 void BeginState()
 void ClientDying(name DamageType, vector HitLocation)
 void Killed(Pawn Killer, Pawn Other, name damageType)
 void LongFall()
 void SetFall()
 void TryToDuck(vector duckDir, bool bReversed)
 void SpecialFire()


State VictoryDance Function Summary
 void BeginState()
 void EnemyAcquired()
 void TakeDamage(int Damage, Pawn instigatedBy, Vector hitlocation, Vector momentum, name damageType)


State RangedAttack Function Summary
 void EndState()
 void BeginState()
 void SpecialFire()
     
// ASMD combo move
 void AnimEnd()
 void Timer()
 void KeepAttacking()
 void EnemyNotVisible()
 void StopWaiting()
 void StopFiring()
 void TakeDamage(int Damage, Pawn instigatedBy, Vector hitlocation, Vector momentum, name damageType)


State FallingState Function Summary
 void EndState()
 void BeginState()
 void FindNewJumpDest()
 void EnemyAcquired()
 void SetFall()
 void EnemyNotVisible()
 void SeePlayer(Actor SeenPlayer)
 void Landed(vector HitNormal)
 void Timer()
 bool SetEnemy(Pawn NewEnemy)
 void TakeDamage(int Damage, Pawn instigatedBy, Vector hitlocation, Vector momentum, name damageType)
 void adjustJump()
     
//choose a jump velocity
 void ZoneChange(ZoneInfo newZone)
 void AnimEnd()


State ImpactJumping Function Summary
 void EndState()
 void ChangeToHammer()
 void AnimEnd()
 vector ImpactLook()
 void TakeDamage(int Damage, Pawn instigatedBy, Vector hitlocation, Vector momentum, name damageType)


State TakeHit Function Summary
 void BeginState()
 void PlayHitAnim(vector HitLocation, float Damage)
 void Timer()
 void Landed(vector HitNormal)
 void TakeDamage(int Damage, Pawn instigatedBy, Vector hitlocation, Vector momentum, name damageType)


State StakeOut Function Summary
 void EndState()
 void BeginState()
 bool ContinueStakeOut()
 void FindNewStakeOutDir()
 bool ClearShot()
 rotator AdjustAim(float projSpeed, vector projStart, int aimerror, bool leadTarget, bool warnTarget)
 void Timer()
 bool SetEnemy(Pawn NewEnemy)
 void SetFall()
 void HearNoise(float Loudness, Actor NoiseMaker)
 void TakeDamage(int Damage, Pawn instigatedBy, Vector hitlocation, Vector momentum, name damageType)


State Hunting Function Summary
 void EndState()
 void BeginState()
 bool FindViewSpot()
 void PickDestination()
 bool TryToward(Inventory Inv, float Weight)
 void HitWall(vector HitNormal, Actor Wall)
 void Timer()
 void AnimEnd()
 bool SetEnemy(Pawn NewEnemy)
 void SetFall()
 void HearNoise(float Loudness, Actor NoiseMaker)
 void TakeDamage(int Damage, Pawn instigatedBy, Vector hitlocation, Vector momentum, name damageType)
 void FearThisSpot(Actor aSpot)
 bool CheckBumpAttack(Pawn Other)
 void MayFall()
     
	/* MayFall() called by engine physics if walking and bCanJump, and
		is about to go off a ledge.  Pawn has opportunity (by setting 
		bCanJump to false) to avoid fall
	*/


State TacticalMove Function Summary
 void EndState()
 void BeginState()
 void PickRegDestination(bool bNoCharge)
 void PickDestination(bool bNoCharge)
     
/* PickDestination()
Choose a destination for the tactical move, based on aggressiveness and the tactical
situation. Make sure destination is reachable
*/
 void PainTimer()
 bool TryToward(Inventory Inv, float Weight)
 void GiveUpTactical(bool bNoCharge)
 void EnemyNotVisible()
 void Timer()
 void AnimEnd()
 void FearThisSpot(Actor aSpot)
 void HitWall(vector HitNormal, Actor Wall)
 void TakeDamage(int Damage, Pawn instigatedBy, Vector hitlocation, Vector momentum, name damageType)
 void SetFall()
 void WarnTarget(Pawn shooter, float projSpeed, vector FireDir)


State Charging Function Summary
 void EndState()
 void BeginState()
 void EnemyNotVisible()
 void Timer()
 void AnimEnd()
 void TakeDamage(int Damage, Pawn instigatedBy, Vector hitlocation, Vector momentum, name damageType)
 bool TryStrafe(vector sideDir)
 bool StrafeFromDamage(vector momentum, float Damage, name DamageType, bool bFindDest)
 void TryToDuck(vector duckDir, bool bReversed)
 void FearThisSpot(Actor aSpot)
 void SetFall()
 void HitWall(vector HitNormal, Actor Wall)
 void MayFall()
     
	/* MayFall() called by engine physics if walking and bCanJump, and
		is about to go off a ledge.  Pawn has opportunity (by setting 
		bCanJump to false) to avoid fall
	*/


State Fallback Function Summary
 void EndState()
 void BeginState()
 void AnimEnd()
 bool CheckBumpAttack(Pawn Other)
 void PickDestination()
 void HitWall(vector HitNormal, Actor Wall)
 void SetFall()
 void Timer()
 void TakeDamage(int Damage, Pawn instigatedBy, Vector hitlocation, Vector momentum, name damageType)
 void HearNoise(float Loudness, Actor NoiseMaker)
 void SeePlayer(Actor SeenPlayer)
 void EnemyNotVisible()
 void MayFall()


State Retreating Function Summary
 void EndState()
 void BeginState()
 void AnimEnd()
 void PickNextSpot()
 void ReachedHome()
 bool CheckBumpAttack(Pawn Other)
 void ChangeDestination()
 void PickDestination()
 void HitWall(vector HitNormal, Actor Wall)
 void SetFall()
 void Timer()
 void TakeDamage(int Damage, Pawn instigatedBy, Vector hitlocation, Vector momentum, name damageType)
 void HearNoise(float Loudness, Actor NoiseMaker)
 void SeePlayer(Actor SeenPlayer)
 void WarnTarget(Pawn shooter, float projSpeed, vector FireDir)
 void MayFall()


State Attacking Function Summary
 void BeginState()
 void Timer()
 void EnemyNotVisible()
     
//EnemyNotVisible implemented so engine will update LastSeenPos
 void ChooseAttackMode()


State Acquisition Function Summary
 void EndState()
 void BeginState()
 void SeePlayer(Actor SeenPlayer)
 void HearNoise(float Loudness, Actor NoiseMaker)
 void TakeDamage(int Damage, Pawn instigatedBy, Vector hitlocation, Vector momentum, name damageType)
 void WarnTarget(Pawn shooter, float projSpeed, vector FireDir)


State Wandering Function Summary
 void EndState()
 void BeginState()
 void FearThisSpot(Actor aSpot)
 void AnimEnd()
 void PickDestination()
 bool TestDirection(vector dir, out vector)
 void HitWall(vector HitNormal, Actor Wall)
 void EnemyAcquired()
 void SetFall()
 void Timer()
 void TakeDamage(int Damage, Pawn instigatedBy, Vector hitlocation, Vector momentum, name damageType)
 void ShootTarget(Actor NewTarget)
 void SetOrders(name NewOrders, Pawn OrderGiver, optional bool)
 bool DeferTo(Bot Other)


State Roaming Function Summary
 void EndState()
 void BeginState()
 void ShareWith(Pawn Other)
 void AnimEnd()
 void PickDestination()
 void HitWall(vector HitNormal, Actor Wall)
 void EnemyAcquired()
 void SetFall()
 void Timer()
 void FearThisSpot(Actor aSpot)
 void TakeDamage(int Damage, Pawn instigatedBy, Vector hitlocation, Vector momentum, name damageType)
 void HandleHelpMessageFrom(Pawn Other)
 void MayFall()
 void ShootTarget(Actor NewTarget)
 void HearPickup(Pawn Other)
 void SetOrders(name NewOrders, Pawn OrderGiver, optional bool)


State Hold Function Summary
 void BeginState()
 void Landed(vector HitNormal)
 void AnimEnd()
 void PickDestination()
 void HitWall(vector HitNormal, Actor Wall)
 void EnemyAcquired()
 void SetFall()
 void Timer()
 void FearThisSpot(Actor aSpot)
 void HandleHelpMessageFrom(Pawn Other)
 void TakeDamage(int Damage, Pawn instigatedBy, Vector hitlocation, Vector momentum, name damageType)


State Holding Function Summary
 void EndState()
 void BeginState()
 void Landed(vector HitNormal)
 void AnimEnd()
 void EnemyAcquired()
 void Timer()
 void TakeDamage(int Damage, Pawn instigatedBy, Vector hitlocation, Vector momentum, name damageType)
 void ShootTarget(Actor NewTarget)


State StartUp Function Summary
 void BeginState()



Source Code


00001	//=============================================================================
00002	// Bot.
00003	//=============================================================================
00004	class Bot expands Pawn
00005		abstract;
00006	
00007	var(Pawn) class<carcass> CarcassType;
00008	
00009	// Advanced AI attributes.
00010	var(Orders) name	Orders;			//orders a bot is carrying out 
00011	var(Orders) name	OrderTag;		// tag of object referred to by orders
00012	var		actor		OrderObject;		// object referred to by orders (if applicable)
00013	var(Combat) float	TimeBetweenAttacks;  // seconds - modified by difficulty
00014	var 	name		NextAnim;		// used in states with multiple, sequenced animations	
00015	var(Combat) float	Aggressiveness; //0.0 to 1.0 (typically)
00016	var		float       BaseAggressiveness; 
00017	var   	Pawn		OldEnemy;
00018	var		int			numHuntPaths;
00019	var		vector		HidingSpot;
00020	var		float		WalkingSpeed;
00021	var(Combat) float	RefireRate;
00022	var		float		StrafingAbility;
00023	
00024	//AI flags
00025	var	 	bool   		bReadyToAttack;		// can attack again 
00026	var		bool		bCanFire;			//used by TacticalMove and Charging states
00027	var		bool		bCanDuck;
00028	var		bool		bStrafeDir;
00029	var(Combat) bool	bLeadTarget;		// lead target with projectile attack
00030	var		bool		bSpecialGoal;
00031	var		bool		bChangeDir;			// tactical move boolean
00032	var		bool		bFiringPaused;
00033	var		bool		bComboPaused;
00034	var		bool		bSpecialPausing;
00035	var		bool		bGreenBlood;
00036	var		bool		bFrustrated;
00037	var		bool		bNoShootDecor;
00038	var		bool		bGathering;
00039	var		bool		bCamping;
00040	var config	bool	bVerbose; //for debugging
00041	var		bool		bViewTarget; //is being used as a viewtarget
00042	var		bool		bWantsToCamp;
00043	var		bool		bWallAdjust;
00044	var		bool		bCanTranslocate;
00045	var		bool		bInitLifeMessage;
00046	var		bool		bNoClearSpecial;
00047	var		bool		bStayFreelance;
00048	var		bool		bNovice;
00049	var		bool		bThreePlus;		// high skill novice
00050	var		bool		bKamikaze;
00051	var		bool		bClearShot;
00052	var		bool		bQuickFire;		// fire quickly as moving in and out of cover
00053	var		bool		bDevious;
00054	var		bool		bDumbDown;		// dumb down team AI 
00055	var		bool		bJumpy;
00056	var		bool		bHasImpactHammer;
00057	var		bool		bImpactJumping;
00058	var		bool		bSniping;
00059	var		bool		bFireFalling;
00060	var		bool		bLeading;
00061	var		bool		bSpecialAmbush;
00062	var		bool		bCampOnlyOnce;
00063	var		bool		bPowerPlay;
00064	var		bool		bBigJump;
00065	var     bool		bTacticalDir;		// used during movement between pathnodes
00066	var		bool		bNoTact;
00067	var		bool		bMustHunt;
00068	var		bool		bIsCrouching;
00069	
00070	var Weapon EnemyDropped;
00071	var float LastInvFind;
00072	var class<Weapon> FavoriteWeapon;
00073	var float Accuracy;
00074	var vector WanderDir;
00075	
00076	var     name		LastPainAnim;
00077	var		float		LastPainTime;
00078	var		float		LastAcquireTime;
00079	
00080	var(Sounds) sound 	drown;
00081	var(Sounds) sound	breathagain;
00082	var(Sounds) sound	Footstep1;
00083	var(Sounds) sound	Footstep2;
00084	var(Sounds) sound	Footstep3;
00085	var(Sounds) sound	HitSound3;
00086	var(Sounds) sound	HitSound4;
00087	var(Sounds)	Sound	Deaths[6];
00088	var(Sounds) sound	GaspSound;
00089	var(Sounds) sound	UWHit1;
00090	var(Sounds) sound	UWHit2;
00091	var(Sounds) sound   LandGrunt;
00092	var(Sounds) sound	JumpSound;
00093	
00094	var name OldMessageType;
00095	var int OldMessageID;
00096	
00097	var float PointDied;
00098	var float CampTime;
00099	var float CampingRate;
00100	var float LastCampCheck;
00101	var float LastAttractCheck;
00102	var Ambushpoint AmbushSpot;
00103	var AlternatePath AlternatePath; //used by game AI for team games with bases
00104	var Actor RoamTarget, ImpactTarget;
00105	var float Rating;
00106	var int	FaceSkin;
00107	var int	FixedSkin;
00108	var int	TeamSkin1;
00109	var int	TeamSkin2;
00110	var string DefaultSkinName;
00111	var string DefaultPackage;
00112	var float BaseAlertness;
00113	
00114	var Translocator MyTranslocator;
00115	
00116	var PlayerPawn SupportingPlayer;
00117	var NavigationPoint BlockedPath;
00118	var vector RealLastSeenPos;
00119	var float TacticalOffset;
00120	
00121	// for debugging
00122	var string GoalString;
00123	
00124	// HUD status 
00125	var texture StatusDoll, StatusBelt;
00126	
00127	// allowed voices
00128	var string VoicePackMetaClass;
00129	
00130	function PreBeginPlay()
00131	{
00132		bIsPlayer = true;
00133		Super.PreBeginPlay();
00134	
00135		if (Orders == '')
00136			Orders = 'FreeLance';
00137	}
00138	
00139	// called when using movetoward with bAdvancedTactics true to temporarily modify destination
00140	event AlterDestination()
00141	{
00142		local float dir, dist;
00143	
00144		dist = VSize(Destination - Location);
00145		if ( dist < 120 )
00146		{
00147			bAdvancedTactics = false;
00148			return;
00149		}
00150		if ( bNoTact )
00151			return;
00152	
00153		if ( bTacticalDir )
00154			Dir = 1;
00155		else
00156			Dir = -1;
00157		Destination = Destination + 1.2 * Dir * dist * Normal((Destination - Location) Cross vect(0,0,1));
00158	}
00159	
00160	// Mover has notifies pawn that pawn is underneath it
00161	function UnderLift(Mover M)
00162	{
00163		local NavigationPoint N;
00164	
00165		// find nearest lift exit and go for that
00166		if ( (MoveTarget != None) && MoveTarget.IsA('LiftCenter') )
00167			for ( N=Level.NavigationPointList; N!=None; N=N.NextNavigationPoint )
00168				if ( N.IsA('LiftExit') && (LiftExit(N).LiftTag == M.Tag)
00169					&& ActorReachable(N) )
00170				{
00171					MoveTarget = N;
00172					return;
00173				}
00174	}
00175	
00176	simulated function PostBeginPlay()
00177	{
00178		if ( class'GameInfo'.Default.bVeryLowGore )
00179			bGreenBlood = true;
00180		InitRating();
00181		Super.PostBeginPlay();
00182		if ( Level.NetMode != NM_DedicatedServer )
00183			Shadow = Spawn(class'PlayerShadow',self);
00184	}
00185	 
00186	function StartMatch();
00187	
00188	function StopFiring()
00189	{
00190		bFire = 0;
00191		bAltFire = 0;
00192		SetTimer((0.5 + 0.5 * FRand()) * TimeBetweenAttacks, false);
00193	}
00194	
00195	function ShootTarget(Actor NewTarget);
00196		
00197	function InitRating() 
00198	{
00199		if ( !Level.Game.IsA('DeathMatchPlus') )
00200			return;
00201		
00202		Rating = 1000 + 400 * skill;
00203		if ( DeathMatchPlus(Level.Game).bNoviceMode )
00204			Rating -= 500;
00205	}
00206	
00207	function float GetRating()
00208	{
00209		return Rating;
00210	}
00211	
00212	function PlayLookAround()
00213	{
00214		PlayWaiting();
00215	}
00216	
00217	function PlayWaving()
00218	{
00219		TweenToWaiting(0.4);
00220	}
00221	
00222	function PlayFlip()
00223	{
00224		PlayAnim('Flip', 1.35 * FMax(0.35, Region.Zone.ZoneGravity.Z/Region.Zone.Default.ZoneGravity.Z), 0.06);
00225	}
00226	
00227	singular event BaseChange()
00228	{
00229		local actor HitActor;
00230		local vector HitNormal, HitLocation;
00231	
00232		if ( Mover(Base) != None )
00233		{
00234			// handle shootable secret floors
00235			if ( Mover(Base).bDamageTriggered && !Mover(Base).bOpening
00236				&& (MoveTarget != None) )
00237			{
00238				HitActor = Trace(HitLocation, HitNormal, MoveTarget.Location, Location, true);
00239				if ( HitActor == Base )
00240				{
00241					Target = Base;
00242					bShootSpecial = true;
00243					FireWeapon();
00244					bFire = 0;
00245					bAltFire = 0;
00246					Base.Trigger(Base, Self);
00247					bShootSpecial = false;
00248				}
00249			}
00250		}
00251		else
00252			Super.BaseChange();
00253	}
00254	
00255	function YellAt(Pawn Moron)
00256	{
00257		local float Threshold;
00258	
00259		if ( Enemy == None )
00260			Threshold = 0.4;
00261		else
00262			Threshold = 0.7;
00263		if ( FRand() < Threshold )
00264			return;
00265	
00266		SendTeamMessage(None, 'FRIENDLYFIRE', Rand(class<ChallengeVoicePack>(PlayerReplicationInfo.VoiceType).Default.NumFFires), 5);
00267	}	
00268	
00269	function bool AddInventory( inventory NewItem )
00270	{
00271		Super.AddInventory(NewItem);
00272	
00273		if ( NewItem.IsA('Translocator') )
00274			MyTranslocator = Translocator(NewItem);
00275	}
00276	
00277	function HaltFiring()
00278	{
00279		bCanFire = false;
00280		bFire = 0;
00281		bAltFire = 0;
00282		SetTimer((0.75 + 0.5 * FRand()) * TimeBetweenAttacks, false);
00283		if ( Weapon != None )
00284			Weapon.Tick(0.001);
00285	}
00286	
00287	function bool TryToward(inventory Inv, float Weight)
00288	{
00289		return true;
00290	}
00291	
00292	function SendTeamMessage(PlayerReplicationInfo Recipient, name MessageType, byte MessageID, float Wait)
00293	{
00294		//log(self@"Send message"@MessageType@MessageID@"at"@Level.TimeSeconds);
00295		if ( (MessageType == OldMessageType) && (MessageID == OldMessageID)
00296			&& (Level.TimeSeconds - OldMessageTime < Wait) )
00297			return;
00298	
00299		//log("Passed filter");
00300		OldMessageID = MessageID;
00301		OldMessageType = MessageType;
00302	
00303		SendVoiceMessage(PlayerReplicationInfo, Recipient, MessageType, MessageID, 'TEAM');
00304	}
00305	
00306	function SendGlobalMessage(PlayerReplicationInfo Recipient, name MessageType, byte MessageID, float Wait)
00307	{
00308		//log(self@"Send message"@MessageType@MessageID@"at"@Level.TimeSeconds);
00309		if ( (MessageType == OldMessageType) && (MessageID == OldMessageID) 
00310			&& (Level.TimeSeconds - OldMessageTime < Wait) )
00311			return;
00312	
00313		//log("Passed filter");
00314		OldMessageID = MessageID;
00315		OldMessageType = MessageType;
00316	
00317		SendVoiceMessage(PlayerReplicationInfo, Recipient, MessageType, MessageID, 'GLOBAL');
00318	}
00319	
00320	function SetOrders(name NewOrders, Pawn OrderGiver, optional bool bNoAck)
00321	{
00322		local Pawn P;
00323		local Bot B;
00324	
00325		if ( NewOrders != BotReplicationInfo(PlayerReplicationInfo).RealOrders )
00326		{ 
00327			if ( (IsInState('Roaming') && bCamping) || IsInState('Wandering') )
00328				GotoState('Roaming', 'PreBegin');
00329			else if ( !IsInState('Dying') )
00330				GotoState('Attacking');
00331		}
00332	
00333		bLeading = false;
00334		if ( NewOrders == 'Point' )
00335		{
00336			NewOrders = 'Attack';
00337			SupportingPlayer = PlayerPawn(OrderGiver);
00338		}
00339		else
00340			SupportingPlayer = None;
00341	
00342		if ( bSniping && (NewOrders != 'Defend') )
00343			bSniping = false;
00344		bStayFreelance = false;
00345		if ( !bNoAck && (OrderGiver != None) )
00346			SendTeamMessage(OrderGiver.PlayerReplicationInfo, 'ACK', Rand(class<ChallengeVoicePack>(PlayerReplicationInfo.VoiceType).Default.NumAcks), 5);
00347	
00348		BotReplicationInfo(PlayerReplicationInfo).SetRealOrderGiver(OrderGiver);
00349		BotReplicationInfo(PlayerReplicationInfo).RealOrders = NewOrders;
00350	
00351		Aggressiveness = BaseAggressiveness;
00352		if ( Orders == 'Follow' )
00353			Aggressiveness -= 1;
00354		Orders = NewOrders;
00355		if ( !bNoAck && (HoldSpot(OrderObject) != None) )
00356		{
00357			OrderObject.Destroy();
00358			OrderObject = None;
00359		}
00360		if ( Orders == 'Hold' )
00361		{
00362			Aggressiveness += 1;
00363			if ( !bNoAck )
00364				OrderObject = OrderGiver.Spawn(class'HoldSpot');
00365		}
00366		else if ( Orders == 'Follow' )
00367		{
00368			Aggressiveness += 1;
00369			OrderObject = OrderGiver;
00370		}
00371		else if ( Orders == 'Defend' )
00372		{
00373			if ( Level.Game.IsA('TeamGamePlus') )
00374				OrderObject = TeamGamePlus(Level.Game).SetDefenseFor(self);
00375			else
00376				OrderObject = None;
00377			if ( OrderObject == None )
00378			{
00379				Orders = 'Freelance';
00380				if ( bVerbose )
00381					log(self$" defender couldn't find defense object");
00382			}
00383			else
00384				CampingRate = 1.0;
00385		}
00386		else if ( Orders == 'Attack' )
00387		{
00388			CampingRate = 0.0;
00389			// set bLeading if have supporters
00390			if ( Level.Game.bTeamGame )
00391				for ( P=Level.PawnList; P!=None; P=P.NextPawn )
00392					if ( P.bIsPlayer && (P.PlayerReplicationInfo.Team == PlayerReplicationInfo.Team) )
00393					{
00394						B = Bot(P);
00395						if ( (B != None) && (B.OrderObject == self) && (BotReplicationInfo(B.PlayerReplicationInfo).RealOrders == 'Follow') )
00396						{
00397							bLeading = true;
00398							break;
00399						}
00400					}
00401		}	
00402					
00403		BotReplicationInfo(PlayerReplicationInfo).OrderObject = OrderObject;
00404	}
00405	
00406	function BotVoiceMessage(name messagetype, byte messageID, Pawn Sender)
00407	{
00408		if ( !Level.Game.bTeamGame || (Sender.PlayerReplicationInfo.Team != PlayerReplicationInfo.Team) )
00409			return;
00410	
00411		if ( messagetype == 'ORDER' )
00412			SetOrders(class'ChallengeTeamHUD'.default.OrderNames[messageID], Sender);
00413	}
00414	
00415	function float AdjustDesireFor(Inventory Inv)
00416	{
00417		if ( inv.class == FavoriteWeapon )
00418			return 0.35;
00419	
00420		return 0;
00421	}
00422	
00423	function bool SwitchToBestWeapon()
00424	{
00425		local float rating;
00426		local int usealt, favalt;
00427		local inventory MyFav;
00428	
00429		if ( Inventory == None )
00430			return false;
00431	
00432		PendingWeapon = Inventory.RecommendWeapon(rating, usealt);
00433		if ( PendingWeapon == None )
00434			return false;
00435	
00436		if ( (FavoriteWeapon != None) && (PendingWeapon.class != FavoriteWeapon) )
00437		{
00438			MyFav = FindInventoryType(FavoriteWeapon);
00439			if ( (MyFav != None) && (Weapon(MyFav).RateSelf(favalt) + 0.22 > PendingWeapon.RateSelf(usealt)) )
00440			{
00441				usealt = favalt;
00442				PendingWeapon = Weapon(MyFav);
00443			}
00444		}
00445		if ( Weapon == None )
00446			ChangedWeapon();
00447		else if ( Weapon != PendingWeapon )
00448			Weapon.PutDown();
00449	
00450		return (usealt > 0);
00451	}
00452	
00453	// ASMD combo move
00454	function SpecialFire()
00455	{
00456		bComboPaused = true;
00457		SpecialPause = 0.75 + VSize(Target.Location - Location)/Weapon.AltProjectileSpeed;
00458		NextState = 'Attacking';
00459		NextLabel = 'Begin'; 
00460		Acceleration = vect(0,0,0);
00461		GotoState('RangedAttack');
00462	}
00463	
00464	//*********************************************************************
00465	/* Default location specific take hits  - make sure pain frames are named right */
00466	function PlayGutHit(float tweentime)
00467	{
00468		if ( (LastPainTime - Level.TimeSeconds < 0.3) && (LastPainAnim == 'GutHit') )
00469		{
00470			if (FRand() < 0.5)
00471				TweenAnim('LeftHit', tweentime);
00472			else
00473				TweenAnim('RightHit', tweentime);
00474		}
00475		else
00476			TweenAnim('GutHit', tweentime);
00477	}
00478	
00479	function PlayHeadHit(float tweentime)
00480	{
00481		if ( (LastPainTime - Level.TimeSeconds < 0.3) && (LastPainAnim == 'HeadHit') )
00482		{
00483			if (FRand() < 0.5)
00484				TweenAnim('LeftHit', tweentime);
00485			else
00486				TweenAnim('RightHit', tweentime);
00487		}
00488		else
00489			TweenAnim('HeadHit', tweentime);
00490	}
00491	
00492	function PlayLeftHit(float tweentime)
00493	{
00494		if ( (LastPainTime - Level.TimeSeconds < 0.3) && (LastPainAnim == 'LeftHit') )
00495			TweenAnim('GutHit', tweentime);
00496		else
00497			TweenAnim('LeftHit', tweentime);
00498	}
00499	
00500	function PlayRightHit(float tweentime)
00501	{
00502		if ( (LastPainTime - Level.TimeSeconds < 0.3) && (LastPainAnim == 'RightHit') )
00503			TweenAnim('GutHit', tweentime);
00504		else
00505			TweenAnim('RightHit', tweentime);
00506	}
00507	
00508	function bool StrafeFromDamage(vector momentum, float Damage,name DamageType, bool bFindDest);
00509	
00510	//**********************************************************************
00511	
00512	function PlayHit(float Damage, vector HitLocation, name damageType, vector Momentum)
00513	{
00514		local float rnd;
00515		local Bubble1 bub;
00516		local bool bOptionalTakeHit;
00517		local vector BloodOffset, Mo;
00518	
00519		if (Damage > 1) //spawn some blood
00520		{
00521			if (damageType == 'Drowned')
00522			{
00523				bub = spawn(class 'Bubble1',,, Location 
00524					+ 0.7 * CollisionRadius * vector(ViewRotation) + 0.3 * BaseEyeHeight * vect(0,0,1));
00525				if (bub != None)
00526					bub.DrawScale = FRand()*0.06+0.04; 
00527			}
00528			else if ( damageType != 'Corroded' )
00529			{
00530				BloodOffset = 0.2 * CollisionRadius * Normal(HitLocation - Location);
00531				BloodOffset.Z = BloodOffset.Z * 0.5;
00532				if ( bGreenBlood )
00533					spawn(class 'UT_GreenBloodPuff',self,,hitLocation + BloodOffset, rotator(BloodOffset));
00534				else if ( (!Level.bDropDetail || (FRand() < 0.67))
00535					&& ((DamageType == 'shot') || (DamageType == 'decapitated') || (DamageType == 'shredded')) )
00536				{
00537					Mo = Momentum;
00538					if ( Mo.Z > 0 )
00539						Mo.Z *= 0.5;
00540					spawn(class 'UT_BloodHit',self,,hitLocation + BloodOffset, rotator(Mo));
00541				}
00542				else
00543					spawn(class 'UT_BloodBurst',self,,hitLocation + BloodOffset);
00544			}
00545		}	
00546	
00547		bFireFalling = false;
00548		bOptionalTakeHit = ( (Level.TimeSeconds - LastPainTime > 0.3 + 0.25 * skill)
00549							&& (Damage * FRand() > 0.08 * Health) && (bNovice || (Skill < 2))
00550							&& (GetAnimGroup(AnimSequence) != 'MovingAttack') 
00551							&& (GetAnimGroup(AnimSequence) != 'Attack') ); 
00552	
00553		PlayTakeHitSound(Damage, damageType, 2);
00554		if ( ((Weapon == None) || !Weapon.bPointing)
00555			 && (GetAnimGroup(AnimSequence) != 'Dodge') 
00556			&& (bOptionalTakeHit || (Momentum.Z > 140) 
00557				 || (Damage * FRand() > (0.17 + 0.04 * skill) * Health)) ) 
00558		{
00559			PlayHitAnim(HitLocation, Damage);
00560			if ( (Enemy != None) && !bNovice && (FRand() * Skill > 0.5) )
00561			{
00562				NextState = 'FallingState';
00563				NextLabel = 'FireWhileFalling';
00564			}
00565		}
00566		else if ( (Region.Zone.ZoneGravity.Z > Region.Zone.Default.ZoneGravity.Z)
00567					&& (Momentum.Z/Region.Zone.ZoneGravity.Z < -0.5) )
00568			bFireFalling = true;
00569		else if (NextState == 'TakeHit')
00570			NextState = '';
00571	}
00572	
00573	function PlayHitAnim(vector HitLocation, float Damage)
00574	{
00575		NextAnim = ''; 
00576		NextState = 'TakeHit';
00577		PlayTakeHit(0.08, hitLocation, Damage); 
00578	} 
00579	
00580	function PlayDeathHit(float Damage, vector HitLocation, name damageType, vector Momentum)
00581	{
00582		local Bubble1 bub;
00583		local UT_BloodBurst b;
00584		local vector Mo;
00585	
00586		if ( Region.Zone.bDestructive && (Region.Zone.ExitActor != None) )
00587			Spawn(Region.Zone.ExitActor);
00588		if (HeadRegion.Zone.bWaterZone)
00589		{
00590			bub = spawn(class 'Bubble1',,, Location 
00591				+ 0.3 * CollisionRadius * vector(Rotation) + 0.8 * BaseEyeHeight * vect(0,0,1));
00592			if (bub != None)
00593				bub.DrawScale = FRand()*0.08+0.03; 
00594			bub = spawn(class 'Bubble1',,, Location 
00595				+ 0.2 * CollisionRadius * VRand() + 0.7 * BaseEyeHeight * vect(0,0,1));
00596			if (bub != None)
00597				bub.DrawScale = FRand()*0.08+0.03; 
00598			bub = spawn(class 'Bubble1',,, Location 
00599				+ 0.3 * CollisionRadius * VRand() + 0.6 * BaseEyeHeight * vect(0,0,1));
00600			if (bub != None)
00601				bub.DrawScale = FRand()*0.08+0.03; 
00602		}
00603		if ( !bGreenBlood && (DamageType == 'shot') || (DamageType == 'decapitated') )
00604		{
00605			Mo = Momentum;
00606			if ( Mo.Z > 0 )
00607				Mo.Z *= 0.5;
00608			spawn(class 'UT_BloodHit',self,,hitLocation, rotator(Mo));
00609		}
00610		else if ( (damageType != 'Burned') && (damageType != 'Corroded') 
00611			 && (damageType != 'Drowned') && (damageType != 'Fell') )
00612		{
00613			b = spawn(class 'UT_BloodBurst',self,'', hitLocation);
00614			if ( bGreenBlood && (b != None) ) 
00615				b.GreenBlood();		
00616		}
00617	}
00618	
00619	function PlayChallenge()
00620	{
00621		TweenToFighter(0.1);
00622	}
00623	
00624	simulated function PlayFootStep()
00625	{
00626		local sound step;
00627		local float decision;
00628	
00629		if ( FootRegion.Zone.bWaterZone )
00630		{
00631			PlaySound(sound 'LSplash', SLOT_Interact, 1, false, 1500.0, 1.0);
00632			return;
00633		}
00634	
00635		decision = FRand();
00636		if ( decision < 0.34 )
00637			step = Footstep1;
00638		else if (decision < 0.67 )
00639			step = Footstep2;
00640		else
00641			step = Footstep3;
00642	
00643		PlaySound(step, SLOT_Interact, 2.2, false, 1000.0, 1.0);
00644	}
00645	
00646	function PlayDyingSound()
00647	{
00648		local int rnd;
00649	
00650		if ( HeadRegion.Zone.bWaterZone )
00651		{
00652			if ( FRand() < 0.5 )
00653				PlaySound(UWHit1, SLOT_Pain,16,,,Frand()*0.2+0.9);
00654			else
00655				PlaySound(UWHit2, SLOT_Pain,16,,,Frand()*0.2+0.9);
00656			return;
00657		}
00658	
00659		rnd = Rand(6);
00660		PlaySound(Deaths[rnd], SLOT_Talk, 16);	
00661		PlaySound(Deaths[rnd], SLOT_Pain, 16);	
00662	}
00663	
00664	function PlayTakeHitSound(int damage, name damageType, int Mult)
00665	{
00666		if ( Level.TimeSeconds - LastPainSound < 0.25 )
00667			return;
00668		LastPainSound = Level.TimeSeconds;
00669	
00670		if ( HeadRegion.Zone.bWaterZone )
00671		{
00672			if ( damageType == 'Drowned' )
00673				PlaySound(drown, SLOT_Pain, 12);
00674			else if ( FRand() < 0.5 )
00675				PlaySound(UWHit1, SLOT_Pain,16,,,Frand()*0.15+0.9);
00676			else
00677				PlaySound(UWHit2, SLOT_Pain,16,,,Frand()*0.15+0.9);
00678			return;
00679		}
00680		damage *= FRand();
00681	
00682		if (damage < 8) 
00683			PlaySound(HitSound1, SLOT_Pain,16,,,Frand()*0.2+0.9);
00684		else if (damage < 25)
00685		{
00686			if (FRand() < 0.5) PlaySound(HitSound2, SLOT_Pain,16,,,Frand()*0.15+0.9);			
00687			else PlaySound(HitSound3, SLOT_Pain,16,,,Frand()*0.15+0.9);
00688		}
00689		else
00690			PlaySound(HitSound4, SLOT_Pain,16,,,Frand()*0.15+0.9);			
00691	}
00692	
00693	function CallForHelp()
00694	{
00695		local Pawn P;
00696	
00697		//log(self$" call for help");
00698		SendTeamMessage(None, 'Other', 4, 15);
00699			
00700		for ( P=Level.PawnList; P!=None; P=P.NextPawn )
00701			if ( P.IsA('Bot') && (P.PlayerReplicationInfo.Team == PlayerReplicationInfo.Team) )
00702				P.HandleHelpMessageFrom(self);
00703	}
00704	
00705	function string KillMessage(name damageType, pawn Other)
00706	{
00707		return ( Level.Game.PlayerKillMessage(damageType, Other.PlayerReplicationInfo)$PlayerReplicationInfo.PlayerName );
00708	}
00709	
00710	function Gasp()
00711	{
00712		if ( PainTime < 2 )
00713			PlaySound(GaspSound, SLOT_Talk, 2.0);
00714		else
00715			PlaySound(BreathAgain, SLOT_Talk, 2.0);
00716	}
00717	
00718	function ZoneChange(ZoneInfo newZone)
00719	{
00720		local vector jumpDir;
00721	
00722		if ( newZone.bWaterZone )
00723		{
00724			if (!bCanSwim)
00725				MoveTimer = -1.0;
00726			else if (Physics != PHYS_Swimming)
00727			{
00728				if (Physics != PHYS_Falling)
00729					PlayDive(); 
00730				setPhysics(PHYS_Swimming);
00731			}
00732		}
00733		else if (Physics == PHYS_Swimming)
00734		{
00735			if ( bCanFly )
00736				 SetPhysics(PHYS_Flying); 
00737			else
00738			{ 
00739				SetPhysics(PHYS_Falling);
00740				if ( bCanWalk && (Abs(Acceleration.X) + Abs(Acceleration.Y) > 0)
00741					&& (Destination.Z >= Location.Z) 
00742					&& CheckWaterJump(jumpDir) )
00743					JumpOutOfWater(jumpDir);
00744			}
00745		}
00746	}
00747	
00748	function JumpOutOfWater(vector jumpDir)
00749	{
00750		Falling();
00751		Velocity = jumpDir * WaterSpeed;
00752		Acceleration = jumpDir * AccelRate;
00753		velocity.Z = 380; //set here so physics uses this for remainder of tick
00754		PlayOutOfWater();
00755		bUpAndOut = true;
00756	}
00757	
00758	function PreSetMovement()
00759	{
00760		if (JumpZ > 0)
00761			bCanJump = true;
00762		bCanWalk = true;
00763		bCanSwim = true;
00764		bCanFly = false;
00765		MinHitWall = -0.5;
00766		bCanOpenDoors = true;
00767		bCanDoSpecial = true;
00768		SetPeripheralVision();
00769		if ( bNovice )
00770		{
00771			RotationRate.Yaw = 30000 + 3000 * skill;
00772			bCanDuck = false;
00773			if ( bThreePlus )
00774				MaxDesiredSpeed = 1;
00775			else
00776				MaxDesiredSpeed = 0.5 + 0.1 * skill;
00777			bCanDuck = false;
00778		}
00779		else
00780		{
00781			MaxDesiredSpeed = 1;
00782			if ( Skill == 3 )
00783				RotationRate.Yaw = 100000;
00784			else
00785				RotationRate.Yaw = 40000 + 11000 * skill;
00786			bCanDuck = ( skill > 1 );
00787		}
00788	}
00789	
00790	function SetPeripheralVision()
00791	{
00792		if ( bNovice )
00793			PeripheralVision = 0.7;
00794		else if ( Skill == 3 )
00795			PeripheralVision = -0.2;
00796		else
00797			PeripheralVision = 0.65 - 0.33 * skill;
00798	
00799		PeripheralVision = FMin(PeripheralVision - BaseAlertness, 0.9);
00800		if ( bSniping && (AmbushSpot != None) )
00801			SightRadius = AmbushSpot.SightRadius;
00802		else
00803			SightRadius = Default.SightRadius;
00804	}
00805	
00806	function PainTimer()
00807	{
00808		local float depth;
00809		if (Health <= 0)
00810			return;
00811	
00812		if (FootRegion.Zone.bPainZone)
00813			Super.PainTimer();
00814		else if (HeadRegion.Zone.bWaterZone)
00815		{
00816			if (bDrowning)
00817				self.TakeDamage(5, None, Location + CollisionHeight * vect(0,0,0.5), vect(0,0,0), 'Drowned'); 
00818			else if ( !Level.Game.IsA('Assault') )
00819			{
00820				bDrowning = true;
00821				GotoState('FindAir');
00822			}
00823			if (Health > 0)
00824				PainTime = 2.0;
00825		}
00826	}	
00827	
00828	function ChangedWeapon()
00829	{
00830		local int usealt;
00831	
00832		if ( Weapon == PendingWeapon )
00833		{
00834			if ( Weapon == None )
00835				SwitchToBestWeapon();
00836			else if ( Weapon.GetStateName() == 'DownWeapon' ) 
00837				Weapon.GotoState('Idle');
00838			PendingWeapon = None;
00839		}
00840		else
00841			Super.ChangedWeapon();
00842	
00843		if ( Weapon != None )
00844		{
00845			if ( (bFire > 0) || (bAltFire > 0) )
00846			{
00847				Weapon.RateSelf(usealt);
00848				if ( usealt == 0 )
00849				{
00850					bAltFire = 0;
00851					bFire = 1;
00852					Weapon.Fire(1.0);
00853				}
00854				else
00855				{
00856					bAltFire = 0;
00857					bFire = 1;
00858					Weapon.AltFire(1.0);
00859				}
00860			}
00861			Weapon.SetHand(0);
00862			// Weapon.FireOffset.Y = 0;
00863		}
00864	}
00865	
00866	function bool Gibbed( name damageType)
00867	{
00868		if ( (damageType == 'decapitated') || (damageType == 'shot') )
00869			return false; 	
00870		return ( (Health < -80) || ((Health < -40) && (FRand() < 0.6)) );
00871	}
00872	
00873	function SpawnGibbedCarcass()
00874	{
00875		local carcass carc;
00876	
00877		carc = Spawn(CarcassType);
00878		if ( carc != None )
00879		{
00880			carc.Initfor(self);
00881			carc.ChunkUp(-1 * Health);
00882		}
00883	}
00884	
00885	function Carcass SpawnCarcass()
00886	{
00887		local carcass carc;
00888	
00889		carc = Spawn(CarcassType);
00890		if ( carc != None )
00891			carc.Initfor(self);
00892	
00893		return carc;
00894	}
00895	
00896	function JumpOffPawn()
00897	{
00898		Velocity += (100 + CollisionRadius) * VRand();
00899		Velocity.Z = 200 + CollisionHeight;
00900		SetPhysics(PHYS_Falling);
00901		bJumpOffPawn = true;
00902		SetFall();
00903	}
00904	
00905	//=============================================================================
00906		
00907	function SetMovementPhysics()
00908	{
00909		if (Physics == PHYS_Falling)
00910			return;
00911		if ( Region.Zone.bWaterZone )
00912			SetPhysics(PHYS_Swimming);
00913		else
00914			SetPhysics(PHYS_Walking); 
00915	}
00916	
00917	function FearThisSpot(Actor aSpot)
00918	{
00919		Acceleration = vect(0,0,0);
00920		MoveTimer = -1.0;
00921	}
00922	
00923	function FastInAir()
00924	{
00925		PlayInAir();
00926	}
00927	
00928	/*
00929	SetAlertness()
00930	Change creature's alertness, and appropriately modify attributes used by engine for determining
00931	seeing and hearing.
00932	SeePlayer() is affected by PeripheralVision, and also by SightRadius and the target's visibility
00933	HearNoise() is affected by HearingThreshold
00934	*/
00935	final function SetAlertness(float NewAlertness)
00936	{
00937		if ( Alertness != NewAlertness )
00938		{
00939			PeripheralVision += 0.707 * (Alertness - NewAlertness); //Used by engine for SeePlayer()
00940			HearingThreshold += 0.5 * (Alertness - NewAlertness); //Used by engine for HearNoise()
00941			Alertness = NewAlertness;
00942		}
00943	}
00944	
00945	function WhatToDoNext(name LikelyState, name LikelyLabel)
00946	{
00947		if ( bVerbose )
00948		{
00949			log(self$" what to do next");
00950			log("enemy "$Enemy);
00951			log("old enemy "$OldEnemy);
00952		}
00953		if ( (Level.NetMode != NM_Standalone) 
00954			&& Level.Game.IsA('DeathMatchPlus')
00955			&& DeathMatchPlus(Level.Game).TooManyBots() )
00956		{
00957			Destroy();
00958			return;
00959		}
00960	
00961		BlockedPath = None;
00962		bDevious = false;
00963		bFire = 0;
00964		bAltFire = 0;
00965		bKamikaze = false;
00966		SetOrders(BotReplicationInfo(PlayerReplicationInfo).RealOrders, BotReplicationInfo(PlayerReplicationInfo).RealOrderGiver, true);
00967		Enemy = OldEnemy;
00968		OldEnemy = None;
00969		bReadyToAttack = false;
00970		if ( Enemy != None )
00971		{
00972			bReadyToAttack = !bNovice;
00973			GotoState('Attacking');
00974		}
00975		else if ( (Orders == 'Hold') && (Weapon.AIRating > 0.4) && (Health > 70) )
00976				GotoState('Hold');
00977		else
00978		{
00979			GotoState('Roaming');
00980			if ( Skill > 2.7 )
00981				bReadyToAttack = true; 
00982		}
00983	}
00984	
00985	function bool CheckBumpAttack(Pawn Other)
00986	{
00987		local pawn CurrentEnemy;
00988	
00989		CurrentEnemy = Enemy;
00990		if ( SetEnemy(Other) )
00991		{
00992			if ( (Enemy == Other) && (Weapon != None) && !Weapon.bMeleeWeapon )
00993			{
00994				bReadyToAttack = true;
00995				GotoState('RangedAttack');
00996				return true;
00997			} 
00998			else 
00999			{
01000				Enemy = CurrentEnemy;
01001				if ( OldEnemy == CurrentEnemy )
01002					OldEnemy = None;
01003			}
01004		}
01005		return false;
01006	}
01007	
01008	function bool DeferTo(Bot Other)
01009	{
01010		if ( (Other.PlayerReplicationInfo.HasFlag != None) 
01011			|| ((Orders == 'Follow') && (Other == OrderObject)) )
01012		{
01013			if ( Level.Game.IsA('TeamGamePlus') && TeamGamePlus(Level.Game).HandleTieUp(self, Other) )
01014				return false;
01015			if ( (Enemy != None) && LineOfSightTo(Enemy) )
01016				GotoState('TacticalMove', 'NoCharge');
01017			else
01018			{
01019				Enemy = None;
01020				OldEnemy = None;
01021				if ( (Health > 0) && (Acceleration == vect(0,0,0)) )
01022				{
01023					WanderDir = Normal(Location - Other.Location);
01024					GotoState('Wandering', 'Begin');
01025				}
01026			}
01027			Other.SetTimer(FClamp(TimerRate, 0.001, 0.2), false);
01028			return true;
01029		}
01030		return false;
01031	}
01032	
01033	function Bump(actor Other)
01034	{
01035		local vector VelDir, OtherDir;
01036		local float speed, dist;
01037		local Pawn P,M;
01038		local bool bDestinationObstructed, bAmLeader;
01039		local int num;
01040	
01041		P = Pawn(Other);
01042		if ( (P != None) && CheckBumpAttack(P) )
01043			return;
01044		if ( TimerRate <= 0 )
01045			setTimer(1.0, false);
01046		
01047		if ( Level.Game.bTeamGame && (P != None) && (MoveTarget != None) )
01048		{
01049			OtherDir = P.Location - MoveTarget.Location;
01050			if ( abs(OtherDir.Z) < P.CollisionHeight )
01051			{
01052				OtherDir.Z = 0;
01053				dist = VSize(OtherDir);
01054				bDestinationObstructed = ( VSize(OtherDir) < P.CollisionRadius ); 
01055				if ( P.IsA('Bot') )
01056					bAmLeader = ( Bot(P).DeferTo(self) || (PlayerReplicationInfo.HasFlag != None) );
01057	
01058				// check if someone else is on destination or within 3 * collisionradius
01059				for ( M=Level.PawnList; M!=None; M=M.NextPawn )
01060					if ( M != self )
01061					{
01062						dist = VSize(M.Location - MoveTarget.Location);
01063						if ( dist < M.CollisionRadius )
01064						{
01065							bDestinationObstructed = true;
01066							if ( M.IsA('Bot') )
01067								bAmLeader = Bot(M).DeferTo(self) || bAmLeader;
01068						}
01069						if ( dist < 3 * M.CollisionRadius ) 
01070						{
01071							num++;
01072							if ( num >= 2 )
01073							{
01074								bDestinationObstructed = true;
01075								if ( M.IsA('Bot') )
01076									bAmLeader = Bot(M).DeferTo(self) || bAmLeader;
01077							}
01078						}
01079					}
01080					
01081				if ( bDestinationObstructed && !bAmLeader )
01082				{
01083					// P is standing on my destination
01084					MoveTimer = -1;
01085					if ( Enemy != None )
01086					{
01087						if ( LineOfSightTo(Enemy) )
01088						{
01089							if ( !IsInState('TacticalMove') )
01090								GotoState('TacticalMove', 'NoCharge');
01091						}
01092						else if ( !IsInState('StakeOut') && (FRand() < 0.5) )
01093						{
01094							GotoState('StakeOut');
01095							LastSeenTime = 0;
01096							bClearShot = false;
01097						}		
01098					}
01099					else if ( (Health > 0) && !IsInState('Wandering') || (Acceleration == vect(0,0,0)) )
01100					{
01101						WanderDir = Normal(Location - P.Location);
01102						GotoState('Wandering', 'Begin');
01103					}
01104				}
01105			}
01106		}
01107		speed = VSize(Velocity);
01108		if ( speed > 10 )
01109		{
01110			VelDir = Velocity/speed;
01111			VelDir.Z = 0;
01112			OtherDir = Other.Location - Location;
01113			OtherDir.Z = 0;
01114			OtherDir = Normal(OtherDir);
01115			if ( (VelDir Dot OtherDir) > 0.8 )
01116			{
01117				Velocity.X = VelDir.Y;
01118				Velocity.Y = -1 * VelDir.X;
01119				Velocity *= FMax(speed, 280);
01120			}
01121		} 
01122		else if ( (Health > 0) && (Enemy == None) && (bCamping 
01123					|| ((Orders == 'Follow') && (MoveTarget == OrderObject) && (MoveTarget.Acceleration == vect(0,0,0)))) )
01124			GotoState('Wandering', 'Begin');
01125		Disable('Bump');
01126	}
01127			
01128	singular function Falling()
01129	{
01130		if (bCanFly)
01131		{
01132			SetPhysics(PHYS_Flying);
01133			return;
01134		}			
01135		//log(class$" Falling");
01136		// SetPhysics(PHYS_Falling); //note - done by default in physics
01137	 	if (health > 0)
01138			SetFall();
01139	}
01140		
01141	function SetFall()
01142	{
01143		if (Enemy != None)
01144		{
01145			NextState = 'Attacking'; //default
01146			NextLabel = 'Begin';
01147			TweenToFalling();
01148			NextAnim = AnimSequence;
01149			GotoState('FallingState');
01150		}
01151	}
01152	
01153	function LongFall()
01154	{
01155		SetFall();
01156		if ( (Enemy != None) && (Region.Zone.ZoneGravity.Z > Region.Zone.Default.ZoneGravity.Z) )
01157			GotoState('FallingState', 'FireWhileFalling');
01158		else 
01159			GotoState('FallingState', 'LongFall');
01160	}
01161	
01162	event UpdateTactics(float DeltaTime)
01163	{
01164		if ( bTacticalDir )
01165		{
01166			TacticalOffset += DeltaTime;
01167			if ( TacticalOffset > 0.5 )
01168			{
01169				bTacticalDir = false;
01170				bNoTact = ( FRand() < 0.3 );
01171			}
01172		}
01173		else
01174		{
01175			TacticalOffset -= DeltaTime;
01176			if ( TacticalOffset < -0.5 )
01177			{
01178				bTacticalDir = true;
01179				bNoTact = ( FRand() < 0.3 );
01180			}
01181		}
01182	}
01183	
01184	// UpdateEyeHeight() called if bot is viewtarget of a player
01185	event UpdateEyeHeight(float DeltaTime)
01186	{
01187		local float smooth, bound, TargetYaw, TargetPitch;
01188		local Pawn P;
01189		local rotator OldViewRotation;
01190		local vector T;
01191	
01192		// update viewrotation
01193		OldViewRotation = ViewRotation;			
01194		if ( (bFire == 0) && (bAltFire == 0) )
01195			ViewRotation = Rotation;
01196	
01197		//check if still viewtarget
01198		bViewTarget = false;
01199		for ( P=Level.PawnList; P!=None; P=P.NextPawn )
01200			if ( P.IsA('PlayerPawn') && (PlayerPawn(P).ViewTarget == self) )
01201			{
01202				bViewTarget = true;
01203				if ( bVerbose )
01204				{
01205					if ( (Enemy != None) && Enemy.bIsPlayer )
01206						P.ClientMessage(PlayerReplicationInfo.PlayerName@"Orders"@orders@"State"@GetStateName()@"MoveTarget"@MoveTarget@"AlternatePath"@AlternatePath@"Enemy"@Enemy.PlayerReplicationInfo.PlayerName@"See"@LineOfSightTo(Enemy), 'CriticalEvent' );
01207					else					
01208						P.ClientMessage(PlayerReplicationInfo.PlayerName@"Orders"@orders@"State"@GetStateName()@"MoveTarget"@MoveTarget@"AlternatePath"@AlternatePath@"Enemy"@Enemy, 'CriticalEvent' );
01209				}
01210				break;
01211			}
01212	
01213		if ( !bViewTarget )
01214		{
01215			bVerbose = false;
01216			return;
01217		}
01218	
01219		if ( Enemy == None )
01220		{
01221			ViewRotation.Roll = 0;
01222			if ( DeltaTime < 0.2 )
01223			{
01224				OldViewRotation.Yaw = OldViewRotation.Yaw & 65535;
01225				OldViewRotation.Pitch = OldViewRotation.Pitch & 65535;
01226				TargetYaw = float(ViewRotation.Yaw & 65535);
01227				if ( Abs(TargetYaw - OldViewRotation.Yaw) > 32768 )
01228				{
01229					if ( TargetYaw < OldViewRotation.Yaw )
01230						TargetYaw += 65536;
01231					else
01232						TargetYaw -= 65536;
01233				}
01234				TargetYaw = float(OldViewRotation.Yaw) * (1 - 5 * DeltaTime) + TargetYaw * 5 * DeltaTime;
01235				ViewRotation.Yaw = int(TargetYaw);
01236	
01237				TargetPitch = float(ViewRotation.Pitch & 65535);
01238				if ( Abs(TargetPitch - OldViewRotation.Pitch) > 32768 )
01239				{
01240					if ( TargetPitch < OldViewRotation.Pitch )
01241						TargetPitch += 65536;
01242					else
01243						TargetPitch -= 65536;
01244				}
01245				TargetPitch = float(OldViewRotation.Pitch) * (1 - 5 * DeltaTime) + TargetPitch * 5 * DeltaTime;
01246				ViewRotation.Pitch = int(TargetPitch);
01247			}
01248		}
01249	
01250		smooth = FMin(1.0, 10.0 * DeltaTime/Level.TimeDilation);
01251		// smooth up/down stairs
01252		If ( (Physics == PHYS_Walking) && !bJustLanded)
01253		{
01254			EyeHeight = (EyeHeight - Location.Z + OldLocation.Z) * (1 - smooth) + BaseEyeHeight * smooth;
01255			bound = -0.5 * CollisionHeight;
01256			if (EyeHeight < bound)
01257				EyeHeight = bound;
01258			else
01259			{
01260				bound = CollisionHeight + FMin(FMax(0.0,(OldLocation.Z - Location.Z)), MaxStepHeight); 
01261				 if ( EyeHeight > bound )
01262					EyeHeight = bound;
01263			}
01264		}
01265		else
01266		{
01267			smooth = FMax(smooth, 0.35);
01268			bJustLanded = false;
01269			EyeHeight = EyeHeight * ( 1 - smooth) + BaseEyeHeight * smooth;
01270		}
01271	}
01272	
01273	/* Adjust hit location - adjusts the hit location in for pawns, and returns
01274	true if it was really a hit, and false if not (for ducking, etc.)
01275	*/
01276	simulated function bool AdjustHitLocation(out vector HitLocation, vector TraceDir)
01277	{
01278		local float adjZ, maxZ;
01279	
01280		TraceDir = Normal(TraceDir);
01281		HitLocation = HitLocation + 0.5 * CollisionRadius * TraceDir;
01282		if ( BaseEyeHeight == Default.BaseEyeHeight )
01283			return true;
01284	
01285		maxZ = Location.Z + BaseEyeHeight + 0.25 * CollisionHeight;
01286		if ( HitLocation.Z > maxZ )
01287		{
01288			if ( TraceDir.Z >= 0 )
01289				return false;
01290			adjZ = (maxZ - HitLocation.Z)/TraceDir.Z;
01291			HitLocation.Z = maxZ;
01292			HitLocation.X = HitLocation.X + TraceDir.X * adjZ;
01293			HitLocation.Y = HitLocation.Y + TraceDir.Y * adjZ;
01294			if ( VSize(HitLocation - Location) > CollisionRadius )	
01295				return false;
01296		}
01297		return true;
01298	}
01299	
01300	function HearPickup(Pawn Other);
01301	
01302	function HearNoise(float Loudness, Actor NoiseMaker)
01303	{
01304		//log(class@"heard noise by"@NoiseMaker.class);
01305		SetEnemy(NoiseMaker.instigator);
01306	}
01307	
01308	function GiveUpTactical(bool bNoCharge);
01309	
01310	function SeePlayer(Actor SeenPlayer)
01311	{
01312		SetEnemy(Pawn(SeenPlayer));
01313	}
01314	
01315	/* FindBestPathToward() assumes the desired destination is not directly reachable, 
01316	given the creature's intelligence, it tries to set Destination to the location of the 
01317	best waypoint, and returns true if successful
01318	*/
01319	function bool FindBestPathToward(actor desired, bool bClearPaths)
01320	{
01321		local Actor path;
01322		local bool success;
01323		
01324		if ( specialGoal != None)
01325			desired = specialGoal;
01326		path = None;
01327		path = FindPathToward(desired,,bClearPaths); 
01328			
01329		success = (path != None);	
01330		if (success)
01331		{
01332			MoveTarget = path; 
01333			Destination = path.Location;
01334		}	
01335		return success;
01336	}	
01337	
01338	function bool NeedToTurn(vector targ)
01339	{
01340		local int YawErr;
01341	
01342		DesiredRotation = Rotator(targ - location);
01343		DesiredRotation.Yaw = DesiredRotation.Yaw & 65535;
01344		YawErr = (DesiredRotation.Yaw - (Rotation.Yaw & 65535)) & 65535;
01345		if ( (YawErr < 4000) || (YawErr > 61535) )
01346			return false;
01347	
01348		return true;
01349	}
01350	
01351	/* NearWall() returns true if there is a nearby barrier at eyeheight, and
01352	changes Focus to a suggested value
01353	*/
01354	function bool NearWall(float walldist)
01355	{
01356		local actor HitActor;
01357		local vector HitLocation, HitNormal, ViewSpot, ViewDist, LookDir;
01358	
01359		LookDir = vector(Rotation);
01360		ViewSpot = Location + BaseEyeHeight * vect(0,0,1);
01361		ViewDist = LookDir * walldist; 
01362		HitActor = Trace(HitLocation, HitNormal, ViewSpot + ViewDist, ViewSpot, false);
01363		if ( HitActor == None )
01364			return false;
01365	
01366		ViewDist = Normal(HitNormal Cross vect(0,0,1)) * walldist;
01367		if (FRand() < 0.5)
01368			ViewDist *= -1;
01369	
01370		if ( FastTrace(ViewSpot + ViewDist, ViewSpot) )
01371		{
01372			Focus = Location + ViewDist;
01373			return true;
01374		}
01375	
01376		ViewDist *= -1;
01377	
01378		if ( FastTrace(ViewSpot + ViewDist, ViewSpot) )
01379		{
01380			Focus = Location + ViewDist;
01381			return true;
01382		}
01383	
01384		Focus = Location - LookDir * 300;
01385		return true;
01386	}
01387	
01388	function FireWeapon()
01389	{
01390		local bool bUseAltMode;
01391		local Weapon MyAutomag;
01392	
01393		if ( (Enemy == None) && bShootSpecial )
01394		{
01395			//fake use automag
01396			MyAutomag = Weapon(FindInventoryType(class'Enforcer'));
01397			if ( MyAutoMag == None )
01398				Spawn(class'PlasmaSphere',,, Location,Rotator(Target.Location - Location));
01399			else
01400				MyAutoMag.TraceFire(0);
01401	
01402			return;
01403		}
01404	
01405		bUseAltMode = SwitchToBestWeapon();
01406	
01407		if( Weapon!=None )
01408		{
01409			if ( (Weapon.AmmoType != None) && (Weapon.AmmoType.AmmoAmount <= 0) )
01410			{
01411				bReadyToAttack = true;
01412				return;
01413			}
01414	
01415	 		if ( !bComboPaused && !bShootSpecial && (Enemy != None) )
01416	 			Target = Enemy;
01417			ViewRotation = Rotation;
01418			PlayFiring();
01419			if ( bUseAltMode )
01420			{
01421				bFire = 0;
01422				bAltFire = 1;
01423				Weapon.AltFire(1.0);
01424			}
01425			else
01426			{
01427				bFire = 1;
01428				bAltFire = 0;
01429				Weapon.Fire(1.0);
01430			}
01431		}
01432		bShootSpecial = false;
01433	}
01434	
01435	function PlayFiring();
01436	
01437	// check for line of sight to target deltatime from now.
01438	function bool CheckFutureSight(float deltatime)
01439	{
01440		local vector FutureLoc, FireSpot;
01441	
01442		if ( Target == None )
01443			Target = Enemy;
01444		if ( Target == None )
01445			return false;
01446	
01447		if ( Acceleration == vect(0,0,0) )
01448			FutureLoc = Location;
01449		else
01450			FutureLoc = Location + GroundSpeed * Normal(Acceleration) * deltaTime;
01451	
01452		if ( Base != None ) 
01453			FutureLoc += Base.Velocity * deltaTime;
01454		//make sure won't run into something
01455		if ( !FastTrace(FutureLoc, Location) && (Physics != PHYS_Falling) )
01456			return false;
01457	
01458		//check if can still see target
01459		if ( FastTrace(Target.Location + Target.Velocity * deltatime, FutureLoc) )
01460			return true;
01461	
01462		return false;
01463	}
01464	
01465	/*
01466	Adjust the aim at target.  
01467		- add aim error
01468		- adjust up or down if barrier
01469	*/
01470	
01471	function rotator AdjustToss(float projSpeed, vector projStart, int aimerror, bool leadTarget, bool warnTarget)
01472	{
01473		local rotator FireRotation;
01474		local vector FireSpot;
01475		local actor HitActor;
01476		local vector HitLocation, HitNormal, FireDir;
01477		local float TargetDist, TossSpeed, TossTime;
01478		local int realYaw;
01479	
01480		if ( projSpeed == 0 )
01481			return AdjustAim(projSpeed, projStart, aimerror, leadTarget, warnTarget);
01482		if ( Target == None )
01483			Target = Enemy;
01484		if ( Target == None )
01485			return Rotation;
01486		FireSpot = Target.Location;
01487		TargetDist = VSize(Target.Location - ProjStart);
01488	
01489		if ( !Target.bIsPawn )
01490		{
01491			if ( (Region.Zone.ZoneGravity.Z != Region.Zone.Default.ZoneGravity.Z) 
01492				|| (TargetDist > projSpeed) )
01493			{
01494				TossTime = TargetDist/projSpeed;
01495				FireSpot.Z -= ((0.25 * Region.Zone.ZoneGravity.Z * TossTime + 200) * TossTime + 60);	
01496			}
01497			viewRotation = Rotator(FireSpot - ProjStart);
01498			return viewRotation;
01499		}					
01500		aimerror = aimerror * (11 - 10 *  
01501			((Target.Location - Location)/TargetDist 
01502				Dot Normal((Target.Location + 1.2 * Target.Velocity) - (ProjStart + Velocity)))); 
01503	
01504		if ( bNovice )
01505		{
01506			if ( (Target != Enemy) || (Enemy.Weapon == None) || !Enemy.Weapon.bMeleeWeapon || (TargetDist > 650) )
01507				aimerror = aimerror * (2.1 - 0.2 * (skill + FRand()));
01508			else
01509				aimerror *= 0.75;
01510			if ( Level.TimeSeconds - LastPainTime < 0.15 )
01511				aimerror *= 1.3;
01512		}
01513		else
01514		{
01515			aimerror = aimerror * (1.5 - 0.35 * (skill + FRand()));
01516			if ( (Skill < 2) && (Level.TimeSeconds - LastPainTime < 0.15) )
01517				aimerror *= 1.2;
01518		}
01519		if ( (bNovice && (LastAcquireTime > Level.TimeSeconds - 5 + 0.6 * Skill))
01520			|| (LastAcquireTime > Level.TimeSeconds - 2.5 + Skill) )
01521		{
01522			LastAcquireTime = Level.TimeSeconds - 5;
01523			aimerror *= 1.75;
01524		}
01525	
01526		if ( !leadTarget || (accuracy < 0) )
01527			aimerror -= aimerror * accuracy;
01528	
01529		if ( leadTarget )
01530		{
01531			FireSpot += FMin(1, 0.7 + 0.6 * FRand()) * (Target.Velocity * TargetDist/projSpeed);
01532			if ( !FastTrace(FireSpot, ProjStart) )
01533				FireSpot = 0.5 * (FireSpot + Target.Location);
01534		}
01535	
01536		//try middle
01537		FireSpot.Z = Target.Location.Z;
01538	
01539		if ( (Target == Enemy) && !FastTrace(FireSpot, ProjStart) )
01540		{
01541			FireSpot = LastSeenPos;
01542		 	HitActor = Trace(HitLocation, HitNormal, FireSpot, ProjStart, false);
01543			if ( HitActor != None )
01544			{
01545				bFire = 0;
01546				bAltFire = 0;
01547				FireSpot += 2 * Target.CollisionHeight * HitNormal;
01548				SetTimer(TimeBetweenAttacks, false);
01549			}
01550		}
01551	
01552		// adjust for toss distance (assume 200 z velocity add & 60 init height)
01553		if ( FRand() < 0.75 )
01554		{
01555			TossSpeed = projSpeed + 0.4 * VSize(Velocity); 
01556			if ( (Region.Zone.ZoneGravity.Z != Region.Zone.Default.ZoneGravity.Z) 
01557				|| (TargetDist > TossSpeed) )
01558			{
01559				TossTime = TargetDist/TossSpeed;
01560				FireSpot.Z -= ((0.25 * Region.Zone.ZoneGravity.Z * TossTime + 200) * TossTime + 60);	
01561			}
01562		}
01563	
01564		FireRotation = Rotator(FireSpot - ProjStart);
01565		realYaw = FireRotation.Yaw;
01566		aimerror = Rand(2 * aimerror) - aimerror;
01567		FireRotation.Yaw = (FireRotation.Yaw + aimerror) & 65535;
01568	
01569		if ( (Abs(FireRotation.Yaw - (Rotation.Yaw & 65535)) > 8192)
01570			&& (Abs(FireRotation.Yaw - (Rotation.Yaw & 65535)) < 57343) )
01571		{
01572			if ( (FireRotation.Yaw > Rotation.Yaw + 32768) || 
01573				((FireRotation.Yaw < Rotation.Yaw) && (FireRotation.Yaw > Rotation.Yaw - 32768)) )
01574				FireRotation.Yaw = Rotation.Yaw - 8192;
01575			else
01576				FireRotation.Yaw = Rotation.Yaw + 8192;
01577		}
01578		FireDir = vector(FireRotation);
01579		// avoid shooting into wall
01580		HitActor = Trace(HitLocation, HitNormal, ProjStart + FMin(VSize(FireSpot-ProjStart), 400) * FireDir, ProjStart, false); 
01581		if ( (HitActor != None) && (HitNormal.Z < 0.7) )
01582		{
01583			FireRotation.Yaw = (realYaw - aimerror) & 65535;
01584			if ( (Abs(FireRotation.Yaw - (Rotation.Yaw & 65535)) > 8192)
01585				&& (Abs(FireRotation.Yaw - (Rotation.Yaw & 65535)) < 57343) )
01586			{
01587				if ( (FireRotation.Yaw > Rotation.Yaw + 32768) || 
01588					((FireRotation.Yaw < Rotation.Yaw) && (FireRotation.Yaw > Rotation.Yaw - 32768)) )
01589					FireRotation.Yaw = Rotation.Yaw - 8192;
01590				else
01591					FireRotation.Yaw = Rotation.Yaw + 8192;
01592			}
01593			FireDir = vector(FireRotation);
01594		}
01595	
01596		if ( warnTarget && (Pawn(Target) != None) ) 
01597			Pawn(Target).WarnTarget(self, projSpeed, FireDir); 
01598	
01599		viewRotation = FireRotation;			
01600		return FireRotation;
01601	}
01602	
01603	/*
01604	AdjustAim()
01605	Returns a rotation which is the direction the bot should aim - after introducing the appropriate aiming error
01606	*/
01607	function rotator AdjustAim(float projSpeed, vector projStart, int aimerror, bool leadTarget, bool warnTarget)
01608	{
01609		local rotator FireRotation, TargetLook;
01610		local vector FireSpot, FireDir, TargetVel;
01611		local float FireDist, TargetDist;
01612		local actor HitActor;
01613		local vector HitLocation, HitNormal;
01614		local int realYaw;
01615		local bool bDefendMelee, bClean;
01616	
01617		// make sure bot has a valid target
01618		if ( Target == None )
01619			Target = Enemy;
01620		if ( Target == None )
01621		{
01622			bFire = 0;
01623			bAltFire = 0;
01624			return Rotation;
01625		}
01626		// perfect aim at stationary objects
01627		if ( !Target.bIsPawn || Target.IsA('FortStandard') )
01628			return rotator(Target.Location - projstart);
01629						
01630		FireSpot = Target.Location;
01631		TargetDist = VSize(Target.Location - Location);
01632	
01633		// figure out the relative motion of the target across the bots view, and adjust aim error
01634		// based on magnitude of relative motion
01635		aimerror = aimerror * (11 - 10 *  
01636			((Target.Location - Location)/TargetDist 
01637				Dot Normal((Target.Location + 1.25 * Target.Velocity) - (Location + Velocity)))); 
01638	
01639		// if enemy is charging straight at bot with a melee weapon, improve aim
01640		bDefendMelee = ( (Target == Enemy) && (Enemy.Weapon != None) && Enemy.Weapon.bMeleeWeapon && (TargetDist < 700) );
01641		if ( bDefendMelee )
01642			aimerror *= 0.5;
01643	
01644		// if instant hit weapon, then adjust aim error based on skill
01645		// the initial aim error passed in is much higher for instant hit weapons than for other weapons
01646		if ( ((projSpeed == 0) || (Projspeed >= 1000000)) )
01647		{
01648			if ( bNovice )
01649				aimerror *= 0.5;
01650			else
01651				aimerror *= 0.5 + 0.19 * skill;
01652		}
01653	
01654		if ( bNovice )
01655		{
01656			// adjust aim error based on skill
01657			if ( !bDefendMelee )
01658				aimerror = aimerror * (2.4 - 0.2 * (skill + FRand()));
01659			// Bots don't aim as well if recently hit, or if they or their target is flying through the air
01660			if ( (Level.TimeSeconds - LastPainTime < 0.2) || (Physics == PHYS_Falling) || (Target.Physics == PHYS_Falling) )
01661				aimerror *= 1.5;
01662		}
01663		else
01664		{
01665			// adjust aim error based on skill
01666			aimerror = aimerror * (1.7 - 0.4 * (skill + FRand()));
01667			// Bots don't aim as well if recently hit, or if they or their target is flying through the air
01668			if ( (Skill < 2) 
01669				&& ((Level.TimeSeconds - LastPainTime < 0.15) || (Physics == PHYS_Falling) || (Target.Physics == PHYS_Falling)) )
01670				aimerror *= 1.2;
01671		}
01672	
01673		// Bots don't aim as well at recently acquired targets (because they haven't had a chance to lock in to the target)
01674		if ( (bNovice && (LastAcquireTime > Level.TimeSeconds - 5 + 0.5 * skill))
01675			|| (LastAcquireTime > Level.TimeSeconds - 2.5 + skill) )
01676		{
01677			LastAcquireTime = Level.TimeSeconds - 5;
01678			if ( bDefendMelee )
01679				aimerror *= 1.3;
01680			else
01681				aimerror *= 2;
01682		}
01683		
01684		// adjust aim error based on bot accuracy rating 
01685		if ( !leadTarget || (accuracy < 0) )
01686			aimerror -= aimerror * accuracy;
01687	
01688		// lead target with non instant hit projectiles
01689		if (leadTarget && (projSpeed > 0))
01690		{
01691			TargetVel = Target.Velocity;
01692			// hack guess at projecting falling velocity of target
01693			if ( Target.Physics == PHYS_Falling )
01694			{
01695				if ( Target.Region.Zone.ZoneGravity == Target.Region.Zone.Default.ZoneGravity )
01696					TargetVel.Z = FMin(-160, TargetVel.Z);
01697				else
01698					TargetVel.Z = FMin(0, TargetVel.Z);
01699			}
01700			// more or less lead target (with some random variation)
01701			FireSpot += FMin(1, 0.7 + 0.6 * FRand()) * TargetVel * TargetDist/projSpeed;
01702			FireSpot.Z = FMin(Target.Location.Z, FireSpot.Z);
01703	
01704			if ( (Target.Physics != PHYS_Falling) && (FRand() < 0.55) && (VSize(FireSpot - ProjStart) > 1000) )
01705			{
01706				// don't always lead far away targets, especially if they are moving sideways with respect to the bot
01707				TargetLook = Target.Rotation;
01708				if ( Target.Physics == PHYS_Walking )
01709					TargetLook.Pitch = 0;
01710				if ( ((Vector(TargetLook) Dot Normal(Target.Velocity)) < 0.71) )
01711					bClean = false;
01712				else
01713					bClean = FastTrace(FireSpot, ProjStart);
01714			}
01715			else // make sure that bot isn't leading into a wall
01716	
01717				bClean = FastTrace(FireSpot, ProjStart);
01718			if ( !bClean)
01719			{
01720				// reduce amount of leading
01721				if ( FRand() < 0.3 )
01722					FireSpot = Target.Location;
01723				else
01724					FireSpot = 0.5 * (FireSpot + Target.Location);
01725			}
01726		}
01727	
01728		bClean = false; //so will fail first check unless shooting at feet  
01729		if ( Target.bIsPawn && (!bNovice || bDefendMelee) 
01730			&& (Weapon != None) 
01731			&& (Weapon.bRecommendSplashDamage || (Weapon.bRecommendAltSplashDamage && (bAltFire != 0))) 
01732			&& (((Target.Physics == PHYS_Falling) && (Location.Z + 80 >= Target.Location.Z))
01733				|| ((Location.Z + 19 >= Target.Location.Z) && (bDefendMelee || (skill > 2.5 * FRand() - 0.5)))) )
01734		{
01735		 	HitActor = Trace(HitLocation, HitNormal, FireSpot - vect(0,0,1) * (Target.CollisionHeight + 6), FireSpot, false);
01736	 		bClean = (HitActor == None);
01737			if ( !bClean )
01738			{
01739				FireSpot = HitLocation + vect(0,0,3);
01740				bClean = FastTrace(FireSpot, ProjStart);
01741			}
01742			else if ( Target.Physics == PHYS_Falling )
01743				bClean = FastTrace(FireSpot, ProjStart);
01744			else
01745				bClean = false;
01746		}
01747		if ( !bClean )
01748		{
01749			//try middle
01750			FireSpot.Z = Target.Location.Z;
01751	 		bClean = FastTrace(FireSpot, ProjStart);
01752		}
01753		if( !bClean ) 
01754		{
01755			////try head
01756	 		FireSpot.Z = Target.Location.Z + 0.9 * Target.CollisionHeight;
01757	 		bClean = FastTrace(FireSpot, ProjStart);
01758		}
01759		if ( !bClean && (Target == Enemy) )
01760		{
01761			FireSpot = LastSeenPos;
01762			if ( Location.Z >= LastSeenPos.Z )
01763				FireSpot.Z -= 0.7 * Enemy.CollisionHeight;
01764		 	HitActor = Trace(HitLocation, HitNormal, FireSpot, ProjStart, false);
01765			if ( HitActor != None )
01766			{
01767				FireSpot = LastSeenPos + 2 * Enemy.CollisionHeight * HitNormal;
01768				if ( Weapon.bSplashDamage && !bNovice )
01769				{
01770				 	HitActor = Trace(HitLocation, HitNormal, FireSpot, ProjStart, false);
01771					if ( HitActor != None )
01772						FireSpot += 2 * Enemy.CollisionHeight * HitNormal;
01773				}
01774				if ( Weapon.RefireRate < 0.99 )
01775					bFire = 0;
01776				if ( Weapon.AltRefireRate < 0.99 )
01777					bAltFire = 0;
01778				SetTimer(TimeBetweenAttacks, false);
01779			}
01780		}
01781		
01782		FireRotation = Rotator(FireSpot - ProjStart);
01783		realYaw = FireRotation.Yaw;
01784		aimerror = Rand(2 * aimerror) - aimerror;
01785		FireRotation.Yaw = (FireRotation.Yaw + aimerror) & 65535;
01786	
01787		if ( (Abs(FireRotation.Yaw - (Rotation.Yaw & 65535)) > 8192)
01788			&& (Abs(FireRotation.Yaw - (Rotation.Yaw & 65535)) < 57343) )
01789		{
01790			if ( (FireRotation.Yaw > Rotation.Yaw + 32768) || 
01791				((FireRotation.Yaw < Rotation.Yaw) && (FireRotation.Yaw > Rotation.Yaw - 32768)) )
01792				FireRotation.Yaw = Rotation.Yaw - 8192;
01793			else
01794				FireRotation.Yaw = Rotation.Yaw + 8192;
01795		}
01796		FireDir = vector(FireRotation);
01797		// avoid shooting into wall
01798		FireDist = FMin(VSize(FireSpot-ProjStart), 400);
01799		FireSpot = ProjStart + FireDist * FireDir;
01800		HitActor = Trace(HitLocation, HitNormal, FireSpot, ProjStart, false); 
01801		if ( HitActor != None )
01802		{
01803			if ( HitNormal.Z < 0.7 )
01804			{
01805				FireRotation.Yaw = (realYaw - aimerror) & 65535;
01806				if ( (Abs(FireRotation.Yaw - (Rotation.Yaw & 65535)) > 8192)
01807					&& (Abs(FireRotation.Yaw - (Rotation.Yaw & 65535)) < 57343) )
01808				{
01809					if ( (FireRotation.Yaw > Rotation.Yaw + 32768) || 
01810						((FireRotation.Yaw < Rotation.Yaw) && (FireRotation.Yaw > Rotation.Yaw - 32768)) )
01811						FireRotation.Yaw = Rotation.Yaw - 8192;
01812					else
01813						FireRotation.Yaw = Rotation.Yaw + 8192;
01814				}
01815				FireDir = vector(FireRotation);
01816				FireSpot = ProjStart + FireDist * FireDir;
01817				HitActor = Trace(HitLocation, HitNormal, FireSpot, ProjStart, false); 
01818			}
01819			if ( HitActor != None )
01820			{
01821				FireSpot += HitNormal * 2 * Target.CollisionHeight;
01822				if ( !bNovice )
01823				{
01824					HitActor = Trace(HitLocation, HitNormal, FireSpot, ProjStart, false); 
01825					if ( HitActor != None )
01826						FireSpot += Target.CollisionHeight * HitNormal; 
01827				}
01828				FireDir = Normal(FireSpot - ProjStart);
01829				FireRotation = rotator(FireDir);		
01830			}
01831		}
01832	
01833		if ( warnTarget && (Pawn(Target) != None) ) 
01834			Pawn(Target).WarnTarget(self, projSpeed, FireDir); 
01835	
01836		viewRotation = FireRotation;			
01837		return FireRotation;
01838	}
01839	
01840	function WarnTarget(Pawn shooter, float projSpeed, vector FireDir)
01841	{
01842		local float enemyDist;
01843		local vector X,Y,Z, enemyDir;
01844	
01845		// AI controlled creatures may duck if not falling
01846		if ( (health <= 0) || !bCanDuck || (Enemy == None) 
01847			|| (Physics == PHYS_Falling) || (Physics == PHYS_Swimming) )
01848			return;
01849	
01850		if ( bNovice )
01851		{
01852			if ( FRand() > 0.11 * skill )
01853				return;
01854		}
01855		else if ( FRand() > 0.22 * skill + 0.33 )
01856			return;
01857	
01858		// and projectile time is long enough
01859		enemyDist = VSize(shooter.Location - Location);
01860		if (enemyDist/projSpeed < 0.11 + 0.15 * FRand()) 
01861			return;
01862						
01863		// only if tight FOV
01864		GetAxes(Rotation,X,Y,Z);
01865		enemyDir = (shooter.Location - Location)/enemyDist;
01866		if ((enemyDir Dot X) < 0.8)
01867			return;
01868	
01869		if ( (FireDir Dot Y) > 0 )
01870		{
01871			Y *= -1;
01872			TryToDuck(Y, true);
01873		}
01874		else
01875			TryToDuck(Y, false);
01876	}
01877	
01878	function TryToDuck(vector duckDir, bool bReversed)
01879	{
01880		local vector HitLocation, HitNormal, Extent;
01881		local actor HitActor;
01882		local bool bSuccess, bDuckLeft;
01883	
01884		if ( Region.Zone.bWaterZone || (Region.Zone.ZoneGravity.Z > Region.Zone.Default.ZoneGravity.Z) )
01885			return;
01886	
01887		duckDir.Z = 0;
01888		bDuckLeft = !bReversed;
01889		Extent.X = CollisionRadius;
01890		Extent.Y = CollisionRadius;
01891		Extent.Z = CollisionHeight;
01892		HitActor = Trace(HitLocation, HitNormal, Location + 240 * duckDir, Location, false, Extent);
01893		bSuccess = ( (HitActor == None) || (VSize(HitLocation - Location) > 150) );
01894		if ( !bSuccess )
01895		{
01896			bDuckLeft = !bDuckLeft;
01897			duckDir *= -1;
01898			HitActor = Trace(HitLocation, HitNormal, Location + 240 * duckDir, Location, false, Extent);
01899			bSuccess = ( (HitActor == None) || (VSize(HitLocation - Location) > 150) );
01900		}
01901		if ( !bSuccess )
01902			return;
01903		
01904		if ( HitActor == None )
01905			HitLocation = Location + 240 * duckDir; 
01906	
01907		HitActor = Trace(HitLocation, HitNormal, HitLocation - MaxStepHeight * vect(0,0,1), HitLocation, false, Extent);
01908		if (HitActor == None)
01909			return;
01910			
01911		SetFall();
01912		Velocity = duckDir * 400;
01913		Velocity.Z = 160;
01914		PlayDodge(bDuckLeft);
01915		PlaySound(JumpSound, SLOT_Talk, 1.0, true, 800, 1.0 );
01916		SetPhysics(PHYS_Falling);
01917		if ( (Weapon != None) && Weapon.bSplashDamage
01918			&& ((bFire != 0) || (bAltFire != 0)) && (Enemy != None) 
01919			&& !FastTrace(Enemy.Location, HitLocation) 
01920			&& FastTrace(Enemy.Location, Location) )
01921		{
01922			bFire = 0;
01923			bAltFire = 0;
01924		}
01925		GotoState('FallingState','Ducking');
01926	}
01927	
01928	function PlayDodge(bool bDuckLeft)
01929	{
01930		PlayDuck();
01931	}
01932	
01933	// CloseToPointMan - called if orders are 'follow' to check if close enough to point man
01934	function bool CloseToPointMan(Pawn Other)
01935	{
01936		local float dist;
01937	
01938		// for certain games, have bots wait for leader for a while
01939		if ( TeamGamePlus(Level.Game).WaitForPoint(self) )
01940			return true;
01941	
01942		if ( (Base != None) && (Other.Base != None) && (Other.Base != Base) )
01943			return false;	
01944	
01945		dist = VSize(Location - Other.Location);
01946		if ( dist > 400 )
01947			return false;
01948		
01949		// check if point is moving away
01950		if ( (Region.Zone.bWaterZone || (dist > 200)) && (((Other.Location - Location) Dot Other.Velocity) > 0) )
01951			return false;
01952					
01953		return ( LineOfSightTo(Other) );
01954	}
01955	
01956	// Can Stake Out - check if I can see my current Destination point, and so can enemy
01957	function bool CanStakeOut()
01958	{
01959		if ( VSize(Enemy.Location - LastSeenPos) > 800 )
01960			return false;		
01961		
01962		return ( FastTrace(LastSeenPos, Location + EyeHeight * vect(0,0,1))
01963				&& FastTrace(LastSeenPos , Enemy.Location + Enemy.BaseEyeHeight * vect(0,0,1)) );
01964	}
01965	
01966	function eAttitude AttitudeTo(Pawn Other)
01967	{
01968		local byte result;
01969	
01970		if ( Level.Game.IsA('DeathMatchPlus') )
01971		{
01972			result = DeathMatchPlus(Level.Game).AssessBotAttitude(self, Other);
01973			Switch (result)
01974			{
01975				case 0: return ATTITUDE_Fear;
01976				case 1: return ATTITUDE_Hate;
01977				case 2: return ATTITUDE_Ignore;
01978				case 3: return ATTITUDE_Friendly;
01979			}
01980		}
01981	
01982		if ( Level.Game.bTeamGame && (PlayerReplicationInfo.Team == Other.PlayerReplicationInfo.Team) )
01983			return ATTITUDE_Friendly; //teammate
01984	
01985		return ATTITUDE_Hate;
01986	}
01987	
01988	function float AssessThreat( Pawn NewThreat )
01989	{
01990		local float ThreatValue, NewStrength, Dist;
01991		local eAttitude NewAttitude;
01992	
01993		NewStrength = RelativeStrength(NewThreat);
01994	
01995		ThreatValue = FMax(0, NewStrength);
01996		if ( NewThreat.Health < 20 )
01997			ThreatValue += 0.3;
01998	
01999		Dist = VSize(NewThreat.Location - Location);
02000		if ( Dist < 800 )
02001			ThreatValue += 0.3;
02002	
02003		if ( (NewThreat != Enemy) && (Enemy != None) )
02004		{
02005			if ( Dist > 0.7 * VSize(Enemy.Location - Location) )
02006				ThreatValue -= 0.25;
02007			ThreatValue -= 0.2;
02008	
02009			if ( !LineOfSightTo(Enemy) )
02010			{
02011				if ( Dist < 1200 )
02012					ThreatValue += 0.2;
02013				if ( SpecialPause > 0 )
02014					ThreatValue += 5;
02015				if ( IsInState('Hunting') && (NewStrength < 0.2) 
02016					&& (Level.TimeSeconds - LastSeenTime < 3)
02017					&& (relativeStrength(Enemy) < FMin(0, NewStrength)) )
02018					ThreatValue -= 0.3;
02019			}
02020		}
02021	
02022		if ( NewThreat.IsA('PlayerPawn') )
02023		{
02024			if ( Level.Game.bTeamGame )
02025				ThreatValue -= 0.15;
02026			else
02027				ThreatValue += 0.15;
02028		}
02029	
02030		if ( Level.Game.IsA('DeathMatchPlus') )
02031			ThreatValue += DeathMatchPlus(Level.Game).GameThreatAdd(self, NewThreat);
02032		return ThreatValue;
02033	}
02034	
02035	
02036	function bool SetEnemy( Pawn NewEnemy )
02037	{
02038		local bool result, bNotSeen;
02039		local eAttitude newAttitude, oldAttitude;
02040		local float newStrength;
02041		local Pawn Friend;
02042	
02043		if (Enemy == NewEnemy)
02044			return true;
02045		if ( (NewEnemy == Self) || (NewEnemy == None) || (NewEnemy.Health <= 0) || NewEnemy.IsA('FlockPawn') )
02046			return false;
02047	
02048		result = false;
02049		newAttitude = AttitudeTo(NewEnemy);
02050		if ( newAttitude == ATTITUDE_Friendly )
02051		{
02052			Friend = NewEnemy;
02053			if ( Level.TimeSeconds - Friend.LastSeenTime > 5 )
02054				return false;
02055			NewEnemy = NewEnemy.Enemy;
02056			if ( (NewEnemy == None) || (NewEnemy == Self) || (NewEnemy.Health <= 0) || NewEnemy.IsA('FlockPawn') || NewEnemy.IsA('StationaryPawn') )
02057				return false;
02058			if (Enemy == NewEnemy)
02059				return true;
02060	
02061			bNotSeen = true;
02062			newAttitude = AttitudeTo(NewEnemy);
02063		}
02064	
02065		if ( newAttitude >= ATTITUDE_Ignore )
02066			return false;
02067	
02068		if ( Enemy != None )
02069		{
02070			if ( AssessThreat(NewEnemy) > AssessThreat(Enemy) )
02071			{
02072				OldEnemy = Enemy;
02073				Enemy = NewEnemy;
02074				result = true;
02075			}
02076			else if ( OldEnemy == None )
02077				OldEnemy = NewEnemy;
02078		}
02079		else
02080		{
02081			result = true;
02082			Enemy = NewEnemy;
02083		}
02084	
02085		if ( result )
02086		{
02087			if ( bNotSeen )
02088			{
02089				LastSeenTime = Friend.LastSeenTime;
02090				LastSeeingPos = Friend.LastSeeingPos;
02091				LastSeenPos = Friend.LastSeenPos;
02092			}
02093			else
02094			{
02095				LastSeenTime = Level.TimeSeconds;
02096				LastSeeingPos = Location;
02097				LastSeenPos = Enemy.Location;
02098			}
02099			EnemyAcquired();
02100		}
02101					
02102		return result;
02103	}
02104	
02105	function InitializeSkill(float InSkill)
02106	{
02107		Skill = InSkill;
02108		bNovice = ( Skill < 4 );
02109		if ( !bNovice )
02110			Skill -= 4;
02111		Skill = FClamp(Skill, 0, 3);
02112		ReSetSkill();
02113	}
02114	
02115	function ReSetSkill()
02116	{
02117		//log(self$" at skill "$Skill$" novice "$bNovice);
02118		bThreePlus = ( (Skill >= 3) && Level.Game.IsA('DeathMatchPlus') && DeathMatchPlus(Level.Game).bThreePlus );
02119		bLeadTarget = ( !bNovice || bThreePlus );
02120		if ( bNovice )
02121			ReFireRate = Default.ReFireRate;
02122		else
02123			ReFireRate = Default.ReFireRate * (1 - 0.25 * skill);
02124	
02125		PreSetMovement();
02126	}
02127	
02128	function MaybeTaunt(Pawn Other)
02129	{
02130		if ( (FRand() < 0.25) && (Orders != 'Attack')
02131			&& (!Level.Game.IsA('TeamGamePlus') || (TeamGamePlus(Level.Game).PriorityObjective(self) < 1)) )
02132		{
02133			Target = Other;
02134			GotoState('VictoryDance');
02135		}
02136		else
02137			GotoState('Attacking'); 
02138	}
02139	
02140	function Killed(pawn Killer, pawn Other, name damageType)
02141	{
02142		local Pawn aPawn;
02143	
02144		if ( Killer == self )
02145			Other.Health = FMin(Other.Health, -11); // don't let other do stagger death
02146	
02147		if ( Health <= 0 )
02148			return;
02149	
02150		if ( OldEnemy == Other )
02151			OldEnemy = None;
02152	
02153		if ( Enemy == Other )
02154		{
02155			bFire = 0;
02156			bAltFire = 0;
02157			bReadyToAttack = ( skill > 3 * FRand() );
02158			EnemyDropped = Enemy.Weapon;
02159			Enemy = None;
02160			if ( (Killer == self) && (OldEnemy == None) )
02161			{
02162				for ( aPawn=Level.PawnList; aPawn!=None; aPawn=aPawn.nextPawn )
02163					if ( aPawn.bIsPlayer && aPawn.bCollideActors 
02164						&& (VSize(Location - aPawn.Location) < 1600)
02165						&& CanSee(aPawn) && SetEnemy(aPawn) )
02166					{
02167						GotoState('Attacking');
02168						return;
02169					}
02170	
02171				MaybeTaunt(Other);
02172			}
02173			else 
02174				GotoState('Attacking');
02175		}
02176		else if ( Level.Game.bTeamGame && Other.bIsPlayer
02177				&& (Other.PlayerReplicationInfo.Team == PlayerReplicationInfo.Team) )
02178		{
02179			if ( Other == Self )
02180				return;
02181			else
02182			{
02183				if ( (VSize(Location - Other.Location) < 1400)
02184					&& LineOfSightTo(Other) )
02185					SendTeamMessage(None, 'OTHER', 5, 10);
02186				if ( (Orders == 'follow') && (Other == OrderObject) )
02187					PointDied = Level.TimeSeconds;
02188			}
02189		}
02190	}	
02191	
02192	function EnemyAcquired()
02193	{
02194		//log(Class$" just acquired an enemy - no action");
02195	}
02196	
02197	/* RelativeStrength()
02198	returns a value indicating the relative strength of other
02199	0.0 = equal to self
02200	> 0 stronger than self
02201	< 0 weaker than self
02202	
02203	Since the result will be compared to the creature's aggressiveness, it should be
02204	on the same order of magnitude (-1 to 1)
02205	
02206	Assess based on health and weapon
02207	*/
02208	
02209	function float RelativeStrength(Pawn Other)
02210	{
02211		local float compare;
02212		local int adjustedStrength, adjustedOther;
02213		local int bTemp;
02214	
02215		adjustedStrength = health;
02216		adjustedOther = 0.5 * (Other.health + Other.Default.Health);	
02217		compare = 0.01 * float(adjustedOther - adjustedStrength);
02218		if ( Weapon != None )
02219		{
02220			compare -= DamageScaling * (Weapon.RateSelf(bTemp) - 0.3);
02221			if ( Weapon.AIRating < 0.5 )
02222			{
02223				compare += 0.3;
02224				if ( (Other.Weapon != None) && (Other.Weapon.AIRating > 0.5) )
02225					compare += 0.35;
02226			}
02227		}
02228		if ( Other.Weapon != None )
02229			compare += Other.DamageScaling * (Other.Weapon.RateSelf(bTemp) - 0.3);
02230	
02231		if ( Other.Location.Z > Location.Z + 400 )
02232			compare -= 0.15;
02233		else if ( Location.Z > Other.Location.Z + 400 )
02234			compare += 0.15;
02235		//log(other.class@"relative strength to"@class@"is"@compare);
02236		return compare;
02237	}
02238	
02239	function bool CanFireAtEnemy()
02240	{
02241		local vector HitLocation, HitNormal,X,Y,Z, projStart;
02242		local actor HitActor;
02243		
02244		if ( Weapon == None )
02245			return false;
02246		
02247		GetAxes(Rotation,X,Y,Z);
02248		projStart = Location + Weapon.CalcDrawOffset() + Weapon.FireOffset.X * X + 1.2 * Weapon.FireOffset.Y * Y + Weapon.FireOffset.Z * Z;
02249		if ( Weapon.bInstantHit )
02250			HitActor = Trace(HitLocation, HitNormal, Enemy.Location + Enemy.CollisionHeight * vect(0,0,0.7), projStart, true);
02251		else
02252			HitActor = Trace(HitLocation, HitNormal, 
02253					projStart + FMin(280, VSize(Enemy.Location - Location)) * Normal(Enemy.Location + Enemy.CollisionHeight * vect(0,0,0.7) - Location), 
02254					projStart, true);
02255	
02256		if ( HitActor == Enemy )
02257			return true;
02258		if ( (Pawn(HitActor) != None) && (AttitudeTo(Pawn(HitActor)) < ATTITUDE_Ignore) )
02259			return true;
02260		if ( HitActor != None )
02261			return false;
02262	
02263		return true;
02264	}
02265	
02266	function bool FaceDestination(float F)
02267	{
02268		local float RelativeDir;
02269	
02270		if ( Level.TimeSeconds - LastSeenTime > 7.5 - F )
02271			return true;
02272		if ( (Weapon == None) || (Enemy == None) || (Enemy.IsA('StationaryPawn') && !LineOfSightTo(Enemy)) )
02273			return true;
02274		if ( !bNovice && (skill >= 2) && !Weapon.bMeleeWeapon )
02275			return false;
02276		if ( Level.TimeSeconds - LastSeenTime > 4 - F)
02277			return true;
02278	
02279		RelativeDir = Normal(Enemy.Location - Location - vect(0,0,1) * (Enemy.Location.Z - Location.Z)) 
02280				Dot Normal(MoveTarget.Location - Location - vect(0,0,1) * (MoveTarget.Location.Z - Location.Z));
02281	
02282		if ( RelativeDir > 0.93 )
02283			return false;
02284		if ( Weapon.bMeleeWeapon && (RelativeDir < 0) )
02285			return true;
02286	
02287		if ( bNovice )
02288		{
02289			if ( 0.6 * Skill - F * FRand() + RelativeDir - 0.75 + StrafingAbility < 0 )
02290				return true;
02291		}
02292		else 
02293		{
02294			if ( FRand() < 0.2 * (2 - F) )
02295				return false;
02296			if ( Skill - F * FRand() + RelativeDir + 0.6 + StrafingAbility < 0 )
02297				return true;
02298		}
02299		return false;
02300	}
02301	
02302	function PlayMeleeAttack()
02303	{
02304		//log("play melee attack");
02305		Acceleration = AccelRate * VRand();
02306		TweenToWaiting(0.15); 
02307		FireWeapon();
02308	}
02309	
02310	function PlayRangedAttack()
02311	{
02312		TweenToWaiting(0.11);
02313		FireWeapon();
02314	}
02315	
02316	function PlayMovingAttack()
02317	{
02318		PlayRunning();
02319		FireWeapon();
02320	}
02321	
02322	function PlayOutOfWater()
02323	{
02324		PlayDuck();
02325	}
02326	
02327	function PlayCombatMove()
02328	{	
02329		if ( (Physics == PHYS_Falling) && (Velocity.Z < -300) )
02330			FastInAir();
02331		else
02332			PlayRunning();
02333		if ( Enemy == None )
02334			return;
02335		if ( !bNovice && (Skill > 0) )
02336			bReadyToAttack = true;
02337		if ( Weapon == None )
02338		{
02339			bAltFire = 0;
02340			bFire = 0;
02341			return;
02342		}
02343		if ( bReadyToAttack && bCanFire )
02344		{
02345			if ( NeedToTurn(Enemy.Location) )
02346			{
02347				if ( Weapon.RefireRate < 0.99 )
02348					bFire = 0;
02349				if ( Weapon.AltRefireRate < 0.99 )
02350					bAltFire = 0;
02351			}
02352			else 
02353				FireWeapon(); 
02354		}		
02355		else 
02356		{
02357			// keep firing if rapid fire weapon unless can't see enemy
02358			if ( Weapon.RefireRate < 0.99 )
02359				bFire = 0;
02360			if ( Weapon.AltRefireRate < 0.99 )
02361				bAltFire = 0;
02362	
02363			if ( (bFire + bAltFire > 0) && ((Level.TimeSeconds - LastSeenTime > 1) || NeedToTurn(Enemy.Location)) )
02364			{
02365				bFire = 0;
02366				bAltFire = 0;
02367			}
02368		}
02369	}
02370	
02371	function float StrafeAdjust()
02372	{
02373		local vector Focus2D, Loc2D, Dest2D;
02374		local float strafemag; 
02375	
02376		Focus2D = Focus;
02377		Focus2D.Z = 0;
02378		Loc2D = Location;
02379		Loc2D.Z = 0;
02380		Dest2D = Destination;
02381		Dest2D.Z = 0;
02382		strafeMag = Abs( Normal(Focus2D - Loc2D) dot Normal(Dest2D - Loc2D) );
02383	
02384		return ((strafeMag - 2.0)/GroundSpeed);
02385	}
02386	
02387	function Trigger( actor Other, pawn EventInstigator )
02388	{
02389		local Pawn currentEnemy;
02390	
02391		if ( (Other == Self) || (Health <= 0) )
02392			return;
02393		currentEnemy = Enemy;
02394		SetEnemy(EventInstigator);
02395		if (Enemy != currentEnemy)
02396			GotoState('Attacking');
02397	}
02398	
02399	function TranslocateToTarget(Actor Destn)
02400	{
02401		PendingWeapon = MyTranslocator;
02402		MyTranslocator.DesiredTarget = Destn;
02403		if ( Weapon == None )
02404			ChangedWeapon();
02405		else if ( Weapon != PendingWeapon )
02406			Weapon.PutDown();
02407		else
02408			MyTranslocator.PlayPostSelect();
02409		MoveTarget = Destn;
02410		DesiredRotation = rotator(MoveTarget.Location - Location);
02411		SpecialPause = 1.5;
02412	}
02413	
02414	function bool CanImpactJump()
02415	{
02416		return ( bHasImpactHammer && (Health > 60) );
02417	}
02418	
02419	function ImpactJump(Actor JumpDest)
02420	{
02421		if ( Health < 60 )
02422			return;
02423	
02424		SetFall();
02425		ImpactTarget = JumpDest;
02426		GotoState('ImpactJumping');
02427	}
02428	
02429	function BigJump(Actor JumpDest)
02430	{
02431		SetPhysics(PHYS_Falling);
02432		Velocity = GroundSpeed * Normal(JumpDest.Location - Location);
02433		if ( JumpDest.IsA('JumpSpot') && JumpSpot(JumpDest).bAlwaysAccel )
02434		{
02435			bBigJump = true;
02436			Acceleration = AccelRate * Normal(Destination - Location);
02437		}
02438		else
02439			Acceleration = vect(0,0,0);
02440		if ( bCountJumps )
02441			Inventory.OwnerJumped();
02442		Velocity.Z = JumpZ;
02443		Velocity = EAdjustJump();
02444		bJumpOffPawn = true;
02445		DesiredRotation = Rotator(JumpDest.Location - Location);
02446		if ( Region.Zone.ZoneGravity == Region.Zone.Default.ZoneGravity )
02447			MoveTarget = None;
02448		SetFall();
02449	}
02450	
02451	function bool FindAmbushSpot()
02452	{
02453		local Pawn P;
02454	
02455		bSpecialAmbush = false;
02456		if ( (AmbushSpot == None) && Level.Game.IsA('DeathMatchPlus') )
02457			DeathMatchPlus(Level.Game).PickAmbushSpotFor(self);
02458		if ( bSpecialAmbush )
02459			return true;
02460	
02461		if ( (AmbushSpot == None) && (Ambushpoint(MoveTarget) != None)
02462			&& !AmbushPoint(MoveTarget).taken )
02463			AmbushSpot = Ambushpoint(MoveTarget);
02464						
02465		if ( Ambushspot != None )
02466		{
02467			GoalString = "Ambush"@Ambushspot;
02468			Ambushspot.taken = true;
02469			if ( VSize(Ambushspot.Location - Location) < 2 * CollisionRadius )
02470			{
02471				GoalString = GoalString$" there";	
02472				if ( !bInitLifeMessage && (Orders == 'Defend') )
02473				{
02474					bInitLifeMessage = true;	
02475					SendTeamMessage(None, 'OTHER', 9, 60);
02476				}
02477				if ( Level.Game.bTeamGame )
02478					for ( P=Level.PawnList; P!=None; P=P.NextPawn )
02479						if ( P.bIsPlayer && (P.PlayerReplicationInfo != None)
02480							&& (P.PlayerReplicationInfo.Team == PlayerReplicationInfo.Team)
02481							&& P.IsA('Bot') && (P != self) 
02482							&& (Bot(P).Ambushspot == AmbushSpot) )
02483								Bot(P).AmbushSpot = None;
02484	
02485				bSniping = ((Orders == 'Defend') && AmbushSpot.bSniping);
02486				CampTime = 10.0;
02487				SightRadius = AmbushSpot.SightRadius;
02488				GotoState('Roaming', 'LongCamp');
02489				return true;
02490			}
02491			if ( ActorReachable(Ambushspot) )
02492			{
02493				GoalString = GoalString$" reachable";	
02494				MoveTarget = Ambushspot;
02495				return true;
02496			}
02497			GoalString = GoalString$" path there";	
02498			MoveTarget = FindPathToward(Ambushspot);
02499			if ( MoveTarget != None )
02500				return true;
02501			Ambushspot.taken = false;
02502			GoalString = "No ambush";
02503			Ambushspot = None;
02504		}
02505		return false;
02506	}	
02507	
02508	function bool PickLocalInventory(float MaxDist, float MinDistraction)
02509	{
02510		local inventory Inv, BestInv, KnowPath;
02511		local float NewWeight, DroppedDist, BestWeight;
02512		local actor BestPath;
02513		local bool bCanReach;
02514		local NavigationPoint N;
02515	
02516		if ( (EnemyDropped != None) && !EnemyDropped.bDeleteMe 
02517			&& (EnemyDropped.Owner == None) )
02518		{
02519			DroppedDist = VSize(EnemyDropped.Location - Location);
02520			NewWeight = EnemyDropped.BotDesireability(self);
02521			if ( (DroppedDist < MaxDist) 
02522				&& ((NewWeight > MinDistraction) || (DroppedDist < 0.5 * MaxDist))
02523				&& ((EnemyDropped.Physics != PHYS_Falling) || (Region.Zone.ZoneGravity.Z == Region.Zone.Default.ZoneGravity.Z))
02524				&& ActorReachable(EnemyDropped) )
02525			{
02526				BestWeight = NewWeight; 		
02527				if ( BestWeight > 0.4 )
02528				{
02529					MoveTarget = EnemyDropped;
02530					EnemyDropped = None;
02531					return true; 
02532				}
02533				BestInv = EnemyDropped;
02534				BestWeight = BestWeight/DroppedDist;
02535				KnowPath = BestInv;
02536			}	
02537		}	
02538	
02539		EnemyDropped = None;
02540									
02541		//first look at nearby inventory < MaxDist
02542		foreach visiblecollidingactors(class'Inventory', Inv, MaxDist,,true)
02543			if ( (Inv.IsInState('PickUp')) && (Inv.MaxDesireability/60 > BestWeight)
02544				&& (Inv.Physics != PHYS_Falling)
02545				&& (Inv.Location.Z < Location.Z + MaxStepHeight + CollisionHeight) )
02546			{
02547				NewWeight = inv.BotDesireability(self);
02548				if ( (NewWeight > MinDistraction) 
02549					 || (Inv.bHeldItem && Inv.IsA('Weapon') && (VSize(Inv.Location - Location) < 0.6 * MaxDist)) )
02550				{
02551					NewWeight = NewWeight/VSize(Inv.Location - Location);
02552					if ( NewWeight > BestWeight )
02553					{
02554						BestWeight = NewWeight;
02555						BestInv = Inv;
02556					}
02557				}
02558			}
02559	
02560		if ( BestInv != None )
02561		{
02562			bCanJump = ( bCanTranslocate || (BestInv.Location.Z > Location.Z - CollisionHeight - MaxStepHeight) );
02563			bCanReach = ActorReachable(BestInv);
02564		}
02565		else
02566			bCanReach = false;
02567		bCanJump = true;
02568		if ( bCanReach )
02569		{
02570			//GoalString = "local"@BestInv;
02571			MoveTarget = BestInv;
02572			return true;
02573		}
02574		else if ( KnowPath != None )
02575		{
02576			//GoalString = "local"@KnowPath;
02577			MoveTarget = KnowPath;
02578			return true;
02579		}
02580		//GoalString="No local";
02581		return false;
02582	}
02583	
02584	//**********************************************************************************
02585	//Base Monster AI
02586	
02587	auto state StartUp
02588	{
02589		function BeginState()
02590		{
02591			SetMovementPhysics(); 
02592			if (Physics == PHYS_Walking)
02593				SetPhysics(PHYS_Falling);
02594		}
02595	
02596	Begin:
02597		WhatToDoNext('','');
02598	}
02599	
02600	state Holding
02601	{
02602		function ShootTarget(Actor NewTarget)
02603		{
02604			Target = NewTarget;
02605			bFiringPaused = true;
02606			SpecialPause = 2.0;
02607			NextState = GetStateName();
02608			NextLabel = 'Begin';
02609			GotoState('RangedAttack');
02610		}	
02611		
02612		function TakeDamage( int Damage, Pawn instigatedBy, Vector hitlocation, 
02613								Vector momentum, name damageType)
02614		{
02615			Global.TakeDamage(Damage, instigatedBy, hitlocation, momentum, damageType);
02616			if ( health <= 0 )
02617				return;
02618			if ( (Enemy != None) && (Enemy == InstigatedBy) )
02619			{
02620				LastSeenPos = Enemy.Location;
02621				LastSeenTime = Level.TimeSeconds;
02622			}
02623			if (NextState == 'TakeHit')
02624			{
02625				NextState = 'Attacking'; 
02626				NextLabel = 'Begin';
02627				GotoState('TakeHit'); 
02628			}
02629			else if ( Enemy != None )
02630				GotoState('Attacking');
02631		}
02632		
02633		function Timer()
02634		{
02635			Enable('Bump');
02636		}
02637		
02638		function EnemyAcquired()
02639		{
02640			GotoState('Acquisition', 'PlayOut');
02641		}
02642		
02643		function AnimEnd()
02644		{
02645			PlayWaiting();
02646		}
02647	 
02648		function Landed(vector HitNormal)
02649		{
02650			SetPhysics(PHYS_None);
02651		}
02652	
02653		function BeginState()
02654		{
02655			Enemy = None;
02656			bStasis = false;
02657			Acceleration = vect(0,0,0);
02658			SetAlertness(0.0);
02659		}
02660	
02661		function EndState()
02662		{
02663			if ( HoldSpot(OrderObject) != None )
02664				HoldSpot(OrderObject).Holder = None;
02665		}
02666	
02667	TurnFromWall:
02668		if ( NearWall(2 * CollisionRadius + 50) )
02669		{
02670			PlayTurning();
02671			TurnTo(Focus);
02672		}
02673	Begin:
02674		if ( HoldSpot(OrderObject) == None )
02675		{
02676			if ( bVerbose )
02677				log(self$" give up hold");
02678			SetOrders('Freelance', None);
02679			GotoState('Roaming');
02680		} 
02681		else 
02682			HoldSpot(OrderObject).Holder = self;
02683		TweenToWaiting(0.4);
02684	Waving:
02685		bReadyToAttack = false;
02686		DesiredRotation = OrderObject.Rotation;
02687		Sleep(2.5);
02688		GotoState('Roaming');
02689	}
02690	
02691	state Hold
02692	{
02693		function TakeDamage( int Damage, Pawn instigatedBy, Vector hitlocation, 
02694								Vector momentum, name damageType)
02695		{
02696			Global.TakeDamage(Damage, instigatedBy, hitlocation, momentum, damageType);
02697			if ( health <= 0 )
02698				return;
02699			if ( (Enemy != None) && (Enemy == InstigatedBy) )
02700			{
02701				LastSeenPos = Enemy.Location;
02702				LastSeenTime = Level.TimeSeconds;
02703			}
02704			if (NextState == 'TakeHit')
02705			{
02706				NextState = 'Attacking'; 
02707				NextLabel = 'Begin';
02708				GotoState('TakeHit'); 
02709			}
02710			else if ( Enemy != None )
02711				GotoState('Attacking');
02712		}
02713		
02714		function HandleHelpMessageFrom(Pawn Other)
02715		{
02716			if ( (Health > 70) && (Weapon.AIRating > 0.5) && (Other.Enemy != None)
02717				&& ((Other.bIsPlayer && (Other.PlayerReplicationInfo.Team == PlayerReplicationInfo.Team)))
02718				//	|| (Other.IsA('StationaryPawn') && StationaryPawn(Other).SameTeamAs(PlayerReplicationInfo.Team)))
02719				&& (VSize(Other.Enemy.Location - Location) < 800) )
02720				{
02721					if ( Other.bIsPlayer )
02722						SendTeamMessage(Other.PlayerReplicationInfo, 'OTHER', 10, 10);
02723					SetEnemy(Other.Enemy);
02724					GotoState('Attacking');
02725				}
02726		}
02727	
02728		function FearThisSpot(Actor aSpot)
02729		{
02730			Destination = Location + 120 * Normal(Location - aSpot.Location); 
02731			GotoState('Wandering', 'Moving');
02732		}
02733		
02734		function Timer()
02735		{
02736			bReadyToAttack = True;
02737			Enable('Bump');
02738		}
02739	
02740		function SetFall()
02741		{
02742			NextState = 'Hold'; 
02743			NextLabel = 'Landed';
02744			NextAnim = AnimSequence;
02745			GotoState('FallingState'); 
02746		}
02747	
02748		function EnemyAcquired()
02749		{
02750			GotoState('Acquisition');
02751		}
02752	
02753		function HitWall(vector HitNormal, actor Wall)
02754		{
02755			if (Physics == PHYS_Falling)
02756				return;
02757			if ( Wall.IsA('Mover') && Mover(Wall).HandleDoor(self) )
02758			{
02759				if ( SpecialPause > 0 )
02760					Acceleration = vect(0,0,0);
02761				GotoState('Hold', 'SpecialNavig');
02762				return;
02763			}
02764			Focus = Destination;
02765			if (PickWallAdjust())
02766			{
02767				if ( Physics == PHYS_Falling )
02768					SetFall();
02769				else
02770					GotoState('Hold', 'AdjustFromWall');
02771			}
02772			else
02773				MoveTimer = -1.0;
02774		}
02775		
02776		function PickDestination()
02777		{
02778			local Vector Direction;
02779	
02780			if ( (HoldSpot(OrderObject) == None) )
02781			{
02782				SetOrders('Freelance', None);
02783				GotoState('Roaming');
02784			} 
02785			Direction = Location - OrderObject.Location;
02786			if ( (Direction.X * Direction.X + Direction.Y * Direction.Y < 256) 
02787				&& (Abs(Direction.Z) < 48) )
02788			{
02789				SendTeamMessage(None, 'OTHER', 9, 45);
02790				if ( !bInitLifeMessage )
02791				{
02792					bInitLifeMessage = true;
02793					PlayWaving();
02794				}
02795				else
02796					TweenToWaiting(0.25);
02797				GotoState('Holding', 'Waving');
02798				return;
02799			}
02800			if ( ActorReachable(OrderObject) )
02801			{
02802				if ( HoldSpot(OrderObject).Holder != None )
02803					GotoState('Wandering');
02804				MoveTarget = OrderObject;
02805				return;
02806			}
02807			MoveTarget = FindPathToward(OrderObject);
02808			if ( MoveTarget == None ) 
02809			{
02810				SetOrders('Freelance', None);
02811				GotoState('Roaming');
02812			} 
02813		}
02814	
02815		function AnimEnd()
02816		{
02817			PlayRunning();
02818		}
02819	 
02820		function Landed(vector HitNormal)
02821		{
02822			SetPhysics(PHYS_None);
02823		}
02824	
02825		function BeginState()
02826		{
02827			SpecialGoal = None;
02828			SpecialPause = 0.0;
02829			bSpecialGoal = false;
02830		}
02831	
02832	TurnFromWall:
02833		if ( NearWall(2 * CollisionRadius + 50) )
02834		{
02835			PlayTurning();
02836			TurnTo(Focus);
02837		}
02838	Begin:
02839		SwitchToBestWeapon();
02840		TweenToRunning(0.1);
02841		WaitForLanding();
02842		
02843	RunAway:
02844		PickDestination();
02845	SpecialNavig:
02846		if (SpecialPause > 0.0)
02847		{
02848			Disable('AnimEnd');
02849			Acceleration = vect(0,0,0);
02850			TweenToPatrolStop(0.3);
02851			Sleep(SpecialPause);
02852			SpecialPause = 0.0;
02853			Enable('AnimEnd');
02854			TweenToRunning(0.1);
02855			Goto('RunAway');
02856		}
02857	Moving:
02858		if ( !IsAnimating() )
02859			AnimEnd();
02860		if ( MoveTarget == None )
02861		{
02862			Acceleration = vect(0,0,0);
02863			Sleep(0.1);
02864			Goto('RunAway');
02865		}
02866		MoveToward(MoveTarget);
02867		Goto('RunAway');
02868	
02869	
02870	TakeHit:
02871		TweenToRunning(0.12);
02872		Goto('Moving');
02873	
02874	Landed:
02875		if ( MoveTarget == None )
02876			Goto('RunAway');
02877		Goto('Moving');
02878	
02879	AdjustFromWall:
02880		if ( !IsAnimating() )
02881			AnimEnd();
02882		bCamping = false;
02883		StrafeTo(Destination, Focus); 
02884		Destination = Focus; 
02885		MoveTo(Destination);
02886		Goto('Moving');
02887	}
02888	
02889	state Roaming
02890	{
02891		ignores EnemyNotVisible;
02892	
02893		function SetOrders(name NewOrders, Pawn OrderGiver, optional bool bNoAck)
02894		{
02895			Global.SetOrders(NewOrders, OrderGiver, bNoAck);
02896			if ( bCamping && ((Orders == 'Hold') || (Orders == 'Follow')) )
02897				GotoState('Roaming', 'PreBegin');
02898		}
02899	
02900		function HearPickup(Pawn Other)
02901		{
02902			if ( bNovice || (Skill < 4 * FRand() - 1) )
02903				return;
02904			if ( (Health > 70) && (Weapon.AiRating > 0.6) 
02905				&& (RelativeStrength(Other) < 0) )
02906				HearNoise(0.5, Other);
02907		}
02908					
02909		function ShootTarget(Actor NewTarget)
02910		{
02911			Target = NewTarget;
02912			bFiringPaused = true;
02913			SpecialPause = 2.0;
02914			NextState = GetStateName();
02915			NextLabel = 'Begin';
02916			GotoState('RangedAttack');
02917		}
02918	
02919		function MayFall()
02920		{
02921			bCanJump = ( (MoveTarget != None) 
02922						&& ((MoveTarget.Physics != PHYS_Falling) || !MoveTarget.IsA('Inventory')) );
02923		}
02924		
02925		function HandleHelpMessageFrom(Pawn Other)
02926		{
02927			if ( (Health > 70) && (Weapon.AIRating > 0.5) && (Other.Enemy != None)
02928				&& ((Other.bIsPlayer && (Other.PlayerReplicationInfo.Team == PlayerReplicationInfo.Team)))
02929				//	|| (Other.IsA('StationaryPawn') && StationaryPawn(Other).SameTeamAs(PlayerReplicationInfo.Team)))
02930				&& (VSize(Other.Enemy.Location - Location) < 800) )
02931			{
02932				if ( Other.bIsPlayer )
02933					SendTeamMessage(Other.PlayerReplicationInfo, 'OTHER', 10, 10);
02934				SetEnemy(Other.Enemy);
02935				GotoState('Attacking');
02936			}
02937		}
02938	
02939		function TakeDamage( int Damage, Pawn instigatedBy, Vector hitlocation, 
02940								Vector momentum, name damageType)
02941		{
02942			Global.TakeDamage(Damage, instigatedBy, hitlocation, momentum, damageType);
02943			if ( health <= 0 )
02944				return;
02945			if (NextState == 'TakeHit')
02946			{
02947				NextState = 'Attacking'; 
02948				NextLabel = '';
02949				GotoState('TakeHit'); 
02950			}
02951			else if ( !bCanFire && (skill > 3 * FRand()) )
02952				GotoState('Attacking');
02953		}
02954	
02955		function FearThisSpot(Actor aSpot)
02956		{
02957			Destination = Location + 120 * Normal(Location - aSpot.Location); 
02958			GotoState('Wandering', 'Moving');
02959		}
02960		
02961		function Timer()
02962		{
02963			bReadyToAttack = True;
02964			Enable('Bump');
02965		}
02966	
02967		function SetFall()
02968		{
02969			bWallAdjust = false;
02970			NextState = 'Roaming'; 
02971			NextLabel = 'Landed';
02972			NextAnim = AnimSequence;
02973			GotoState('FallingState'); 
02974		}
02975	
02976		function EnemyAcquired()
02977		{
02978			GotoState('Acquisition');
02979		}
02980	
02981		function HitWall(vector HitNormal, actor Wall)
02982		{
02983			if (Physics == PHYS_Falling)
02984				return;
02985			if ( Wall.IsA('Mover') && Mover(Wall).HandleDoor(self) )
02986			{
02987				if ( SpecialPause > 0 )
02988					Acceleration = vect(0,0,0);
02989				GotoState('Roaming', 'SpecialNavig');
02990				return;
02991			}
02992			Focus = Destination;
02993			if ( !bWallAdjust && PickWallAdjust() )
02994			{
02995				if ( Physics == PHYS_Falling )
02996					SetFall();
02997				else
02998					GotoState('Roaming', 'AdjustFromWall');
02999			}
03000			else
03001			{
03002				MoveTimer = -1.0;
03003				bWallAdjust = false;
03004			}
03005		}
03006	
03007		function PickDestination()
03008		{
03009			local inventory Inv, BestInv;
03010			local float Bestweight, NewWeight, DroppedDist;
03011			local actor BestPath;
03012			local decoration Dec;
03013			local NavigationPoint N;
03014			local int i;
03015			local bool bTriedToPick, bLockedAndLoaded, bNearPoint;
03016			local byte TeamPriority;
03017			local Pawn P;
03018	
03019			bCanTranslocate = ( Level.Game.IsA('DeathMatchPlus') && DeathMatchPlus(Level.Game).CanTranslocate(self) );
03020			if ( Level.Game.IsA('TeamGamePlus') )
03021			{
03022				if ( (Orders == 'FreeLance') && !bStayFreelance
03023					 &&	(Orders != BotReplicationInfo(PlayerReplicationInfo).RealOrders) ) 
03024					SetOrders(BotReplicationInfo(PlayerReplicationInfo).RealOrders, BotReplicationInfo(PlayerReplicationInfo).RealOrderGiver, true);
03025				if ( FRand() < 0.5 )
03026					bStayFreelance = false;
03027				LastAttractCheck = Level.TimeSeconds - 0.1;
03028				if ( TeamGamePlus(Level.Game).FindSpecialAttractionFor(self) )
03029				{
03030					if ( IsInState('Roaming') )
03031					{
03032						TeamPriority = TeamGamePlus(Level.Game).PriorityObjective(self);
03033						if ( TeamPriority > 16 )
03034						{
03035							PickLocalInventory(160, 1.8);
03036							return;
03037						}
03038						else if ( TeamPriority > 1 )
03039						{
03040							PickLocalInventory(200, 1);
03041							return;
03042						}
03043						else if ( TeamPriority > 0 )
03044						{
03045							PickLocalInventory(280, 0.55);
03046							return;
03047						}
03048						PickLocalInventory(400, 0.5);
03049					}
03050					return;
03051				}
03052			}
03053			bLockedAndLoaded = ( (Weapon.AIRating > 0.4) && (Health > 60) );
03054	
03055			if (  Orders == 'Follow' )
03056			{
03057				if ( Pawn(OrderObject) == None )
03058					SetOrders('FreeLance', None);
03059				else if ( (Pawn(OrderObject).Health > 0) )
03060				{
03061					bNearPoint = CloseToPointMan(Pawn(OrderObject));
03062					if ( !bNearPoint )
03063					{
03064						if ( !bLockedAndLoaded )
03065						{
03066							bTriedToPick = true;
03067							if ( PickLocalInventory(600, 0) )
03068								return;
03069	
03070							if ( !OrderObject.IsA('PlayerPawn') )
03071							{
03072								BestWeight = 0;
03073								BestPath = FindBestInventoryPath(BestWeight, !bNovice && (skill >= 2));
03074								if ( BestPath != None )
03075								{
03076									MoveTarget = BestPath;
03077									return;
03078								}
03079							}
03080						}				
03081						if ( ActorReachable(OrderObject) )
03082							MoveTarget = OrderObject;
03083						else
03084							MoveTarget = FindPathToward(OrderObject);
03085						if ( (MoveTarget != None) && (VSize(Location - MoveTarget.Location) > 2 * CollisionRadius) )
03086							return;
03087						if ( (VSize(OrderObject.Location - Location) < 1600) && LineOfSightTo(OrderObject) )
03088							bNearPoint = true;
03089						if ( bVerbose )
03090							log(self$" found no path to "$OrderObject);
03091					}
03092					else if ( !bInitLifeMessage && (Pawn(OrderObject).Health > 0) 
03093								&& (VSize(Location - OrderObject.Location) < 500) )
03094					{
03095						bInitLifeMessage = true;
03096						SendTeamMessage(Pawn(OrderObject).PlayerReplicationInfo, 'OTHER', 3, 10);
03097					}
03098				}
03099			}
03100			if ( (Orders == 'Defend') && bLockedAndLoaded )
03101			{
03102				if ( PickLocalInventory(300, 0.55) )
03103					return;
03104				if ( FindAmbushSpot() ) 
03105					return;
03106				if ( !LineOfSightTo(OrderObject) )
03107				{
03108					MoveTarget = FindPathToward(OrderObject);
03109					if ( MoveTarget != None )
03110						return;
03111				}
03112				else if ( !bInitLifeMessage )
03113				{
03114					bInitLifeMessage = true;
03115					SendTeamMessage(None, 'OTHER', 9, 10);
03116				}
03117			}
03118	
03119			if ( (Orders == 'Hold') && bLockedAndLoaded && !LineOfSightTo(OrderObject) )
03120			{
03121				GotoState('Hold');
03122				return;
03123			}
03124	
03125			if ( !bTriedToPick && PickLocalInventory(600, 0) )
03126				return;
03127	
03128			if ( (Orders == 'Hold') && bLockedAndLoaded )
03129			{
03130				if ( VSize(Location - OrderObject.Location) < 20 )
03131					GotoState('Holding');
03132				else
03133					GotoState('Hold');
03134				return;
03135			}
03136	
03137			if ( ((Orders == 'Follow') && (bNearPoint || (Level.Game.IsA('TeamGamePlus') && TeamGamePlus(Level.Game).WaitForPoint(self))))
03138				|| ((Orders == 'Defend') && bLockedAndLoaded && LineOfSightTo(OrderObject)) )
03139			{
03140				if ( FRand() < 0.35 )
03141					GotoState('Wandering');
03142				else
03143				{
03144					CampTime = 0.8;
03145					GotoState('Roaming', 'Camp');
03146				}
03147				return;
03148			}
03149	
03150			if ( (OrderObject != None) && !OrderObject.IsA('Ambushpoint') )
03151				bWantsToCamp = false;
03152			else if ( (Weapon.AIRating > 0.5) && (Health > 90) && !Region.Zone.bWaterZone )
03153			{
03154				bWantsToCamp = ( bWantsToCamp || (FRand() < CampingRate * FMin(1.0, Level.TimeSeconds - LastCampCheck)) );
03155				LastCampCheck = Level.TimeSeconds;
03156			}
03157			else 
03158				bWantsToCamp = false;
03159	
03160			if ( bWantsToCamp && FindAmbushSpot() )
03161				return;
03162	
03163			// if none found, check for decorations with inventory
03164			if ( !bNoShootDecor )
03165				foreach visiblecollidingactors(class'Decoration', Dec, 500,,true)
03166					if ( Dec.Contents != None )
03167					{
03168						bNoShootDecor = true;
03169						Target = Dec;
03170						GotoState('Roaming', 'ShootDecoration');
03171						return;
03172					}
03173	
03174			bNoShootDecor = false;
03175			BestWeight = 0;
03176	
03177			// look for long distance inventory 
03178			BestPath = FindBestInventoryPath(BestWeight, !bNovice && (skill >= 2));
03179			//log("roam to"@BestPath);
03180			//log("---------------------------------");
03181			if ( BestPath != None )
03182			{
03183				MoveTarget = BestPath;
03184				return;
03185			}
03186	
03187			// nothing around - maybe just wait a little
03188			if ( (FRand() < 0.35) && bNovice 
03189				&& (!Level.Game.IsA('DeathMatchPlus') || !DeathMatchPlus(Level.Game).OneOnOne())  )
03190			{
03191				GoalString = " Nothing cool, so camp ";
03192				CampTime = 3.5 + FRand() - skill;
03193				GotoState('Roaming', 'Camp');
03194			}
03195	
03196			// if roamed to ambush point, stay there maybe
03197			if ( (AmbushPoint(RoamTarget) != None)
03198				&& (VSize(Location - RoamTarget.Location) < 2 * CollisionRadius)
03199				&& (FRand() < 0.4) )
03200			{
03201				CampTime = 4.0;
03202				GotoState('Roaming', 'LongCamp');
03203				return;
03204			}
03205	
03206			// hunt player
03207			if ( (!bNovice || (Level.Game.IsA('DeathMatchPlus') && DeathMatchPlus(Level.Game).OneOnOne()))
03208				&& (Weapon.AIRating > 0.5) && (Health > 60) )
03209			{
03210				if ( (PlayerPawn(RoamTarget) != None) && !LineOfSightTo(RoamTarget) )
03211				{
03212					BestPath = FindPathToward(RoamTarget);
03213					if ( BestPath != None )
03214					{
03215						MoveTarget = BestPath;
03216						return;
03217					}
03218				}
03219				else
03220				{
03221					// high skill bots go hunt player
03222					for ( P=Level.PawnList; P!=None; P=P.NextPawn )
03223						if ( P.bIsPlayer && P.IsA('PlayerPawn') 
03224							&& ((VSize(P.Location - Location) > 1500) || !LineOfSightTo(P)) )
03225						{
03226							BestPath = FindPathToward(P);
03227							if ( BestPath != None )
03228							{
03229								RoamTarget = P;
03230								MoveTarget = BestPath;
03231								return;
03232							}
03233						}
03234				}
03235				bWantsToCamp = true; // don't camp if couldn't go to player
03236			}
03237			
03238			// look for ambush spot if didn't already try
03239			if ( !bWantsToCamp && FindAmbushSpot() )
03240			{
03241				RoamTarget = AmbushSpot;
03242				return;
03243			}
03244			
03245			// find a roamtarget
03246			if ( RoamTarget == None )
03247			{
03248				i = 0;
03249				for ( N=Level.NavigationPointList; N!=None; N=N.NextNavigationPoint )
03250					if ( N.IsA('InventorySpot') )
03251					{
03252						i++;
03253						if ( (RoamTarget == None) || (Rand(i) == 0) )
03254							RoamTarget = N;
03255					}
03256			}	
03257	
03258			// roam around
03259			if ( RoamTarget != None )
03260			{
03261				if ( ActorReachable(RoamTarget) )
03262				{
03263					MoveTarget = RoamTarget;
03264					RoamTarget = None;
03265					if ( VSize(MoveTarget.Location - Location) > 2 * CollisionRadius )
03266						return;
03267				}
03268				else
03269				{
03270					BestPath = FindPathToward(RoamTarget);
03271					if ( BestPath != None )
03272					{
03273						MoveTarget = BestPath;
03274						return;
03275					}
03276					else
03277						RoamTarget = None;
03278				}
03279			}
03280													
03281			 // wander or camp
03282			if ( FRand() < 0.35 )
03283				GotoState('Wandering');
03284			else
03285			{
03286				GoalString = " Nothing cool, so camp ";
03287				CampTime = 3.5 + FRand() - skill;
03288				GotoState('Roaming', 'Camp');
03289			}
03290		}
03291	
03292		function AnimEnd() 
03293		{
03294			if ( bCamping )
03295			{
03296				SetPeripheralVision();
03297				if ( FRand() < 0.2 )
03298				{
03299					PeripheralVision -= 0.5;
03300					PlayLookAround();
03301				}
03302				else
03303					PlayWaiting();
03304			}
03305			else
03306				PlayRunning();
03307		}
03308	
03309		function ShareWith(Pawn Other)
03310		{
03311			local bool bHaveItem, bIsHealth, bOtherHas, bIsWeapon;
03312			local Pawn P;
03313	
03314			if ( MoveTarget.IsA('Weapon') )
03315			{
03316				if ( (Weapon == None) || (Weapon.AIRating < 0.5) || Weapon(MoveTarget).bWeaponStay )
03317					return;
03318				bIsWeapon = true;
03319				bHaveItem = (FindInventoryType(MoveTarget.class) != None);
03320			}
03321			else if ( MoveTarget.IsA('Health') )
03322			{
03323				bIsHealth = true;
03324				if ( Health < 80 )
03325					return;
03326			}
03327	
03328			if ( (Other.Health <= 0) || Other.PlayerReplicationInfo.bIsSpectator || (VSize(Other.Location - Location) > 1250)
03329				|| !LineOfSightTo(Other) )
03330				return;
03331	
03332			//decide who needs it more
03333			CampTime = 2.0;
03334			if ( bIsHealth )
03335			{
03336				if ( Health > Other.Health + 10 )
03337				{
03338					GotoState('Roaming', 'GiveWay');
03339					return;
03340				}
03341			}
03342			else if ( bIsWeapon && (Other.Weapon != None) && (Other.Weapon.AIRating < 0.5) )
03343			{
03344				GotoState('Roaming', 'GiveWay');
03345				return;
03346			}
03347			else
03348			{
03349				bOtherHas = (Other.FindInventoryType(MoveTarget.class) != None);
03350				if ( bHaveItem && !bOtherHas )
03351				{
03352					GotoState('Roaming', 'GiveWay');
03353					return;
03354				}
03355			}
03356		}
03357							 
03358		function BeginState()
03359		{
03360			bNoShootDecor = false;
03361			bCanFire = false;
03362			bCamping = false;
03363			if ( bNoClearSpecial )
03364				bNoClearSpecial = false;
03365			else
03366			{
03367				bSpecialPausing = false;
03368				bSpecialGoal = false;
03369				SpecialGoal = None;
03370				SpecialPause = 0.0;
03371			}
03372		}
03373	
03374		function EndState()
03375		{
03376			SetPeripheralVision();
03377			if ( !bSniping && (AmbushSpot != None) )
03378			{
03379				AmbushSpot.taken = false;
03380				AmbushSpot = None;
03381			}
03382			bCamping = false;
03383			bWallAdjust = false;
03384			bCanTranslocate = false;
03385		}
03386	
03387	LongCamp:
03388		bCamping = true;
03389		Acceleration = vect(0,0,0);
03390		TweenToWaiting(0.15);
03391		TurnTo(Location + Ambushspot.lookdir);
03392		Sleep(CampTime);
03393		Goto('PreBegin');
03394	
03395	GiveWay:	
03396		//log("sharing");	
03397		bCamping = true;
03398		Acceleration = vect(0,0,0);
03399		if ( GetAnimGroup(AnimSequence) != 'Waiting' )
03400			TweenToWaiting(0.15);
03401		if ( NearWall(200) )
03402		{
03403			PlayTurning();
03404			TurnTo(MoveTarget.Location);
03405		}
03406		Sleep(CampTime);
03407		Goto('PreBegin');
03408	
03409	Camp:
03410		bCamping = true;
03411		Acceleration = vect(0,0,0);
03412		TweenToWaiting(0.15);
03413	ReCamp:
03414		if ( NearWall(200) )
03415		{
03416			PlayTurning();
03417			TurnTo(Focus);
03418		}
03419		Sleep(CampTime);
03420		if ( bLeading || bCampOnlyOnce )
03421		{
03422			bCampOnlyOnce = false;
03423			Goto('PreBegin');
03424		}
03425		if ( ((Orders != 'Follow') || ((Pawn(OrderObject).Health > 0) && CloseToPointMan(Pawn(OrderObject)))) 
03426			&& (Weapon != None) && (Weapon.AIRating > 0.4) && (3 * FRand() > skill + 1) )
03427			Goto('ReCamp');
03428	PreBegin:
03429		SetPeripheralVision();
03430		WaitForLanding();
03431		bCamping = false;
03432		PickDestination();
03433		TweenToRunning(0.1);
03434		bCanTranslocate = false;
03435		Goto('SpecialNavig');
03436	Begin:
03437		SwitchToBestWeapon();
03438		bCamping = false;
03439		TweenToRunning(0.1);
03440		WaitForLanding();
03441		
03442	RunAway:
03443		PickDestination();
03444		bCanTranslocate = false;
03445	SpecialNavig:
03446		if (SpecialPause > 0.0)
03447		{
03448			Disable('AnimEnd');
03449			Acceleration = vect(0,0,0);
03450			TweenToPatrolStop(0.3);
03451			Sleep(SpecialPause);
03452			SpecialPause = 0.0;
03453			Enable('AnimEnd');
03454			TweenToRunning(0.1);
03455			Goto('RunAway');
03456		}
03457	Moving:
03458		if ( !IsAnimating() )
03459			AnimEnd();
03460		if ( MoveTarget == None )
03461		{
03462			Acceleration = vect(0,0,0);
03463			Sleep(0.0);
03464			Goto('RunAway');
03465		}
03466		if ( MoveTarget.IsA('InventorySpot') )
03467		{
03468			if ( (!Level.Game.IsA('TeamGamePlus') || (TeamGamePlus(Level.Game).PriorityObjective(self) == 0))
03469				&& (InventorySpot(MoveTarget).markedItem != None)
03470				&& (InventorySpot(MoveTarget).markedItem.BotDesireability(self) > 0) )
03471			{
03472				if ( InventorySpot(MoveTarget).markedItem.GetStateName() == 'Pickup' )
03473					MoveTarget = InventorySpot(MoveTarget).markedItem;
03474				else if (	(InventorySpot(MoveTarget).markedItem.LatentFloat < 5.0)
03475							&& (InventorySpot(MoveTarget).markedItem.GetStateName() == 'Sleeping')	
03476							&& (abs(Location.Z - MoveTarget.Location.Z) < CollisionHeight)
03477							&& (VSize(Location - MoveTarget.Location + vect(0,0,1) * (MoveTarget.Location.Z - Location.Z)) < CollisionRadius * CollisionRadius) )
03478				{
03479					CampTime = FMin(5, InventorySpot(MoveTarget).markedItem.LatentFloat + 0.5);
03480					bCampOnlyOnce = true;
03481					Goto('Camp');
03482				}
03483			}
03484			else if ( MoveTarget.IsA('TrapSpringer')
03485					&& (abs(Location.Z - MoveTarget.Location.Z) < CollisionHeight)
03486					&& (VSize(Location - MoveTarget.Location + vect(0,0,1) * (MoveTarget.Location.Z - Location.Z)) < CollisionRadius * CollisionRadius) )
03487			{
03488				PlayVictoryDance();	
03489				bCampOnlyOnce = true;		
03490				bCamping = true;
03491				CampTime = 1.2;
03492				Acceleration = vect(0,0,0);
03493				Goto('ReCamp');
03494			}
03495		}
03496		else if ( MoveTarget.IsA('Inventory') && Level.Game.bTeamGame )
03497		{
03498			if ( Orders == 'Follow' )
03499				ShareWith(Pawn(OrderObject));
03500			else if ( SupportingPlayer != None )
03501				ShareWith(SupportingPlayer);
03502		}
03503	
03504		bCamping = false;
03505		MoveToward(MoveTarget);
03506		Goto('RunAway');
03507	
03508	TakeHit:
03509		TweenToRunning(0.12);
03510		Goto('Moving');
03511	
03512	Landed:
03513		if ( MoveTarget == None ) 
03514			Goto('RunAway');
03515		Goto('Moving');
03516	
03517	AdjustFromWall:
03518		if ( !IsAnimating() )
03519			AnimEnd();
03520		bWallAdjust = true;
03521		bCamping = false;
03522		StrafeTo(Destination, Focus); 
03523		Destination = Focus; 
03524		MoveTo(Destination);
03525		bWallAdjust = false;
03526		Goto('Moving');
03527	
03528	ShootDecoration:
03529		TurnToward(Target);
03530		if ( Target != None )
03531		{
03532			FireWeapon();
03533			bAltFire = 0;
03534			bFire = 0;
03535		}
03536		Goto('RunAway');
03537	}
03538	
03539	state Wandering
03540	{
03541		ignores EnemyNotVisible;
03542	
03543		function bool DeferTo(Bot Other)
03544		{
03545			if ( Acceleration == vect(0,0,0) )
03546				return Global.DeferTo(Other);
03547	
03548			return false;
03549		}
03550	
03551		function SetOrders(name NewOrders, Pawn OrderGiver, optional bool bNoAck)
03552		{
03553			Global.SetOrders(NewOrders, OrderGiver, bNoAck);
03554			if ( (Orders == 'Hold') || (Orders == 'Follow') )
03555				GotoState('Roaming');
03556		}
03557	
03558		singular event BaseChange()
03559		{
03560			if ( (Base != None) && Base.IsA('Mover') )
03561				Destination = Location - 300 * Normal(Velocity);
03562			else
03563				Super.BaseChange();
03564		}
03565	
03566		function ShootTarget(Actor NewTarget)
03567		{
03568			Target = NewTarget;
03569			bFiringPaused = true;
03570			SpecialPause = 2.0;
03571			NextState = GetStateName();
03572			NextLabel = 'Begin';
03573			GotoState('RangedAttack');
03574		}
03575	
03576		function TakeDamage( int Damage, Pawn instigatedBy, Vector hitlocation, 
03577							Vector momentum, name damageType)
03578		{
03579			Global.TakeDamage(Damage, instigatedBy, hitlocation, momentum, damageType);
03580			if ( health <= 0 )
03581				return;
03582			if ( (Enemy != None) && (Enemy == InstigatedBy) )
03583			{
03584				LastSeenPos = Enemy.Location;
03585				LastSeenTime = Level.TimeSeconds;
03586			}
03587	
03588			if ( NextState == 'TakeHit' )
03589				{
03590				NextState = 'Attacking'; 
03591				NextLabel = 'Begin';
03592				GotoState('TakeHit'); 
03593				}
03594			else
03595				GotoState('Attacking');
03596		}
03597	
03598		function Timer()
03599		{
03600			Enable('Bump');
03601		}
03602	
03603		function SetFall()
03604		{
03605			NextState = 'Wandering'; 
03606			NextLabel = 'ContinueWander';
03607			NextAnim = AnimSequence;
03608			GotoState('FallingState'); 
03609		}
03610	
03611		function EnemyAcquired()
03612		{
03613			GotoState('Acquisition');
03614		}
03615	
03616		function HitWall(vector HitNormal, actor Wall)
03617		{
03618			if (Physics == PHYS_Falling)
03619				return;
03620			if ( Wall.IsA('Mover') && Mover(Wall).HandleDoor(self) )
03621			{
03622				if ( SpecialPause > 0 )
03623					Acceleration = vect(0,0,0);
03624				GotoState('Wandering', 'Pausing');
03625				return;
03626			}
03627			Focus = Destination;
03628			if ( PickWallAdjust() && (FRand() < 0.7) )
03629			{
03630				if ( Physics == PHYS_Falling )
03631					SetFall();
03632				else
03633					GotoState('Wandering', 'AdjustFromWall');
03634			}
03635			else
03636				MoveTimer = -1.0;
03637		}
03638		
03639		function bool TestDirection(vector dir, out vector pick)
03640		{	
03641			local vector HitLocation, HitNormal, dist;
03642			local float minDist;
03643			local actor HitActor;
03644	
03645			minDist = FMin(150.0, 4*CollisionRadius);
03646			if ( (Orders == 'Follow') && (VSize(Location - OrderObject.Location) < 500) )
03647				pick = dir * (minDist + (200 + 6 * CollisionRadius) * FRand());
03648			else
03649				pick = dir * (minDist + (450 + 12 * CollisionRadius) * FRand());
03650	
03651			HitActor = Trace(HitLocation, HitNormal, Location + pick + 1.5 * CollisionRadius * dir , Location, false);
03652			if (HitActor != None)
03653			{
03654				pick = HitLocation + (HitNormal - dir) * 2 * CollisionRadius;
03655				if ( !FastTrace(pick, Location) )
03656					return false;
03657			}
03658			else
03659				pick = Location + pick;
03660			 
03661			dist = pick - Location;
03662			if (Physics == PHYS_Walking)
03663				dist.Z = 0;
03664			
03665			return (VSize(dist) > minDist); 
03666		}
03667				
03668		function PickDestination()
03669		{
03670			local vector pick, pickdir;
03671			local bool success, bMustWander;
03672			local float XY;
03673	
03674			//Favor XY alignment
03675			XY = FRand();
03676			if ( WanderDir != vect(0,0,0) )
03677			{
03678				pickdir = WanderDir;
03679				XY = 1;
03680				bMustWander = true;
03681			}
03682			else if (XY < 0.3)
03683			{
03684				pickdir.X = 1;
03685				pickdir.Y = 0;
03686			}
03687			else if (XY < 0.6)
03688			{
03689				pickdir.X = 0;
03690				pickdir.Y = 1;
03691			}
03692			else
03693			{
03694				pickdir.X = 2 * FRand() - 1;
03695				pickdir.Y = 2 * FRand() - 1;
03696			}
03697			if (Physics != PHYS_Walking)
03698			{
03699				pickdir.Z = 2 * FRand() - 1;
03700				pickdir = Normal(pickdir);
03701			}
03702			else
03703			{
03704				pickdir.Z = 0;
03705				if (XY >= 0.6)
03706					pickdir = Normal(pickdir);
03707			}	
03708	
03709			success = TestDirection(pickdir, pick);
03710			if (!success)
03711				success = TestDirection(-1 * pickdir, pick);
03712			
03713			if (success)	
03714				Destination = pick;
03715			else if ( bMustWander )
03716			{
03717				WanderDir = Normal(WanderDir + VRand());
03718				WanderDir.Z = 0;
03719				Destination = Location + 100 * WanderDir;
03720			}
03721			else
03722				GotoState('Wandering', 'Turn');
03723	
03724			WanderDir = vect(0,0,0);
03725		}
03726	
03727		function AnimEnd()
03728		{
03729			PlayPatrolStop();
03730		}
03731	
03732		function FearThisSpot(Actor aSpot)
03733		{
03734			Destination = Location + 120 * Normal(Location - aSpot.Location); 
03735		}
03736	
03737		function BeginState()
03738		{
03739			Enemy = None;
03740			SetAlertness(0.2);
03741			bReadyToAttack = false;
03742			Disable('AnimEnd');
03743			NextAnim = '';
03744			bCanJump = false;
03745			bAvoidLedges = true;
03746			bStopAtLedges = true;
03747			MinHitWall += 0.15;
03748		}
03749		
03750		function EndState()
03751		{
03752			MinHitWall -= 0.15;
03753			bStopAtLedges = false;
03754			bAvoidLedges = false;
03755			if (JumpZ > 0)
03756				bCanJump = true;
03757		}
03758	
03759	
03760	Begin:
03761		//log(class$" Wandering");
03762	
03763	Wander: 
03764		WaitForLanding();
03765		PickDestination();
03766		TweenToWalking(0.15);
03767		FinishAnim();
03768		PlayWalking();
03769		
03770	Moving:
03771		Enable('HitWall');
03772		MoveTo(Destination, WalkingSpeed);
03773	Pausing:
03774		if ( Level.Game.bTeamGame 
03775			&& (bLeading || ((Orders == 'Follow') && !CloseToPointMan(Pawn(OrderObject)))) )
03776			GotoState('Roaming');
03777		Acceleration = vect(0,0,0);
03778		if ( NearWall(200) )
03779		{
03780			PlayTurning();
03781			TurnTo(Focus);
03782		}
03783		Enable('AnimEnd');
03784		NextAnim = '';
03785		TweenToPatrolStop(0.2);
03786		Sleep(1.0);
03787		Disable('AnimEnd');
03788		FinishAnim();
03789		GotoState('Roaming');
03790	
03791	ContinueWander:
03792		FinishAnim();
03793		PlayWalking();
03794		if (FRand() < 0.2)
03795			Goto('Turn');
03796		Goto('Wander');
03797	
03798	Turn:
03799		Acceleration = vect(0,0,0);
03800		PlayTurning();
03801		TurnTo(Location + 20 * VRand());
03802		Goto('Pausing');
03803	
03804	AdjustFromWall:
03805		StrafeTo(Destination, Focus); 
03806		Destination = Focus; 
03807		Goto('Moving');
03808	}
03809		
03810	/* Acquisition - 
03811	Creature has just reacted to stimulus, and set an enemy
03812	- depending on strength of stimulus, and ongoing stimulii, vary time to focus on target and start attacking (or whatever.  FIXME - need some acquisition specific animation
03813	HearNoise and SeePlayer used to improve/change stimulus
03814	*/
03815	
03816	state Acquisition
03817	{
03818	ignores falling, landed; 
03819	
03820		function WarnTarget(Pawn shooter, float projSpeed, vector FireDir)
03821		{
03822		}
03823	
03824		function TakeDamage( int Damage, Pawn instigatedBy, Vector hitlocation, 
03825								Vector momentum, name damageType)
03826		{
03827			LastSeenPos = Enemy.Location;
03828			LastSeenTime = Level.TimeSeconds;
03829			Global.TakeDamage(Damage, instigatedBy, hitlocation, momentum, damageType);
03830			if ( health <= 0 )
03831				return;
03832			if (NextState == 'TakeHit')
03833			{
03834				NextState = 'Attacking'; 
03835				NextLabel = 'Begin';
03836				GotoState('TakeHit'); 
03837			}
03838			else
03839				GotoState('Attacking');
03840		}
03841		
03842		singular function HearNoise(float Loudness, Actor NoiseMaker)
03843		{
03844			local vector OldLastSeenPos;
03845			
03846			if ( SetEnemy(NoiseMaker.instigator) )
03847			{
03848				OldLastSeenPos = LastSeenPos;
03849				if ( Enemy ==  NoiseMaker.instigator  )
03850					LastSeenPos = 0.5 * (NoiseMaker.Location + VSize(NoiseMaker.Location - Location) * vector(Rotation));
03851				else if ( (Pawn(NoiseMaker) != None) && (Enemy == Pawn(NoiseMaker).Enemy) )
03852					LastSeenPos = 0.5 * (Pawn(NoiseMaker).Enemy.Location + VSize(Pawn(NoiseMaker).Enemy.Location - Location) * vector(Rotation));
03853				if ( VSize(OldLastSeenPos - Enemy.Location) < VSize(LastSeenPos - Enemy.Location) )
03854					LastSeenPos = OldLastSeenPos;				
03855			}
03856			
03857		}
03858		
03859		function SeePlayer(Actor SeenPlayer)
03860		{
03861			if ( SetEnemy(Pawn(SeenPlayer)) )
03862			{
03863				MakeNoise(1.0);
03864				NextAnim = '';
03865				GotoState('Attacking');
03866			}
03867		} 
03868		
03869		function BeginState()
03870		{
03871			Disable('Tick'); //only used for bounding anim time
03872			SetAlertness(-0.5);
03873		}
03874	
03875		function EndState()
03876		{
03877			LastAcquireTime = Level.TimeSeconds;
03878		}
03879			
03880	PlayOut:
03881		Acceleration = vect(0,0,0);
03882		if ( (AnimFrame < 0.6) && IsAnimating() )
03883		{
03884			Sleep(0.05);
03885			Goto('PlayOut');
03886		}
03887			
03888	Begin:
03889		Acceleration = vect(0,0,0);
03890		if (NeedToTurn(LastSeenPos))
03891		{	
03892			PlayTurning();
03893			TurnTo(LastSeenPos);
03894		}
03895		DesiredRotation = Rotator(LastSeenPos - Location);
03896		TweenToFighter(0.2); 
03897		FinishAnim();
03898		if ( Enemy == None )
03899			WhatToDoNext('','');	
03900		if ( Enemy.IsA('StationaryPawn') )
03901			GotoState('Attacking');
03902		////log("Stimulus="$Stimulus);
03903		if ( AttitudeTo(Enemy) == ATTITUDE_Fear )  //will run away from noise
03904		{
03905			LastSeenPos = Enemy.Location; 
03906			NextAnim = '';
03907			GotoState('Attacking');
03908		}
03909		else if ( !bNovice )
03910		{
03911			bMustHunt = true;
03912			GotoState('Attacking');
03913		}
03914		else
03915			WhatToDoNext('','');
03916	}
03917	
03918	/* Attacking
03919	Master attacking state - choose which type of attack to do from here
03920	*/
03921	state Attacking
03922	{
03923	ignores SeePlayer, HearNoise, Bump, HitWall;
03924	
03925		function ChooseAttackMode()
03926		{
03927			local eAttitude AttitudeToEnemy;
03928			local float Aggression;
03929			local pawn changeEn;
03930			local TeamGamePlus TG;
03931			local bool bWillHunt;
03932	
03933			bWillHunt = bMustHunt;
03934			bMustHunt = false;
03935			if ((Enemy == None) || (Enemy.Health <= 0))
03936			{
03937				WhatToDoNext('','');
03938				return;
03939			}
03940			if ( Weapon == None )
03941			{
03942				log(self$" health "$health$" had no weapon");
03943				SwitchToBestWeapon();
03944			}
03945			AttitudeToEnemy = AttitudeTo(Enemy);
03946			TG = TeamGamePlus(Level.Game);
03947			if ( TG != None )
03948			{
03949				if ( (Level.TimeSeconds - LastAttractCheck > 0.5)
03950					|| (AttitudeToEnemy == ATTITUDE_Fear)
03951					|| (TG.PriorityObjective(self) > 1) ) 
03952				{
03953					goalstring = "attract check";
03954					if ( TG.FindSpecialAttractionFor(self) )
03955						return;
03956					if ( Enemy == None )
03957					{
03958						WhatToDoNext('','');
03959						return;
03960					}
03961				}
03962				else
03963				{
03964					goalstring = "no attract check";
03965				}
03966			}
03967				
03968			if (AttitudeToEnemy == ATTITUDE_Fear)
03969			{
03970				GotoState('Retreating');
03971				return;
03972			}
03973			else if (AttitudeToEnemy == ATTITUDE_Friendly)
03974			{
03975				WhatToDoNext('','');
03976				return;
03977			}
03978			else if ( !LineOfSightTo(Enemy) )
03979			{
03980				if ( (OldEnemy != None) 
03981					&& (AttitudeTo(OldEnemy) == ATTITUDE_Hate) && LineOfSightTo(OldEnemy) )
03982				{
03983					changeEn = enemy;
03984					enemy = oldenemy;
03985					oldenemy = changeEn;
03986				}	
03987				else 
03988				{
03989					goalstring = "attract check";
03990					if ( (TG != None) && TG.FindSpecialAttractionFor(self) )
03991						return;
03992					if ( Enemy == None )
03993					{
03994						WhatToDoNext('','');
03995						return;
03996					}
03997					if ( (Orders == 'Hold') && (Level.TimeSeconds - LastSeenTime > 5) )
03998					{
03999						NumHuntPaths = 0; 
04000						GotoState('StakeOut');
04001					}
04002					else if ( bWillHunt || (!bSniping && (VSize(Enemy.Location - Location) 
04003								> 600 + (FRand() * RelativeStrength(Enemy) - CombatStyle) * 600)) )
04004					{
04005						bDevious = ( !bNovice && !Level.Game.bTeamGame && Level.Game.IsA('DeathMatchPlus') 
04006									&& (FRand() < 0.52 - 0.12 * DeathMatchPlus(Level.Game).NumBots) );
04007						GotoState('Hunting');
04008					}
04009					else
04010					{
04011						NumHuntPaths = 0; 
04012						GotoState('StakeOut');
04013					}
04014					return;
04015				}
04016			}	
04017			
04018			if (bReadyToAttack)
04019			{
04020				////log("Attack!");
04021				Target = Enemy;
04022				SetTimer(TimeBetweenAttacks, False);
04023			}
04024				
04025			GotoState('TacticalMove');
04026		}
04027		
04028		//EnemyNotVisible implemented so engine will update LastSeenPos
04029		function EnemyNotVisible()
04030		{
04031			////log("enemy not visible");
04032		}
04033	
04034		function Timer()
04035		{
04036			bReadyToAttack = True;
04037		}
04038	
04039		function BeginState()
04040		{
04041			if ( TimerRate <= 0.0 )
04042				SetTimer(TimeBetweenAttacks  * (1.0 + FRand()),false); 
04043			if (Physics == PHYS_None)
04044				SetMovementPhysics(); 
04045		}
04046	
04047	Begin:
04048		//log(class$" choose Attack");
04049		ChooseAttackMode();
04050	}
04051	
04052	
04053	/* Retreating for a bot is going toward an item while still engaged with an enemy, but fearing that enemy (so
04054	no desire to remain engaged)
04055	   TacticalGet is for going to an item while engaged, and remaining engaged. TBD
04056	   Roaming is going to items w/ no enemy. TBD
04057	*/
04058	
04059	state Retreating
04060	{
04061	ignores EnemyNotVisible;
04062	
04063		function MayFall()
04064		{
04065			bAdvancedTactics = false;
04066			if ( bCanFire ) // MoveTarget is player, not destination
04067				bCanJump = ( (MoveTarget != None) 
04068							&& ((MoveTarget.Physics != PHYS_Falling) || !MoveTarget.IsA('Inventory')) );
04069		}
04070	
04071		function WarnTarget(Pawn shooter, float projSpeed, vector FireDir)
04072		{	
04073			if ( bCanFire && (FRand() < 0.4) ) 
04074				return;
04075	
04076			Super.WarnTarget(shooter, projSpeed, FireDir);
04077		}
04078	
04079		function SeePlayer(Actor SeenPlayer)
04080		{
04081			if ( (SeenPlayer == Enemy) || LineOfSightTo(Enemy) )
04082			{
04083				LastSeenTime = Level.TimeSeconds;
04084				return;
04085			}
04086			if ( SetEnemy(Pawn(SeenPlayer)) )
04087			{
04088				MakeNoise(1.0);
04089				GotoState('Attacking');
04090			}
04091		}
04092	
04093		singular function HearNoise(float Loudness, Actor NoiseMaker)
04094		{
04095			if ( (NoiseMaker.instigator == Enemy) || LineOfSightTo(Enemy) )
04096				return;
04097	
04098			if ( SetEnemy(NoiseMaker.instigator) )
04099			{
04100				MakeNoise(1.0);
04101				GotoState('Attacking');
04102			}
04103		}
04104		
04105		function TakeDamage( int Damage, Pawn instigatedBy, Vector hitlocation, 
04106								Vector momentum, name damageType)
04107		{
04108			Global.TakeDamage(Damage, instigatedBy, hitlocation, momentum, damageType);
04109			if ( health <= 0 )
04110				return;
04111			if (NextState == 'TakeHit')
04112			{
04113				NextState = 'Retreating'; 
04114				NextLabel = 'TakeHit';
04115				GotoState('TakeHit'); 
04116			}
04117			else if ( !bCanFire && (skill > 3 * FRand()) )
04118				GotoState('Retreating', 'Moving');
04119		}
04120	
04121		function Timer()
04122		{
04123			bReadyToAttack = True;
04124			Enable('Bump');
04125		}
04126		
04127		function SetFall()
04128		{
04129			NextState = 'Retreating'; 
04130			NextLabel = 'Landed';
04131			NextAnim = AnimSequence;
04132			GotoState('FallingState'); 
04133		}
04134	
04135		function HitWall(vector HitNormal, actor Wall)
04136		{
04137			if (Physics == PHYS_Falling)
04138				return;
04139			if ( Wall.IsA('Mover') && Mover(Wall).HandleDoor(self) )
04140			{
04141				if ( SpecialPause > 0 )
04142					Acceleration = vect(0,0,0);
04143				GotoState('Retreating', 'SpecialNavig');
04144				return;
04145			}
04146			bTacticalDir = !bTacticalDir;
04147			Focus = Destination;
04148			if ( PickWallAdjust() && (FRand() < 0.7) )
04149			{
04150				bAdvancedTactics = false;
04151				if ( Physics == PHYS_Falling )
04152					SetFall();
04153				else
04154					GotoState('Retreating', 'AdjustFromWall');
04155			}
04156			else
04157				MoveTimer = -1.0;
04158		}
04159	
04160		function PickDestination()
04161		{
04162		 	local inventory Inv, BestInv, SecondInv;
04163			local float Bestweight, NewWeight, invDist, MaxDist, SecondWeight;
04164			local actor BestPath;
04165			local bool bTriedFar;
04166	
04167			if ( !bReadyToAttack && (TimerRate == 0.0) )
04168				SetTimer(0.7, false);
04169	
04170			// do I still fear my enemy?
04171			if ( (Level.TimeSeconds - LastSeenTime > 12)
04172				|| (Level.Game.bTeamGame && (Level.TimeSeconds - LastSeenTime > 8)) )
04173				Enemy = None;
04174			if ( (Enemy == None) || (AttitudeTo(Enemy) > ATTITUDE_Fear) )
04175			{
04176				GotoState('Attacking');
04177				return;
04178			}
04179	
04180			bestweight = 0;
04181	
04182			//first look at nearby inventory < 500 dist
04183			MaxDist = 500 + 70 * skill;
04184			foreach visiblecollidingactors(class'Inventory', Inv, MaxDist,,true)
04185				if ( (Inv.IsInState('PickUp')) && (Inv.MaxDesireability/200 > BestWeight)
04186					&& (Inv.Location.Z < Location.Z + MaxStepHeight + CollisionHeight)
04187					&& (Inv.Location.Z > FMin(Location.Z, Enemy.Location.Z) - CollisionHeight) )
04188				{
04189					NewWeight = inv.BotDesireability(self)/VSize(Inv.Location - Location);
04190					if ( NewWeight > BestWeight )
04191					{
04192						SecondWeight = BestWeight;
04193						BestWeight = NewWeight;
04194						SecondInv = BestInv;
04195						BestInv = Inv;
04196					}
04197				}
04198				 
04199			 // see if better long distance inventory 
04200			if ( BestWeight < 0.001 )
04201			{ 
04202				bTriedFar = true;
04203				BestPath = FindBestInventoryPath(BestWeight, false);
04204				if ( Level.Game.bTeamGame && (BestWeight < 0.0002) )
04205				{
04206					if ( !Enemy.IsA('TeamCannon') && (Enemy.Location.Z < Location.Z + 500) )
04207					{
04208						bKamikaze = true;
04209						if ( LineOfSightTo(Enemy) )
04210						{
04211							LastInvFind = Level.TimeSeconds;
04212							GotoState('TacticalMove', 'NoCharge');
04213							return;
04214						}
04215					}
04216					else if ( Level.Game.IsA('TeamGamePlus') && TeamGamePlus(Level.Game).SendBotToGoal(self) )
04217						return;
04218				}
04219				if ( BestPath != None )
04220				{
04221					//GoalString = string(1000 * BestWeight);
04222					MoveTarget = BestPath;
04223					return;
04224				}
04225			}
04226	
04227			if ( (BestInv != None) && ActorReachable(BestInv) )
04228			{
04229				MoveTarget = BestInv;
04230				return;
04231			}
04232	
04233			if ( (SecondInv != None) && ActorReachable(SecondInv) )
04234			{
04235				MoveTarget = SecondInv;
04236				return;
04237			}
04238			if ( !bTriedFar )
04239			{ 
04240				BestWeight = 0;
04241				BestPath = FindBestInventoryPath(BestWeight, false);
04242				if ( BestPath != None )
04243				{
04244					MoveTarget = BestPath;
04245					return;
04246				}
04247			}
04248			if ( bVerbose )
04249				log(self$" give up retreat");
04250	
04251			// if nothing, then tactical move
04252			if ( LineOfSightTo(Enemy) )
04253			{
04254				LastInvFind = Level.TimeSeconds;
04255				bKamikaze = true;
04256				GotoState('TacticalMove', 'NoCharge');
04257				return;
04258			}
04259			WhatToDoNext('','');
04260		}
04261	
04262	
04263		function ChangeDestination()
04264		{
04265			local actor oldTarget;
04266			local Actor path;
04267			
04268			oldTarget = Home;
04269			PickDestination();
04270			if (Home == oldTarget)
04271			{
04272				bKamikaze = true;
04273				//log("same old target");
04274				GotoState('TacticalMove', 'TacticalTick');
04275			}
04276			else
04277			{
04278				path = FindPathToward(Home);
04279				if (path == None)
04280				{
04281					//log("no new target");
04282					bKamikaze = true;
04283					GotoState('TacticalMove', 'TacticalTick');
04284				}
04285				else 
04286				{
04287					MoveTarget = path;
04288					Destination = path.Location;
04289				}
04290			}
04291		}
04292		
04293		function bool CheckBumpAttack(Pawn Other)
04294		{
04295			if ( (Other == Enemy) && (((Other.Location - Location) Dot Velocity) > 0) )
04296				bKamikaze = true;
04297			
04298			if ( SetEnemy(Other) && (Enemy == Other) && (Weapon != None) && !Weapon.bMeleeWeapon )
04299			{
04300				bReadyToAttack = true;
04301				GotoState('RangedAttack');
04302				return true;
04303			}
04304			return false;
04305		}
04306		
04307		function ReachedHome()
04308		{
04309			if (LineOfSightTo(Enemy))
04310			{
04311				if (Homebase(home) != None)
04312				{
04313					//log(class$" reached home base - turn and fight");
04314					bKamikaze = true;
04315					MakeNoise(1.0);
04316					GotoState('Attacking');
04317				}
04318				else
04319					ChangeDestination();
04320			}
04321			else
04322			{
04323				if (Homebase(home) != None)
04324					MakeNoise(1.0);
04325				bKamikaze = true;
04326				GotoState('Attacking');
04327			}
04328		}
04329	
04330		function PickNextSpot()
04331		{
04332			local Actor path;
04333			local vector dist2d;
04334			local float zdiff;
04335	
04336			if ( Home == None )
04337			{
04338				PickDestination();
04339				if ( Home == None )
04340					return;
04341			}
04342			//log("find retreat spot");
04343			dist2d = Home.Location - Location;
04344			zdiff = dist2d.Z;
04345			dist2d.Z = 0.0;	
04346			if ((VSize(dist2d) < 2 * CollisionRadius) && (Abs(zdiff) < CollisionHeight))
04347				ReachedHome();
04348			else
04349			{
04350				if (ActorReachable(Home))
04351				{
04352					//log("almost there");
04353					path = Home;
04354					if (HomeBase(Home) == None)
04355						Home = None;
04356				}
04357				else
04358				{
04359					if (SpecialGoal != None)
04360						path = FindPathToward(SpecialGoal);
04361					else
04362						path = FindPathToward(Home);
04363				}
04364					
04365				if (path == None)
04366					ChangeDestination();
04367				else
04368				{
04369					MoveTarget = path;
04370					Destination = path.Location;
04371				}
04372			}
04373		}
04374	
04375		function AnimEnd() 
04376		{
04377			if ( bCanFire && LineOfSightTo(Enemy) )
04378				PlayCombatMove();
04379			else if ( (Physics == PHYS_Falling) && (Velocity.Z < -300) )
04380				FastInAir();
04381			else
04382				PlayRunning();
04383		}
04384	
04385		function BeginState()
04386		{
04387			if ( Level.Game.bTeamGame && !Enemy.IsA('StationaryPawn') )
04388				CallForHelp();
04389			bSpecialPausing = false;
04390			bCanFire = false;
04391			SpecialGoal = None;
04392			SpecialPause = 0.0;
04393		}
04394	
04395		function EndState()
04396		{
04397			bAdvancedTactics = false;
04398		}
04399	
04400	Begin:
04401		if ( bReadyToAttack && (FRand() < 0.4 - 0.1 * Skill) )
04402			bReadyToAttack = false;
04403		if ( (TimerRate == 0.0) || !bReadyToAttack )
04404			SetTimer(TimeBetweenAttacks, false);
04405	
04406		TweenToRunning(0.1);
04407		WaitForLanding();
04408		
04409	RunAway:
04410		PickDestination();
04411		bAdvancedTactics = ( !bNovice && (Level.TimeSeconds - LastSeenTime < 1.0) 
04412							&& (Skill > 2.5 * FRand() - 1)
04413							&& (!MoveTarget.IsA('NavigationPoint') || !NavigationPoint(MoveTarget).bNeverUseStrafing) );
04414	SpecialNavig:
04415		if (SpecialPause > 0.0)
04416		{
04417			if ( LineOfSightTo(Enemy) )
04418			{
04419				if ( ((Base == None) || (Base == Level))
04420					&& (FRand() < 0.6) )
04421					GotoState('TacticalMove', 'NoCharge');
04422				Target = Enemy;
04423				bFiringPaused = true;
04424				NextState = 'Retreating';
04425				NextLabel = 'RunAway';
04426				GotoState('RangedAttack');
04427			}
04428			Disable('AnimEnd');
04429			Acceleration = vect(0,0,0);
04430			TweenToPatrolStop(0.3);
04431			Sleep(SpecialPause);
04432			SpecialPause = 0.0;
04433			Enable('AnimEnd');
04434			TweenToRunning(0.1);
04435			Goto('RunAway');
04436		}
04437	Moving:
04438		if ( !IsAnimating() )
04439			AnimEnd();
04440		if ( MoveTarget == None )
04441		{
04442			Sleep(0.0);
04443			Goto('RunAway');
04444		}
04445		if ( MoveTarget.IsA('InventorySpot') && (InventorySpot(MoveTarget).markedItem != None) 
04446			&& (InventorySpot(MoveTarget).markedItem.GetStateName() == 'Pickup')
04447			&& (InventorySpot(MoveTarget).markedItem.BotDesireability(self) > 0) )
04448				MoveTarget = InventorySpot(MoveTarget).markedItem;
04449		if ( FaceDestination(2) )
04450		{
04451			HaltFiring();
04452			MoveToward(MoveTarget);
04453		}
04454		else
04455		{
04456			bCanFire = true;
04457			StrafeFacing(MoveTarget.Location, Enemy);
04458		}
04459		Goto('RunAway');
04460	
04461	Landed:
04462		if ( MoveTarget == None )
04463			Goto('RunAway');
04464		Goto('Moving');
04465	
04466	TakeHit:
04467		TweenToRunning(0.12);
04468		Goto('Moving');
04469	
04470	AdjustFromWall:
04471		if ( !IsAnimating() )
04472			AnimEnd();
04473		StrafeTo(Destination, Focus); 
04474		Destination = Focus; 
04475		MoveTo(Destination);
04476		Goto('Moving');
04477	}
04478	
04479	state Fallback
04480	{
04481	ignores EnemyNotVisible;
04482	
04483		function MayFall()
04484		{
04485			bAdvancedTactics = false;
04486			bCanJump = ( (MoveTarget != None) 
04487						&& ((MoveTarget.Physics != PHYS_Falling) || !MoveTarget.IsA('Inventory')) );
04488		}
04489	
04490		function EnemyNotVisible()
04491		{
04492			local Pawn P;
04493	
04494			if ( (OldEnemy != None) && LineOfSightTo(OldEnemy) )
04495			{
04496				P = OldEnemy;
04497				OldEnemy = Enemy;
04498				Enemy = P;
04499			}
04500			if ( Enemy.IsA('TeamCannon') )
04501			{
04502				Enemy = OldEnemy;
04503				OldEnemy = None;
04504				if ( Enemy == None )
04505					GotoState('Roaming');
04506			}
04507		}
04508	
04509		function SeePlayer(Actor SeenPlayer)
04510		{
04511			if ( SeenPlayer == Enemy )
04512			{
04513				LastSeenTime = Level.TimeSeconds;
04514				return;
04515			}
04516			if ( SetEnemy(Pawn(SeenPlayer)) )
04517				MakeNoise(1.0);
04518		}
04519	
04520		singular function HearNoise(float Loudness, Actor NoiseMaker)
04521		{
04522			if ( (NoiseMaker.instigator == Enemy) || LineOfSightTo(Enemy) )
04523				return;
04524	
04525			if ( SetEnemy(NoiseMaker.instigator) )
04526			{
04527				LastSeenPos = 0.5 * (NoiseMaker.Location + VSize(NoiseMaker.Location - Location) * vector(Rotation));
04528				MakeNoise(1.0);
04529			}
04530		}
04531		
04532		function TakeDamage( int Damage, Pawn instigatedBy, Vector hitlocation, 
04533								Vector momentum, name damageType)
04534		{
04535			Global.TakeDamage(Damage, instigatedBy, hitlocation, momentum, damageType);
04536			if ( health <= 0 )
04537				return;
04538			if (NextState == 'TakeHit')
04539			{
04540				NextState = 'Fallback'; 
04541				NextLabel = 'TakeHit';
04542				GotoState('TakeHit'); 
04543			}
04544			else if ( !bCanFire && (skill > 3 * FRand()) )
04545				GotoState('Fallback', 'Moving');
04546		}
04547	
04548		function Timer()
04549		{
04550			bReadyToAttack = True;
04551			Enable('Bump');
04552		}
04553		
04554		function SetFall()
04555		{
04556			NextState = 'Fallback'; 
04557			NextLabel = 'Landed';
04558			NextAnim = AnimSequence;
04559			GotoState('FallingState'); 
04560		}
04561	
04562		function HitWall(vector HitNormal, actor Wall)
04563		{
04564			if (Physics == PHYS_Falling)
04565				return;
04566			if ( Wall.IsA('Mover') && Mover(Wall).HandleDoor(self) )
04567			{
04568				if ( SpecialPause > 0 )
04569					Acceleration = vect(0,0,0);
04570				GotoState('Fallback', 'SpecialNavig');
04571				return;
04572			}
04573			Focus = Destination;
04574			if (PickWallAdjust())
04575			{
04576				bAdvancedTactics = false;
04577				if ( Physics == PHYS_Falling )
04578					SetFall();
04579				else
04580					GotoState('Fallback', 'AdjustFromWall');
04581			}
04582			else
04583				MoveTimer = -1.0;
04584		}
04585	
04586		function PickDestination()
04587		{
04588			local byte TeamPriority;
04589	
04590			if ( Level.TimeSeconds - LastSeenTime > 9 )
04591				Enemy = None;
04592			if ( Enemy == None )
04593			{
04594				WhatToDoNext('','');
04595				return;
04596			}
04597			bCanTranslocate = ( Level.Game.IsA('DeathMatchPlus') && DeathMatchPlus(Level.Game).CanTranslocate(self) );
04598			LastAttractCheck = Level.TimeSeconds - 0.1;
04599	
04600			if ( Level.Game.IsA('TeamGamePlus')
04601				&& TeamGamePlus(Level.Game).FindSpecialAttractionFor(self) )
04602			{
04603				if ( IsInState('Fallback') )
04604				{
04605					TeamPriority = TeamGamePlus(Level.Game).PriorityObjective(self);
04606					if ( TeamPriority > 16 )
04607					{
04608						PickLocalInventory(160, 1.8);
04609						return;
04610					}
04611					else if ( TeamPriority > 1 )
04612					{
04613						PickLocalInventory(200, 1);
04614						return;
04615					}
04616					else if ( TeamPriority > 0 )
04617					{
04618						PickLocalInventory(200, 0.55);
04619						return;
04620					}
04621					PickLocalInventory(400, 0.5);
04622					if ( MoveTarget == None )
04623					{
04624						if ( bVerbose )
04625							log(self$" no destination in fallback!");
04626						Orders = 'Freelance';
04627						GotoState('Attacking');
04628					}
04629				}
04630				return;
04631			}
04632			else if ( (Orders == 'Attack') || (OrderObject == None) )
04633			{
04634				if ( bVerbose )
04635					log(self$" attack fallback turned to freelance");
04636				Orders = 'Freelance';
04637				GotoState('Attacking');
04638			}
04639			else if ( (VSize(Location - OrderObject.Location) < 20)
04640				|| ((VSize(Location - OrderObject.Location) < 600) && LineOfSightTo(OrderObject)) )
04641			{
04642				if ( Enemy.IsA('TeamCannon') || ((Level.TimeSeconds - LastSeenTime > 5) && (Orders == 'Hold')) )
04643				{
04644					Enemy = OldEnemy;
04645					OldEnemy = None;
04646				}
04647				GotoState('Attacking');
04648			}
04649			else if ( ActorReachable(OrderObject) )
04650				MoveTarget = OrderObject;
04651			else
04652			{
04653				MoveTarget = FindPathToward(OrderObject);
04654				if ( MoveTarget == None )
04655				{
04656					if ( bVerbose )
04657						log(self@"fallback turned to freelance (no path to"@OrderObject@")");
04658					Orders = 'Freelance';
04659					GotoState('Attacking');
04660				}
04661			}
04662		}
04663	
04664		function bool CheckBumpAttack(Pawn Other)
04665		{
04666			SetEnemy(Other);
04667			if ( Enemy == Other )
04668			{
04669				bReadyToAttack = true;
04670				bCanFire = true;
04671			}
04672			return false;
04673		}
04674	
04675		function AnimEnd() 
04676		{
04677			if ( bCanFire && LineOfSightTo(Enemy) )
04678				PlayCombatMove();
04679			else
04680			{
04681				bFire = 0;
04682				bAltFire = 0;
04683				if ( (Physics == PHYS_Falling) && (Velocity.Z < -300) )
04684					FastInAir();
04685				else
04686					PlayRunning();
04687			}
04688		}
04689	
04690		function BeginState()
04691		{
04692			//log(self$" fallback");
04693			bCanFire = false;
04694			if ( bNoClearSpecial )
04695				bNoClearSpecial = false;
04696			else
04697			{
04698				bSpecialPausing = false;
04699				SpecialGoal = None;
04700				SpecialPause = 0.0;
04701			}
04702		}
04703	
04704		function EndState()
04705		{
04706			bAdvancedTactics = false;
04707			bCanTranslocate = false;
04708		}
04709	
04710	Begin:
04711		TweenToRunning(0.12);
04712		WaitForLanding();
04713		
04714	RunAway:
04715		PickDestination();
04716		bAdvancedTactics = ( !bNovice && (Level.TimeSeconds - LastSeenTime < 1.0) 
04717							&& (Skill > 2.5 * FRand() - 1)
04718							&& (!MoveTarget.IsA('NavigationPoint') || !NavigationPoint(MoveTarget).bNeverUseStrafing) );
04719	SpecialNavig:
04720		if (SpecialPause > 0.0)
04721		{
04722			if ( LineOfSightTo(Enemy) )
04723			{
04724				Target = Enemy;
04725				bFiringPaused = true;
04726				NextState = 'Fallback';
04727				NextLabel = 'RunAway';
04728				GotoState('RangedAttack');
04729			}
04730			Disable('AnimEnd');
04731			Acceleration = vect(0,0,0);
04732			TweenToPatrolStop(0.3);
04733			Sleep(SpecialPause);
04734			SpecialPause = 0.0;
04735			Enable('AnimEnd');
04736			TweenToRunning(0.1);
04737			Goto('RunAway');
04738		}
04739	Moving:
04740		if ( !IsAnimating() )
04741			AnimEnd();
04742	
04743		if ( MoveTarget == None )
04744		{
04745			Sleep(0.0);
04746			Goto('RunAway');
04747		}
04748		if ( FaceDestination(1) )
04749		{
04750			HaltFiring();
04751			MoveToward(MoveTarget);
04752		}
04753		else
04754		{
04755			bReadyToAttack = True;
04756			bCanFire = true;
04757			StrafeFacing(MoveTarget.Location, Enemy);
04758		}
04759		Goto('RunAway');
04760	
04761	Landed:
04762		if ( MoveTarget == None )
04763			Goto('RunAway');
04764		Goto('Moving');
04765	
04766	TakeHit:
04767		TweenToRunning(0.12);
04768		Goto('Moving');
04769	
04770	AdjustFromWall:
04771		if ( !IsAnimating() )
04772			AnimEnd();
04773		StrafeTo(Destination, Focus); 
04774		Destination = Focus; 
04775		MoveTo(Destination);
04776		Goto('Moving');
04777	}
04778	
04779	state Charging
04780	{
04781	ignores SeePlayer, HearNoise;
04782	
04783		/* MayFall() called by engine physics if walking and bCanJump, and
04784			is about to go off a ledge.  Pawn has opportunity (by setting 
04785			bCanJump to false) to avoid fall
04786		*/
04787	
04788		function MayFall()
04789		{
04790			bAdvancedTactics = false;
04791			if ( MoveTarget != Enemy )
04792				return;
04793	
04794			bCanJump = ActorReachable(Enemy);
04795			if ( !bCanJump )
04796					GotoState('TacticalMove', 'NoCharge');
04797		}
04798	
04799		function HitWall(vector HitNormal, actor Wall)
04800		{
04801			if (Physics == PHYS_Falling)
04802				return;
04803			if ( Wall.IsA('Mover') && Mover(Wall).HandleDoor(self) )
04804			{
04805				if ( SpecialPause > 0 )
04806					Acceleration = vect(0,0,0);
04807				GotoState('Charging', 'SpecialNavig');
04808				return;
04809			}
04810			Focus = Destination;
04811			if (PickWallAdjust())
04812			{
04813				bAdvancedTactics = false;
04814				if ( Physics == PHYS_Falling )
04815					SetFall();
04816				else
04817					GotoState('Charging', 'AdjustFromWall');
04818			}
04819			else
04820				MoveTimer = -1.0;
04821		}
04822		
04823		function SetFall()
04824		{
04825			NextState = 'Charging'; 
04826			NextLabel = 'ResumeCharge';
04827			NextAnim = AnimSequence;
04828			GotoState('FallingState'); 
04829		}
04830	
04831		function FearThisSpot(Actor aSpot)
04832		{
04833			Destination = Location + 120 * Normal(Normal(Destination - Location) + Normal(Location - aSpot.Location)); 
04834			GotoState('TacticalMove', 'DoStrafeMove');
04835		}
04836	
04837		function TryToDuck(vector duckDir, bool bReversed)
04838		{
04839			if ( FRand() < 0.6 )
04840			{
04841				Global.TryToDuck(duckDir, bReversed);
04842				return;
04843			}
04844			if ( MoveTarget == Enemy ) 
04845				TryStrafe(duckDir);
04846		}
04847	
04848		function bool StrafeFromDamage(vector momentum, float Damage, name DamageType, bool bFindDest)
04849		{
04850			local vector sideDir;
04851			local float healthpct;
04852	
04853			if ( (damageType == 'shot') || (damageType == 'jolted') || (damageType == 'Zapped') )
04854				healthpct = 0.17;
04855			else
04856				healthpct = 0.25;
04857	
04858			healthpct *= CombatStyle;
04859			if ( FRand() * Damage < healthpct * Health ) 
04860				return false;
04861	
04862			if ( !bFindDest )
04863				return true;
04864	
04865			sideDir = Normal( Normal(Enemy.Location - Location) Cross vect(0,0,1) );
04866			if ( (momentum Dot sidedir) > 0 )
04867				sidedir *= -1;
04868	
04869			return TryStrafe(sideDir);
04870		}
04871	
04872		function bool TryStrafe(vector sideDir)
04873		{ 
04874			local vector extent, HitLocation, HitNormal;
04875			local actor HitActor;
04876	
04877			Extent.X = CollisionRadius;
04878			Extent.Y = CollisionRadius;
04879			Extent.Z = CollisionHeight;
04880			HitActor = Trace(HitLocation, HitNormal, Location + 100 * sideDir, Location, false, Extent);
04881			if (HitActor != None)
04882			{
04883				sideDir *= -1;
04884				HitActor = Trace(HitLocation, HitNormal, Location + 100 * sideDir, Location, false, Extent);
04885			}
04886			if (HitActor != None)
04887				return false;
04888			
04889			if ( Physics == PHYS_Walking )
04890			{
04891				HitActor = Trace(HitLocation, HitNormal, Location + 100 * sideDir - MaxStepHeight * vect(0,0,1), Location + 100 * sideDir, false, Extent);
04892				if ( HitActor == None )
04893					return false;
04894			}
04895			Destination = Location + 250 * sideDir;
04896			GotoState('TacticalMove', 'DoStrafeMove');
04897			return true;
04898		}
04899				
04900		function TakeDamage( int Damage, Pawn instigatedBy, Vector hitlocation, 
04901								Vector momentum, name damageType)
04902		{
04903			local float pick;
04904			local vector sideDir, extent;
04905			local bool bWasOnGround;
04906	
04907			bWasOnGround = (Physics == PHYS_Walking);
04908			Global.TakeDamage(Damage, instigatedBy, hitlocation, momentum, damageType);
04909			if ( health <= 0 )
04910				return;
04911			if (NextState == 'TakeHit')
04912			{
04913				if ( AttitudeTo(Enemy) == ATTITUDE_Fear )
04914				{
04915					NextState = 'Retreating';
04916					NextLabel = 'Begin';
04917				}
04918				else if ( StrafeFromDamage(momentum, Damage, damageType, false) )
04919				{
04920					NextState = 'TacticalMove';
04921					NextLabel = 'NoCharge';
04922				}
04923				else
04924				{
04925					NextState = 'Charging';
04926					NextLabel = 'TakeHit';
04927				}
04928				GotoState('TakeHit'); 
04929			}
04930			else if ( StrafeFromDamage(momentum, Damage, damageType, true) )
04931				return;
04932			else if ( bWasOnGround && (MoveTarget == Enemy) && 
04933						(Physics == PHYS_Falling) ) //weave
04934			{
04935				pick = 1.0;
04936				if ( bStrafeDir )
04937					pick = -1.0;
04938				sideDir = Normal( Normal(Enemy.Location - Location) Cross vect(0,0,1) );
04939				sideDir.Z = 0;
04940				Velocity += pick * GroundSpeed * 0.7 * sideDir;   
04941				if ( FRand() < 0.2 )
04942					bStrafeDir = !bStrafeDir;
04943			}
04944		}
04945								
04946		function AnimEnd() 
04947		{
04948			PlayCombatMove();
04949		}
04950		
04951		function Timer()
04952		{
04953			bReadyToAttack = True;
04954			Target = Enemy;	
04955			if ( Enemy == None )
04956			{
04957				GotoState('Attacking');
04958				return;
04959			}
04960			if ( (VSize(Enemy.Location - Location) 
04961					<= (MeleeRange + Enemy.CollisionRadius + CollisionRadius))
04962				|| ((Weapon != None) && !Weapon.bMeleeWeapon && (FRand() > 0.7 + 0.1 * skill)) ) 
04963				GotoState('RangedAttack');
04964		}
04965		
04966		function EnemyNotVisible()
04967		{
04968			GotoState('Hunting'); 
04969		}
04970	
04971		function BeginState()
04972		{
04973			bCanFire = false;
04974			SpecialGoal = None;
04975			SpecialPause = 0.0;
04976		}
04977	
04978		function EndState()
04979		{
04980			bAdvancedTactics = false;
04981			if ( JumpZ > 0 )
04982				bCanJump = true;
04983		}
04984	
04985	AdjustFromWall:
04986		StrafeTo(Destination, Focus); 
04987		Goto('CloseIn');
04988	
04989	ResumeCharge:
04990		PlayRunning();
04991		Goto('Charge');
04992	
04993	Begin:
04994		TweenToRunning(0.1);
04995	
04996	Charge:
04997		bFromWall = false;
04998		
04999	CloseIn:
05000		if ( (Enemy == None) || (Enemy.Health <=0) )
05001			GotoState('Attacking');
05002	
05003		if ( Enemy.Region.Zone.bWaterZone )
05004		{
05005			if (!bCanSwim)
05006				GotoState('TacticalMove', 'NoCharge');
05007		}
05008		else if (!bCanFly && !bCanWalk)
05009			GotoState('TacticalMove', 'NoCharge');
05010	
05011		if (Physics == PHYS_Falling)
05012		{
05013			DesiredRotation = Rotator(Enemy.Location - Location);
05014			Focus = Enemy.Location;
05015			Destination = Enemy.Location;
05016			WaitForLanding();
05017		}
05018		if( actorReachable(Enemy) )
05019		{
05020			bCanFire = true;
05021			bAdvancedTactics = ( !bNovice && !Level.Game.bTeamGame && (Weapon != None) && !Weapon.bMeleeWeapon && (FRand() < 0.75) );
05022			MoveToward(Enemy);
05023			if (bFromWall)
05024			{
05025				bFromWall = false;
05026				if (PickWallAdjust())
05027				{
05028					if ( Physics == PHYS_Falling )
05029						SetFall();
05030					else
05031						StrafeFacing(Destination, Enemy);
05032				}
05033				else
05034					GotoState('TacticalMove', 'NoCharge');
05035			}
05036		}
05037		else
05038		{
05039	NoReach:
05040			bCanFire = false;
05041			bFromWall = false;
05042			//log("route to enemy"@Enemy);
05043			if ( !FindBestPathToward(Enemy, true) )
05044			{
05045				Sleep(0.0);
05046				GotoState('TacticalMove', 'NoCharge');
05047			}
05048	SpecialNavig:
05049			if ( SpecialPause > 0.0 )
05050			{
05051				Target = Enemy;
05052				bFiringPaused = true;
05053				NextState = 'Charging';
05054				NextLabel = 'Begin';
05055				GotoState('RangedAttack');
05056			}
05057	Moving:
05058			if (VSize(MoveTarget.Location - Location) < 2.5 * CollisionRadius)
05059			{
05060				bCanFire = true;
05061				StrafeFacing(MoveTarget.Location, Enemy);
05062			}
05063			else
05064			{
05065				if ( FaceDestination(1.5) )
05066				{
05067					if ( GetAnimGroup(AnimSequence) == 'MovingAttack' )
05068					{
05069						AnimSequence = '';
05070						TweenToRunning(0.12);
05071					}
05072					HaltFiring();
05073					MoveToward(MoveTarget);
05074				}
05075				else
05076				{
05077					bCanFire = true;
05078					StrafeFacing(MoveTarget.Location, Enemy);	
05079				}
05080			}
05081		}
05082	
05083		GotoState('Attacking');
05084	
05085	GotThere:
05086		Target = Enemy;
05087		if ( !Weapon.bMeleeWeapon )
05088			GotoState('RangedAttack');
05089		Sleep(0.1 - 0.02 * Skill );
05090		Goto('Charge');
05091	
05092	TakeHit:
05093		TweenToRunning(0.12);
05094		if (MoveTarget == Enemy)
05095		{
05096			bCanFire = true;
05097			MoveToward(MoveTarget);
05098		}
05099		
05100		Goto('Charge');
05101	}
05102	
05103	state TacticalMove
05104	{
05105	ignores SeePlayer, HearNoise;
05106	
05107		function WarnTarget(Pawn shooter, float projSpeed, vector FireDir)
05108		{	
05109			if ( bCanFire && (FRand() < 0.4) ) 
05110				return;
05111	
05112			Super.WarnTarget(shooter, projSpeed, FireDir);
05113		}
05114	
05115		function SetFall()
05116		{
05117			Acceleration = vect(0,0,0);
05118			Destination = Location;
05119			NextState = 'Attacking'; 
05120			NextLabel = 'Begin';
05121			NextAnim = 'Fighter';
05122			GotoState('FallingState');
05123		}
05124	
05125		function TakeDamage( int Damage, Pawn instigatedBy, Vector hitlocation, 
05126							Vector momentum, name damageType)
05127		{
05128			Global.TakeDamage(Damage, instigatedBy, hitlocation, momentum, damageType);
05129			if ( health <= 0 )
05130				return;
05131			if ( NextState == 'TakeHit' )
05132			{
05133				NextState = 'TacticalMove'; 
05134				NextLabel = 'TakeHit';
05135				GotoState('TakeHit'); 
05136			}
05137		}
05138	
05139		function HitWall(vector HitNormal, actor Wall)
05140		{
05141			if (Physics == PHYS_Falling)
05142				return;
05143			Focus = Destination;
05144			if ( Enemy == None )
05145			{
05146				GotoState('Attacking');
05147				return;
05148			}
05149			//if (PickWallAdjust())
05150			//	GotoState('TacticalMove', 'AdjustFromWall');
05151			if ( bChangeDir || (FRand() < 0.5) 
05152				|| (((Enemy.Location - Location) Dot HitNormal) < 0) )
05153			{
05154				DesiredRotation = Rotator(Enemy.Location - location);
05155				GiveUpTactical(false);
05156			}
05157			else
05158			{
05159				bChangeDir = true;
05160				Destination = Location - HitNormal * FRand() * 500;
05161			}
05162		}
05163	
05164		function FearThisSpot(Actor aSpot)
05165		{
05166			Destination = Location + 120 * Normal(Location - aSpot.Location); 
05167		}
05168	
05169		function AnimEnd() 
05170		{
05171			if ( bCanFire && LineOfSightTo(Enemy) )
05172				PlayCombatMove();
05173			else if ( (Physics == PHYS_Falling) && (Velocity.Z < -300) )
05174				FastInAir();
05175			else
05176				PlayRunning();
05177		}
05178	
05179		function Timer()
05180		{
05181		
05182			bReadyToAttack = True;
05183			Enable('Bump');
05184			Target = Enemy;
05185			if ( Enemy == None )
05186				return;
05187			if (VSize(Enemy.Location - Location) 
05188					<= (MeleeRange + Enemy.CollisionRadius + CollisionRadius))
05189				GotoState('RangedAttack');		 
05190			else if ( !Weapon.bMeleeWeapon && ((Enemy.Weapon == None) || !Enemy.Weapon.bMeleeWeapon) )
05191			{
05192				if ( bNovice )
05193				{
05194					if ( FRand() > 0.4 + 0.18 * skill ) 
05195						GotoState('RangedAttack');
05196				}
05197				else if ( FRand() > 0.5 + 0.17 * skill ) 
05198					GotoState('RangedAttack');
05199			}
05200		}
05201	
05202		function EnemyNotVisible()
05203		{
05204			if ( !bGathering && (aggressiveness > relativestrength(enemy)) )
05205			{
05206				if ( FastTrace(Enemy.Location, LastSeeingPos) )
05207				{
05208					bCanFire = false;
05209					GotoState('TacticalMove','RecoverEnemy');
05210				}
05211				else
05212					GotoState('Attacking');
05213			}
05214			Disable('EnemyNotVisible');
05215		}
05216			
05217		function GiveUpTactical(bool bNoCharge)
05218		{	
05219			if ( !bNoCharge && (Weapon.bMeleeWeapon || (2 * CombatStyle + 0.1 * Skill > FRand())) )
05220				GotoState('Charging');
05221			else if ( bReadyToAttack && !Weapon.bMeleeWeapon && !bNovice )
05222				GotoState('RangedAttack');
05223			else
05224				GotoState('RangedAttack', 'Challenge'); 
05225		}		
05226	
05227		function bool TryToward(inventory Inv, float Weight)
05228		{
05229			local bool success; 
05230			local vector pickdir, collSpec, minDest, HitLocation, HitNormal;
05231			local Actor HitActor;
05232	
05233			if ( (Weight < 0.0008) && ((Weight < 0.0008 - 0.0002 * skill) 
05234					|| !Enemy.LineOfSightTo(Inv)) )
05235				return false;
05236	
05237			pickdir = Inv.Location - Location;
05238			if ( Physics == PHYS_Walking )
05239				pickDir.Z = 0;
05240			pickDir = Normal(PickDir);
05241	
05242			collSpec.X = CollisionRadius;
05243			collSpec.Y = CollisionRadius;
05244			collSpec.Z = FMax(6, CollisionHeight - 18);
05245			
05246			minDest = Location + FMin(160.0, 3*CollisionRadius) * pickDir;
05247			HitActor = Trace(HitLocation, HitNormal, minDest, Location, false, collSpec);
05248			if (HitActor == None)
05249			{
05250				success = (Physics != PHYS_Walking);
05251				if ( !success )
05252				{
05253					collSpec.X = FMin(14, 0.5 * CollisionRadius);
05254					collSpec.Y = collSpec.X;
05255					HitActor = Trace(HitLocation, HitNormal, minDest - (18 + MaxStepHeight) * vect(0,0,1), minDest, false, collSpec);
05256					success = (HitActor != None);
05257				}
05258				if ( success )
05259				{
05260					Destination = Inv.Location;
05261					bGathering = true;
05262					if ( 2.7 * FRand() < skill )
05263						GotoState('TacticalMove','DoStrafeMove');
05264					else
05265						GotoState('TacticalMove','DoDirectMove');
05266					return true;
05267				}
05268			}
05269	
05270			return false;
05271		}
05272	
05273		function PainTimer()
05274		{
05275			if ( (FootRegion.Zone.bPainZone) && (FootRegion.Zone.DamagePerSec > 0)
05276				&& (FootRegion.Zone.DamageType != ReducedDamageType) )
05277				GotoState('Retreating');
05278			Super.PainTimer();
05279		}
05280	
05281	
05282	/* PickDestination()
05283	Choose a destination for the tactical move, based on aggressiveness and the tactical
05284	situation. Make sure destination is reachable
05285	*/
05286		function PickDestination(bool bNoCharge)
05287		{
05288			local inventory Inv, BestInv, SecondInv;
05289			local float Bestweight, NewWeight, MaxDist, SecondWeight;
05290	
05291			// possibly pick nearby inventory
05292			// higher skill bots will always strafe, lower skill
05293			// both do this less, and strafe less
05294	
05295			if ( !bReadyToAttack && (TimerRate == 0.0) )
05296				SetTimer(0.7, false);
05297			if ( bNovice )
05298			{
05299				if ( Level.TimeSeconds - LastInvFind < 4 )
05300				{
05301					PickRegDestination(bNoCharge);
05302					return;
05303				}
05304			}
05305			else if ( Level.TimeSeconds - LastInvFind < 3 - 0.5 * skill )
05306			{
05307				PickRegDestination(bNoCharge);
05308				return;
05309			}
05310	
05311			LastInvFind = Level.TimeSeconds;
05312			bGathering = false;
05313			MaxDist = 700 + 70 * skill;
05314			BestWeight = 0.5/MaxDist;
05315			foreach visiblecollidingactors(class'Inventory', Inv, MaxDist,,true)
05316				if ( (Inv.IsInState('PickUp')) && (Inv.MaxDesireability/200 > BestWeight)
05317					&& (Inv.Location.Z < Location.Z + MaxStepHeight + CollisionHeight)
05318					&& (Inv.Location.Z > FMin(Location.Z, Enemy.Location.Z) - CollisionHeight) )
05319				{
05320					NewWeight = inv.BotDesireability(self)/VSize(Inv.Location - Location);
05321					if ( NewWeight > BestWeight )
05322					{
05323						SecondWeight = BestWeight;
05324						BestWeight = NewWeight;
05325						SecondInv = BestInv;
05326						BestInv = Inv;
05327					}
05328				}
05329	
05330			if ( BestInv == None )
05331			{
05332				PickRegDestination(bNoCharge);
05333				return;
05334			}
05335	
05336			if ( TryToward(BestInv, BestWeight) )
05337				return;
05338	
05339			if ( SecondInv == None )
05340			{
05341				PickRegDestination(bNoCharge);
05342				return;
05343			}
05344	
05345			if ( TryToward(SecondInv, SecondWeight) )
05346				return;
05347	
05348			PickRegDestination(bNoCharge);
05349		}
05350	
05351		function PickRegDestination(bool bNoCharge)
05352		{
05353			local vector pickdir, enemydir, enemyPart, X,Y,Z, minDest;
05354			local actor HitActor;
05355			local vector HitLocation, HitNormal, collSpec;
05356			local float Aggression, enemydist, minDist, strafeSize, optDist;
05357			local bool success, bNoReach;
05358		
05359			if ( Orders == 'Hold' )
05360				bNoCharge = true;
05361	
05362			bChangeDir = false;
05363			if (Region.Zone.bWaterZone && !bCanSwim && bCanFly)
05364			{
05365				Destination = Location + 75 * (VRand() + vect(0,0,1));
05366				Destination.Z += 100;
05367				return;
05368			}
05369			if ( Enemy.Region.Zone.bWaterZone )
05370				bNoCharge = bNoCharge || !bCanSwim;
05371			else 
05372				bNoCharge = bNoCharge || (!bCanFly && !bCanWalk);
05373			
05374			if( Weapon.bMeleeWeapon && !bNoCharge )
05375			{
05376				GotoState('Charging');
05377				return;
05378			}
05379			enemyDist = VSize(Location - Enemy.Location);
05380			if ( (bNovice && (FRand() > 0.3 + 0.15 * skill)) || (FRand() > 0.7 + 0.15 * skill) 
05381				&& ((EnemyDist > 900) || (Enemy.Weapon == None) || !Enemy.Weapon.bMeleeWeapon) 
05382				&& (!Level.Game.IsA('TeamGamePlus') || (TeamGamePlus(Level.Game).PriorityObjective(self) == 0)) )
05383				GiveUpTactical(true);
05384	
05385			success = false;
05386			if ( (bSniping || (Orders == 'Hold'))  
05387				&& (!Level.Game.IsA('TeamGamePlus') || (TeamGamePlus(Level.Game).PriorityObjective(self) == 0)) )
05388				bNoCharge = true;
05389			if ( bSniping && Weapon.IsA('SniperRifle') )
05390			{
05391				bReadyToAttack = true;
05392				GotoState('RangedAttack');
05393				return;
05394			}
05395							
05396			Aggression = 2 * (CombatStyle + FRand()) - 1.1;
05397			if ( Enemy.bIsPlayer && (AttitudeTo(Enemy) == ATTITUDE_Fear) && (CombatStyle > 0) )
05398				Aggression = Aggression - 2 - 2 * CombatStyle;
05399			if ( Weapon != None )
05400				Aggression += 2 * Weapon.SuggestAttackStyle();
05401			if ( Enemy.Weapon != None )
05402				Aggression += 2 * Enemy.Weapon.SuggestDefenseStyle();
05403	
05404			if ( enemyDist > 1000 )
05405				Aggression += 1;
05406			if ( !bNoCharge )
05407				bNoCharge = ( Aggression < FRand() );
05408	
05409			if ( (Physics == PHYS_Walking) || (Physics == PHYS_Falling) )
05410			{
05411				if (Location.Z > Enemy.Location.Z + 150) //tactical height advantage
05412					Aggression = FMax(0.0, Aggression - 1.0 + CombatStyle);
05413				else if (Location.Z < Enemy.Location.Z - CollisionHeight) // below enemy
05414				{
05415					if ( !bNoCharge && (Aggression > 0) && (FRand() < 0.6) )
05416					{
05417						GotoState('Charging');
05418						return;
05419					}
05420					else if ( (enemyDist < 1.1 * (Enemy.Location.Z - Location.Z)) 
05421							&& !actorReachable(Enemy) ) 
05422					{
05423						bNoReach = true;
05424						aggression = -1.5 * FRand();
05425					}
05426				}
05427			}
05428		
05429			if (!bNoCharge && (Aggression > 2 * FRand()))
05430			{
05431				if ( bNoReach && (Physics != PHYS_Falling) )
05432				{
05433					TweenToRunning(0.1);
05434					GotoState('Charging', 'NoReach');
05435				}
05436				else
05437					GotoState('Charging');
05438				return;
05439			}
05440	
05441			if ( !bNovice && ((Weapon == None) || !Weapon.bRecommendSplashDamage) && (FRand() < 0.35) && (bJumpy || (FRand()*Skill > 0.4)) )
05442			{
05443				GetAxes(Rotation,X,Y,Z);
05444	
05445				if ( FRand() < 0.5 )
05446				{
05447					Y *= -1;
05448					TryToDuck(Y, true);
05449				}
05450				else
05451					TryToDuck(Y, false);
05452				if ( !IsInState('TacticalMove') )
05453					return;
05454			}
05455				
05456			if (enemyDist > FMax(VSize(OldLocation - Enemy.OldLocation), 240))
05457				Aggression += 0.4 * FRand();
05458				 
05459			enemydir = (Enemy.Location - Location)/enemyDist;
05460			if ( bJumpy )
05461				minDist = 160;
05462			else
05463				minDist = FMin(160.0, 3*CollisionRadius);
05464			optDist = 80 + FMin(EnemyDist, 250 * (FRand() + FRand()));  
05465			Y = (enemydir Cross vect(0,0,1));
05466			if ( Physics == PHYS_Walking )
05467			{
05468				Y.Z = 0;
05469				enemydir.Z = 0;
05470			}
05471			else 
05472				enemydir.Z = FMax(0,enemydir.Z);
05473				
05474			strafeSize = FMax(-0.7, FMin(0.85, (2 * Aggression * FRand() - 0.3)));
05475			enemyPart = enemydir * strafeSize;
05476			strafeSize = FMax(0.0, 1 - Abs(strafeSize));
05477			pickdir = strafeSize * Y;
05478			if ( bStrafeDir )
05479				pickdir *= -1;
05480			bStrafeDir = !bStrafeDir;
05481			collSpec.X = CollisionRadius;
05482			collSpec.Y = CollisionRadius;
05483			collSpec.Z = FMax(6, CollisionHeight - 18);
05484			
05485			minDest = Location + minDist * (pickdir + enemyPart);
05486			HitActor = Trace(HitLocation, HitNormal, minDest, Location, false, collSpec);
05487			if (HitActor == None)
05488			{
05489				success = (Physics != PHYS_Walking);
05490				if ( !success )
05491				{
05492					collSpec.X = FMin(14, 0.5 * CollisionRadius);
05493					collSpec.Y = collSpec.X;
05494					HitActor = Trace(HitLocation, HitNormal, minDest - (18 + MaxStepHeight) * vect(0,0,1), minDest, false, collSpec);
05495					success = (HitActor != None);
05496				}
05497				if (success)
05498					Destination = minDest + (pickdir + enemyPart) * optDist;
05499			}
05500		
05501			if ( !success )
05502			{					
05503				collSpec.X = CollisionRadius;
05504				collSpec.Y = CollisionRadius;
05505				minDest = Location + minDist * (enemyPart - pickdir); 
05506				HitActor = Trace(HitLocation, HitNormal, minDest, Location, false, collSpec);
05507				if (HitActor == None)
05508				{
05509					success = (Physics != PHYS_Walking);
05510					if ( !success )
05511					{
05512						collSpec.X = FMin(14, 0.5 * CollisionRadius);
05513						collSpec.Y = collSpec.X;
05514						HitActor = Trace(HitLocation, HitNormal, minDest - (18 + MaxStepHeight) * vect(0,0,1), minDest, false, collSpec);
05515						success = (HitActor != None);
05516					}
05517					if (success)
05518						Destination = minDest + (enemyPart - pickdir) * optDist;
05519				}
05520				else 
05521				{
05522					if ( (CombatStyle <= 0) || (Enemy.bIsPlayer && (AttitudeTo(Enemy) == ATTITUDE_Fear)) )
05523						enemypart = vect(0,0,0);
05524					else if ( (enemydir Dot enemyPart) < 0 )
05525						enemyPart = -1 * enemyPart;
05526					pickDir = Normal(enemyPart - pickdir + HitNormal);
05527					minDest = Location + minDist * pickDir;
05528					collSpec.X = CollisionRadius;
05529					collSpec.Y = CollisionRadius;
05530					HitActor = Trace(HitLocation, HitNormal, minDest, Location, false, collSpec);
05531					if (HitActor == None)
05532					{
05533						success = (Physics != PHYS_Walking);
05534						if ( !success )
05535						{
05536							collSpec.X = FMin(14, 0.5 * CollisionRadius);
05537							collSpec.Y = collSpec.X;
05538							HitActor = Trace(HitLocation, HitNormal, minDest - (18 + MaxStepHeight) * vect(0,0,1), minDest, false, collSpec);
05539							success = (HitActor != None);
05540						}
05541						if (success)
05542							Destination = minDest + pickDir * optDist;
05543					}
05544				}	
05545			}
05546						
05547			if ( !success )
05548				GiveUpTactical(bNoCharge);
05549			else 
05550			{
05551				if ( bJumpy || (Weapon.bRecommendSplashDamage && !bNovice 
05552					&& (FRand() < 0.2 + 0.2 * Skill)
05553					&& (Enemy.Location.Z - Enemy.CollisionHeight <= Location.Z + MaxStepHeight - CollisionHeight)) 
05554					&& !NeedToTurn(Enemy.Location) )
05555				{
05556					FireWeapon();
05557					if ( (bJumpy && (FRand() < 0.75)) || Weapon.SplashJump() )
05558					{
05559						// try jump move
05560						SetPhysics(PHYS_Falling);
05561						Acceleration = vect(0,0,0);
05562						Destination = minDest;
05563						NextState = 'Attacking'; 
05564						NextLabel = 'Begin';
05565						NextAnim = 'Fighter';
05566						GotoState('FallingState');
05567						return;
05568					}
05569				}
05570				pickDir = (Destination - Location);
05571				enemyDist = VSize(pickDir);
05572				if ( enemyDist > minDist + 2 * CollisionRadius )
05573				{
05574					pickDir = pickDir/enemyDist;
05575					HitActor = Trace(HitLocation, HitNormal, Destination + 2 * CollisionRadius * pickdir, Location, false);
05576					if ( (HitActor != None) && ((HitNormal Dot pickDir) < -0.6) )
05577						Destination = HitLocation - 2 * CollisionRadius * pickdir;
05578				}
05579			}
05580		}
05581	
05582		function BeginState()
05583		{
05584			if ( bNovice ) 
05585				MaxDesiredSpeed = 0.4 + 0.08 * skill;
05586			MinHitWall += 0.15;
05587			bAvoidLedges = true;
05588			bStopAtLedges = true;
05589			bCanJump = false;
05590			bCanFire = false;
05591		}
05592		
05593		function EndState()
05594		{
05595			if ( bNovice ) 
05596				MaxDesiredSpeed = 0.5 + 0.1 * skill;
05597			bAvoidLedges = false;
05598			bStopAtLedges = false;
05599			bQuickFire = false;
05600			MinHitWall -= 0.15;
05601			if (JumpZ > 0)
05602				bCanJump = true;
05603		}
05604	
05605	TacticalTick:
05606		Sleep(0.02);	
05607	Begin:
05608		TweenToRunning(0.15);
05609		Enable('AnimEnd');
05610		if (Physics == PHYS_Falling)
05611		{
05612			DesiredRotation = Rotator(Enemy.Location - Location);
05613			Focus = Enemy.Location;
05614			Destination = Enemy.Location;
05615			WaitForLanding();
05616		}
05617		PickDestination(false);
05618	
05619	DoMove:
05620		if ( !bCanStrafe )
05621		{ 
05622	DoDirectMove:
05623			Enable('AnimEnd');
05624			if ( GetAnimGroup(AnimSequence) == 'MovingAttack' )
05625			{
05626				AnimSequence = '';
05627				TweenToRunning(0.12);
05628			}
05629			HaltFiring();
05630			MoveTo(Destination);
05631		}
05632		else
05633		{
05634	DoStrafeMove:
05635			Enable('AnimEnd');
05636			bCanFire = true;
05637			StrafeFacing(Destination, Enemy);	
05638		}
05639	
05640		if ( (Enemy != None) && !LineOfSightTo(Enemy) && FastTrace(Enemy.Location, LastSeeingPos) )
05641			Goto('RecoverEnemy');
05642		else
05643		{
05644			bReadyToAttack = true;
05645			GotoState('Attacking');
05646		}
05647		
05648	NoCharge:
05649		TweenToRunning(0.1);
05650		Enable('AnimEnd');
05651		if (Physics == PHYS_Falling)
05652		{
05653			DesiredRotation = Rotator(Enemy.Location - Location);
05654			Focus = Enemy.Location;
05655			Destination = Enemy.Location;
05656			WaitForLanding();
05657		}
05658		PickDestination(true);
05659		Goto('DoMove');
05660		
05661	AdjustFromWall:
05662		Enable('AnimEnd');
05663		StrafeTo(Destination, Focus); 
05664		Destination = Focus; 
05665		Goto('DoMove');
05666	
05667	TakeHit:
05668		TweenToRunning(0.12);
05669		Goto('DoMove');
05670	
05671	RecoverEnemy:
05672		Enable('AnimEnd');
05673		bReadyToAttack = true;
05674		HidingSpot = Location;
05675		bCanFire = false;
05676		Destination = LastSeeingPos + 4 * CollisionRadius * Normal(LastSeeingPos - Location);
05677		StrafeFacing(Destination, Enemy);
05678	
05679		if ( !Weapon.bMeleeWeapon && LineOfSightTo(Enemy) && CanFireAtEnemy() )
05680		{
05681			Disable('AnimEnd');
05682			DesiredRotation = Rotator(Enemy.Location - Location);
05683			bQuickFire = true;
05684			FireWeapon();
05685			bQuickFire = false;
05686			Acceleration = vect(0,0,0);
05687			if ( Weapon.bSplashDamage )
05688			{
05689				bFire = 0;
05690				bAltFire = 0;
05691				bReadyToAttack = true;
05692				Sleep(0.2);
05693			}
05694			else
05695				Sleep(0.35 + 0.3 * FRand());
05696			if ( (FRand() + 0.1 > CombatStyle) )
05697			{
05698				bFire = 0;
05699				bAltFire = 0;
05700				bReadyToAttack = true;
05701				Enable('EnemyNotVisible');
05702				Enable('AnimEnd');
05703				Destination = HidingSpot + 4 * CollisionRadius * Normal(HidingSpot - Location);
05704				Goto('DoMove');
05705			}
05706		}
05707	
05708		GotoState('Attacking');
05709	}
05710	
05711	state Hunting
05712	{
05713	ignores EnemyNotVisible; 
05714	
05715		/* MayFall() called by engine physics if walking and bCanJump, and
05716			is about to go off a ledge.  Pawn has opportunity (by setting 
05717			bCanJump to false) to avoid fall
05718		*/
05719		function MayFall()
05720		{
05721			bCanJump = ( ((MoveTarget != None) 
05722						&& ((MoveTarget.Physics != PHYS_Falling) || !MoveTarget.IsA('Inventory')))
05723						|| PointReachable(Destination) );
05724		}
05725	
05726		function bool CheckBumpAttack(Pawn Other)
05727		{
05728			SetEnemy(Other);
05729			if ( Enemy == Other )
05730			{
05731				bReadyToAttack = true;
05732				LastSeenTime = Level.TimeSeconds;
05733				LastSeenPos = Enemy.Location;
05734				GotoState('Attacking');
05735				return true;
05736			}
05737			return false;
05738		}
05739		
05740		function FearThisSpot(Actor aSpot)
05741		{
05742			Destination = Location + 120 * Normal(Normal(Destination - Location) + Normal(Location - aSpot.Location)); 
05743			MoveTarget = None;
05744			GotoState('Hunting', 'SpecialNavig');
05745		}
05746	
05747		function TakeDamage( int Damage, Pawn instigatedBy, Vector hitlocation, 
05748								Vector momentum, name damageType)
05749		{
05750			Global.TakeDamage(Damage, instigatedBy, hitlocation, momentum, damageType);
05751			if ( health <= 0 )
05752				return;
05753			bFrustrated = true;
05754			if (NextState == 'TakeHit')
05755			{
05756				if (AttitudeTo(Enemy) == ATTITUDE_Fear)
05757				{
05758					NextState = 'Retreating';
05759					NextLabel = 'Begin';
05760				}
05761				else
05762				{
05763					NextState = 'Hunting';
05764					NextLabel = 'AfterFall';
05765				}
05766				GotoState('TakeHit'); 
05767			}
05768		}
05769	
05770		singular function HearNoise(float Loudness, Actor NoiseMaker)
05771		{
05772			SetEnemy(NoiseMaker.instigator);
05773		}
05774	
05775		function SetFall()
05776		{
05777			NextState = 'Hunting'; 
05778			NextLabel = 'AfterFall';
05779			NextAnim = AnimSequence;
05780			GotoState('FallingState'); 
05781		}
05782	
05783		function bool SetEnemy(Pawn NewEnemy)
05784		{
05785			local float rnd;
05786	
05787			if (Global.SetEnemy(NewEnemy))
05788			{
05789				bDevious = false;
05790				BlockedPath = None;
05791				rnd = FRand();
05792				bReadyToAttack = true;
05793				DesiredRotation = Rotator(Enemy.Location - Location);
05794				if ( CombatStyle > FRand() )
05795					GotoState('Charging'); 
05796				else
05797					GotoState('Attacking');
05798				return true;
05799			}
05800			return false;
05801		} 
05802	
05803		function AnimEnd()
05804		{
05805			bFire = 0;
05806			bAltFire = 0;
05807			bReadyToAttack = true;
05808			if ( (Physics == PHYS_Falling) && (Velocity.Z < -300) )
05809				FastInAir();
05810			else
05811			{
05812				PlayRunning();
05813				Disable('AnimEnd');
05814			}
05815		}
05816		
05817		function Timer()
05818		{
05819			bReadyToAttack = true;
05820			Enable('Bump');
05821			SetTimer(1.0, false);
05822		}
05823	
05824		function HitWall(vector HitNormal, actor Wall)
05825		{
05826			if (Physics == PHYS_Falling)
05827				return;
05828			if ( Wall.IsA('Mover') && Mover(Wall).HandleDoor(self) )
05829			{
05830				if ( SpecialPause > 0 )
05831					Acceleration = vect(0,0,0);
05832				GotoState('Hunting', 'SpecialNavig');
05833				return;
05834			}
05835			Focus = Destination;
05836			if (PickWallAdjust())
05837			{
05838				if ( Physics == PHYS_Falling )
05839					SetFall();
05840				else
05841					GotoState('Hunting', 'AdjustFromWall');
05842			}
05843			else
05844				MoveTimer = -1.0;
05845		}
05846	
05847		function bool TryToward(inventory Inv, float Weight)
05848		{
05849			local bool success; 
05850			local vector pickdir, collSpec, minDest, HitLocation, HitNormal;
05851			local Actor HitActor;
05852	
05853			pickdir = Inv.Location - Location;
05854			if ( Physics == PHYS_Walking )
05855				pickDir.Z = 0;
05856			pickDir = Normal(PickDir);
05857	
05858			collSpec.X = CollisionRadius;
05859			collSpec.Y = CollisionRadius;
05860			collSpec.Z = FMax(6, CollisionHeight - 18);
05861			
05862			minDest = Location + FMin(160.0, 3*CollisionRadius) * pickDir;
05863			HitActor = Trace(HitLocation, HitNormal, minDest, Location, false, collSpec);
05864			if (HitActor == None)
05865			{
05866				success = (Physics != PHYS_Walking);
05867				if ( !success )
05868				{
05869					collSpec.X = FMin(14, 0.5 * CollisionRadius);
05870					collSpec.Y = collSpec.X;
05871					HitActor = Trace(HitLocation, HitNormal, minDest - (18 + MaxStepHeight) * vect(0,0,1), minDest, false, collSpec);
05872					success = (HitActor != None);
05873				}
05874				if ( success )
05875				{
05876					MoveTarget = Inv;
05877					return true;
05878				}
05879			}
05880	
05881			return false;
05882		}
05883	
05884		function PickDestination()
05885		{
05886			local inventory Inv, BestInv, SecondInv;
05887			local float Bestweight, NewWeight, MaxDist, SecondWeight;
05888			local NavigationPoint path;
05889			local actor HitActor;
05890			local vector HitNormal, HitLocation, nextSpot, ViewSpot;
05891			local float posZ;
05892			local bool bCanSeeLastSeen;
05893			local int i;
05894	
05895			// If no enemy, or I should see him but don't, then give up		
05896			if ( Level.TimeSeconds - LastSeenTime > 26 - Level.Game.NumPlayers - DeathMatchPlus(Level.Game).NumBots )
05897				Enemy = None;
05898			if ( (Enemy == None) || (Enemy.Health <= 0) )
05899			{
05900				WhatToDoNext('','');
05901				return;
05902			}
05903		
05904			bAvoidLedges = false;
05905	
05906			if ( JumpZ > 0 )
05907				bCanJump = true;
05908			
05909			if ( ActorReachable(Enemy) )
05910			{
05911				BlockedPath = None;
05912				if ( (numHuntPaths < 8 + Skill) || (Level.TimeSeconds - LastSeenTime < 15)
05913					|| ((Normal(Enemy.Location - Location) Dot vector(Rotation)) > -0.5) )
05914				{
05915					Destination = Enemy.Location;
05916					MoveTarget = None;
05917					numHuntPaths++;
05918				}
05919				else
05920					WhatToDoNext('','');
05921				return;
05922			}
05923	
05924			if ( Level.TimeSeconds - LastInvFind > 2.5 - 0.4 * skill )
05925			{
05926				LastInvFind = Level.TimeSeconds;
05927				MaxDist = 600 + 70 * skill;
05928				BestWeight = 0.6/MaxDist;
05929				foreach visiblecollidingactors(class'Inventory', Inv, MaxDist,, true)
05930					if ( (Inv.IsInState('PickUp')) && (Inv.MaxDesireability/200 > BestWeight)
05931						&& (Inv.Location.Z < Location.Z + MaxStepHeight + CollisionHeight)
05932						&& (Inv.Location.Z > FMin(Location.Z, Enemy.Location.Z) - CollisionHeight) )
05933					{
05934						NewWeight = inv.BotDesireability(self)/VSize(Inv.Location - Location);
05935						if ( NewWeight > BestWeight )
05936						{
05937							SecondWeight = BestWeight;
05938							BestWeight = NewWeight;
05939							SecondInv = BestInv;
05940							BestInv = Inv;
05941						}
05942					}
05943	
05944				if ( BestInv != None )
05945				{
05946					if ( TryToward(BestInv, BestWeight) )
05947						return;
05948	
05949					if ( (SecondInv != None) && TryToward(SecondInv, SecondWeight) )
05950						return;
05951				}
05952			}
05953	
05954			numHuntPaths++;
05955	
05956			ViewSpot = Location + BaseEyeHeight * vect(0,0,1);
05957			bCanSeeLastSeen = false;
05958			bCanSeeLastSeen = FastTrace(LastSeenPos, ViewSpot);
05959			if ( bCanSeeLastSeen )
05960				bHunting = !FastTrace(LastSeenPos, Enemy.Location);
05961			else
05962				bHunting = true;
05963	
05964			bCanTranslocate = ( Level.Game.IsA('DeathMatchPlus') && DeathMatchPlus(Level.Game).CanTranslocate(self) );
05965	
05966			if ( bDevious )
05967			{
05968				if ( BlockedPath == None )
05969				{
05970					// block the first path visible to the enemy
05971					if ( FindPathToward(Enemy) != None )
05972					{
05973						for ( i=0; i<16; i++ )
05974						{
05975							if ( RouteCache[i] == None )
05976								break;
05977							else if ( Enemy.LineOfSightTo(RouteCache[i]) )
05978							{
05979								BlockedPath = RouteCache[i];
05980								break;
05981							}
05982						}
05983					}
05984					else if ( CanStakeOut() )
05985					{
05986						GotoState('StakeOut');
05987						return;
05988					}
05989					else
05990					{
05991						WhatToDoNext('', '');
05992						return;
05993					}
05994				}
05995				// control path weights
05996				ClearPaths();
05997				BlockedPath.Cost = 1500;
05998				if ( FindBestPathToward(Enemy, false) )
05999					return;
06000			}
06001			else if ( FindBestPathToward(Enemy, true) )
06002				return;
06003	
06004			MoveTarget = None;
06005			if ( bFromWall )
06006			{
06007				bFromWall = false;
06008				if ( !PickWallAdjust() )
06009				{
06010					if ( CanStakeOut() )
06011						GotoState('StakeOut');
06012					else
06013						WhatToDoNext('', '');
06014				}
06015				return;
06016			}
06017			
06018			if ( (NumHuntPaths > 60) && (bNovice || !Level.Game.IsA('DeathMatchPlus') || !DeathMatchPlus(Level.Game).OneOnOne()) )
06019			{
06020				WhatToDoNext('', '');
06021				return;
06022			}
06023	
06024			if ( LastSeeingPos != vect(1000000,0,0) )
06025			{
06026				Destination = LastSeeingPos;
06027				LastSeeingPos = vect(1000000,0,0);		
06028				if ( FastTrace(Enemy.Location, ViewSpot) )
06029				{
06030					If (VSize(Location - Destination) < 20)
06031					{
06032						SetEnemy(Enemy);
06033						return;
06034					}
06035					return;
06036				}
06037			}
06038	
06039			bAvoidLedges = (CollisionRadius > 42);
06040			posZ = LastSeenPos.Z + CollisionHeight - Enemy.CollisionHeight;
06041			nextSpot = LastSeenPos - Normal(Enemy.Location - Enemy.OldLocation) * CollisionRadius;
06042			nextSpot.Z = posZ;
06043			if ( FastTrace(nextSpot, ViewSpot) )
06044				Destination = nextSpot;
06045			else if ( bCanSeeLastSeen )
06046				Destination = LastSeenPos;
06047			else
06048			{
06049				Destination = LastSeenPos;
06050				if ( !FastTrace(LastSeenPos, ViewSpot) )
06051				{
06052					// check if could adjust and see it
06053					if ( PickWallAdjust() || FindViewSpot() )
06054					{
06055						if ( Physics == PHYS_Falling )
06056							SetFall();
06057						else
06058							GotoState('Hunting', 'AdjustFromWall');
06059					}
06060					else if ( VSize(Enemy.Location - Location) < 1200 )
06061					{
06062						GotoState('StakeOut');
06063						return;
06064					}
06065					else
06066					{
06067						WhatToDoNext('Waiting', 'TurnFromWall');
06068						return;
06069					}
06070				}
06071			}
06072			LastSeenPos = Enemy.Location;				
06073		}	
06074	
06075		function bool FindViewSpot()
06076		{
06077			local vector X,Y,Z;
06078			local bool bAlwaysTry;
06079	
06080			GetAxes(Rotation,X,Y,Z);
06081	
06082			// try left and right
06083			// if frustrated, always move if possible
06084			bAlwaysTry = bFrustrated;
06085			bFrustrated = false;
06086			
06087			if ( FastTrace(Enemy.Location, Location + 2 * Y * CollisionRadius) )
06088			{
06089				Destination = Location + 2.5 * Y * CollisionRadius;
06090				return true;
06091			}
06092	
06093			if ( FastTrace(Enemy.Location, Location - 2 * Y * CollisionRadius) )
06094			{
06095				Destination = Location - 2.5 * Y * CollisionRadius;
06096				return true;
06097			}
06098			if ( bAlwaysTry )
06099			{
06100				if ( FRand() < 0.5 )
06101					Destination = Location - 2.5 * Y * CollisionRadius;
06102				else
06103					Destination = Location - 2.5 * Y * CollisionRadius;
06104				return true;
06105			}
06106	
06107			return false;
06108		}
06109	
06110		function BeginState()
06111		{
06112			//log(self$" hunting");
06113			SpecialGoal = None;
06114			SpecialPause = 0.0;
06115			bFromWall = false;
06116			SetAlertness(0.5);
06117		}
06118	
06119		function EndState()
06120		{
06121			bCanTranslocate = false;
06122			bAvoidLedges = false;
06123			bHunting = false;
06124			if ( JumpZ > 0 )
06125				bCanJump = true;
06126		}
06127	
06128	AdjustFromWall:
06129		Enable('AnimEnd');
06130		StrafeTo(Destination, Focus); 
06131		Destination = Focus; 
06132		if ( MoveTarget != None )
06133			Goto('SpecialNavig');
06134		else
06135			Goto('Follow');
06136	
06137	Begin:
06138		numHuntPaths = 0;
06139	AfterFall:
06140		TweenToRunning(0.1);
06141		bFromWall = false;
06142	
06143	Follow:
06144		if ( Level.Game.IsA('TeamGamePlus') )
06145			TeamGamePlus(Level.Game).FindSpecialAttractionFor(self);
06146		if ( bSniping )
06147			GotoState('StakeOut');
06148		if ( (Orders == 'Hold') || (Orders == 'Follow') ) 
06149		{
06150			if ( !LineOfSightTo(OrderObject) )
06151				GotoState('Fallback');
06152		}
06153		else if ( Orders == 'Defend' )
06154		{
06155			if ( AmbushSpot != None )
06156			{
06157				if ( !LineOfSightTo(AmbushSpot) )
06158					GotoState('Fallback');
06159			}
06160			else if ( !LineOfSightTo(OrderObject) )
06161				GotoState('Fallback');
06162		}
06163		WaitForLanding();
06164		if ( CanSee(Enemy) )
06165			SetEnemy(Enemy);
06166		PickDestination();
06167	SpecialNavig:
06168		if ( SpecialPause > 0.0 )
06169		{
06170			Disable('AnimEnd');
06171			Acceleration = vect(0,0,0);
06172			bFire = 0;
06173			bAltFire = 0;
06174			PlayChallenge();
06175			Sleep(SpecialPause);
06176			SpecialPause = 0.0;
06177			Enable('AnimEnd');
06178			Goto('AfterFall');
06179		}
06180		if (MoveTarget == None)
06181			MoveTo(Destination);
06182		else
06183			MoveToward(MoveTarget); 
06184	
06185		Goto('Follow');
06186	}
06187	
06188	state StakeOut
06189	{
06190	ignores EnemyNotVisible; 
06191	
06192		function TakeDamage( int Damage, Pawn instigatedBy, Vector hitlocation, 
06193								Vector momentum, name damageType)
06194		{
06195			Global.TakeDamage(Damage, instigatedBy, hitlocation, momentum, damageType);
06196			if ( health <= 0 )
06197				return;
06198			bFrustrated = true;
06199			LastSeenPos = Enemy.Location;
06200			if (NextState == 'TakeHit')
06201			{
06202				if (AttitudeTo(Enemy) == ATTITUDE_Fear)
06203				{
06204					NextState = 'Retreating';
06205					NextLabel = 'Begin';
06206				}
06207				else
06208				{
06209					NextState = 'Attacking';
06210					NextLabel = 'Begin';
06211				}
06212				GotoState('TakeHit'); 
06213			}
06214			else
06215				GotoState('Attacking');
06216		}
06217	
06218		singular function HearNoise(float Loudness, Actor NoiseMaker)
06219		{
06220			if ( SetEnemy(NoiseMaker.instigator) )
06221				LastSeenPos = Enemy.Location; 
06222		}
06223	
06224		function SetFall()
06225		{
06226			NextState = 'StakeOut'; 
06227			NextLabel = 'Begin';
06228			NextAnim = AnimSequence;
06229			GotoState('FallingState'); 
06230		}
06231	
06232		function bool SetEnemy(Pawn NewEnemy)
06233		{
06234			if (Global.SetEnemy(NewEnemy))
06235			{
06236				bReadyToAttack = true;
06237				DesiredRotation = Rotator(Enemy.Location - Location);
06238				GotoState('Attacking');
06239				return true;
06240			}
06241			return false;
06242		} 
06243		
06244		function Timer()
06245		{
06246			bReadyToAttack = true;
06247			Enable('Bump');
06248			SetTimer(1.0, false);
06249		}
06250	
06251		function rotator AdjustAim(float projSpeed, vector projStart, int aimerror, bool leadTarget, bool warnTarget)
06252		{
06253			local vector FireSpot, X,Y,Z;
06254			local actor HitActor;
06255			local vector HitLocation, HitNormal;
06256					
06257			FireSpot = LastSeenPos;
06258				 
06259			HitActor = Trace(HitLocation, HitNormal, FireSpot, ProjStart, false);
06260			if( HitActor != None ) 
06261			{
06262				FireSpot += 2 * Enemy.CollisionHeight * HitNormal;
06263				bClearShot = FastTrace(FireSpot, ProjStart);
06264				if ( !bClearShot )
06265				{
06266					FireSpot = LastSeenPos;
06267					bFire = 0;
06268					bAltFire = 0;
06269				}
06270			}
06271			
06272			ViewRotation = Rotator(FireSpot - ProjStart);
06273			return ViewRotation;
06274		}
06275		
06276		function bool ClearShot()
06277		{
06278			if ( Weapon.bSplashDamage && (VSize(Location - LastSeenPos) < 300) )
06279				return false;
06280	
06281			if ( !FastTrace(LastSeenPos + vect(0,0,0.9) * Enemy.CollisionHeight, Location) )
06282			{
06283				bFire = 0;
06284				bAltFire = 0;
06285				return false;
06286			}
06287			return true;
06288		}
06289		
06290		function FindNewStakeOutDir()
06291		{
06292			local NavigationPoint N, Best;
06293			local vector Dir, EnemyDir;
06294			local float Dist, BestVal, Val;
06295	
06296			EnemyDir = Normal(Enemy.Location - Location);
06297			for ( N=Level.NavigationPointList; N!=None; N=N.NextNavigationPoint )
06298			{
06299				Dir = N.Location - Location;
06300				Dist = VSize(Dir);
06301				if ( (Dist < 800) && (Dist > 100) )
06302				{
06303					Val = (EnemyDir Dot Dir/Dist);
06304					if ( Level.Game.bTeamgame )
06305						Val += FRand();
06306					if ( (Val > BestVal) && LineOfSightTo(N) )
06307					{
06308						BestVal = Val;
06309						Best = N;
06310					}
06311				}
06312			}
06313	
06314			if ( Best != None )
06315				LastSeenPos = Best.Location + 0.5 * CollisionHeight * vect(0,0,1);			
06316		}
06317			
06318		function bool ContinueStakeOut()
06319		{
06320			local float relstr;
06321	
06322			relstr = RelativeStrength(Enemy);
06323			if ( (VSize(Enemy.Location - Location) > 300 + (FRand() * relstr - CombatStyle) * 350)
06324				 || (Level.TimeSeconds - LastSeenTime > 2.5 + FMax(-1, 3 * (FRand() + 2 * (relstr - CombatStyle))) ) || !ClearShot() )
06325				return false;
06326			else if ( CanStakeOut() )
06327				return true;
06328			else
06329				return false;
06330		}
06331	
06332		function BeginState()
06333		{
06334	
06335			Acceleration = vect(0,0,0);
06336			bClearShot = ClearShot();
06337			bCanJump = false;
06338			bReadyToAttack = true;
06339			SetAlertness(0.5);
06340			RealLastSeenPos = LastSeenPos;
06341			if ( !bClearShot || ((Level.TimeSeconds - LastSeenTime > 6) && (FRand() < 0.5)) )
06342				FindNewStakeOutDir();
06343		}
06344	
06345		function EndState()
06346		{
06347			LastSeenPos = RealLastSeenPos;
06348			if ( JumpZ > 0 )
06349				bCanJump = true;
06350		}
06351	
06352	Begin:
06353		if ( AmbushSpot == None )
06354			bSniping = false;
06355		if ( (bSniping && (VSize(Location - AmbushSpot.Location) > 3 * CollisionRadius)) 
06356			|| (Level.Game.IsA('DeathMatchPlus') && DeathMatchPlus(Level.Game).NeverStakeOut(self)) )
06357		{
06358			Enemy = None;
06359			OldEnemy = None;
06360			WhatToDoNext('','');
06361		}
06362		Acceleration = vect(0,0,0);
06363		PlayChallenge();
06364		TurnTo(LastSeenPos);
06365		if ( Enemy == None )
06366			WhatToDoNext('','');
06367		if ( (Weapon != None) && !Weapon.bMeleeWeapon && (FRand() < 0.5) && (VSize(Enemy.Location - LastSeenPos) < 150) 
06368			 && ClearShot() && CanStakeOut() )
06369			PlayRangedAttack();
06370		else
06371		{
06372			bFire = 0;
06373			bAltFire = 0;
06374		}
06375		FinishAnim();
06376		if ( !bNovice || (FRand() < 0.65) )
06377			TweenToWaiting(0.17);
06378		else
06379			PlayChallenge();
06380		Sleep(1 + FRand());
06381		if ( Level.Game.IsA('TeamGamePlus') )
06382			TeamGamePlus(Level.Game).FindSpecialAttractionFor(self);
06383		if ( ContinueStakeOut() )
06384		{
06385			if ( bSniping && (AmbushSpot != None) )
06386				LastSeenPos = Location + Ambushspot.lookdir;
06387			else if ( (FRand() < 0.3) || !FastTrace(LastSeenPos + vect(0,0,0.9) * Enemy.CollisionHeight, Location + vect(0,0,0.8) * CollisionHeight) )
06388				FindNewStakeOutDir();
06389			Goto('Begin');
06390		}
06391		else
06392		{
06393			if ( bSniping )
06394				WhatToDoNext('','');
06395			BlockedPath = None;	
06396			bDevious = ( !bNovice && !Level.Game.bTeamGame && Level.Game.IsA('DeathMatchPlus') 
06397						&& (FRand() < 0.75 - 0.15 * DeathMatchPlus(Level.Game).NumBots) );
06398			GotoState('Hunting', 'AfterFall');
06399		}
06400	}
06401	
06402	state TakeHit 
06403	{
06404	ignores seeplayer, hearnoise, bump, hitwall;
06405	
06406		function TakeDamage( int Damage, Pawn instigatedBy, Vector hitlocation, 
06407							Vector momentum, name damageType)
06408		{
06409			Global.TakeDamage(Damage, instigatedBy, hitlocation, momentum, damageType);
06410		}
06411	
06412		function Landed(vector HitNormal)
06413		{
06414			if (Velocity.Z < -1.4 * JumpZ)
06415				MakeNoise(-0.5 * Velocity.Z/(FMax(JumpZ, 150.0)));
06416			bJustLanded = true;
06417		}
06418	
06419		function Timer()
06420		{
06421			bReadyToAttack = true;
06422		}
06423	
06424		function PlayHitAnim(vector HitLocation, float Damage)
06425		{
06426			if ( LastPainTime - Level.TimeSeconds > 0.1 )
06427			{
06428				PlayTakeHit(0.1, hitLocation, Damage);
06429				BeginState();
06430				GotoState('TakeHit', 'Begin');
06431			} 
06432		}	
06433	
06434		function BeginState()
06435		{
06436			LastPainTime = Level.TimeSeconds;
06437			LastPainAnim = AnimSequence;
06438			if ( (NextState == 'TacticalMove') && (Region.Zone.ZoneGravity.Z > Region.Zone.Default.ZoneGravity.Z) )
06439				Destination = location;
06440		}
06441			
06442	Begin:
06443		if ( bFireFalling )
06444		{
06445			bFireFalling = false;
06446			GotoState('FallingState', 'Ducking');
06447		}
06448		FinishAnim();
06449		if ( bNovice || (Skill < 2) )
06450			Sleep(0.05);
06451		if ( (Physics == PHYS_Falling) && !Region.Zone.bWaterZone )
06452		{
06453			NextAnim = '';
06454			GotoState('FallingState', 'Ducking');
06455		}
06456		else if (NextState != '')
06457			GotoState(NextState, NextLabel);
06458		else
06459			GotoState('Attacking');
06460	}
06461	
06462	state ImpactJumping
06463	{
06464		function TakeDamage( int Damage, Pawn instigatedBy, Vector hitlocation, 
06465								Vector momentum, name damageType)
06466		{
06467			local name RealState, RealLabel;
06468	
06469			RealState = NextState;
06470			RealLabel = NextLabel;
06471			Global.TakeDamage(Damage, instigatedBy, hitlocation, momentum, damageType);
06472			if ( health <= 0 )
06473				return;
06474			if ( (Enemy != None) && (Enemy == InstigatedBy) )
06475			{
06476				LastSeenPos = Enemy.Location;
06477				LastSeenTime = Level.TimeSeconds;
06478			}
06479			NextState = RealState;
06480			NextLabel = RealLabel;
06481			MoveTarget = None;
06482			bJumpOffPawn = true;
06483			bImpactJumping = true;
06484			GotoState('fallingstate');
06485		}
06486	
06487		function vector ImpactLook()
06488		{
06489			local vector result;
06490			
06491			result = 1000 * Normal(ImpactTarget.Location - Location);
06492			result.Z = Location.Z - 400;
06493			return Result;
06494		}
06495		
06496		function AnimEnd()
06497		{
06498			bFire = 1;
06499			PlayWaiting();
06500			bFire = 0;
06501		}
06502					
06503		function ChangeToHammer()
06504		{
06505			local Inventory MyHammer;
06506	
06507			MyHammer = FindInventoryType(class'ImpactHammer');
06508			if ( MyHammer == None )
06509			{
06510				GotoState('NextState', 'NextLabel');
06511				return;
06512			}
06513			PendingWeapon = Weapon(MyHammer);
06514			PendingWeapon.AmbientSound = ImpactHammer(MyHammer).TensionSound;
06515			PendingWeapon.SetLocation(Location);
06516			if ( Weapon == None )
06517				ChangedWeapon();
06518			else if ( Weapon != PendingWeapon )
06519				Weapon.PutDown();
06520		}
06521	
06522		function EndState()
06523		{
06524			local Inventory MyHammer;
06525			MyHammer = FindInventoryType(class'ImpactHammer');
06526			if ( MyHammer != None )
06527				MyHammer.AmbientSound = None;
06528		}
06529	
06530	
06531	Begin:
06532		Acceleration = vect(0,0,0);
06533		if ( !Weapon.IsA('ImpactHammer') )
06534			ChangeToHammer();
06535		else
06536		{
06537			Weapon.SetLocation(Location);
06538			Weapon.AmbientSound = ImpactHammer(Weapon).TensionSound;
06539		}
06540		TweenToWaiting(0.2);
06541		TurnTo(ImpactLook());
06542		CampTime = Level.TimeSeconds;
06543		While ( !Weapon.IsA('ImpactHammer') && (Level.TimeSeconds - Camptime < 2.0) )
06544			Sleep(0.1);
06545		CampTime = 1.0;
06546		Sleep(0.5);
06547		MakeNoise(1.0);	
06548		if ( Physics != PHYS_Falling )
06549		{
06550			Velocity = ImpactTarget.Location - Location;
06551			Velocity.Z = 320;
06552			Velocity = Default.GroundSpeed * Normal(Velocity);
06553			TakeDamage(36.0, self, Location, 69000.0 * 1.5 * vect(0,0,1), Weapon.MyDamageType);
06554		}
06555		GotoState(NextState, NextLabel);
06556	}
06557	
06558	state FallingState 
06559	{
06560	ignores Bump, Hitwall, WarnTarget;
06561	
06562		singular event BaseChange()
06563		{
06564			local actor HitActor;
06565			local vector HitNormal, HitLocation;
06566	
06567			if ( (Base != None) && Base.IsA('Mover')
06568				&& ((MoveTarget == Base) 
06569					|| ((MoveTarget != None) && (MoveTarget == Mover(Base).myMarker))) )
06570			{
06571				MoveTimer = -1.0;
06572				MoveTarget = None;
06573				acceleration = vect(0,0,0);
06574			}
06575			else
06576				Super.BaseChange();
06577		}
06578	
06579		function AnimEnd()
06580		{
06581			PlayInAir();
06582		}
06583	
06584		function ZoneChange(ZoneInfo newZone)
06585		{
06586			Global.ZoneChange(newZone);
06587			if (newZone.bWaterZone)
06588			{
06589				TweenToWaiting(0.15);
06590				GotoState('FallingState', 'Splash');
06591			}
06592		}
06593		
06594		//choose a jump velocity
06595		function adjustJump()
06596		{
06597			local float velZ;
06598			local vector FullVel;
06599	
06600			velZ = Velocity.Z;
06601			FullVel = Normal(Velocity) * GroundSpeed;
06602			Acceleration = vect(0,0,0);
06603			If (Location.Z > Destination.Z + CollisionHeight + 2 * MaxStepHeight)
06604			{
06605				Velocity = FullVel;
06606				Velocity.Z = velZ;
06607				Velocity = EAdjustJump();
06608				Velocity.Z = 0;
06609				if ( VSize(Velocity) < 0.9 * GroundSpeed )
06610				{
06611					Velocity.Z = velZ;
06612					return;
06613				}
06614			}
06615	
06616			PlaySound(JumpSound, SLOT_Talk, 1.5, true, 1200, 1.0 );
06617			Velocity = FullVel;
06618			Velocity.Z = Default.JumpZ + velZ;
06619			Velocity = EAdjustJump();
06620		}
06621	
06622		function TakeDamage( int Damage, Pawn instigatedBy, Vector hitlocation, 
06623								Vector momentum, name damageType)
06624		{
06625			Global.TakeDamage(Damage, instigatedBy, hitlocation, momentum, damageType);
06626	
06627			if (Enemy == None)
06628			{
06629				SetEnemy(instigatedBy);
06630				if ( Enemy != None )
06631				{ 
06632					NextState = 'Attacking'; 
06633					NextLabel = 'Begin';
06634				}
06635			}
06636			if ( (Enemy != None) && (instigatedBy == Enemy) )
06637			{
06638				LastSeenTime = Level.TimeSeconds;
06639				LastSeenPos = Enemy.Location;
06640			}
06641			if (NextState == 'TakeHit')
06642			{
06643				NextState = 'Attacking'; 
06644				NextLabel = 'Begin';
06645				GotoState('TakeHit'); 
06646			}
06647		}
06648	
06649		function bool SetEnemy(Pawn NewEnemy)
06650		{
06651			local bool result;
06652			result = false;
06653			if ( Global.SetEnemy(NewEnemy))
06654			{
06655				result = true;
06656				NextState = 'Attacking'; 
06657				NextLabel = 'Begin';
06658			}
06659			return result;
06660		} 
06661	
06662		function Timer()
06663		{
06664			if ( Enemy != None )
06665			{
06666				bReadyToAttack = true;
06667				if ( CanFireAtEnemy() )
06668					GotoState('FallingState', 'FireWhileFalling');
06669			}
06670		}
06671	
06672		function Landed(vector HitNormal)
06673		{
06674			local vector Vel2D;
06675	
06676			if ( MoveTarget != None )
06677			{
06678				Vel2D = Velocity;
06679				Vel2D.Z = 0;
06680				if ( (Vel2D Dot (MoveTarget.Location - Location)) < 0 )
06681					Acceleration = vect(0,0,0);
06682			}
06683			//Note - physics changes type to PHYS_Walking by default for landed pawns
06684			PlayLanded(Velocity.Z);
06685			TakeFallingDamage();
06686			if (Velocity.Z < -1.4 * JumpZ)
06687			{
06688				if ( health > 0 )
06689					GotoState('FallingState', 'Landed');
06690			}
06691			else 
06692				GotoState('FallingState', 'Done');
06693		}
06694		
06695		function SeePlayer(Actor SeenPlayer)
06696		{
06697			Global.SeePlayer(SeenPlayer);
06698			disable('SeePlayer');
06699			disable('HearNoise');
06700		}
06701	
06702		function EnemyNotVisible()
06703		{
06704			enable('SeePlayer');
06705			enable('HearNoise');
06706		}
06707	
06708		function SetFall()
06709		{
06710			if (!bUpAndOut)
06711				GotoState('FallingState');
06712		}
06713		
06714		function EnemyAcquired()
06715		{
06716			NextState = 'Acquisition';
06717			NextLabel = 'Begin';
06718		}
06719	
06720		function FindNewJumpDest()
06721		{
06722			local NavigationPoint N, Best;
06723			local float BestRating, Rating;
06724			local vector Dist;
06725	
06726			// look for pathnode below current location and visible
06727			BestRating = 1;
06728			for ( N=Level.NavigationPointList; N!=None; N=N.NextNavigationPoint )
06729				if ( N.Location.Z + 100 < Location.Z )
06730				{
06731					Dist = Location - N.Location;
06732					Rating = Dist.Z * Dist.Z/(Dist.X * Dist.X + Dist.Y * Dist.Y); 
06733					if ( (Rating > BestRating) && FastTrace(N.Location, Location) )
06734					{
06735						BestRating = Rating;
06736						Best = N;
06737					}
06738				}
06739					
06740	
06741			if ( Best != None )
06742				Destination = Best.Location;
06743		}
06744	
06745		function BeginState()
06746		{
06747			if (Enemy == None)
06748				Disable('EnemyNotVisible');
06749			else
06750			{
06751				Disable('HearNoise');
06752				Disable('SeePlayer');
06753			}
06754			if ( (bFire > 0) || (bAltFire > 0) || (Skill == 3) )
06755				SetTimer(0.01, false);
06756		}
06757	
06758		function EndState()
06759		{
06760			//log(self$" left falling state ");
06761			bUpAndOut = false;
06762			bJumpOffPawn = false;
06763			bBigJump = false;
06764			if ( bImpactJumping )
06765			{
06766				bImpactJumping = false;
06767				SwitchToBestWeapon();
06768			}
06769			if ( (MoveTarget != None) && (MoveTarget.Location.Z - Location.Z > 256) )
06770				MoveTarget = None;
06771		}
06772	
06773	FireWhileFalling:
06774		Disable('HearNoise');
06775		Disable('SeePlayer');
06776		if ( Physics != PHYS_Falling )
06777			Goto('Done');
06778		if ( Enemy == None )
06779			Goto('LongFall');
06780		TurnToward(Enemy);
06781		if ( CanFireAtEnemy() )
06782			FireWeapon();
06783		if ( Region.Zone.ZoneGravity.Z > Region.Zone.Default.ZoneGravity.Z )
06784		{
06785			if ( (Velocity.Z < 0) && (Destination.Z > Location.Z + MaxStepHeight + CollisionHeight) )
06786				FindNewJumpDest();			
06787			StrafeFacing(Destination, Enemy);
06788		}
06789		else
06790			Sleep(0.5 + 0.2 * FRand());
06791		if ( LineOfSightTo(Enemy) )
06792			Goto('FireWhileFalling');
06793	 			
06794	LongFall:
06795		if ( (Region.Zone.ZoneGravity.Z > Region.Zone.Default.ZoneGravity.Z)
06796			&& (Velocity.Z < 0) && (Destination.Z > Location.Z + MaxStepHeight + CollisionHeight) )
06797		{
06798			FindNewJumpDest();
06799			MoveTo(Destination);
06800		}			
06801		if ( bCanFly )
06802		{
06803			SetPhysics(PHYS_Flying);
06804			Goto('Done');
06805		}
06806		Sleep(0.7);
06807		if ( Enemy != None )
06808		{
06809			TurnToward(Enemy);
06810			if ( CanFireAtEnemy() )
06811			{
06812				PlayRangedAttack();
06813			}
06814		}
06815		if ( (Velocity.Z > -150) && (Region.Zone.ZoneGravity.Z <= Region.Zone.Default.ZoneGravity.Z) ) //stuck
06816		{
06817			SetPhysics(PHYS_Falling);
06818			if ( Enemy != None )
06819				Velocity = groundspeed * normal(Enemy.Location - Location);
06820			else
06821				Velocity = groundspeed * VRand();
06822	
06823			Velocity.Z = FMax(JumpZ, 250);
06824		}
06825		Goto('LongFall');	
06826	
06827	Landed:
06828		//log("Playing"@animsequence@"at"@animframe);
06829		Disable('AnimEnd');
06830		FinishAnim();
06831		//log("Finished"@animsequence@"at"@animframe);
06832	Done:
06833		//log("After fall"@NextState@NextLabel);
06834		if ( NextAnim == '' )
06835		{
06836			bUpAndOut = false;
06837			if ( (NextState != '') && (NextState != 'FallingState') )
06838				GotoState(NextState, NextLabel);
06839			else 
06840				GotoState('Attacking');
06841		}
06842		if ( !bUpAndOut )
06843		{
06844			if ( NextAnim == 'Fighter' )
06845				TweenToFighter(0.2);
06846			else
06847				TweenAnim(NextAnim, 0.12);
06848		} 
06849	
06850	Splash:
06851		bUpAndOut = false;
06852		if ( NextState != '' )
06853			GotoState(NextState, NextLabel);
06854		else 
06855			GotoState('Attacking');
06856				
06857	Begin:
06858		if (Enemy == None)
06859			Disable('EnemyNotVisible');
06860		else
06861		{
06862			Disable('HearNoise');
06863			Disable('SeePlayer');
06864		}
06865		if ( !bUpAndOut ) // not water jump
06866		{	
06867			if ( Region.Zone.bWaterZone )
06868			{
06869				SetPhysics(PHYS_Swimming);
06870				GotoState(NextState, NextLabel);
06871			}	
06872			if ( !bJumpOffPawn )
06873				AdjustJump();
06874	PlayFall:
06875			if ( (Velocity.Z > 300) && (MoveTarget != None)
06876				&& ((FRand() < 0.13) || ((Region.Zone.ZoneGravity.Z > Region.Zone.Default.ZoneGravity.Z) && (FRand() < 0.2)))
06877				&& (VSize(Destination - Location) > 160)
06878				&& ((Vector(Rotation) Dot (Destination - Location)) > 0) )
06879				PlayFlip();
06880			else
06881				TweenToFalling();
06882		}
06883		if (Physics != PHYS_Falling)
06884			Goto('Done');
06885		if ( !bNovice && (Enemy != None) && (Region.Zone.ZoneGravity.Z > Region.Zone.Default.ZoneGravity.Z) )
06886		{
06887			Acceleration = AccelRate * Normal(Destination - Location);
06888			Goto('FireWhileFalling');
06889		}
06890	
06891		if ( bJumpOffPawn )
06892		{
06893			if ( bBigJump )
06894			{
06895				While( bBigJump )
06896				{
06897					Sleep(0.25);
06898					Acceleration = AccelRate * Normal(Destination - Location);
06899				}
06900			}
06901			else
06902			{
06903				Sleep(0.2);
06904				While ( (Abs(Velocity.X) < 60) && (Abs(Velocity.Y) < 60) )
06905					Sleep(0.1);
06906				Acceleration = vect(0,0,0);
06907				Sleep(1.5);
06908			}
06909			bBigJump = false;
06910			bJumpOffPawn = false;
06911		}
06912		else
06913			Sleep(2);
06914	
06915		Goto('LongFall');
06916	
06917	Ducking:
06918		if ( Region.Zone.ZoneGravity.Z > Region.Zone.Default.ZoneGravity.Z )
06919		{
06920			Acceleration = AccelRate * Normal(Destination - Location);
06921			if ( bNovice )
06922				Sleep(0.4);
06923			PlayInAir();
06924			if ( Enemy != None )
06925				Goto('FireWhileFalling');
06926		}
06927	}
06928	
06929	state RangedAttack
06930	{
06931	ignores SeePlayer, HearNoise, Bump;
06932	
06933		function TakeDamage( int Damage, Pawn instigatedBy, Vector hitlocation, 
06934							Vector momentum, name damageType)
06935		{
06936			Global.TakeDamage(Damage, instigatedBy, hitlocation, momentum, damageType);
06937			if ( health <= 0 )
06938				return;
06939			if (NextState == 'TakeHit')
06940			{
06941				NextState = 'RangedAttack';
06942				NextLabel = 'Begin';
06943			}
06944		}
06945	
06946		function StopFiring()
06947		{
06948			Super.StopFiring();
06949			GotoState('Attacking');
06950		}
06951	
06952		function StopWaiting()
06953		{
06954			Timer();
06955		}
06956	
06957		function EnemyNotVisible()
06958		{
06959			////log("enemy not visible");
06960			//let attack animation complete
06961			if ( bComboPaused || bFiringPaused )
06962				return;
06963			if ( (Weapon == None) || Weapon.bMeleeWeapon
06964				|| (FRand() < 0.13) )
06965			{
06966				bReadyToAttack = true;
06967				GotoState('Attacking');
06968				return;
06969			}
06970		}
06971	
06972		function KeepAttacking()
06973		{
06974			local TranslocatorTarget T;
06975			local int BaseSkill;
06976	
06977			if ( bComboPaused || bFiringPaused )
06978			{
06979				if ( TimerRate <= 0.0 )
06980				{
06981					TweenToRunning(0.12);
06982					GotoState(NextState, NextLabel);
06983				}
06984				if ( bComboPaused )
06985					return;
06986	
06987				T = TranslocatorTarget(Target);
06988				if ( (T != None) && !T.Disrupted() && LineOfSightTo(T) )
06989					return;
06990				if ( (Enemy == None) || (Enemy.Health <= 0) || !LineOfSightTo(Enemy) )
06991				{
06992					bFire = 0;
06993					bAltFire = 0; 
06994					TweenToRunning(0.12);
06995					GotoState(NextState, NextLabel);
06996				}
06997			}
06998			if ( (Enemy == None) || (Enemy.Health <= 0) || !LineOfSightTo(Enemy) )
06999			{
07000				bFire = 0;
07001				bAltFire = 0; 
07002				GotoState('Attacking');
07003				return;
07004			}
07005			if ( (Weapon != None) && Weapon.bMeleeWeapon )
07006			{
07007				bReadyToAttack = true;
07008				GotoState('TacticalMove');
07009				return;
07010			}
07011			BaseSkill = Skill;
07012			if ( !bNovice )
07013				BaseSkill += 3;
07014			if ( (Enemy.Weapon != None) && Enemy.Weapon.bMeleeWeapon 
07015				&& (VSize(Enemy.Location - Location) < 500) )
07016				BaseSkill += 3;
07017			if ( (BaseSkill > 3 * FRand() + 2)
07018				|| ((bFire == 0) && (bAltFire == 0) && (BaseSkill > 6 * FRand() - 1)) )
07019			{
07020				bReadyToAttack = true;
07021				GotoState('TacticalMove');
07022			}
07023		}
07024	
07025		function Timer()
07026		{
07027			if ( bComboPaused || bFiringPaused )
07028			{
07029				TweenToRunning(0.12);
07030				GotoState(NextState, NextLabel);
07031			}
07032		}
07033	
07034		function AnimEnd()
07035		{
07036			local float decision;
07037	
07038			if ( (Weapon == None) || Weapon.bMeleeWeapon
07039				|| ((bFire == 0) && (bAltFire == 0)) )
07040			{
07041				GotoState('Attacking');
07042				return;
07043			}
07044			decision = FRand() - 0.2 * skill;
07045			if ( !bNovice )
07046				decision -= 0.5;
07047			if ( decision < 0 )
07048				GotoState('RangedAttack', 'DoneFiring');
07049			else
07050			{
07051				PlayWaiting();
07052				FireWeapon();
07053			}
07054		}
07055		
07056		// ASMD combo move
07057		function SpecialFire()
07058		{
07059			if ( Enemy == None )
07060				return;
07061			bComboPaused = true;
07062			SetTimer(0.75 + VSize(Enemy.Location - Location)/Weapon.AltProjectileSpeed, false);
07063			SpecialPause = 0.0;
07064			NextState = 'Attacking';
07065			NextLabel = 'Begin'; 
07066		}
07067		
07068		function BeginState()
07069		{
07070			Disable('AnimEnd');
07071			if ( bComboPaused || bFiringPaused )
07072			{
07073				SetTimer(SpecialPause, false);
07074				SpecialPause = 0;
07075			}
07076			else
07077				Target = Enemy;
07078		}
07079		
07080		function EndState()
07081		{
07082			bFiringPaused = false;
07083			bComboPaused = false;
07084		}
07085	
07086	Challenge:
07087		Disable('AnimEnd');
07088		Acceleration = vect(0,0,0); //stop
07089		DesiredRotation = Rotator(Enemy.Location - Location);
07090		PlayChallenge();
07091		FinishAnim();
07092		TweenToFighter(0.1);
07093		Goto('FaceTarget');
07094	
07095	Begin:
07096		if ( Target == None )
07097		{
07098			Target = Enemy;
07099			if ( Target == None )
07100				GotoState('Attacking');
07101		}
07102		Acceleration = vect(0,0,0); //stop
07103		DesiredRotation = Rotator(Target.Location - Location);
07104		TweenToFighter(0.16 - 0.2 * Skill);
07105		
07106	FaceTarget:
07107		Disable('AnimEnd');
07108		if ( NeedToTurn(Target.Location) )
07109		{
07110			PlayTurning();
07111			TurnToward(Target);
07112			TweenToFighter(0.1);
07113		}
07114		FinishAnim();
07115	
07116	ReadyToAttack:
07117		DesiredRotation = Rotator(Target.Location - Location);
07118		PlayRangedAttack();
07119		if ( Weapon.bMeleeWeapon )
07120			GotoState('Attacking');
07121		Enable('AnimEnd');
07122	Firing:
07123		if ( Target == None )
07124			GotoState('Attacking');
07125		TurnToward(Target);
07126		Goto('Firing');
07127	DoneFiring:
07128		Disable('AnimEnd');
07129		KeepAttacking();  
07130		Goto('FaceTarget');
07131	}
07132	
07133	state VictoryDance
07134	{
07135	ignores EnemyNotVisible; 
07136	
07137		function TakeDamage( int Damage, Pawn instigatedBy, Vector hitlocation, 
07138								Vector momentum, name damageType)
07139		{
07140			Global.TakeDamage(Damage, instigatedBy, hitlocation, momentum, damageType);
07141			if ( health <= 0 )
07142				return;
07143			SetEnemy(instigatedBy);
07144			if ( Enemy == None )
07145				return;
07146			if ( NextState == 'TakeHit' )
07147			{
07148				NextState = 'Attacking'; //default
07149				NextLabel = 'Begin';
07150				GotoState('TakeHit'); 
07151			}
07152			else if (health > 0)
07153				GotoState('Attacking');
07154		}
07155	
07156		function EnemyAcquired()
07157		{
07158			GotoState('Acquisition');
07159		}
07160		
07161		function BeginState()
07162		{
07163			SpecialGoal = None;
07164			SpecialPause = 0.0;
07165			SetAlertness(-0.3);
07166		}
07167	
07168	Begin:
07169		Acceleration = vect(0,0,0);
07170		TweenToFighter(0.2);
07171		FinishAnim();
07172		PlayTurning();
07173		TurnToward(Target);
07174		DesiredRotation = rot(0,0,0);
07175		DesiredRotation.Yaw = Rotation.Yaw;
07176		setRotation(DesiredRotation);
07177		TweenToFighter(0.2);
07178		FinishAnim();
07179		PlayVictoryDance();
07180		FinishAnim(); 
07181		WhatToDoNext('Waiting','TurnFromWall');
07182	}
07183	
07184	state GameEnded
07185	{
07186	ignores SeePlayer, EnemyNotVisible, HearNoise, TakeDamage, Died, Bump, Trigger, HitWall, HeadZoneChange, FootZoneChange, ZoneChange, Falling, WarnTarget, PainTimer;
07187	
07188		function SpecialFire()
07189		{
07190		}
07191		function TryToDuck(vector duckDir, bool bReversed)
07192		{
07193		}
07194		function SetFall()
07195		{
07196		}
07197		function LongFall()
07198		{
07199		}
07200		function Killed(pawn Killer, pawn Other, name damageType)
07201		{
07202		}
07203		function ClientDying(name DamageType, vector HitLocation)
07204		{
07205		}
07206	
07207		function BeginState()
07208		{
07209			AnimRate = 0.0;
07210			bFire = 0;
07211			bAltFire = 0;
07212			SimAnim.Y = 0;
07213			SetCollision(false,false,false);
07214			SetPhysics(PHYS_None);
07215			Velocity = vect(0,0,0);
07216		}
07217	}
07218	
07219	state Dying
07220	{
07221	ignores SeePlayer, EnemyNotVisible, HearNoise, Died, Bump, Trigger, HitWall, HeadZoneChange, FootZoneChange, ZoneChange, Falling, WarnTarget, LongFall, SetFall, PainTimer;
07222	
07223		function ReStartPlayer()
07224		{
07225			if( bHidden && Level.Game.RestartPlayer(self) )
07226			{
07227				if ( bNovice )
07228					bDumbDown = ( FRand() < 0.5 );
07229				else
07230					bDumbDown = ( FRand() < 0.35 );
07231				Velocity = vect(0,0,0);
07232				Acceleration = vect(0,0,0);
07233				ViewRotation = Rotation;
07234				ReSetSkill();
07235				SetPhysics(PHYS_Falling);
07236				SetOrders(BotReplicationInfo(PlayerReplicationInfo).RealOrders, BotReplicationInfo(PlayerReplicationInfo).RealOrderGiver, true);
07237				GotoState('Roaming');
07238			}
07239			else if ( !IsInState('GameEnded') )
07240				GotoState('Dying', 'TryAgain');
07241		}
07242		
07243		function TakeDamage( int Damage, Pawn instigatedBy, Vector hitlocation, 
07244								Vector momentum, name damageType)
07245		{
07246			if ( !bHidden )
07247				Super.TakeDamage(Damage, instigatedBy, hitlocation, momentum, damageType);
07248		}
07249		
07250		function BeginState()
07251		{
07252			if ( (Level.NetMode != NM_Standalone) 
07253				&& Level.Game.IsA('DeathMatchPlus')
07254				&& DeathMatchPlus(Level.Game).TooManyBots() )
07255			{
07256				Destroy();
07257				return;
07258			}
07259			SetTimer(0, false);
07260			Enemy = None;
07261			if ( bSniping && (AmbushSpot != None) )
07262				AmbushSpot.taken = false;
07263			AmbushSpot = None;
07264			PointDied = -1000;
07265			bFire = 0;
07266			bAltFire = 0;
07267			bSniping = false;
07268			bKamikaze = false;
07269			bDevious = false;
07270			bDumbDown = false;
07271			BlockedPath = None;
07272			bInitLifeMessage = false;
07273			MyTranslocator = None;
07274		}
07275	
07276	
07277	Begin:
07278		if ( Level.Game.bGameEnded )
07279			GotoState('GameEnded');
07280		Sleep(0.2);
07281		if ( !bHidden )
07282			SpawnCarcass();
07283	TryAgain:
07284		if ( !bHidden )
07285			HidePlayer();
07286		Sleep(0.25 + DeathMatchPlus(Level.Game).SpawnWait(self));
07287		ReStartPlayer();
07288		Goto('TryAgain');
07289	WaitingForStart:
07290		bHidden = true;
07291	}
07292	
07293	state FindAir
07294	{
07295	ignores SeePlayer, HearNoise, Bump;
07296	
07297		function HeadZoneChange(ZoneInfo newHeadZone)
07298		{
07299			Global.HeadZoneChange(newHeadZone);
07300			if (!newHeadZone.bWaterZone)
07301				GotoState('Attacking');
07302		}
07303	
07304		function TakeDamage( int Damage, Pawn instigatedBy, Vector hitlocation, 
07305							Vector momentum, name damageType)
07306		{
07307			Super.TakeDamage(Damage, instigatedBy, hitlocation, momentum, damageType);
07308			if ( health <= 0 )
07309				return;
07310			if ( NextState == 'TakeHit' )
07311			{
07312				NextState = 'FindAir'; 
07313				NextLabel = 'TakeHit';
07314				GotoState('TakeHit'); 
07315			}
07316		}
07317	
07318		function HitWall(vector HitNormal, actor Wall)
07319		{
07320			//change directions
07321			Destination = 200 * (Normal(Destination - Location) + HitNormal);
07322		}
07323	
07324		function AnimEnd() 
07325		{
07326			if (Enemy != None)
07327				PlayCombatMove();
07328			else if ( (Physics == PHYS_Falling) && (Velocity.Z < -300) )
07329				FastInAir();
07330			else
07331				PlayRunning();
07332		}
07333	
07334		function Timer()
07335		{
07336			bReadyToAttack = True;
07337			settimer(0.5, false);
07338		}
07339	
07340		function EnemyNotVisible()
07341		{
07342			////log("enemy not visible");
07343			bReadyToAttack = false;
07344		}
07345	
07346	/* PickDestination()
07347	*/
07348		function PickDestination(bool bNoCharge)
07349		{
07350			Destination = VRand();
07351			Destination.Z = 1;
07352			Destination = Location + 200 * Destination;				
07353		}
07354	
07355	Begin:
07356		//log("Find air");
07357		TweenToRunning(0.2);
07358		Enable('AnimEnd');
07359		PickDestination(false);
07360	
07361	DoMove:	
07362		if ( Enemy == None )
07363			MoveTo(Destination);
07364		else
07365		{
07366			bCanFire = true;
07367			StrafeFacing(Destination, Enemy);	
07368		}
07369		GotoState('Attacking');
07370	
07371	TakeHit:
07372		TweenToRunning(0.12);
07373		Goto('DoMove');
07374	
07375	}
07376	
07377	/* Skin Stuff */
07378	static function GetMultiSkin( Actor SkinActor, out string SkinName, out string FaceName )
07379	{
07380		local string ShortSkinName, FullSkinName, ShortFaceName, FullFaceName;
07381	
07382		FullSkinName  = String(SkinActor.Multiskins[default.FixedSkin]);
07383		ShortSkinName = SkinActor.GetItemName(FullSkinName);
07384	
07385		FullFaceName = String(SkinActor.Multiskins[default.FaceSkin]);
07386		ShortFaceName = SkinActor.GetItemName(FullFaceName);
07387	
07388		SkinName = Left(FullSkinName, Len(FullSkinName) - Len(ShortSkinName)) $ Left(ShortSkinName, 4);
07389		FaceName = Left(FullFaceName, Len(FullFaceName) - Len(ShortFaceName)) $Mid(ShortFaceName, 5);
07390	}
07391	
07392	static function SetMultiSkin(Actor SkinActor, string SkinName, string FaceName, byte TeamNum)
07393	{
07394		local string MeshName, FacePackage, SkinItem, FaceItem, SkinPackage;
07395	
07396		MeshName = SkinActor.GetItemName(string(SkinActor.Mesh));
07397	
07398		SkinItem = SkinActor.GetItemName(SkinName);
07399		FaceItem = SkinActor.GetItemName(FaceName);
07400		FacePackage = Left(FaceName, Len(FaceName) - Len(FaceItem));
07401		SkinPackage = Left(FaceName, Len(SkinName) - Len(SkinItem));
07402	
07403		if(SkinPackage == "")
07404		{
07405			SkinPackage=default.DefaultPackage;
07406			SkinName=SkinPackage$SkinName;
07407		}
07408		if(FacePackage == "")
07409		{
07410			FacePackage=default.DefaultPackage;
07411			FaceName=FacePackage$FaceName;
07412		}
07413		// Set the fixed skin element.  If it fails, go to default skin & no face.
07414		if(!SetSkinElement(SkinActor, default.FixedSkin, SkinName$string(default.FixedSkin+1), default.DefaultSkinName$string(default.FixedSkin+1)))
07415		{
07416			SkinName = default.DefaultSkinName;
07417			FaceName = "";
07418		}
07419	
07420		// Set the face - if it fails, set the default skin for that face element.
07421		SetSkinElement(SkinActor, default.FaceSkin, FacePackage$SkinItem$String(default.FaceSkin+1)$FaceItem, SkinName$String(default.FaceSkin+1));
07422		// Set the team elements
07423		if( TeamNum != 255 )
07424		{
07425			SetSkinElement(SkinActor, default.TeamSkin1, SkinName$string(default.TeamSkin1+1)$"T_"$String(TeamNum), SkinName$string(default.TeamSkin1+1));
07426			SetSkinElement(SkinActor, default.TeamSkin2, SkinName$string(default.TeamSkin2+1)$"T_"$String(TeamNum), SkinName$string(default.TeamSkin2+1));
07427		}
07428		else
07429		{
07430			SetSkinElement(SkinActor, default.TeamSkin1, SkinName$string(default.TeamSkin1+1), "");
07431			SetSkinElement(SkinActor, default.TeamSkin2, SkinName$string(default.TeamSkin2+1), "");
07432		}
07433		// Set the talktexture
07434		if(Pawn(SkinActor) != None)
07435		{
07436			if(FaceName != "")
07437				Pawn(SkinActor).PlayerReplicationInfo.TalkTexture = Texture(DynamicLoadObject(FacePackage$SkinItem$"5"$FaceItem, class'Texture'));
07438			else
07439				Pawn(SkinActor).PlayerReplicationInfo.TalkTexture = None;
07440		}
07441	}
07442	
07443	defaultproperties
07444	{
07445	     CarcassType=Class'Engine.Carcass'
07446	     TimeBetweenAttacks=0.600000
07447	     Aggressiveness=0.300000
07448	     BaseAggressiveness=0.300000
07449	     WalkingSpeed=0.350000
07450	     RefireRate=0.900000
07451	     bLeadTarget=True
07452	     PointDied=-1000.000000
07453	     StatusDoll=Texture'Botpack.Icons.Man'
07454	     StatusBelt=Texture'Botpack.Icons.ManBelt'
07455	     VoicePackMetaClass="BotPack.ChallengeVoicePack"
07456	     bIsPlayer=True
07457	     bCanStrafe=True
07458	     bAutoActivate=True
07459	     bIsMultiSkinned=True
07460	     MeleeRange=40.000000
07461	     GroundSpeed=400.000000
07462	     AirSpeed=400.000000
07463	     AccelRate=2048.000000
07464	     AirControl=0.350000
07465	     SightRadius=5000.000000
07466	     HearingThreshold=0.300000
07467	     BaseEyeHeight=23.000000
07468	     EyeHeight=23.000000
07469	     UnderWaterTime=20.000000
07470	     Intelligence=BRAINS_HUMAN
07471	     Land=Sound'UnrealShare.Generic.Land1'
07472	     WaterStep=Sound'UnrealShare.Generic.LSplash'
07473	     CombatStyle=0.100000
07474	     VoiceType="BotPack.VoiceMaleTwo"
07475	     PlayerReplicationInfoClass=Class'Botpack.BotReplicationInfo'
07476	     bStasis=False
07477	     DrawType=DT_Mesh
07478	     AmbientGlow=17
07479	     LightBrightness=70
07480	     LightHue=40
07481	     LightSaturation=128
07482	     LightRadius=6
07483	     Buoyancy=100.000000
07484	     RotationRate=(Pitch=3072,Yaw=30000,Roll=2048)
07485	     NetPriority=3.000000
07486	}

End Source Code