Engine
Class Pawn

source: e:\games\UnrealTournament\Engine\Classes\Pawn.uc
Core.Object
   |
   +--Engine.Actor
      |
      +--Engine.Pawn
Direct Known Subclasses:Bot, StationaryPawn, PlayerPawn, Scout, MoviePawn, Bots, FlockMasterPawn, FlockPawn, ScriptedPawn

class Pawn
extends Engine.Actor

//============================================================================= // Pawn, the base class of all actors that can be controlled by players or AI. // This is a built-in Unreal class and it shouldn't be modified. //=============================================================================
Variables
 float AvgPhysicsTime
           used for alternating LineOfSight traces
 float BaseEyeHeight
           Base eye height above collision center.
 float DamageScaling
           for queueing states
 class DropWhenKilled
           Either a damagetype name or 'All', 'AllEnvironment' (Burned, Corroded, Frozen)
 float EyeHeight
           Current eye height, adjusted for bobbing and stairs.
 PointRegion FootRegion
           used for alternating LineOfSight traces
 float FovAngle
           X field of view angle in degrees, usually 90.
 PointRegion HeadRegion
           used for alternating LineOfSight traces
 int Health
           Health: 100 = normal maximum
 string MenuName
           Name used for this pawn type in menus (e.g. player selection)
 Actor MoveTarget
           set by movement natives
 float MoveTimer
           used for alternating LineOfSight traces
 string NameArticle
           article used in conjunction with this class (e.g. "a", "an")
 name NextLabel
           for queueing states
 name NextState
           for queueing states
 float OldMessageTime
           to limit frequency of voice messages
 float OrthoZoom
           Orthogonal/map view zoom factor.
 Weapon PendingWeapon
           Will become weapon once current weapon is put down
 Name PlayerReStartState
           for queueing states
 PlayerReplicationInfo PlayerReplicationInfo
           to limit frequency of voice messages
 class PlayerReplicationInfoClass
           to limit frequency of voice messages
 float ReducedDamagePct
           Either a damagetype name or 'All', 'AllEnvironment' (Burned, Corroded, Frozen)
 name ReducedDamageType
           Either a damagetype name or 'All', 'AllEnvironment' (Burned, Corroded, Frozen)
 NavigationPoint RouteCache[16]
           to limit frequency of voice messages
 Inventory SelectedItem
           currently selected inventory item
 string SelectionMesh
           Health: 100 = normal maximum
 Decal Shadow
           to limit frequency of voice messages
 float SoundDampening
           for queueing states
 string SpecialMesh
           Health: 100 = normal maximum
 float SplashTime
           time of last splash
 SecretCount, Spree
           X field of view angle in degrees, usually 90.
 rotator ViewRotation
           View rotation.
 byte Visibility
           How visible is the pawn? 0 = invisible.
 byte VoicePitch
           for speech
 string VoiceType
           for speech
 vector WalkBob
           View rotation.
 Weapon Weapon
           The pawn's current weapon.
 bool bBehindView
           Outside-the-player view.
 bool bFromWall
           used for alternating LineOfSight traces
 bool bHitSlopedWall
           used by Physics
 bool bIsPlayer
           Pawn is a player or a player-bot.
 bool bIsWalking
           used by swimming
 bool bJustLanded
           used by eyeheight adjustment
 bool bLOSflag
           used for alternating LineOfSight traces
 bool bNeverSwitchOnPickup
           if true, don't automatically switch to picked up weapon
 bool bReducedSpeed
           used by movement natives
 bool bUpAndOut
           used by swimming
 bool bUpdatingDisplay
           to avoid infinite recursion through inventory setdisplay
 bool bWarping
           Set when travelling through warpzone (so shouldn't telefrag)
 input byte
           Either a damagetype name or 'All', 'AllEnvironment' (Burned, Corroded, Frozen)
 NavigationPoint home
           set when begin play, used for retreating and attitude checks
 Pawn nextPawn
           Either a damagetype name or 'All', 'AllEnvironment' (Burned, Corroded, Frozen)
 float noise1loudness
           Either a damagetype name or 'All', 'AllEnvironment' (Burned, Corroded, Frozen)
 Pawn noise1other
           Either a damagetype name or 'All', 'AllEnvironment' (Burned, Corroded, Frozen)
 vector noise1spot
           Either a damagetype name or 'All', 'AllEnvironment' (Burned, Corroded, Frozen)
 float noise1time
           Either a damagetype name or 'All', 'AllEnvironment' (Burned, Corroded, Frozen)
 float noise2loudness
           Either a damagetype name or 'All', 'AllEnvironment' (Burned, Corroded, Frozen)
 Pawn noise2other
           Either a damagetype name or 'All', 'AllEnvironment' (Burned, Corroded, Frozen)
 vector noise2spot
           Either a damagetype name or 'All', 'AllEnvironment' (Burned, Corroded, Frozen)
 float noise2time
           Either a damagetype name or 'All', 'AllEnvironment' (Burned, Corroded, Frozen)

States
GameEnded, Dying

Function Summary
 bool AddInventory(Inventory NewItem)
     
// Add Item to this pawn's inventory. 
// Returns true if successfully added, false if not.
 void AddPawn()
 void AddVelocity(vector NewVelocity)
 rotator AdjustAim(float projSpeed, vector projStart, int aimerror, bool bLeadTarget, bool bWarnTarget)
     
/* AdjustAim()
ScriptedPawn version does adjustment for non-controlled pawns. 
PlayerPawn version does the adjustment for player aiming help.
Only adjusts aiming at pawns
allows more error in Z direction (full as defined by AutoAim - only half that difference for XY)
*/
 float AdjustDesireFor(Inventory Inv)
     
//=============================================================================
// Inventory related functions.
 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 bLeadTarget, bool bWarnTarget)
 void BecomeViewTarget()
     
//
// Client gateway functions.
//
 void BotVoiceMessage(name messagetype, byte MessageID, Pawn Sender)
 bool CanSee(Actor Other)
     
// CanSee() similar to line of sight, but also takes into account Pawn's peripheral vision
 void ChangedWeapon()
     
// Just changed to pendingWeapon
 bool CheckFutureSight(float DeltaTime)
 bool CheckValidSkinPackage(string SkinPack, string MeshName)
 bool CheckWaterJump(out vector)
 void ClearPaths()
 void ClientDying(name DamageType, vector HitLocation)
 void ClientGameEnded()
 void ClientPutDown(Weapon Current, Weapon Next)
 void ClientReStart()
 void ClientSetLocation(vector NewLocation, rotator NewRotation)
 void ClientSetRotation(rotator NewRotation)
 void ClientVoiceMessage(PlayerReplicationInfo Sender, PlayerReplicationInfo Recipient, name messagetype, byte messageID)
 bool DeleteInventory(Inventory Item)
     
// Remove Item from this pawn's inventory, if it exists.
// Returns true if it existed and was deleted, false if it did not exist.
 void Died(Pawn Killer, name damageType, vector HitLocation)
 void DropDecoration()
 vector EAdjustJump()
 void Falling()
 void FearThisSpot(Actor ASpot)
 Actor FindBestInventoryPath(out float, bool bPredictRespawns)
 Inventory FindInventoryType(class DesiredClass)
     
// FindInventoryType()
// returns the inventory item of the requested class
// if it exists in this pawn's inventory 
 Actor FindPathTo(vector aPoint, optional bool, optional bool)
 Actor FindPathToward(Actor anActor, optional bool, optional bool)
 NavigationPoint FindRandomDest(optional bool)
 int FindStairRotation(float DeltaTime)
 void FireWeapon()
 void Gasp()
 String GetHumanName()
 void GetMultiSkin(Actor SkinActor, out string, out string)
 float GetRating()
 bool Gibbed(name damageType)
 void GrabDecoration()
 void HandleHelpMessageFrom(Pawn Other)
     
//***************************************************************
 void HidePlayer()
 void InitPlayerReplicationInfo()
     
//=============================================================================
// Replication
 void JumpOffPawn()
     
//Base change - if new base is pawn or decoration, damage based on relative mass and old velocity
// Also, non-players will jump off pawns immediately
 string KillMessage(name damageType, Pawn Other)
     
//Typically implemented in subclass
 void Killed(Pawn Killer, Pawn Other, name damageType)
     
// for advanced tactics
 bool LineOfSightTo(Actor Other)
     
// native AI functions
//LineOfSightTo() returns true if any of several points of Other is visible 
// (origin, top, bottom)
 void MoveTo(vector NewDestination, optional float)
     
// Latent Movement.
//Note that MoveTo sets the actor's Destination, and MoveToward sets the
//actor's MoveTarget.  Actor will rotate towards destination
 void MoveToward(Actor NewTarget, optional float)
 void NextItem()
     
// The player/bot wants to select next item
 Actor PickAnyTarget(out float, out float, vector FireDir, vector projStart)
 Pawn PickTarget(out float, out float, vector FireDir, vector projStart)
     
// Pick best pawn target
 bool PickWallAdjust()
     
/* PickWallAdjust()
Check if could jump up over obstruction (only if there is a knee height obstruction)
If so, start jump, and return current destination
Else, try to step around - return a destination 90 degrees right or left depending on traces
out and floor checks
*/
 void PlayBigDeath(name DamageType)
 void PlayCrawling()
 void PlayDeathHit(float Damage, vector HitLocation, name damageType, vector Momentum)
 void PlayDive()
 void PlayDuck()
 void PlayDying(name DamageType, vector HitLoc)
 void PlayFiring()
 void PlayGutDeath(name DamageType)
 void PlayGutHit(float tweentime)
 void PlayHeadDeath(name DamageType)
 void PlayHeadHit(float tweentime)
 void PlayHit(float Damage, vector HitLocation, name damageType, vector Momentum)
 void PlayInAir()
 void PlayLanded(float impactVel)
 void PlayLeftDeath(name DamageType)
 void PlayLeftHit(float tweentime)
 void PlayMovingAttack()
 void PlayOutOfWater()
 void PlayPatrolStop()
 void PlayRecoil(float Rate)
 void PlayRightDeath(name DamageType)
 void PlayRightHit(float tweentime)
 void PlayRunning()
     
//=============================================================================
// Animation playing - should be implemented in subclass, 
//
// PlayWaiting, PlayRunning, and PlayGutHit, PlayMovingAttack (if used)
// and PlayDying are required to be implemented in the subclass
 void PlayTakeHit(float tweentime, vector HitLoc, int damage)
 void PlayTakeHitSound(int Damage, name damageType, int Mult)
     
//-----------------------------------------------------------------------------
// Sound functions
 void PlayThreatening()
 void PlayTurning()
 void PlayVictoryDance()
 void PlayWaiting()
 void PlayWaitingAmbush()
 void PlayWalking()
 void PlayWeaponSwitch(Weapon NewWeapon)
 void PreSetMovement()
     
/* PreSetMovement()
default for walking creature.  Re-implement in subclass
for swimming/flying capability
*/
 void RemovePawn()
 void RestartPlayer()
 void SendGlobalMessage(PlayerReplicationInfo Recipient, name MessageType, byte MessageID, float Wait)
     
//------------------------------------------------------------------------------
// Speech related
 void SendTeamMessage(PlayerReplicationInfo Recipient, name MessageType, byte MessageID, float Wait)
 void SendVoiceMessage(PlayerReplicationInfo Sender, PlayerReplicationInfo Recipient, name messagetype, byte messageID, name broadcasttype)
 void SetDefaultDisplayProperties()
 void SetDisplayProperties(ERenderStyle NewStyle, Texture NewTexture, bool bLighting, bool bEnviroMap)
 
simulated
SetMesh()
 void SetMovementPhysics()
 void SetMultiSkin(Actor SkinActor, string SkinName, string FaceName, byte TeamNum)
     
//=============================================================================
// Multiskin support
 bool SetSkinElement(Actor SkinActor, int SkinNo, string SkinName, string DefaultSkinName)
 void ShakeView(float shaketime, float RollMag, float vertmag)
 Carcass SpawnCarcass()
 void SpawnGibbedCarcass()
 void SpecialFire()
 void StopFiring()
 void StopWaiting()
     
// Force end to sleep
 void StrafeFacing(vector NewDestination, Actor NewTarget)
 void StrafeTo(vector NewDestination, vector NewFocus)
 bool SwitchToBestWeapon()
 void TakeDamage(int Damage, Pawn instigatedBy, Vector hitlocation, Vector momentum, name damageType)
 void TakeFallingDamage()
 void TeamBroadcast(string Msg)
     
//
// Broadcast a message to all players, or all on the same team.
//
 void TossWeapon()
     
// toss out the weapon currently held
 Actor TraceShot(out vector, out vector, vector EndTrace, vector StartTrace)
     
/* TraceShot - used by instant hit weapons, and monsters 
*/
 void TurnTo(vector NewFocus)
 void TurnToward(Actor NewTarget)
 void TweenToFalling()
 void TweenToFighter(float tweentime)
 void TweenToPatrolStop(float tweentime)
 void TweenToRunning(float tweentime)
 void TweenToSwimming(float tweentime)
 void TweenToWaiting(float tweentime)
 void TweenToWalking(float tweentime)
 void UnderLift(Mover M)
 void WaitForLanding()
 void WarnTarget(Pawn shooter, float projSpeed, vector FireDir)
 bool actorReachable(Actor anActor)
 void damageAttitudeTo(Pawn Other)
 void gibbedBy(Actor Other)
 bool pointReachable(vector aPoint)
     
//Reachable returns what part of direct path from Actor to aPoint is traversable
//using the current locomotion method


State GameEnded Function Summary
 void BeginState()


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



Source Code


00001	//=============================================================================
00002	// Pawn, the base class of all actors that can be controlled by players or AI.
00003	// This is a built-in Unreal class and it shouldn't be modified.
00004	//=============================================================================
00005	class Pawn extends Actor 
00006		abstract
00007		native
00008		nativereplication;
00009	
00010	#exec Texture Import File=Textures\Pawn.pcx Name=S_Pawn Mips=Off Flags=2
00011	
00012	//-----------------------------------------------------------------------------
00013	// Pawn variables.
00014	
00015	// General flags.
00016	var bool		bBehindView;    // Outside-the-player view.
00017	var bool        bIsPlayer;      // Pawn is a player or a player-bot.
00018	var bool		bJustLanded;	// used by eyeheight adjustment
00019	var bool		bUpAndOut;		// used by swimming 
00020	var bool		bIsWalking;
00021	var const bool	bHitSlopedWall;	// used by Physics
00022	var globalconfig bool	bNeverSwitchOnPickup;	// if true, don't automatically switch to picked up weapon
00023	var bool		bWarping;		// Set when travelling through warpzone (so shouldn't telefrag)
00024	var bool		bUpdatingDisplay; // to avoid infinite recursion through inventory setdisplay
00025	
00026	//AI flags
00027	var(Combat) bool	bCanStrafe;
00028	var(Orders) bool	bFixedStart;
00029	var const bool		bReducedSpeed;		//used by movement natives
00030	var		bool		bCanJump;
00031	var		bool 		bCanWalk;
00032	var		bool		bCanSwim;
00033	var		bool		bCanFly;
00034	var		bool		bCanOpenDoors;
00035	var		bool		bCanDoSpecial;
00036	var		bool		bDrowning;
00037	var const bool		bLOSflag;			// used for alternating LineOfSight traces
00038	var 	bool 		bFromWall;
00039	var		bool		bHunting;			// tells navigation code that pawn is hunting another pawn,
00040											//	so fall back to finding a path to a visible pathnode if none
00041											//	are reachable
00042	var		bool		bAvoidLedges;		// don't get too close to ledges
00043	var		bool		bStopAtLedges;		// if bAvoidLedges and bStopAtLedges, Pawn doesn't try to walk along the edge at all
00044	var		bool		bJumpOffPawn;		
00045	var		bool		bShootSpecial;
00046	var		bool		bAutoActivate;
00047	var		bool		bIsHuman;			// for games which care about whether a pawn is a human
00048	var		bool		bIsFemale;
00049	var		bool		bIsMultiSkinned;
00050	var		bool		bCountJumps;
00051	var		bool		bAdvancedTactics;	// used during movement between pathnodes
00052	var		bool		bViewTarget;
00053	
00054	// Ticked pawn timers
00055	var		float		SightCounter;	//Used to keep track of when to check player visibility
00056	var		float       PainTime;		//used for getting PainTimer() messages (for Lava, no air, etc.)
00057	var		float		SpeechTime;	
00058	
00059	// Physics updating time monitoring (for AI monitoring reaching destinations)
00060	var const	float		AvgPhysicsTime;
00061	
00062	// Additional pawn region information.
00063	var PointRegion FootRegion;
00064	var PointRegion HeadRegion;
00065	
00066	// Navigation AI
00067	var 	float		MoveTimer;
00068	var 	Actor		MoveTarget;		// set by movement natives
00069	var		Actor		FaceTarget;		// set by strafefacing native
00070	var		vector	 	Destination;	// set by Movement natives
00071	var	 	vector		Focus;			// set by Movement natives
00072	var		float		DesiredSpeed;
00073	var		float		MaxDesiredSpeed;
00074	var(Combat) float	MeleeRange; // Max range for melee attack (not including collision radii)
00075	
00076	// Player and enemy movement.
00077	var(Movement) float      GroundSpeed;     // The maximum ground speed.
00078	var(Movement) float      WaterSpeed;      // The maximum swimming speed.
00079	var(Movement) float      AirSpeed;        // The maximum flying speed.
00080	var(Movement) float		 AccelRate;		  // max acceleration rate
00081	var(Movement) float		 JumpZ;      		// vertical acceleration w/ jump
00082	var(Movement) float      MaxStepHeight;   // Maximum size of upward/downward step.
00083	var(Movement) float      AirControl;		// amount of AirControl available to the pawn
00084	
00085	// AI basics.
00086	var	 	float		MinHitWall;		// Minimum HitNormal dot Velocity.Normal to get a HitWall from the
00087										// physics
00088	var() 	byte       	Visibility;      //How visible is the pawn? 0 = invisible. 
00089										// 128 = normal.  255 = highly visible.
00090	var		float		Alertness; // -1 to 1 ->Used within specific states for varying reaction to stimuli 
00091	var		float 		Stimulus; // Strength of stimulus - Set when stimulus happens, used in Acquisition state 
00092	var(AI) float		SightRadius;     //Maximum seeing distance.
00093	var(AI) float		PeripheralVision;//Cosine of limits of peripheral vision.
00094	var(AI) float		HearingThreshold;  //Minimum noise loudness for hearing
00095	var		vector		LastSeenPos; 		// enemy position when I last saw enemy (auto updated if EnemyNotVisible() enabled)
00096	var		vector		LastSeeingPos;		// position where I last saw enemy (auto updated if EnemyNotVisible enabled)
00097	var		float		LastSeenTime;
00098	var	 	Pawn    	Enemy;
00099	
00100	// Player info.
00101	var travel Weapon       Weapon;        // The pawn's current weapon.
00102	var Weapon				PendingWeapon;	// Will become weapon once current weapon is put down
00103	var travel Inventory	SelectedItem;	// currently selected inventory item
00104	
00105	// Movement.
00106	var rotator     	ViewRotation;  	// View rotation.
00107	var vector			WalkBob;
00108	var() float      	BaseEyeHeight; 	// Base eye height above collision center.
00109	var float        	EyeHeight;     	// Current eye height, adjusted for bobbing and stairs.
00110	var	const	vector	Floor;			// Normal of floor pawn is standing on (only used
00111										//	by PHYS_Spider)
00112	var float			SplashTime;		// time of last splash
00113	
00114	// View
00115	var float        OrthoZoom;     // Orthogonal/map view zoom factor.
00116	var() float      FovAngle;      // X field of view angle in degrees, usually 90.
00117	
00118	// Player game statistics.
00119	var int			DieCount, ItemCount, KillCount, SecretCount, Spree;
00120	
00121	//Health
00122	var() travel int      Health;          // Health: 100 = normal maximum
00123	
00124	// Selection Mesh
00125	var() string			SelectionMesh;
00126	var() string			SpecialMesh;
00127	
00128	// Inherent Armor (for creatures).
00129	var() name	ReducedDamageType; //Either a damagetype name or 'All', 'AllEnvironment' (Burned, Corroded, Frozen)
00130	var() float ReducedDamagePct;
00131	
00132	// Inventory to drop when killed (for creatures)
00133	var() class<inventory> DropWhenKilled;
00134	
00135	// Zone pain
00136	var(Movement) float		UnderWaterTime;  	//how much time pawn can go without air (in seconds)
00137	
00138	var(AI) enum EAttitude  //important - order in decreasing importance
00139	{
00140		ATTITUDE_Fear,		//will try to run away
00141		ATTITUDE_Hate,		// will attack enemy
00142		ATTITUDE_Frenzy,	//will attack anything, indiscriminately
00143		ATTITUDE_Threaten,	// animations, but no attack
00144		ATTITUDE_Ignore,
00145		ATTITUDE_Friendly,
00146		ATTITUDE_Follow 	//accepts player as leader
00147	} AttitudeToPlayer;	//determines how creature will react on seeing player (if in human form)
00148	
00149	var(AI) enum EIntelligence //important - order in increasing intelligence
00150	{
00151		BRAINS_NONE, //only reacts to immediate stimulus
00152		BRAINS_REPTILE, //follows to last seen position
00153		BRAINS_MAMMAL, //simple navigation (limited path length)
00154		BRAINS_HUMAN   //complex navigation, team coordination, use environment stuff (triggers, etc.)
00155	}	Intelligence;
00156	
00157	var(AI) float		Skill;			// skill, scaled by game difficulty (add difficulty to this value)	
00158	var		actor		SpecialGoal;	// used by navigation AI
00159	var		float		SpecialPause;
00160	
00161	// Sound and noise management
00162	var const 	vector 		noise1spot;
00163	var const 	float 		noise1time;
00164	var const	pawn		noise1other;
00165	var const	float		noise1loudness;
00166	var const 	vector 		noise2spot;
00167	var const 	float 		noise2time;
00168	var const	pawn		noise2other;
00169	var const	float		noise2loudness;
00170	var			float		LastPainSound;
00171	
00172	// chained pawn list
00173	var const	pawn		nextPawn;
00174	
00175	// Common sounds
00176	var(Sounds)	sound	HitSound1;
00177	var(Sounds)	sound	HitSound2;
00178	var(Sounds)	sound	Land;
00179	var(Sounds)	sound	Die;
00180	var(Sounds) sound	WaterStep;
00181	
00182	// Input buttons.
00183	var input byte
00184		bZoom, bRun, bLook, bDuck, bSnapLevel,
00185		bStrafe, bFire, bAltFire, bFreeLook, 
00186		bExtra0, bExtra1, bExtra2, bExtra3;
00187	
00188	var(Combat) float CombatStyle; // -1 to 1 = low means tends to stay off and snipe, high means tends to charge and melee
00189	var NavigationPoint home; //set when begin play, used for retreating and attitude checks
00190	 
00191	var name NextState; //for queueing states
00192	var name NextLabel; //for queueing states
00193	
00194	var float SoundDampening;
00195	var float DamageScaling;
00196	
00197	var(Orders) name AlarmTag; // tag of object to go to when see player
00198	var(Orders) name SharedAlarmTag;
00199	var	Decoration	carriedDecoration;
00200	
00201	var Name PlayerReStartState;
00202	
00203	var() localized  string MenuName; //Name used for this pawn type in menus (e.g. player selection) 
00204	var() localized  string NameArticle; //article used in conjunction with this class (e.g. "a", "an")
00205	
00206	var() byte VoicePitch; //for speech
00207	var() string VoiceType; //for speech
00208	var float OldMessageTime; //to limit frequency of voice messages
00209	
00210	// Route Cache for Navigation
00211	var NavigationPoint RouteCache[16];
00212	
00213	// Replication Info
00214	var() class<PlayerReplicationInfo> PlayerReplicationInfoClass;
00215	var PlayerReplicationInfo PlayerReplicationInfo;
00216	
00217	// shadow decal
00218	var Decal Shadow;
00219	
00220	replication
00221	{
00222		// Variables the server should send to the client.
00223		reliable if( Role==ROLE_Authority )
00224			Weapon, PlayerReplicationInfo, Health, bCanFly;
00225		reliable if( bNetOwner && Role==ROLE_Authority )
00226			 bIsPlayer, CarriedDecoration, SelectedItem,
00227			 GroundSpeed, WaterSpeed, AirSpeed, AccelRate, JumpZ, AirControl,
00228			 bBehindView, PlayerRestartState;
00229		unreliable if( (bNetOwner && bIsPlayer && bNetInitial && Role==ROLE_Authority) || bDemoRecording )
00230			ViewRotation;
00231		unreliable if( bNetOwner && Role==ROLE_Authority )
00232	         MoveTarget;
00233		reliable if( bDemoRecording )
00234			EyeHeight;
00235	
00236		// Functions the server calls on the client side.
00237		reliable if( RemoteRole==ROLE_AutonomousProxy ) 
00238			ClientDying, ClientReStart, ClientGameEnded, ClientSetRotation, ClientSetLocation, ClientPutDown;
00239		unreliable if( (!bDemoRecording || bClientDemoRecording && bClientDemoNetFunc) && Role==ROLE_Authority )
00240			ClientHearSound;
00241		reliable if ( (!bDemoRecording || (bClientDemoRecording && bClientDemoNetFunc)) && Role == ROLE_Authority )
00242			ClientVoiceMessage;
00243		reliable if ( (!bDemoRecording || (bClientDemoRecording && bClientDemoNetFunc) || (Level.NetMode==NM_Standalone && IsA('PlayerPawn'))) && Role == ROLE_Authority )
00244			ClientMessage, TeamMessage, ReceiveLocalizedMessage;
00245	
00246		// Functions the client calls on the server.
00247		unreliable if( Role<ROLE_Authority )
00248			SendVoiceMessage, NextItem, SwitchToBestWeapon, TeamBroadcast;
00249	}
00250	
00251	// Latent Movement.
00252	//Note that MoveTo sets the actor's Destination, and MoveToward sets the
00253	//actor's MoveTarget.  Actor will rotate towards destination
00254	
00255	native(500) final latent function MoveTo( vector NewDestination, optional float speed);
00256	native(502) final latent function MoveToward(actor NewTarget, optional float speed);
00257	native(504) final latent function StrafeTo(vector NewDestination, vector NewFocus);
00258	native(506) final latent function StrafeFacing(vector NewDestination, actor NewTarget);
00259	native(508) final latent function TurnTo(vector NewFocus);
00260	native(510) final latent function TurnToward(actor NewTarget);
00261	
00262	// native AI functions
00263	//LineOfSightTo() returns true if any of several points of Other is visible 
00264	// (origin, top, bottom)
00265	native(514) final function bool LineOfSightTo(actor Other); 
00266	// CanSee() similar to line of sight, but also takes into account Pawn's peripheral vision
00267	native(533) final function bool CanSee(actor Other); 
00268	native(518) final function Actor FindPathTo(vector aPoint, optional bool bSinglePath, 
00269													optional bool bClearPaths);
00270	native(517) final function Actor FindPathToward(actor anActor, optional bool bSinglePath, 
00271													optional bool bClearPaths);
00272	
00273	native(525) final function NavigationPoint FindRandomDest(optional bool bClearPaths);
00274	
00275	native(522) final function ClearPaths();
00276	native(523) final function vector EAdjustJump();
00277	
00278	//Reachable returns what part of direct path from Actor to aPoint is traversable
00279	//using the current locomotion method
00280	native(521) final function bool pointReachable(vector aPoint);
00281	native(520) final function bool actorReachable(actor anActor);
00282	
00283	/* PickWallAdjust()
00284	Check if could jump up over obstruction (only if there is a knee height obstruction)
00285	If so, start jump, and return current destination
00286	Else, try to step around - return a destination 90 degrees right or left depending on traces
00287	out and floor checks
00288	*/
00289	native(526) final function bool PickWallAdjust();
00290	native(524) final function int FindStairRotation(float DeltaTime);
00291	native(527) final latent function WaitForLanding();
00292	native(540) final function actor FindBestInventoryPath(out float MinWeight, bool bPredictRespawns);
00293	
00294	native(529) final function AddPawn();
00295	native(530) final function RemovePawn();
00296	
00297	// Pick best pawn target
00298	native(531) final function pawn PickTarget(out float bestAim, out float bestDist, vector FireDir, vector projStart);
00299	native(534) final function actor PickAnyTarget(out float bestAim, out float bestDist, vector FireDir, vector projStart);
00300	
00301	// Force end to sleep
00302	native function StopWaiting();
00303	
00304	native static final function bool CheckValidSkinPackage(string SkinPack, string MeshName);
00305	
00306	event MayFall(); //return true if allowed to fall - called by engine when pawn is about to fall
00307	event AlterDestination(); // called when using movetoward with bAdvancedTactics true to temporarily modify destination
00308	
00309	simulated event RenderOverlays( canvas Canvas )
00310	{
00311		if ( Weapon != None )
00312			Weapon.RenderOverlays(Canvas);
00313	}
00314	
00315	function String GetHumanName()
00316	{
00317		if ( PlayerReplicationInfo != None )
00318			return PlayerReplicationInfo.PlayerName;
00319		return NameArticle$MenuName;
00320	}
00321	
00322	function ClientPutDown(Weapon Current, Weapon Next)
00323	{
00324		Current.ClientPutDown(Next);
00325	}
00326	
00327	function SetDisplayProperties(ERenderStyle NewStyle, texture NewTexture, bool bLighting, bool bEnviroMap )
00328	{
00329		Style = NewStyle;
00330		texture = NewTexture;
00331		bUnlit = bLighting;
00332		bMeshEnviromap = bEnviromap;
00333		if ( Weapon != None )
00334			Weapon.SetDisplayProperties(Style, Texture, bUnlit, bMeshEnviromap);
00335	
00336		if ( !bUpdatingDisplay && (Inventory != None) )
00337		{
00338			bUpdatingDisplay = true;
00339			Inventory.SetOwnerDisplay();
00340		}
00341		bUpdatingDisplay = false;
00342	}
00343	
00344	function SetDefaultDisplayProperties()
00345	{
00346		Style = Default.Style;
00347		texture = Default.Texture;
00348		bUnlit = Default.bUnlit;
00349		bMeshEnviromap = Default.bMeshEnviromap;
00350		if ( Weapon != None )
00351			Weapon.SetDisplayProperties(Weapon.Default.Style, Weapon.Default.Texture, Weapon.Default.bUnlit, Weapon.Default.bMeshEnviromap);
00352	
00353		if ( !bUpdatingDisplay && (Inventory != None) )
00354		{
00355			bUpdatingDisplay = true;
00356			Inventory.SetOwnerDisplay();
00357		}
00358		bUpdatingDisplay = false;
00359	}
00360	
00361	//
00362	// Client gateway functions.
00363	//
00364	event ClientMessage( coerce string S, optional name Type, optional bool bBeep );
00365	event TeamMessage( PlayerReplicationInfo PRI, coerce string S, name Type, optional bool bBeep );
00366	event ReceiveLocalizedMessage( class<LocalMessage> Message, optional int Switch, optional PlayerReplicationInfo RelatedPRI_1, optional PlayerReplicationInfo RelatedPRI_2, optional Object OptionalObject );
00367	
00368	function BecomeViewTarget()
00369	{
00370		bViewTarget = true;
00371	}
00372	
00373	event FellOutOfWorld()
00374	{
00375		if ( Role < ROLE_Authority )
00376			return;
00377		Health = -1;
00378		SetPhysics(PHYS_None);
00379		Weapon = None;
00380		Died(None, 'Fell', Location);
00381	}
00382	
00383	function PlayRecoil(float Rate);
00384	
00385	function SpecialFire();
00386	
00387	function bool CheckFutureSight(float DeltaTime)
00388	{
00389		return true;
00390	}
00391	
00392	function RestartPlayer();
00393	
00394	//
00395	// Broadcast a message to all players, or all on the same team.
00396	//
00397	function TeamBroadcast( coerce string Msg)
00398	{
00399		local Pawn P;
00400		local bool bGlobal;
00401	
00402		if ( Left(Msg, 1) ~= "@" )
00403		{
00404			Msg = Right(Msg, Len(Msg)-1);
00405			bGlobal = true;
00406		}
00407	
00408		if ( Left(Msg, 1) ~= "." )
00409			Msg = "."$VoicePitch$Msg;
00410	
00411		if ( bGlobal || !Level.Game.bTeamGame )
00412		{
00413			if ( Level.Game.AllowsBroadcast(self, Len(Msg)) )
00414				for( P=Level.PawnList; P!=None; P=P.nextPawn )
00415					if( P.bIsPlayer  || P.IsA('MessagingSpectator') )
00416						P.TeamMessage( PlayerReplicationInfo, Msg, 'Say' );
00417			return;
00418		}
00419			
00420		if ( Level.Game.AllowsBroadcast(self, Len(Msg)) )
00421			for( P=Level.PawnList; P!=None; P=P.nextPawn )
00422				if( P.bIsPlayer && (P.PlayerReplicationInfo.Team == PlayerReplicationInfo.Team) )
00423				{
00424					if ( P.IsA('PlayerPawn') )
00425						P.TeamMessage( PlayerReplicationInfo, Msg, 'TeamSay' );
00426				}
00427	}
00428	
00429	//------------------------------------------------------------------------------
00430	// Speech related
00431	
00432	function SendGlobalMessage(PlayerReplicationInfo Recipient, name MessageType, byte MessageID, float Wait)
00433	{
00434		SendVoiceMessage(PlayerReplicationInfo, Recipient, MessageType, MessageID, 'GLOBAL');
00435	}
00436	
00437	
00438	function SendTeamMessage(PlayerReplicationInfo Recipient, name MessageType, byte MessageID, float Wait)
00439	{
00440		SendVoiceMessage(PlayerReplicationInfo, Recipient, MessageType, MessageID, 'TEAM');
00441	}
00442	
00443	function SendVoiceMessage(PlayerReplicationInfo Sender, PlayerReplicationInfo Recipient, name messagetype, byte messageID, name broadcasttype)
00444	{
00445		local Pawn P;
00446		local bool bNoSpeak;
00447	
00448		if ( Level.TimeSeconds - OldMessageTime < 2.5 )
00449			bNoSpeak = true;
00450		else
00451			OldMessageTime = Level.TimeSeconds;
00452	
00453		for ( P=Level.PawnList; P!=None; P=P.NextPawn )
00454		{
00455			if ( P.IsA('PlayerPawn') )
00456			{  
00457				if ( !bNoSpeak )
00458				{
00459					if ( (broadcasttype == 'GLOBAL') || !Level.Game.bTeamGame )
00460						P.ClientVoiceMessage(Sender, Recipient, messagetype, messageID);
00461					else if ( Sender.Team == P.PlayerReplicationInfo.Team )
00462						P.ClientVoiceMessage(Sender, Recipient, messagetype, messageID);
00463				}
00464			}
00465			else if ( (P.PlayerReplicationInfo == Recipient) || ((messagetype == 'ORDER') && (Recipient == None)) )
00466				P.BotVoiceMessage(messagetype, messageID, self);
00467		}
00468	}
00469	
00470	function ClientVoiceMessage(PlayerReplicationInfo Sender, PlayerReplicationInfo Recipient, name messagetype, byte messageID);
00471	function BotVoiceMessage(name messagetype, byte MessageID, Pawn Sender);
00472	
00473	//***************************************************************
00474	function HandleHelpMessageFrom(Pawn Other);
00475	
00476	function FearThisSpot(Actor ASpot);
00477	
00478	function float GetRating()
00479	{
00480		return 1000;
00481	}
00482	
00483	function AddVelocity( vector NewVelocity)
00484	{
00485		if (Physics == PHYS_Walking)
00486			SetPhysics(PHYS_Falling);
00487		if ( (Velocity.Z > 380) && (NewVelocity.Z > 0) )
00488			NewVelocity.Z *= 0.5;
00489		Velocity += NewVelocity;
00490	}
00491	
00492	function ClientSetLocation( vector NewLocation, rotator NewRotation )
00493	{
00494		local Pawn P;
00495	
00496		ViewRotation      = NewRotation;
00497		If ( (ViewRotation.Pitch > RotationRate.Pitch) && (ViewRotation.Pitch < 65536 - RotationRate.Pitch) )
00498		{
00499			If (ViewRotation.Pitch < 32768) 
00500				NewRotation.Pitch = RotationRate.Pitch;
00501			else
00502				NewRotation.Pitch = 65536 - RotationRate.Pitch;
00503		}
00504	
00505		NewRotation.Roll  = 0;
00506		SetRotation( NewRotation );
00507		SetLocation( NewLocation );
00508	}
00509	
00510	function ClientSetRotation( rotator NewRotation )
00511	{
00512		local Pawn P;
00513	
00514		ViewRotation      = NewRotation;
00515		NewRotation.Pitch = 0;
00516		NewRotation.Roll  = 0;
00517		SetRotation( NewRotation );
00518	}
00519	
00520	function ClientDying(name DamageType, vector HitLocation)
00521	{
00522		PlayDying(DamageType, HitLocation);
00523		GotoState('Dying');
00524	}
00525	
00526	function ClientReStart()
00527	{
00528		//log("client restart");
00529		Velocity = vect(0,0,0);
00530		Acceleration = vect(0,0,0);
00531		BaseEyeHeight = Default.BaseEyeHeight;
00532		EyeHeight = BaseEyeHeight;
00533		PlayWaiting();
00534	
00535		if ( Region.Zone.bWaterZone && (PlayerRestartState == 'PlayerWalking') )
00536		{
00537			if (HeadRegion.Zone.bWaterZone)
00538					PainTime = UnderWaterTime;
00539			setPhysics(PHYS_Swimming);
00540			GotoState('PlayerSwimming');
00541		}
00542		else
00543			GotoState(PlayerReStartState);
00544	}
00545	
00546	function ClientGameEnded()
00547	{
00548		GotoState('GameEnded');
00549	}
00550	
00551	//=============================================================================
00552	// Inventory related functions.
00553	
00554	function float AdjustDesireFor(Inventory Inv)
00555	{
00556		return 0;
00557	}
00558	
00559	// toss out the weapon currently held
00560	function TossWeapon()
00561	{
00562		local vector X,Y,Z;
00563		if ( Weapon == None )
00564			return;
00565		GetAxes(Rotation,X,Y,Z);
00566		Weapon.DropFrom(Location + 0.8 * CollisionRadius * X + - 0.5 * CollisionRadius * Y); 
00567	}	
00568	
00569	// The player/bot wants to select next item
00570	exec function NextItem()
00571	{
00572		local Inventory Inv;
00573	
00574		if (SelectedItem==None) {
00575			SelectedItem = Inventory.SelectNext();
00576			Return;
00577		}
00578		if (SelectedItem.Inventory!=None)
00579			SelectedItem = SelectedItem.Inventory.SelectNext(); 
00580		else
00581			SelectedItem = Inventory.SelectNext();
00582	
00583		if ( SelectedItem == None )
00584			SelectedItem = Inventory.SelectNext();
00585	}
00586	
00587	// FindInventoryType()
00588	// returns the inventory item of the requested class
00589	// if it exists in this pawn's inventory 
00590	
00591	function Inventory FindInventoryType( class DesiredClass )
00592	{
00593		local Inventory Inv;
00594	
00595		for( Inv=Inventory; Inv!=None; Inv=Inv.Inventory )   
00596			if ( Inv.class == DesiredClass )
00597				return Inv;
00598		return None;
00599	} 
00600	
00601	// Add Item to this pawn's inventory. 
00602	// Returns true if successfully added, false if not.
00603	function bool AddInventory( inventory NewItem )
00604	{
00605		// Skip if already in the inventory.
00606		local inventory Inv;
00607		
00608		// The item should not have been destroyed if we get here.
00609		if (NewItem ==None )
00610			log("tried to add none inventory to "$self);
00611	
00612		for( Inv=Inventory; Inv!=None; Inv=Inv.Inventory )
00613			if( Inv == NewItem )
00614				return false;
00615	
00616		// Add to front of inventory chain.
00617		NewItem.SetOwner(Self);
00618		NewItem.Inventory = Inventory;
00619		Inventory = NewItem;
00620	
00621		return true;
00622	}
00623	
00624	// Remove Item from this pawn's inventory, if it exists.
00625	// Returns true if it existed and was deleted, false if it did not exist.
00626	function bool DeleteInventory( inventory Item )
00627	{
00628		// If this item is in our inventory chain, unlink it.
00629		local actor Link;
00630	
00631		if ( Item == Weapon )
00632			Weapon = None;
00633		if ( Item == SelectedItem )
00634			SelectedItem = None;
00635		for( Link = Self; Link!=None; Link=Link.Inventory )
00636		{
00637			if( Link.Inventory == Item )
00638			{
00639				Link.Inventory = Item.Inventory;
00640				break;
00641			}
00642		}
00643		Item.SetOwner(None);
00644	}
00645	
00646	// Just changed to pendingWeapon
00647	function ChangedWeapon()
00648	{
00649		local Weapon OldWeapon;
00650	
00651		OldWeapon = Weapon;
00652	
00653		if (Weapon == PendingWeapon)
00654		{
00655			if ( Weapon == None )
00656				SwitchToBestWeapon();
00657			else if ( Weapon.IsInState('DownWeapon') ) 
00658				Weapon.BringUp();
00659			if ( Weapon != None )
00660				Weapon.SetDefaultDisplayProperties();
00661			Inventory.ChangedWeapon(); // tell inventory that weapon changed (in case any effect was being applied)
00662			PendingWeapon = None;
00663			return;
00664		}
00665		if ( PendingWeapon == None )
00666			PendingWeapon = Weapon;
00667		PlayWeaponSwitch(PendingWeapon);
00668		if ( (PendingWeapon != None) && (PendingWeapon.Mass > 20) && (carriedDecoration != None) )
00669			DropDecoration();
00670		if ( Weapon != None )
00671			Weapon.SetDefaultDisplayProperties();
00672			
00673		Weapon = PendingWeapon;
00674		Inventory.ChangedWeapon(); // tell inventory that weapon changed (in case any effect was being applied)
00675		if ( Weapon != None )
00676		{
00677			Weapon.RaiseUp(OldWeapon);
00678			if ( (Level.Game != None) && (Level.Game.Difficulty > 1) )
00679				MakeNoise(0.1 * Level.Game.Difficulty);		
00680		}
00681		PendingWeapon = None;
00682	}
00683	
00684	//==============
00685	// Encroachment
00686	event bool EncroachingOn( actor Other )
00687	{
00688		if ( (Other.Brush != None) || (Brush(Other) != None) )
00689			return true;
00690			
00691		if ( (!bIsPlayer || bWarping) && (Pawn(Other) != None))
00692			return true;
00693			
00694		return false;
00695	}
00696	
00697	event EncroachedBy( actor Other )
00698	{
00699		if ( Pawn(Other) != None )
00700			gibbedBy(Other);
00701			
00702	}
00703	
00704	function gibbedBy(actor Other)
00705	{
00706		local pawn instigatedBy;
00707	
00708		if ( Role < ROLE_Authority )
00709			return;
00710		instigatedBy = pawn(Other);
00711		if (instigatedBy == None)
00712			instigatedBy = Other.instigator;
00713		health = -1000; //make sure gibs
00714		Died(instigatedBy, 'Gibbed', Location);
00715	}
00716	
00717	event PlayerTimeOut()
00718	{
00719		if (Health > 0)
00720			Died(None, 'Suicided', Location);
00721	}
00722	
00723	//Base change - if new base is pawn or decoration, damage based on relative mass and old velocity
00724	// Also, non-players will jump off pawns immediately
00725	function JumpOffPawn()
00726	{
00727		Velocity += 60 * VRand();
00728		Velocity.Z = 180;
00729		SetPhysics(PHYS_Falling);
00730	}
00731	
00732	function UnderLift(Mover M);
00733	
00734	singular event BaseChange()
00735	{
00736		local float decorMass;
00737	
00738		if ( (base == None) && (Physics == PHYS_None) )
00739			SetPhysics(PHYS_Falling);
00740		else if (Pawn(Base) != None)
00741		{
00742			Base.TakeDamage( (1-Velocity.Z/400)* Mass/Base.Mass, Self,Location,0.5 * Velocity , 'stomped');
00743			JumpOffPawn();
00744		}
00745		else if ( (Decoration(Base) != None) && (Velocity.Z < -400) )
00746		{
00747			decorMass = FMax(Decoration(Base).Mass, 1);
00748			Base.TakeDamage((-2* Mass/decorMass * Velocity.Z/400), Self, Location, 0.5 * Velocity, 'stomped');
00749		}
00750	}
00751	
00752	event LongFall();
00753	
00754	//=============================================================================
00755	// Network related functions.
00756	
00757	
00758	simulated event Destroyed()
00759	{
00760		local Inventory Inv;
00761		local Pawn OtherPawn;
00762	
00763		if ( Shadow != None )
00764			Shadow.Destroy();
00765		if ( Role < ROLE_Authority )
00766			return;
00767	
00768		RemovePawn();
00769	
00770		for( Inv=Inventory; Inv!=None; Inv=Inv.Inventory )   
00771			Inv.Destroy();
00772		Weapon = None;
00773		Inventory = None;
00774		if ( bIsPlayer && (Level.Game != None) )
00775			Level.Game.logout(self);
00776		if ( PlayerReplicationInfo != None )
00777			PlayerReplicationInfo.Destroy();
00778		for ( OtherPawn=Level.PawnList; OtherPawn!=None; OtherPawn=OtherPawn.nextPawn )
00779			OtherPawn.Killed(None, self, '');
00780		Super.Destroyed();
00781	}
00782	
00783	//=============================================================================
00784	// functions.
00785	
00786	//
00787	// native client-side functions.
00788	//
00789	native simulated event ClientHearSound ( 
00790		actor Actor, 
00791		int Id, 
00792		sound S, 
00793		vector SoundLocation, 
00794		vector Parameters 
00795	);
00796	
00797	//
00798	// Called immediately before gameplay begins.
00799	//
00800	event PreBeginPlay()
00801	{
00802		AddPawn();
00803		Super.PreBeginPlay();
00804		if ( bDeleteMe )
00805			return;
00806	
00807		// Set instigator to self.
00808		Instigator = Self;
00809		DesiredRotation = Rotation;
00810		SightCounter = 0.2 * FRand();  //offset randomly 
00811		if ( Level.Game != None )
00812			Skill += Level.Game.Difficulty; 
00813		Skill = FClamp(Skill, 0, 3);
00814		PreSetMovement();
00815		
00816		if ( DrawScale != Default.Drawscale )
00817		{
00818			SetCollisionSize(CollisionRadius*DrawScale/Default.DrawScale, CollisionHeight*DrawScale/Default.DrawScale);
00819			Health = Health * DrawScale/Default.DrawScale;
00820		}
00821	
00822		if (bIsPlayer)
00823		{
00824			if (PlayerReplicationInfoClass != None)
00825				PlayerReplicationInfo = Spawn(PlayerReplicationInfoClass, Self,,vect(0,0,0),rot(0,0,0));
00826			else
00827				PlayerReplicationInfo = Spawn(class'PlayerReplicationInfo', Self,,vect(0,0,0),rot(0,0,0));
00828			InitPlayerReplicationInfo();
00829		}
00830	
00831		if (!bIsPlayer) 
00832		{
00833			if ( BaseEyeHeight == 0 )
00834				BaseEyeHeight = 0.8 * CollisionHeight;
00835			EyeHeight = BaseEyeHeight;
00836			if (Fatness == 0) //vary monster fatness slightly if at default
00837				Fatness = 120 + Rand(8) + Rand(8);
00838		}
00839	
00840		if ( menuname == "" )
00841			menuname = GetItemName(string(class));
00842	
00843		if (SelectionMesh == "")
00844			SelectionMesh = string(Mesh);
00845	}
00846	
00847	event PostBeginPlay()
00848	{
00849		Super.PostBeginPlay();
00850		SplashTime = 0;
00851	}
00852	
00853	// called after PostBeginPlay on net client
00854	simulated event PostNetBeginPlay()
00855	{
00856		if ( Role != ROLE_SimulatedProxy )
00857			return;
00858		if ( bIsMultiSkinned )
00859		{
00860			if ( MultiSkins[1] == None )
00861			{
00862				if ( bIsPlayer )
00863					SetMultiSkin(self, "","", PlayerReplicationInfo.team);
00864				else
00865					SetMultiSkin(self, "","", 0);
00866			}
00867		}
00868		else if ( Skin == None )
00869			Skin = Default.Skin;
00870	
00871		if ( (PlayerReplicationInfo != None) 
00872			&& (PlayerReplicationInfo.Owner == None) )
00873			PlayerReplicationInfo.SetOwner(self);
00874	}
00875		
00876	/* PreSetMovement()
00877	default for walking creature.  Re-implement in subclass
00878	for swimming/flying capability
00879	*/
00880	function PreSetMovement()
00881	{
00882		if (JumpZ > 0)
00883			bCanJump = true;
00884		bCanWalk = true;
00885		bCanSwim = false;
00886		bCanFly = false;
00887		MinHitWall = -0.6;
00888		if (Intelligence > BRAINS_Reptile)
00889			bCanOpenDoors = true;
00890		if (Intelligence == BRAINS_Human)
00891			bCanDoSpecial = true;
00892	}
00893	
00894	simulated function SetMesh()
00895	{
00896		mesh = default.mesh;
00897	}
00898	
00899	//=============================================================================
00900	// Multiskin support
00901	static function SetMultiSkin( actor SkinActor, string SkinName, string FaceName, byte TeamNum )
00902	{
00903		local Texture NewSkin;
00904	
00905		if(SkinName != "")
00906		{
00907			NewSkin = texture(DynamicLoadObject(SkinName, class'Texture'));
00908			if ( NewSkin != None )
00909				SkinActor.Skin = NewSkin;
00910		}
00911	}
00912	
00913	static function GetMultiSkin( Actor SkinActor, out string SkinName, out string FaceName )
00914	{
00915		SkinName = String(SkinActor.Skin);
00916		FaceName = "";
00917	}
00918	
00919	static function bool SetSkinElement(Actor SkinActor, int SkinNo, string SkinName, string DefaultSkinName)
00920	{
00921		local Texture NewSkin;
00922		local bool bProscribed;
00923		local string pkg, SkinItem, MeshName;
00924		local int i;
00925	
00926		
00927		if ( (SkinActor.Level.NetMode != NM_Standalone)
00928			&& (SkinActor.Level.NetMode != NM_Client)
00929			&& (DefaultSkinName != "") )
00930		{
00931			// make sure that an illegal skin package is not used
00932			// ignore if already have skins set
00933			if ( SkinActor.Mesh != None )
00934				MeshName = SkinActor.GetItemName(string(SkinActor.Mesh));
00935			else
00936				MeshName = SkinActor.GetItemName(string(SkinActor.Default.Mesh));
00937			SkinItem = SkinActor.GetItemName(SkinName);
00938			pkg = Left(SkinName, Len(SkinName) - Len(SkinItem) - 1);
00939			bProscribed = !CheckValidSkinPackage(pkg, MeshName);
00940			if ( bProscribed )
00941				log("Attempted to use illegal skin from package "$pkg$" for "$Meshname);
00942		}
00943	
00944		NewSkin = Texture(DynamicLoadObject(SkinName, class'Texture'));
00945		if ( !bProscribed && (NewSkin != None) )
00946		{
00947			SkinActor.Multiskins[SkinNo] = NewSkin;
00948			return True;
00949		}
00950		else
00951		{
00952			log("Failed to load "$SkinName$" so load "$DefaultSkinName);
00953			if(DefaultSkinName != "")
00954			{
00955				NewSkin = Texture(DynamicLoadObject(DefaultSkinName, class'Texture'));
00956				SkinActor.Multiskins[SkinNo] = NewSkin;
00957			}
00958			return False;
00959		}
00960	}
00961	
00962	//=============================================================================
00963	// Replication
00964	function InitPlayerReplicationInfo()
00965	{
00966		if (PlayerReplicationInfo.PlayerName == "")
00967			PlayerReplicationInfo.PlayerName = class'GameInfo'.Default.DefaultPlayerName;
00968	}
00969		
00970	//=============================================================================
00971	// Animation playing - should be implemented in subclass, 
00972	//
00973	// PlayWaiting, PlayRunning, and PlayGutHit, PlayMovingAttack (if used)
00974	// and PlayDying are required to be implemented in the subclass
00975	
00976	function PlayRunning()
00977	{
00978		////log("Error - PlayRunning should be implemented in subclass of"@class);
00979	}
00980	
00981	function PlayWalking()
00982	{
00983		PlayRunning(); 
00984	}
00985	
00986	function PlayWaiting()
00987	{
00988		////log("Error - PlayWaiting should be implemented in subclass");
00989	}
00990	
00991	function PlayMovingAttack()
00992	{
00993		////log("Error - PlayMovingAttack should be implemented in subclass");
00994		//Note - must restart attack timer when done with moving attack
00995		PlayRunning();
00996	}
00997	
00998	function PlayWaitingAmbush()
00999	{
01000		PlayWaiting();
01001	}
01002	
01003	function TweenToFighter(float tweentime)
01004	{
01005	}
01006	
01007	function TweenToRunning(float tweentime)
01008	{
01009		TweenToFighter(0.1);
01010	}
01011	
01012	function TweenToWalking(float tweentime)
01013	{
01014		TweenToRunning(tweentime);
01015	}
01016	
01017	function TweenToPatrolStop(float tweentime)
01018	{
01019		TweenToFighter(tweentime);
01020	}
01021	
01022	function TweenToWaiting(float tweentime)
01023	{
01024		TweenToFighter(tweentime);
01025	}
01026	
01027	function PlayThreatening()
01028	{
01029		TweenToFighter(0.1);
01030	}
01031	
01032	function PlayPatrolStop()
01033	{
01034		PlayWaiting();
01035	}
01036	
01037	function PlayTurning()
01038	{
01039		TweenToFighter(0.1);
01040	}
01041	
01042	function PlayBigDeath(name DamageType);
01043	function PlayHeadDeath(name DamageType);
01044	function PlayLeftDeath(name DamageType);
01045	function PlayRightDeath(name DamageType);
01046	function PlayGutDeath(name DamageType);
01047	
01048	function PlayDying(name DamageType, vector HitLoc)
01049	{
01050		local vector X,Y,Z, HitVec, HitVec2D;
01051		local float dotp;
01052	
01053		if ( Velocity.Z > 250 )
01054		{
01055			PlayBigDeath(DamageType);
01056			return;
01057		}
01058		
01059		if ( DamageType == 'Decapitated' )
01060		{
01061			PlayHeadDeath(DamageType);
01062			return;
01063		}
01064				
01065		GetAxes(Rotation,X,Y,Z);
01066		X.Z = 0;
01067		HitVec = Normal(HitLoc - Location);
01068		HitVec2D= HitVec;
01069		HitVec2D.Z = 0;
01070		dotp = HitVec2D dot X;
01071	
01072		//first check for head hit
01073		if ( HitLoc.Z - Location.Z > 0.5 * CollisionHeight )
01074		{
01075			if (dotp > 0)
01076				PlayHeadDeath(DamageType);
01077			else
01078				PlayGutDeath(DamageType);
01079			return;
01080		}
01081		
01082		if (dotp > 0.71) //then hit in front
01083			PlayGutDeath(DamageType);
01084		else
01085		{
01086			dotp = HitVec dot Y;
01087			if (dotp > 0.0)
01088				PlayLeftDeath(DamageType);
01089			else
01090				PlayRightDeath(DamageType);
01091		}
01092	}
01093	
01094	function PlayGutHit(float tweentime)
01095	{
01096		log("Error - play gut hit must be implemented in subclass of"@class);
01097	}
01098	
01099	function PlayHeadHit(float tweentime)
01100	{
01101		PlayGutHit(tweentime);
01102	}
01103	
01104	function PlayLeftHit(float tweentime)
01105	{
01106		PlayGutHit(tweentime);
01107	}
01108	
01109	function PlayRightHit(float tweentime)
01110	{
01111		PlayGutHit(tweentime);
01112	}
01113	
01114	function FireWeapon();
01115	
01116	/* TraceShot - used by instant hit weapons, and monsters 
01117	*/
01118	function actor TraceShot(out vector HitLocation, out vector HitNormal, vector EndTrace, vector StartTrace)
01119	{
01120		local vector realHit;
01121		local actor Other;
01122		Other = Trace(HitLocation,HitNormal,EndTrace,StartTrace,True);
01123		if ( Pawn(Other) != None )
01124		{
01125			realHit = HitLocation;
01126			if ( !Pawn(Other).AdjustHitLocation(HitLocation, EndTrace - StartTrace) )
01127				Other = Pawn(Other).TraceShot(HitLocation,HitNormal,EndTrace,realHit);
01128		}
01129		return Other;
01130	}
01131	
01132	/* Adjust hit location - adjusts the hit location in for pawns, and returns
01133	true if it was really a hit, and false if not (for ducking, etc.)
01134	*/
01135	simulated function bool AdjustHitLocation(out vector HitLocation, vector TraceDir)
01136	{
01137		local float adjZ, maxZ;
01138	
01139		TraceDir = Normal(TraceDir);
01140		HitLocation = HitLocation + 0.4 * CollisionRadius * TraceDir;
01141	
01142		if ( (GetAnimGroup(AnimSequence) == 'Ducking') && (AnimFrame > -0.03) )
01143		{
01144			maxZ = Location.Z + 0.25 * CollisionHeight;
01145			if ( HitLocation.Z > maxZ )
01146			{
01147				if ( TraceDir.Z >= 0 )
01148					return false;
01149				adjZ = (maxZ - HitLocation.Z)/TraceDir.Z;
01150				HitLocation.Z = maxZ;
01151				HitLocation.X = HitLocation.X + TraceDir.X * adjZ;
01152				HitLocation.Y = HitLocation.Y + TraceDir.Y * adjZ;
01153				if ( VSize(HitLocation - Location) > CollisionRadius )	
01154					return false;
01155			}
01156		}
01157		return true;
01158	}
01159				
01160	function PlayTakeHit(float tweentime, vector HitLoc, int damage)
01161	{
01162		local vector X,Y,Z, HitVec, HitVec2D;
01163		local float dotp;
01164		
01165		GetAxes(Rotation,X,Y,Z);
01166		X.Z = 0;
01167		HitVec = Normal(HitLoc - Location);
01168		HitVec2D= HitVec;
01169		HitVec2D.Z = 0;
01170		dotp = HitVec2D dot X;
01171	
01172		//first check for head hit
01173		if ( HitLoc.Z - Location.Z > 0.5 * CollisionHeight )
01174		{
01175			if (dotp > 0)
01176				PlayHeadHit(tweentime);
01177			else
01178				PlayGutHit(tweentime);
01179			return;
01180		}
01181		
01182		if (dotp > 0.71) //then hit in front
01183			PlayGutHit( tweentime);
01184		else if (dotp < -0.71) // then hit in back
01185			PlayHeadHit(tweentime);
01186		else
01187		{
01188			dotp = HitVec dot Y;
01189			if (dotp > 0.0)
01190				PlayLeftHit(tweentime);
01191			else
01192				PlayRightHit(tweentime);
01193		}
01194	}
01195	
01196	function PlayVictoryDance()
01197	{
01198		TweenToFighter(0.1);
01199	}
01200	
01201	function PlayOutOfWater()
01202	{
01203		TweenToFalling();
01204	}
01205	
01206	function PlayDive();
01207	function TweenToFalling();
01208	function PlayInAir();
01209	function PlayDuck();
01210	function PlayCrawling();
01211	
01212	function PlayLanded(float impactVel)
01213	{
01214		local float landVol;
01215		//default - do nothing (keep playing existing animation)
01216		landVol = impactVel/JumpZ;
01217		landVol = 0.005 * Mass * landVol * landVol;
01218		PlaySound(Land, SLOT_Interact, FMin(20, landVol));
01219	}
01220	
01221	function PlayFiring();
01222	function PlayWeaponSwitch(Weapon NewWeapon);
01223	function TweenToSwimming(float tweentime);
01224	
01225	
01226	//-----------------------------------------------------------------------------
01227	// Sound functions
01228	function PlayTakeHitSound(int Damage, name damageType, int Mult)
01229	{
01230		if ( Level.TimeSeconds - LastPainSound < 0.25 )
01231			return;
01232	
01233		if (HitSound1 == None)return;
01234		LastPainSound = Level.TimeSeconds;
01235		if (FRand() < 0.5)
01236			PlaySound(HitSound1, SLOT_Pain, FMax(Mult * TransientSoundVolume, Mult * 2.0));
01237		else
01238			PlaySound(HitSound2, SLOT_Pain, FMax(Mult * TransientSoundVolume, Mult * 2.0));
01239	}
01240	
01241	function Gasp();
01242	
01243	function DropDecoration()
01244	{
01245		if (CarriedDecoration != None)
01246		{
01247			CarriedDecoration.bWasCarried = true;
01248			CarriedDecoration.SetBase(None);
01249			CarriedDecoration.SetPhysics(PHYS_Falling);
01250			CarriedDecoration.Velocity = Velocity + 10 * VRand();
01251			CarriedDecoration.Instigator = self;
01252			CarriedDecoration = None;
01253		}
01254	}
01255	
01256	function GrabDecoration()
01257	{
01258		local vector lookDir, HitLocation, HitNormal, T1, T2, extent;
01259		local actor HitActor;
01260	
01261		if ( carriedDecoration == None )
01262		{
01263			//first trace to find it
01264			lookDir = vector(Rotation);
01265			lookDir.Z = 0;
01266			T1 = Location + BaseEyeHeight * vect(0,0,1) + lookDir * 0.8 * CollisionRadius;
01267			T2 = T1 + lookDir * 1.2 * CollisionRadius;
01268			HitActor = Trace(HitLocation, HitNormal, T2, T1, true);
01269			if ( HitActor == None )
01270			{
01271				T1 = T2 - (BaseEyeHeight + CollisionHeight - 2) * vect(0,0,1);
01272				HitActor = Trace(HitLocation, HitNormal, T1, T2, true);
01273			}
01274			else if ( HitActor == Level )
01275			{
01276				T2 = HitLocation - lookDir;
01277				T1 = T2 - (BaseEyeHeight + CollisionHeight - 2) * vect(0,0,1);
01278				HitActor = Trace(HitLocation, HitNormal, T1, T2, true);
01279			}	
01280			if ( (HitActor == None) || (HitActor == Level) )
01281			{
01282				extent.X = CollisionRadius;
01283				extent.Y = CollisionRadius;
01284				extent.Z = CollisionHeight;
01285				HitActor = Trace(HitLocation, HitNormal, Location + lookDir * 1.2 * CollisionRadius, Location, true, extent);
01286			}
01287	
01288			if ( Mover(HitActor) != None )
01289			{
01290				if ( Mover(HitActor).bUseTriggered )
01291					HitActor.Trigger( self, self );
01292			}		
01293			else if ( (Decoration(HitActor) != None)  && ((weapon == None) || (weapon.Mass < 20)) )
01294			{
01295				CarriedDecoration = Decoration(HitActor);
01296				if ( !CarriedDecoration.bPushable || (CarriedDecoration.Mass > 40) 
01297					|| (CarriedDecoration.StandingCount > 0) )
01298				{
01299					CarriedDecoration = None;
01300					return;
01301				}
01302				lookDir.Z = 0;				
01303				if ( CarriedDecoration.SetLocation(Location + (0.5 * CollisionRadius + CarriedDecoration.CollisionRadius) * lookDir) )
01304				{
01305					CarriedDecoration.SetPhysics(PHYS_None);
01306					CarriedDecoration.SetBase(self);
01307				}
01308				else
01309					CarriedDecoration = None;
01310			}
01311		}
01312	}
01313		
01314	function StopFiring();
01315	
01316	function ShakeView( float shaketime, float RollMag, float vertmag);
01317	
01318	function TakeFallingDamage()
01319	{
01320		if (Velocity.Z < -1.4 * JumpZ)
01321		{
01322			MakeNoise(-0.5 * Velocity.Z/(FMax(JumpZ, 150.0)));
01323			if (Velocity.Z <= -750 - JumpZ)
01324			{
01325				if ( (Velocity.Z < -1650 - JumpZ) && (ReducedDamageType != 'All') )
01326					TakeDamage(1000, None, Location, vect(0,0,0), 'Fell');
01327				else if ( Role == ROLE_Authority )
01328					TakeDamage(-0.15 * (Velocity.Z + 700 + JumpZ), None, Location, vect(0,0,0), 'Fell');
01329				ShakeView(0.175 - 0.00007 * Velocity.Z, -0.85 * Velocity.Z, -0.002 * Velocity.Z);
01330			}
01331		}
01332		else if ( Velocity.Z > 0.5 * Default.JumpZ )
01333			MakeNoise(0.35);				
01334	}
01335	
01336	/* AdjustAim()
01337	ScriptedPawn version does adjustment for non-controlled pawns. 
01338	PlayerPawn version does the adjustment for player aiming help.
01339	Only adjusts aiming at pawns
01340	allows more error in Z direction (full as defined by AutoAim - only half that difference for XY)
01341	*/
01342	
01343	function rotator AdjustAim(float projSpeed, vector projStart, int aimerror, bool bLeadTarget, bool bWarnTarget)
01344	{
01345		return ViewRotation;
01346	}
01347	
01348	function rotator AdjustToss(float projSpeed, vector projStart, int aimerror, bool bLeadTarget, bool bWarnTarget)
01349	{
01350		return ViewRotation;
01351	}
01352	
01353	function WarnTarget(Pawn shooter, float projSpeed, vector FireDir)
01354	{
01355		// AI controlled creatures may duck
01356		// if not falling, and projectile time is long enough
01357		// often pick opposite to current direction (relative to shooter axis)
01358	}
01359	
01360	function SetMovementPhysics()
01361	{
01362		//implemented in sub-class
01363	}
01364	
01365	function PlayHit(float Damage, vector HitLocation, name damageType, vector Momentum)
01366	{
01367	}
01368	
01369	function PlayDeathHit(float Damage, vector HitLocation, name damageType, vector Momentum)
01370	{
01371	}
01372	
01373	function TakeDamage( int Damage, Pawn instigatedBy, Vector hitlocation, 
01374							Vector momentum, name damageType)
01375	{
01376		local int actualDamage;
01377		local bool bAlreadyDead;
01378	
01379		if ( Role < ROLE_Authority )
01380		{
01381			log(self$" client damage type "$damageType$" by "$instigatedBy);
01382			return;
01383		}
01384	
01385		//log(self@"take damage in state"@GetStateName());	
01386		bAlreadyDead = (Health <= 0);
01387	
01388		if (Physics == PHYS_None)
01389			SetMovementPhysics();
01390		if (Physics == PHYS_Walking)
01391			momentum.Z = FMax(momentum.Z, 0.4 * VSize(momentum));
01392		if ( instigatedBy == self )
01393			momentum *= 0.6;
01394		momentum = momentum/Mass;
01395	
01396		actualDamage = Level.Game.ReduceDamage(Damage, DamageType, self, instigatedBy);
01397		if ( bIsPlayer )
01398		{
01399			if (ReducedDamageType == 'All') //God mode
01400				actualDamage = 0;
01401			else if (Inventory != None) //then check if carrying armor
01402				actualDamage = Inventory.ReduceDamage(actualDamage, DamageType, HitLocation);
01403			else
01404				actualDamage = Damage;
01405		}
01406		else if ( (InstigatedBy != None) &&
01407					(InstigatedBy.IsA(Class.Name) || self.IsA(InstigatedBy.Class.Name)) )
01408			ActualDamage = ActualDamage * FMin(1 - ReducedDamagePct, 0.35); 
01409		else if ( (ReducedDamageType == 'All') || 
01410			((ReducedDamageType != '') && (ReducedDamageType == damageType)) )
01411			actualDamage = float(actualDamage) * (1 - ReducedDamagePct);
01412		
01413		if ( Level.Game.DamageMutator != None )
01414			Level.Game.DamageMutator.MutatorTakeDamage( ActualDamage, Self, InstigatedBy, HitLocation, Momentum, DamageType );
01415	
01416		AddVelocity( momentum ); 
01417		Health -= actualDamage;
01418		if (CarriedDecoration != None)
01419			DropDecoration();
01420		if ( HitLocation == vect(0,0,0) )
01421			HitLocation = Location;
01422		if (Health > 0)
01423		{
01424			if ( (instigatedBy != None) && (instigatedBy != Self) )
01425				damageAttitudeTo(instigatedBy);
01426			PlayHit(actualDamage, hitLocation, damageType, Momentum);
01427		}
01428		else if ( !bAlreadyDead )
01429		{
01430			//log(self$" died");
01431			NextState = '';
01432			PlayDeathHit(actualDamage, hitLocation, damageType, Momentum);
01433			if ( actualDamage > mass )
01434				Health = -1 * actualDamage;
01435			if ( (instigatedBy != None) && (instigatedBy != Self) )
01436				damageAttitudeTo(instigatedBy);
01437			Died(instigatedBy, damageType, HitLocation);
01438		}
01439		else
01440		{
01441			//Warn(self$" took regular damage "$damagetype$" from "$instigator$" while already dead");
01442			// SpawnGibbedCarcass();
01443			if ( bIsPlayer )
01444			{
01445				HidePlayer();
01446				GotoState('Dying');
01447			}
01448			else
01449				Destroy();
01450		}
01451		MakeNoise(1.0); 
01452	}
01453	
01454	function Died(pawn Killer, name damageType, vector HitLocation)
01455	{
01456		local pawn OtherPawn;
01457		local actor A;
01458	
01459		// mutator hook to prevent deaths
01460		// WARNING - don't prevent bot suicides - they suicide when really needed
01461		if ( Level.Game.BaseMutator.PreventDeath(self, Killer, damageType, HitLocation) )
01462		{
01463			Health = max(Health, 1); //mutator should set this higher
01464			return;
01465		}
01466		if ( bDeleteMe )
01467			return; //already destroyed
01468		Health = Min(0, Health);
01469		for ( OtherPawn=Level.PawnList; OtherPawn!=None; OtherPawn=OtherPawn.nextPawn )
01470			OtherPawn.Killed(Killer, self, damageType);
01471		if ( CarriedDecoration != None )
01472			DropDecoration();
01473		level.game.Killed(Killer, self, damageType);
01474		//log(class$" dying");
01475		if( Event != '' )
01476			foreach AllActors( class 'Actor', A, Event )
01477				A.Trigger( Self, Killer );
01478		Level.Game.DiscardInventory(self);
01479		Velocity.Z *= 1.3;
01480		if ( Gibbed(damageType) )
01481		{
01482			SpawnGibbedCarcass();
01483			if ( bIsPlayer )
01484				HidePlayer();
01485			else
01486				Destroy();
01487		}
01488		PlayDying(DamageType, HitLocation);
01489		if ( Level.Game.bGameEnded )
01490			return;
01491		if ( RemoteRole == ROLE_AutonomousProxy )
01492			ClientDying(DamageType, HitLocation);
01493		GotoState('Dying');
01494	}
01495	
01496	function bool Gibbed(name damageType)
01497	{
01498		return false;
01499	}
01500	
01501	function Carcass SpawnCarcass()
01502	{
01503		log(self$" should never call base spawncarcass");
01504		return None;
01505	}
01506	
01507	function SpawnGibbedCarcass()
01508	{
01509	}
01510		
01511	function HidePlayer()
01512	{
01513		SetCollision(false, false, false);
01514		TweenToFighter(0.01);
01515		bHidden = true;
01516	}
01517	
01518	event HearNoise( float Loudness, Actor NoiseMaker);
01519	event SeePlayer( actor Seen );
01520	event UpdateEyeHeight( float DeltaTime );
01521	event UpdateTactics(float DeltaTime); // for advanced tactics
01522	event EnemyNotVisible();
01523	
01524	function Killed(pawn Killer, pawn Other, name damageType)
01525	{
01526		if ( Enemy == Other )
01527			Enemy = None;
01528	}
01529	
01530	//Typically implemented in subclass
01531	function string KillMessage( name damageType, pawn Other )
01532	{
01533		local string message;
01534	
01535		message = Level.Game.CreatureKillMessage(damageType, Other);
01536		return (Other.PlayerReplicationInfo.PlayerName$message$namearticle$menuname);
01537	}
01538	
01539	function damageAttitudeTo(pawn Other);
01540	
01541	function Falling()
01542		{
01543			//SetPhysics(PHYS_Falling); //Note - physics changes type to PHYS_Falling by default
01544			//log(class$" Falling");
01545			PlayInAir();
01546		}
01547	
01548	// Pawn interface called while PHYS_Walking and PHYS_Swimming to update the pawn with 
01549	// the latest information about the walk surface -- added by Legend on 1/31/1999
01550	event WalkTexture( texture Texture, vector StepLocation, vector StepNormal );
01551	
01552	event Landed(vector HitNormal)
01553	{
01554		SetMovementPhysics();
01555		if ( !IsAnimating() )
01556			PlayLanded(Velocity.Z);
01557		if (Velocity.Z < -1.4 * JumpZ)
01558			MakeNoise(-0.5 * Velocity.Z/(FMax(JumpZ, 150.0)));
01559		bJustLanded = true;
01560	}
01561	
01562	event FootZoneChange(ZoneInfo newFootZone)
01563	{
01564		local actor HitActor;
01565		local vector HitNormal, HitLocation;
01566		local float splashSize;
01567		local actor splash;
01568		
01569		if ( Level.NetMode == NM_Client )
01570			return;
01571		if ( Level.TimeSeconds - SplashTime > 0.25 ) 
01572		{
01573			SplashTime = Level.TimeSeconds;
01574			if (Physics == PHYS_Falling)
01575				MakeNoise(1.0);
01576			else
01577				MakeNoise(0.3);
01578			if ( FootRegion.Zone.bWaterZone )
01579			{
01580				if ( !newFootZone.bWaterZone && (Role==ROLE_Authority) )
01581				{
01582					if ( FootRegion.Zone.ExitSound != None )
01583						PlaySound(FootRegion.Zone.ExitSound, SLOT_Interact, 1); 
01584					if ( FootRegion.Zone.ExitActor != None )
01585						Spawn(FootRegion.Zone.ExitActor,,,Location - CollisionHeight * vect(0,0,1));
01586				}
01587			}
01588			else if ( newFootZone.bWaterZone && (Role==ROLE_Authority) )
01589			{
01590				splashSize = FClamp(0.000025 * Mass * (300 - 0.5 * FMax(-500, Velocity.Z)), 1.0, 4.0 );
01591				if ( newFootZone.EntrySound != None )
01592				{
01593					HitActor = Trace(HitLocation, HitNormal, 
01594							Location - (CollisionHeight + 40) * vect(0,0,0.8), Location - CollisionHeight * vect(0,0,0.8), false);
01595					if ( HitActor == None )
01596						PlaySound(newFootZone.EntrySound, SLOT_Misc, 2 * splashSize);
01597					else 
01598						PlaySound(WaterStep, SLOT_Misc, 1.5 + 0.5 * splashSize);
01599				}
01600				if( newFootZone.EntryActor != None )
01601				{
01602					splash = Spawn(newFootZone.EntryActor,,,Location - CollisionHeight * vect(0,0,1));
01603					if ( splash != None )
01604						splash.DrawScale = splashSize;
01605				}
01606				//log("Feet entering water");
01607			}
01608		}
01609		
01610		if (FootRegion.Zone.bPainZone)
01611		{
01612			if ( !newFootZone.bPainZone && !HeadRegion.Zone.bWaterZone )
01613				PainTime = -1.0;
01614		}
01615		else if (newFootZone.bPainZone)
01616			PainTime = 0.01;
01617	}
01618		
01619	event HeadZoneChange(ZoneInfo newHeadZone)
01620	{
01621		if ( Level.NetMode == NM_Client )
01622			return;
01623		if (HeadRegion.Zone.bWaterZone)
01624		{
01625			if (!newHeadZone.bWaterZone)
01626			{
01627				if ( bIsPlayer && (PainTime > 0) && (PainTime < 8) )
01628					Gasp();
01629				if ( Inventory != None )
01630					Inventory.ReduceDamage(0, 'Breathe', Location); //inform inventory of zone change
01631				bDrowning = false;
01632				if ( !FootRegion.Zone.bPainZone )
01633					PainTime = -1.0;
01634			}
01635		}
01636		else
01637		{
01638			if (newHeadZone.bWaterZone)
01639			{
01640				if ( !FootRegion.Zone.bPainZone )
01641					PainTime = UnderWaterTime;
01642				if ( Inventory != None )
01643					Inventory.ReduceDamage(0, 'Drowned', Location); //inform inventory of zone change
01644				//log("Can't breathe");
01645			}
01646		}
01647	}
01648	
01649	event SpeechTimer();
01650	
01651	//Pain timer just expired.
01652	//Check what zone I'm in (and which parts are)
01653	//based on that cause damage, and reset PainTime
01654		
01655	event PainTimer()
01656	{
01657		local float depth;
01658	
01659		//log("Pain Timer");
01660		if ( (Health < 0) || (Level.NetMode == NM_Client) )
01661			return;
01662			
01663		if ( FootRegion.Zone.bPainZone )
01664		{
01665			depth = 0.4;
01666			if (Region.Zone.bPainZone)
01667				depth += 0.4;
01668			if (HeadRegion.Zone.bPainZone)
01669				depth += 0.2;
01670	
01671			if (FootRegion.Zone.DamagePerSec > 0)
01672			{
01673				if ( IsA('PlayerPawn') )
01674					Level.Game.SpecialDamageString = FootRegion.Zone.DamageString;
01675				TakeDamage(int(float(FootRegion.Zone.DamagePerSec) * depth), None, Location, vect(0,0,0), FootRegion.Zone.DamageType); 
01676			}
01677			else if ( Health < Default.Health )
01678				Health = Min(Default.Health, Health - depth * FootRegion.Zone.DamagePerSec);
01679	
01680			if (Health > 0)
01681				PainTime = 1.0;
01682		}
01683		else if ( HeadRegion.Zone.bWaterZone )
01684		{
01685			TakeDamage(5, None, Location + CollisionHeight * vect(0,0,0.5), vect(0,0,0), 'Drowned'); 
01686			if ( Health > 0 )
01687				PainTime = 2.0;
01688		}
01689	}		
01690	
01691	function bool CheckWaterJump(out vector WallNormal)
01692	{
01693		local actor HitActor;
01694		local vector HitLocation, HitNormal, checkpoint, start, checkNorm, Extent;
01695	
01696		if (CarriedDecoration != None)
01697			return false;
01698		checkpoint = vector(Rotation);
01699		checkpoint.Z = 0.0;
01700		checkNorm = Normal(checkpoint);
01701		checkPoint = Location + CollisionRadius * checkNorm;
01702		Extent = CollisionRadius * vect(1,1,0);
01703		Extent.Z = CollisionHeight;
01704		HitActor = Trace(HitLocation, HitNormal, checkpoint, Location, true, Extent);
01705		if ( (HitActor != None) && (Pawn(HitActor) == None) )
01706		{
01707			WallNormal = -1 * HitNormal;
01708			start = Location;
01709			start.Z += 1.1 * MaxStepHeight;
01710			checkPoint = start + 2 * CollisionRadius * checkNorm;
01711			HitActor = Trace(HitLocation, HitNormal, checkpoint, start, true);
01712			if (HitActor == None)
01713				return true;
01714		}
01715	
01716		return false;
01717	}
01718	
01719	exec function bool SwitchToBestWeapon()
01720	{
01721		local float rating;
01722		local int usealt;
01723	
01724		if ( Inventory == None )
01725			return false;
01726	
01727		PendingWeapon = Inventory.RecommendWeapon(rating, usealt);
01728		if ( PendingWeapon == Weapon )
01729			PendingWeapon = None;
01730		if ( PendingWeapon == None )
01731			return false;
01732	
01733		if ( Weapon == None )
01734			ChangedWeapon();
01735		if ( Weapon != PendingWeapon )
01736			Weapon.PutDown();
01737	
01738		return (usealt > 0);
01739	}
01740	
01741	State Dying
01742	{
01743	ignores SeePlayer, EnemyNotVisible, HearNoise, KilledBy, Trigger, Bump, HitWall, HeadZoneChange, FootZoneChange, ZoneChange, Falling, WarnTarget, Died, LongFall, PainTimer;
01744	
01745		function TakeDamage( int Damage, Pawn instigatedBy, Vector hitlocation, 
01746								Vector momentum, name damageType)
01747		{
01748			if ( bDeleteMe )
01749				return;
01750			Health = Health - Damage;
01751			Momentum = Momentum/Mass;
01752			AddVelocity( momentum ); 
01753			if ( !bHidden && Gibbed(damageType) )
01754			{
01755				bHidden = true;
01756				SpawnGibbedCarcass();
01757				if ( bIsPlayer )
01758					HidePlayer();
01759				else
01760					Destroy();
01761			}
01762		}
01763	
01764		function Timer()
01765		{
01766			if ( !bHidden )
01767			{
01768				bHidden = true;
01769				SpawnCarcass();
01770				if ( bIsPlayer )
01771					HidePlayer();
01772				else
01773					Destroy();
01774			}
01775		}
01776	
01777		event Landed(vector HitNormal)
01778		{
01779			SetPhysics(PHYS_None);
01780		}
01781	
01782		function BeginState()
01783		{
01784			SetTimer(0.3, false);
01785		}
01786	}
01787	
01788	state GameEnded
01789	{
01790	ignores SeePlayer, HearNoise, KilledBy, Bump, HitWall, HeadZoneChange, FootZoneChange, ZoneChange, Falling, TakeDamage, WarnTarget, Died;
01791	
01792		function BeginState()
01793		{
01794			SetPhysics(PHYS_None);
01795			HidePlayer();
01796		}
01797	}
01798	
01799	defaultproperties
01800	{
01801	     AvgPhysicsTime=0.100000
01802	     MaxDesiredSpeed=1.000000
01803	     GroundSpeed=320.000000
01804	     WaterSpeed=200.000000
01805	     AccelRate=500.000000
01806	     JumpZ=325.000000
01807	     MaxStepHeight=25.000000
01808	     AirControl=0.050000
01809	     Visibility=128
01810	     SightRadius=2500.000000
01811	     HearingThreshold=1.000000
01812	     OrthoZoom=40000.000000
01813	     FovAngle=90.000000
01814	     Health=100
01815	     AttitudeToPlayer=ATTITUDE_Hate
01816	     Intelligence=BRAINS_MAMMAL
01817	     noise1time=-10.000000
01818	     noise2time=-10.000000
01819	     SoundDampening=1.000000
01820	     DamageScaling=1.000000
01821	     PlayerReStartState=PlayerWalking
01822	     NameArticle=" a "
01823	     PlayerReplicationInfoClass=Class'Engine.PlayerReplicationInfo'
01824	     bCanTeleport=True
01825	     bStasis=True
01826	     bIsPawn=True
01827	     RemoteRole=ROLE_SimulatedProxy
01828	     AnimSequence=Fighter
01829	     bDirectional=True
01830	     Texture=Texture'Engine.S_Pawn'
01831	     bIsKillGoal=True
01832	     SoundRadius=9
01833	     SoundVolume=240
01834	     TransientSoundVolume=2.000000
01835	     bCollideActors=True
01836	     bCollideWorld=True
01837	     bBlockActors=True
01838	     bBlockPlayers=True
01839	     bProjTarget=True
01840	     bRotateToDesired=True
01841	     RotationRate=(Pitch=4096,Yaw=50000,Roll=3072)
01842	     NetPriority=2.000000
01843	}

End Source Code