rott/kf_sources/Engine/Classes/Pawn.uc
2026-07-14 20:27:09 +07:00

3178 lines
88 KiB
Ucode

//=============================================================================
// Pawn, the base class of all actors that can be controlled by players or AI.
//
// Pawns are the physical representations of players and creatures in a level.
// Pawns have a mesh, collision, and physics. Pawns can take damage, make sounds,
// and hold weapons and other inventory. In short, they are responsible for all
// physical interaction between the player or AI and the world.
//
// This is a built-in Unreal class and it shouldn't be modified.
//=============================================================================
class Pawn extends Actor
abstract
native
placeable
config(user)
nativereplication
exportstructs;
#exec Texture Import File=Textures\Pawn.pcx Name=S_Pawn Mips=Off MASKED=1
//-----------------------------------------------------------------------------
// Pawn variables.
var Controller Controller;
// cache net relevancy test
var float NetRelevancyTime;
var playerController LastRealViewer;
var actor LastViewer;
var const float LastLocTime; // used to force periodic location replication, even when pawn isn't moving
// Physics related flags.
var bool bJustLanded; // used by eyeheight adjustment
var bool bLandRecovery; // used by eyeheight adjustment
var bool bUpAndOut; // used by swimming
var bool bIsWalking; // currently walking (can't jump, affects animations)
var bool bWarping; // Set when travelling through warpzone (so shouldn't telefrag)
var bool bWantsToCrouch; // if true crouched (physics will automatically reduce collision height to CrouchHeight)
var const bool bIsCrouched; // set by physics to specify that pawn is currently crouched
var const bool bTryToUncrouch; // when auto-crouch during movement, continually try to uncrouch
var() bool bCanCrouch; // if true, this pawn is capable of crouching
var bool bCrawler; // crawling - pitch and roll based on surface pawn is on
var const bool bReducedSpeed; // used by movement natives
var bool bJumpCapable;
var bool bCanJump; // movement capabilities - used by AI
var bool bCanWalk;
var bool bCanSwim;
var bool bCanFly;
var bool bCanClimbLadders;
var bool bCanStrafe;
var bool bCanDoubleJump;
var bool bCanWallDodge;
var bool bAvoidLedges; // don't get too close to ledges
var bool bStopAtLedges; // if bAvoidLedges and bStopAtLedges, Pawn doesn't try to walk along the edge at all
var bool bNoJumpAdjust; // set to tell controller not to modify velocity of a jump/fall
var bool bCountJumps; // if true, inventory wants message whenever this pawn jumps
var const bool bSimulateGravity; // simulate gravity for this pawn on network clients when predicting position (true if pawn is walking or falling)
var bool bUpdateEyeheight; // if true, UpdateEyeheight will get called every tick
var bool bIgnoreForces; // if true, not affected by external forces
var const bool bNoVelocityUpdate; // used by C++ physics
var bool bCanWalkOffLedges; // Can still fall off ledges, even when walking (for Player Controlled pawns)
var bool bSteadyFiring; // used for third person weapon anims/effects
var bool bCanBeBaseForPawns; // all your 'base', are belong to us
var bool bClientCollision; // used on clients when temporarily turning off collision
var const bool bSimGravityDisabled; // used on network clients
var bool bDirectHitWall; // always call pawn hitwall directly (no controller notifyhitwall)
var bool bServerMoveSetPawnRot;
var bool bFlyingKarma; // Tells AI that this vehicle can be flown like PHYS_Flying even though it has karma physics
var bool bDrawCorona;
var globalconfig bool bNoCoronas;
// used by dead pawns (for bodies landing and changing collision box)
var bool bThumped;
var bool bInvulnerableBody;
// AI related flags
var bool bIsFemale;
var bool bAutoActivate; // if true, automatically activate Powerups which have their bAutoActivate==true
var bool bCanPickupInventory; // if true, will pickup inventory when touching pickup actors
var bool bUpdatingDisplay; // to avoid infinite recursion through inventory setdisplay
var bool bAmbientCreature; // AIs will ignore me
var(AI) bool bLOSHearing; // can hear sounds from line-of-sight sources (which are close enough to hear)
// bLOSHearing=true is like UT/Unreal hearing
var(AI) bool bSameZoneHearing; // can hear any sound in same zone (if close enough to hear)
var(AI) bool bAdjacentZoneHearing; // can hear any sound in adjacent zone (if close enough to hear)
var(AI) bool bMuffledHearing; // can hear sounds through walls (but muffled - sound distance increased to double plus 4x the distance through walls
var(AI) bool bAroundCornerHearing; // Hear sounds around one corner (slightly more expensive, and bLOSHearing must also be true)
var(AI) bool bDontPossess; // if true, Pawn won't be possessed at game start
var bool bAutoFire; // used for third person weapon anims/effects
var bool bRollToDesired; // Update roll when turning to desired rotation (normally false)
var bool bIgnorePlayFiring; // if true, ignore the next PlayFiring() call (used by AnimNotify_FireWeapon)
var bool bStationary; // pawn can't move
var bool bCachedRelevant; // network relevancy caching flag
var bool bUseCompressedPosition; // use compressed position in networking - true unless want to replicate roll, or very high velocities
// if _RO_
var bool bWeaponBob;
// else
//var globalconfig bool bWeaponBob;
// endif _RO_
var bool bHideRegularHUD;
var bool bSpecialHUD;
var bool bSpecialCrosshair;
var bool bSpecialCalcView; // If true, the Controller controlling this pawn will call 'SpecialCalcView' to find camera pos.
var bool bNoTeamBeacon; // never display team beacon for this pawn
var bool bNoWeaponFiring;
var bool bIsTyping; // play typing anim if idle
var bool bScriptPostRender; // if true, PostRender2D() gets called instead of native team beacon drawing code
var bool bCanUse; // can this pawn Use things?
var bool bSuperSize; // hack for Leviathan
var byte FlashCount; // used for third person weapon anims/effects
// AI basics.
var byte Visibility; //How visible is the pawn? 0=invisible, 128=normal, 255=highly visible
var float DesiredSpeed;
var float MaxDesiredSpeed;
var(AI) name AIScriptTag; // tag of AIScript which should be associated with this pawn
var(AI) float HearingThreshold; // max distance at which a makenoise(1.0) loudness sound can be heard
var(AI) float Alertness; // -1 to 1 ->Used within specific states for varying reaction to stimuli
var(AI) float SightRadius; // Maximum seeing distance.
var(AI) float PeripheralVision; // Cosine of limits of peripheral vision.
var() float SkillModifier; // skill modifier (same scale as game difficulty)
var const float AvgPhysicsTime; // Physics updating time monitoring (for AI monitoring reaching destinations)
var float MeleeRange; // Max range for melee attack (not including collision radii)
var float NavigationPointRange; // extra slack to have "reached" a NavigationPoint
var NavigationPoint Anchor; // current nearest path;
var const NavigationPoint LastAnchor; // recent nearest path
var float FindAnchorFailedTime; // last time a FindPath() attempt failed to find an anchor.
var float LastValidAnchorTime; // last time a valid anchor was found
var float DestinationOffset; // used to vary destination over NavigationPoints
var float NextPathRadius; // radius of next path in route
var vector SerpentineDir; // serpentine direction
var float SerpentineDist;
var float SerpentineTime; // how long to stay straight before strafing again
var const float UncrouchTime; // when auto-crouch during movement, continually try to uncrouch once this decrements to zero
var float SpawnTime;
// Movement.
var float GroundSpeed; // The maximum ground speed.
var float WaterSpeed; // The maximum swimming speed.
var float AirSpeed; // The maximum flying speed.
var float LadderSpeed; // Ladder climbing speed
var float AccelRate; // max acceleration rate
var float JumpZ; // vertical acceleration w/ jump
var float AirControl; // amount of AirControl available to the pawn
var float WalkingPct; // pct. of running speed that walking speed is
var float CrouchedPct; // pct. of running speed that crouched walking speed is
var float MaxFallSpeed; // max speed pawn can land without taking damage (also limits what paths AI can use)
var vector ConstantAcceleration; // acceleration added to pawn when falling
var Vehicle DrivenVehicle;
var vector ImpactVelocity; // velocity added while falling (bot tries to correct for it)
var() int PitchUpLimit;
var() int PitchDownLimit;
// Player info.
var string OwnerName; // Name of owning player (for save games, coop)
var travel Weapon Weapon; // The pawn's current weapon.
var Weapon PendingWeapon; // Will become weapon once current weapon is put down
var travel Powerups SelectedItem; // currently selected inventory item
var float BaseEyeHeight; // Base eye height above collision center.
var float EyeHeight; // Current eye height, adjusted for bobbing and stairs.
var vector Floor; // Normal of floor pawn is standing on (only used by PHYS_Spider and PHYS_Walking)
var float SplashTime; // time of last splash
var float CrouchHeight; // CollisionHeight when crouching
var float CrouchRadius; // CollisionRadius when crouching
var() float DrivingHeight; // CollisionHeight when driving a vehicle
var() float DrivingRadius; // CollisionRadius when driving a vehicle
var float OldZ; // Old Z Location - used for eyeheight smoothing
var PhysicsVolume HeadVolume; // physics volume of head
var float HealthMax;
var float SuperHealthMax;
var travel int Health; // Health: 100 = normal maximum
var float BreathTime; // used for getting BreathTimer() messages (for no air, etc.)
var float UnderWaterTime; // how much time pawn can go without air (in seconds)
var float LastPainTime; // last time pawn played a takehit animation (updated in PlayHit())
var class<DamageType> ReducedDamageType; // which damagetype this creature is protected from (used by AI)
var float HeadRadius; // Squared radius of the head of the pawn that is vulnerable to headshots
var float HeadHeight; // Distance from base of neck to center of head - used for headshot calculation
var float HeadScale;
var bool bSetPCRotOnPossess;
// Sound and noise management
// remember location and position of last noises propagated
var const vector noise1spot;
var const float noise1time;
var const pawn noise1other;
var const float noise1loudness;
var const vector noise2spot;
var const float noise2time;
var const pawn noise2other;
var const float noise2loudness;
var float LastPainSound;
// view bob
// if _RO_
var float Bob;
// else
//var globalconfig float Bob;
// endif _RO_
var float LandBob, AppliedBob;
var float bobtime;
var vector WalkBob;
var float SoundDampening;
var float DamageScaling;
// if _KF_
var(Sound) float AmbientSoundScaling; // General scaling value for this pawn's ambient sounds. We don't want it config so we can modify it per pawn type - Ramm
//else
//var globalconfig float AmbientSoundScaling;
// endif _KF_
var localized string MenuName; // Name used for this pawn type in menus (e.g. player selection)
// shadow decal
var Projector Shadow;
// blood effect
var class<Effects> BloodEffect;
var class<Effects> LowGoreBlood;
var class<AIController> ControllerClass; // default class to use when pawn is controlled by AI (can be modified by an AIScript)
var PlayerReplicationInfo PlayerReplicationInfo;
var LadderVolume OnLadder; // ladder currently being climbed
var name LandMovementState; // PlayerControllerState to use when moving on land or air
var name WaterMovementState; // PlayerControllerState to use when moving in water
var PlayerStart LastStartSpot; // used to avoid spawn camping
var float LastStartTime;
// Animation status
var name AnimAction; // use for replicating anims
// Animation updating by physics
// Note that animation channels 2 through 11 are used for animation updating
var vector TakeHitLocation; // location of last hit (for playing hit/death anims)
var class<DamageType> HitDamageType; // damage type of last hit (for playing hit/death anims)
var vector TearOffMomentum; // momentum to apply when torn off (bTearOff == true)
var EPhysics OldPhysics;
var bool bPhysicsAnimUpdate;
var bool bWasCrouched;
var bool bWasWalking;
var bool bWasOnGround;
var bool bInitializeAnimation;
var bool bPlayedDeath;
// jjs - physics based animation stuff
var bool bIsIdle; // true when standing still on the ground, Physics can be used for determining other states
var bool bWaitForAnim; // true if the pawn is playing an important non-looping animation (eg. landing/dodge) and doesn't feel like being interrupted
var const bool bReverseRun;
var bool bDoTorsoTwist;
var const bool FootTurning;
var const bool FootStill;
var const byte ViewPitch; // jjs - something to replicate so we can see which way remote clients are looking
var int SmoothViewPitch;
var int SmoothViewYaw;
var float OldRotYaw; // used for determining if pawn is turning
var vector OldAcceleration;
// if RO
var name MovementAnims[8]; // Forward, Back, Left, Right, Forward-Left, Forward-Right, Back-Left, Back-Right
//else
//var name MovementAnims[4]; // Forward, Back, Left, Right
var name TurnLeftAnim;
var name TurnRightAnim; // turning anims when standing in place (scaled by turn speed)
var(AnimTweaks) float BlendChangeTime; // time to blend between movement animations
var float MovementBlendStartTime; // used for delaying the start of run blending
var float ForwardStrafeBias; // bias of strafe blending in forward direction
var float BackwardStrafeBias; // bias of strafe blending in backward direction
var float DodgeSpeedFactor; // dodge speed moved here so animation knows the diff between a jump and a dodge
var float DodgeSpeedZ;
var const int OldAnimDir;
var const Vector OldVelocity;
var float IdleTime;
var name SwimAnims[4]; // 0=forward, 1=backwards, 2=left, 3=right
// if RO
var name CrouchAnims[8]; // Forward, Back, Left, Right, Forward-Left, Forward-Right, Back-Left, Back-Right
var name WalkAnims[8];
//else
//var name CrouchAnims[4];
//var name WalkAnims[4];
var name AirAnims[4];
var name TakeoffAnims[4];
var name LandAnims[4];
var name DoubleJumpAnims[4];
var name DodgeAnims[4];
var name AirStillAnim;
var name TakeoffStillAnim;
var name CrouchTurnRightAnim;
var name CrouchTurnLeftAnim;
var name IdleCrouchAnim;
var name IdleSwimAnim;
var name IdleWeaponAnim; // WeaponAttachment code will set this one
var name IdleRestAnim;
var name IdleChatAnim;
var array<name> TauntAnims; // Array of names of taunt anim that can be played by this character. First 4 assumed to be orders.
var localized string TauntAnimNames[16]; // Text description
var const int FootRot; // torso twisting/looking stuff
var const int TurnDir;
var name RootBone;
var name HeadBone;
var name SpineBone1;
var name SpineBone2;
// xPawn replicated properties - moved here to take advantage of native replication
var(Shield) transient float ShieldStrength; // current shielding (having been activated)
struct HitFXData
{
var() Name Bone;
var() class<DamageType> damtype;
var() bool bSever;
var() Rotator rotDir;
};
var() HitFXData HitFx[8];
var transient int HitFxTicker;
var transient CompressedPosition PawnPosition;
var Controller DelayedDamageInstigatorController;
var Controller LastHitBy; //give kill credit to this guy if hit momentum causes pawn to fall to his death
var float MinFlySpeed;
var float MaxRotation; // minimum dot product of movement direction and rotation vector, ignored if 0
// if _RO_
// Physics related flags.
var bool bWantsToProne; // if true prone (physics will automatically reduce collision height to ProneHeight && ProneRadius)
var const bool bIsCrawling; // set by physics to specify that pawn is currently crawling
var() bool bCanProne; // if true, this pawn is capable of proning
var bool bWasCrawling; // Animation flag used by native phyics anims
var bool bIronSights; // Only applies to player anim swapping
var bool bWasIronSights; // Only applies to player anim swapping
var bool bMeleeHolding; // Player is pulled back ready to perform a melee strike. Used for native anim code
var bool bWasMeleeHolding; // Only applies to player anim swapping
var bool bExplosiveHolding; // Player is pulled back ready to throw an explosive. Used for native anim code
var bool bWasExplosiveHolding; // Only applies to player anim swapping
var bool bIsSprinting; // Is the player currently sprinting?
var bool bIsLimping; // Player was shot in the leg and is limping
var bool bCanStartSprint; // The player has enough stamina to start sprinting. Set serverside and replicated to clients
// Deployment system
var const bool bCanRestWeapon; // The player is in a position where they can rest thier weapon on something
var const bool bRestingWeapon; // The player's weapon is resting on a ledge or wall
var const bool bCanBipodDeploy; // The player is in a position where they deploy thier weapon on a bipod
var bool bBipodDeployed; // Player has thier weapon deployed on a bipod
var bool bWasBipodDeployed; // Only applies to player anim swapping
// Movement
var() float SprintPct; // Relative speed for sprint movement
var() float PronePct; // Relative speed for prone movement
var() float ProneIronPct; // Relative speed for prone movement with iron sights
var() float CrouchedSprintPct; // pct. of running speed that crouched sprint speed is
var() float ProneHeight; // Collision size when prone
var() float ProneRadius; // Collision size when prone
/*==========================================
* Red Orchestra hit detection system
*=========================================*/
// Hit point types
enum EPawnHitPointType
{
PHP_None,
PHP_Head,
PHP_Torso,
PHP_Arm,
PHP_Leg,
PHP_Hand,
PHP_Foot,
};
// Information for each specific hit area
struct native PawnHitpoint
{
var() float PointRadius; // Squared radius of the head of the pawn that is vulnerable to headshots
var() float PointHeight; // Distance from base of neck to center of head - used for headshot calculation
var() float PointScale;
var() name PointBone;
var() vector PointOffset; // Amount to offset the hitpoint from the bone
var() float DamageMultiplier; // Amount to scale damage to the player if this point is hit
var() EPawnHitPointType HitPointType; // What type of hit point this is
};
//PawnHitpoint
var() array<PawnHitpoint> Hitpoints; // An array of possible small points that can be hit. Index zero is always the driver
// Bullet whiz vars
var vector mWhizSoundLocation; // Location to spawn the bullet whiz effect at
var byte SpawnWhizCount; // When this is incremented will spawn a bullet whiz
var byte OldSpawnWhizCount; // Saved bullet whiz counter
var byte LastWhizType; // The last type of bullet whiz. 0 = none, 1 = bullet, 2 = large shell
var float LastWhippedTime; // Last time this pawn heard a bullet whip. Used to limit the rate of bullet whips heard
// Mine volume vars
var float MineAreaEnterTime; // Last time this pawn was in a mine area
var float MineAreaWarnTime; // Last time this pawn was warned in a mine area
//Resupply
var float LastResupplyTime; // Last time this client was resupplied. Not replicated directly as Level.Timeseconds is not the same on server and client
var bool bTouchingResupply; // This pawn is in an ammo resupply zone
var sound AmmoResupplySound; // sound to play when this pawn is resupplied with ammo
var float AnimBlendTime; // Native code calls the AnimBlendTimer event when the amount of time this is set for reaches zero
// IF _KF_
var float CustomAmbientRelevancyScale;// Scale the net relevancy check for Pawns playing ambient sounds by this. Used to have a larger ambient sound radius so sound can be heard well, without making pawns relevant at very long distances
// end _KF_
// End _RO_
// if _KF_
var const float LedgeCheckThreshold; // Used in determining if pawn is going off ledge.
// end _KF_
replication
{
// Variables the server should send to the client.
reliable if( bNetDirty && (Role==ROLE_Authority) )
bSimulateGravity, bIsCrouched, bIsWalking, PlayerReplicationInfo, AnimAction, HitDamageType, TakeHitLocation,HeadScale, bIsTyping, DrivenVehicle, bSpecialHUD;
reliable if( bTearOff && bNetDirty && (Role==ROLE_Authority) )
TearOffMomentum;
reliable if ( bNetDirty && !bNetOwner && (Role==ROLE_Authority) )
bSteadyFiring, ViewPitch; // - jjs
reliable if( bNetDirty && bNetOwner && Role==ROLE_Authority )
Controller,SelectedItem, GroundSpeed, WaterSpeed, AirSpeed, AccelRate, JumpZ, AirControl, bCanWallDodge, PitchUpLimit, PitchDownLimit;
reliable if( bNetDirty && Role==ROLE_Authority )
Health;
reliable if ( bNetDirty && bNetInitial && Role==ROLE_Authority )
HealthMax;
unreliable if ( !bNetOwner && Role==ROLE_Authority )
PawnPosition;
// xPawn replicated properties - moved here to take advantage of native replication
reliable if (Role==ROLE_Authority)
ShieldStrength, HitFx, HitFxTicker;
// replicated functions sent to server by owning client
reliable if( Role<ROLE_Authority )
ServerChangedWeapon, NextItem, ServerNoTranslocator;
// if _RO_
// ROPawn replicated properties - moved here to take advantage of native replication
reliable if (bNetDirty && Role == ROLE_Authority)
bIsCrawling, bIronSights, bIsSprinting, bIsLimping, bMeleeHolding, bExplosiveHolding,
bBipodDeployed;
// ROPawn replicated properties - moved here to take advantage of native replication
reliable if (bNetOwner && bNetDirty && Role == ROLE_Authority)
bCanRestWeapon, bRestingWeapon, bCanBipodDeploy, bTouchingResupply;
// ROPawn replicated properties - moved here to take advantage of native replication
reliable if (bNetDirty && bNetOwner && Role == ROLE_Authority)
bCanStartSprint, SpawnWhizCount, mWhizSoundLocation, LastWhizType;
// Server to client functions
reliable if (Role == ROLE_Authority)
ClientResupplied;
// end _RO_
}
// if _RO_
// ROFunctions - put here to avoid casting
simulated function bool CanProneTransition(){return true;}
simulated function bool CanCrouchTransition(){return true;}
simulated event bool IsTransitioningToProne(){return false;}
simulated event bool IsProneTransitioning(){return false;}
simulated event HandleWhizSound();
// Set the vars so this bullet whiz is replicated to the owning client
event PawnWhizzed(vector WhizLocation, int WhizType)
{
if((Level.TimeSeconds - LastWhippedTime) > (0.15 + FRand() * 0.15))
{
LastWhippedTime = Level.TimeSeconds;
mWhizSoundLocation = WhizLocation;
SpawnWhizCount++;
// Spawn the whiz sound for local non network players
HandleWhizSound();
NetUpdateTime = Level.TimeSeconds - 1;
}
}
// Play ammo resupply sound for ammo resupply areas
simulated function ClientResupplied()
{
PlayOwnedSound(AmmoResupplySound, SLOT_Interact,3.5*TransientSoundVolume,true,10);
// Set this value locally on the client rather than replicating it since this value
// will vary greatly between clients and the server and its only used on the client
// for the hud indicator
LastResupplyTime = Level.TimeSeconds;
}
// Tear off momentum gets rounded too much, so lets scale it up, and then unscale it when its used
// so we avoid the replication rounding
simulated function SetTearOffMomemtum(vector NewMomentum)
{
TearOffMomentum = NewMomentum * 1000;
}
simulated function vector GetTearOffMomemtum()
{
return TearOffMomentum/1000;
}
// Blend the upper body back to full body animation.
// Called by the native code when AnimBlendTime counts down to zero
simulated event AnimBlendTimer()
{
AnimBlendToAlpha(1, 0.0, 0.12);
}
// Get how many frames have passed since this pawn entered ragdoll
simulated native function int GetRagDollFrames();
// end _RO_
static function StaticPrecache(LevelInfo L);
simulated native function SetViewPitch( int NewPitch );
simulated native function SetTwistLook( int twist, int look );
simulated native function int Get4WayDirection( );
simulated event SetHeadScale(float NewScale);
simulated event PostRender2D(Canvas C, float ScreenLocX, float ScreenLocY) // called if bScriptPostRender is true, overrides native team beacon drawing code
{
local PlayerController PC;
PC = Level.GetLocalPlayerController();
if ( (PC != None) && (PC.myHUD != None) )
PC.myHUD.DrawCustomBeacon(C,self, ScreenLocX, ScreenLocY);
}
native function bool ReachedDestination(Actor Goal);
native function ForceCrouch();
simulated function Weapon GetDemoRecordingWeapon()
{
local inventory Inv;
local int i;
for ( Inv=Inventory; Inv!=None; Inv=Inv.Inventory )
{
if ( (Weapon(Inv) != None) && (Inv.ThirdPersonActor != None) )
{
Weapon = Weapon(Inv);
PendingWeapon = Weapon;
Weapon.bSpectated = true;
break;
}
i++;
if ( i > 500 )
return None;
}
return Weapon;
}
simulated function SetBaseEyeheight()
{
if ( !bIsCrouched )
BaseEyeheight = Default.BaseEyeheight;
else
BaseEyeheight = FMin(0.8 * CrouchHeight, CrouchHeight - 10);
Eyeheight = BaseEyeheight;
}
function Pawn GetAimTarget()
{
return self;
}
function DeactivateSpawnProtection()
{
SpawnTime = -100000;
}
function Actor GetPathTo(Actor Dest)
{
if ( PlayerController(Controller) == None )
return Dest;
return PlayerController(Controller).GetPathTo(Dest);
}
function PlayerChangedTeam()
{
Died( None, class'DamageType', Location );
}
/* Reset()
reset actor to initial state - used when restarting level without reloading.
*/
function Reset()
{
if ( (Controller == None) || Controller.bIsPlayer )
{
if ( Controller != None )
Controller.PawnDied(self);
Destroy();
}
else
Super.Reset();
}
function bool HasWeapon()
{
return (Weapon != None);
}
function ChooseFireAt( Actor A )
{
Fire(0);
}
function bool StopWeaponFiring()
{
if (Weapon != None && Weapon.IsFiring())
{
Weapon.ServerStopFire(0);
Weapon.ServerStopFire(1);
return true;
}
return false;
}
simulated function Fire( optional float F )
{
if (Weapon != None)
{
Weapon.Fire(F);
}
}
simulated function AltFire( optional float F )
{
if( Weapon!=None )
Weapon.AltFire(F);
}
function bool RecommendLongRangedAttack()
{
if ( Weapon != None )
return Weapon.RecommendLongRangedAttack();
return false;
}
function bool CanAttack(Actor Other)
{
if ( Weapon == None )
return false;
return Weapon.CanAttack(Other);
}
function bool TooCloseToAttack(Actor Other)
{
return false;
}
function float RefireRate()
{
if (Weapon != None)
return Weapon.RefireRate();
return 0;
}
function bool IsFiring()
{
if (Weapon != None)
return Weapon.IsFiring();
return false;
}
function bool FireOnRelease()
{
if (Weapon != None)
return Weapon.FireOnRelease();
return false;
}
function bool NeedToTurn(vector targ)
{
local vector LookDir, AimDir;
LookDir = Vector(Rotation);
LookDir.Z = 0;
LookDir = Normal(LookDir);
AimDir = targ - Location;
AimDir.Z = 0;
AimDir = Normal(AimDir);
return ((LookDir Dot AimDir) < 0.93);
}
function float ModifyThreat(float current, Pawn Threat)
{
return current;
}
function DrawHUD(Canvas Canvas);
simulated function SpecialDrawCrosshair( Canvas C );
// If returns false, do normal calcview anyway
function bool SpecialCalcView(out Actor ViewActor, out vector CameraLocation, out rotator CameraRotation);
function bool SpectatorSpecialCalcView(PlayerController Viewer, out Actor ViewActor, out vector CameraLocation, out rotator CameraRotation);
simulated function String GetHumanReadableName()
{
if ( PlayerReplicationInfo != None )
return PlayerReplicationInfo.PlayerName;
return MenuName;
}
function PlayTeleportEffect(bool bOut, bool bSound)
{
MakeNoise(1.0);
}
function HoldFlag(Actor FlagActor);
function DropFlag();
function bool PerformDodge(eDoubleClickDir DoubleClickMove, vector Dir, vector Cross);
function NotifyTeamChanged();
/* PossessedBy()
Pawn is possessed by Controller
*/
function PossessedBy(Controller C)
{
Controller = C;
NetPriority = 3;
NetUpdateFrequency = 100;
NetUpdateTime = Level.TimeSeconds - 1;
if ( C.PlayerReplicationInfo != None )
{
PlayerReplicationInfo = C.PlayerReplicationInfo;
OwnerName = PlayerReplicationInfo.PlayerName;
}
if ( C.IsA('PlayerController') )
{
if ( bSetPCRotOnPossess )
C.SetRotation(Rotation);
if ( Level.NetMode != NM_Standalone )
RemoteRole = ROLE_AutonomousProxy;
BecomeViewTarget();
}
else
RemoteRole = Default.RemoteRole;
SetOwner(Controller); // for network replication
Eyeheight = BaseEyeHeight;
ChangeAnimation();
}
function UnPossessed()
{
NetUpdateTime = Level.TimeSeconds - 1;
if ( DrivenVehicle != None )
NetUpdateFrequency = 5;
PlayerReplicationInfo = None;
SetOwner(None);
Controller = None;
}
/* PointOfView()
called by controller when possessing this pawn
false = 1st person, true = 3rd person
*/
simulated function bool PointOfView()
{
return false;
}
function BecomeViewTarget()
{
bUpdateEyeHeight = true;
}
function DropToGround()
{
bCollideWorld = True;
bInterpolating = false;
if ( Health > 0 )
{
SetCollision(true,true);
SetPhysics(PHYS_Falling);
AmbientSound = None;
if ( IsHumanControlled() )
Controller.GotoState(LandMovementState);
}
}
function bool CanGrabLadder()
{
return ( bCanClimbLadders
&& (Controller != None)
&& (Physics != PHYS_Ladder)
&& ((Physics != Phys_Falling) || (abs(Velocity.Z) <= JumpZ)) );
}
event SetWalking(bool bNewIsWalking)
{
if ( bNewIsWalking != bIsWalking )
{
bIsWalking = bNewIsWalking;
ChangeAnimation();
}
}
simulated function bool CanSplash()
{
if ( (Level.TimeSeconds - SplashTime > 0.15)
&& ((Physics == PHYS_Falling) || (Physics == PHYS_Flying))
&& (Abs(Velocity.Z) > 100) )
{
SplashTime = Level.TimeSeconds;
return true;
}
return false;
}
function EndClimbLadder(LadderVolume OldLadder)
{
if ( Controller != None )
Controller.EndClimbLadder();
if ( Physics == PHYS_Ladder )
SetPhysics(PHYS_Falling);
}
function ClimbLadder(LadderVolume L)
{
OnLadder = L;
SetRotation(OnLadder.WallDir);
SetPhysics(PHYS_Ladder);
if ( IsHumanControlled() )
Controller.GotoState('PlayerClimbing');
}
/* DisplayDebug()
list important actor variable on canvas. Also show the pawn's controller and weapon info
*/
simulated function DisplayDebug(Canvas Canvas, out float YL, out float YPos)
{
local string T;
Super.DisplayDebug(Canvas, YL, YPos);
Canvas.SetDrawColor(255,255,255);
Canvas.DrawText("Animation Action "$AnimAction$" Health "$Health);
YPos += YL;
Canvas.SetPos(4,YPos);
Canvas.DrawText("Anchor "$Anchor$" Serpentine Dist "$SerpentineDist$" Time "$SerpentineTime);
YPos += YL;
Canvas.SetPos(4,YPos);
T = "Floor "$Floor$" DesiredSpeed "$DesiredSpeed$" Crouched "$bIsCrouched$" Try to uncrouch "$UncrouchTime;
if ( (OnLadder != None) || (Physics == PHYS_Ladder) )
T=T$" on ladder "$OnLadder;
Canvas.DrawText(T);
YPos += YL;
Canvas.SetPos(4,YPos);
Canvas.DrawText("EyeHeight "$Eyeheight$" BaseEyeHeight "$BaseEyeHeight$" Physics Anim "$bPhysicsAnimUpdate);
YPos += YL;
Canvas.SetPos(4,YPos);
if ( Controller == None )
{
Canvas.SetDrawColor(255,0,0);
Canvas.DrawText("NO CONTROLLER");
YPos += YL;
Canvas.SetPos(4,YPos);
}
else
{
if ( Controller.PlayerReplicationInfo != None )
{
Canvas.SetDrawColor(255,0,0);
Canvas.DrawText("Owned by "$Controller.PlayerReplicationInfo.PlayerName);
YPos += YL;
Canvas.SetPos(4,YPos);
}
Controller.DisplayDebug(Canvas,YL,YPos);
}
if ( Weapon == None )
{
Canvas.SetDrawColor(0,255,0);
Canvas.DrawText("NO WEAPON");
YPos += YL;
Canvas.SetPos(4,YPos);
}
else
Weapon.DisplayDebug(Canvas,YL,YPos);
}
//
// Compute offset for drawing an inventory item.
//
simulated function vector CalcDrawOffset(inventory Inv)
{
local vector DrawOffset;
if ( Controller == None )
return (Inv.PlayerViewOffset >> Rotation) + BaseEyeHeight * vect(0,0,1);
DrawOffset = ((0.9/Weapon.DisplayFOV * 100 * ModifiedPlayerViewOffset(Inv)) >> GetViewRotation() );
if ( !IsLocallyControlled() )
DrawOffset.Z += BaseEyeHeight;
else
{
DrawOffset.Z += EyeHeight;
if( bWeaponBob )
DrawOffset += WeaponBob(Inv.BobDamping);
DrawOffset += CameraShake();
}
return DrawOffset;
}
// IF_RO_
//
// Compute offset for drawing a weapon in ironsights.
//
simulated function vector CalcZoomedDrawOffset(inventory Inv)
{
local vector DrawOffset;
if ( Controller == None )
return (Inv.PlayerViewOffset >> Rotation) + BaseEyeHeight * vect(0,0,1);
DrawOffset = ((0.9/Weapon.DisplayFOV * 100 * ZoomedModifiedPlayerViewOffset(Inv)));
if ( IsLocallyControlled() )
{
DrawOffset += ZoomedWeaponBob(Inv.BobDamping);
DrawOffset += ZoomedCameraShake();
}
return DrawOffset;
}
// Calculate weapon bob for a weapon in IS (removing player rotation since IS weapons are drawn in hud space)
simulated function vector ZoomedWeaponBob(float BobDamping)
{
Local Vector WBob;
WBob = BobDamping * (WalkBob >> (GetViewRotation() * -1));
WBob.Z = (0.45 + 0.55 * BobDamping) * WalkBob.Z;
WBob.Z += LandBob;
return WBob;
}
simulated function vector ZoomedCameraShake()
{
local vector shakevect;
local PlayerController pc;
pc = PlayerController(Controller);
if (pc == None)
return shakevect;
// Scale the shake down 5x since first person weapons are scaled up 5x
shakevect = pc.ShakeOffset * 0.2;
return shakevect;
}
simulated function vector ZoomedModifiedPlayerViewOffset(inventory Inv)
{
return -Inv.PlayerViewOffset;
}
// end _RO_
simulated function vector CameraShake()
{
local vector x, y, z, shakevect;
local PlayerController pc;
pc = PlayerController(Controller);
if (pc == None)
return shakevect;
GetAxes(pc.Rotation, x, y, z);
shakevect = pc.ShakeOffset.X * x +
pc.ShakeOffset.Y * y +
pc.ShakeOffset.Z * z;
return shakevect;
}
simulated function vector ModifiedPlayerViewOffset(inventory Inv)
{
return Inv.PlayerViewOffset;
}
simulated function vector WeaponBob(float BobDamping)
{
Local Vector WBob;
WBob = BobDamping * WalkBob;
WBob.Z = (0.45 + 0.55 * BobDamping) * WalkBob.Z;
WBob.Z += LandBob;
return WBob;
}
function CheckBob(float DeltaTime, vector Y)
{
local float Speed2D;
if( !bWeaponBob || bJustLanded )
{
BobTime = 0;
WalkBob = Vect(0,0,0);
return;
}
Bob = FClamp(Bob, -0.01, 0.01);
if (Physics == PHYS_Walking )
{
Speed2D = VSize(Velocity);
if ( Speed2D < 10 )
BobTime += 0.2 * DeltaTime;
else
BobTime += DeltaTime * (0.3 + 0.7 * Speed2D/GroundSpeed);
WalkBob = Y * Bob * Speed2D * sin(8 * BobTime);
AppliedBob = AppliedBob * (1 - FMin(1, 16 * deltatime));
WalkBob.Z = AppliedBob;
if ( Speed2D > 10 )
WalkBob.Z = WalkBob.Z + 0.75 * Bob * Speed2D * sin(16 * BobTime);
}
else if ( Physics == PHYS_Swimming )
{
BobTime += DeltaTime;
Speed2D = Sqrt(Velocity.X * Velocity.X + Velocity.Y * Velocity.Y);
WalkBob = Y * Bob * 0.5 * Speed2D * sin(4.0 * BobTime);
WalkBob.Z = Bob * 1.5 * Speed2D * sin(8.0 * BobTime);
}
else
{
BobTime = 0;
WalkBob = WalkBob * (1 - FMin(1, 8 * deltatime));
}
}
//***************************************
// Vehicle driving
// StartDriving() and StopDriving() also called on client
// on transitions of bIsDriving setting
simulated event StartDriving(Vehicle V)
{
DrivenVehicle = V;
NetUpdateTime = Level.TimeSeconds - 1;
AmbientSound = None;
StopWeaponFiring();
DeactivateSpawnProtection();
// Move the driver into position, and attach to car.
ShouldCrouch(false);
bIgnoreForces = true;
Velocity = vect(0,0,0);
Acceleration = vect(0,0,0);
bCanTeleport = false;
if ( !V.bRemoteControlled || V.bHideRemoteDriver )
{
SetCollision( False, False, False);
bCollideWorld = false;
V.AttachDriver( Self );
if ( V.bDrawDriverinTP )
CullDistance = 5000;
else
bHidden = true;
}
// set animation
bPhysicsAnimUpdate = false;
bWaitForAnim = false;
if ( !V.bHideRemoteDriver && V.bDrawDriverinTP )
{
if ( HasAnim(DrivenVehicle.DriveAnim) )
LoopAnim(DrivenVehicle.DriveAnim);
else
LoopAnim('Vehicle_Driving');
SetAnimFrame(0.5);
SmoothViewYaw = Rotation.Yaw;
SetTwistLook(0,0);
}
else if ( !V.bRemoteControlled )
{
LoopAnim('Vehicle_Driving');
}
}
simulated event StopDriving(Vehicle V)
{
if ( (Role == ROLE_Authority) && (PlayerController(Controller) != None) )
V.PlayerStartTime = Level.TimeSeconds + 12;
CullDistance = Default.CullDistance;
NetUpdateTime = Level.TimeSeconds - 1;
if (V != None && V.Weapon != None )
V.Weapon.ImmediateStopFire();
if ( Physics == PHYS_Karma )
return;
DrivenVehicle = None;
bIgnoreForces = false;
bHardAttach = false;
bWaitForAnim = false;
bCanTeleport = true;
bCollideWorld = true;
PlayWaiting();
//PrePivot = vect(0,0,0);
if ( V != None )
V.DetachDriver( Self );
bPhysicsAnimUpdate = Default.bPhysicsAnimUpdate;
SetCollision(True, True);
if ( (Role == ROLE_Authority) && (Health > 0) )
{
if ( !V.bRemoteControlled || V.bHideRemoteDriver )
{
Acceleration = vect(0, 0, 24000);
if ( PhysicsVolume.bWaterVolume )
SetPhysics(PHYS_Swimming);
else
SetPhysics(PHYS_Falling);
SetBase(None);
bHidden = false;
}
}
bOwnerNoSee = default.bOwnerNoSee;
if ( Weapon != None )
{
PendingWeapon = None;
Weapon.BringUp();
}
}
simulated function bool FindValidTaunt( out name Sequence )
{
return true;
}
// CheckTauntValid() is obsolete, use FindValidTaunt()
simulated function bool CheckTauntValid( name Sequence )
{
return FindValidTaunt(sequence);
}
//***************************************
// Interface to Pawn's Controller
// return true if controlled by a Player (AI or human)
simulated function bool IsPlayerPawn()
{
return ( (Controller != None) && Controller.bIsPlayer );
}
// return true if was controlled by a Player (AI or human)
simulated function bool WasPlayerPawn()
{
return false;
}
// return true if controlled by a real live human
simulated function bool IsHumanControlled()
{
return ( PlayerController(Controller) != None );
}
// return true if controlled by local (not network) player
simulated function bool IsLocallyControlled()
{
if ( Level.NetMode == NM_Standalone )
return true;
if ( Controller == None )
return false;
if ( PlayerController(Controller) == None )
return true;
return ( Viewport(PlayerController(Controller).Player) != None );
}
// return true if viewing this pawn in first person pov. useful for determining what and where to spawn effects
simulated function bool IsFirstPerson()
{
local PlayerController PC;
PC = PlayerController(Controller);
return ( PC != None && !PC.bBehindView && Viewport(PC.Player) != None );
}
simulated function rotator GetViewRotation()
{
if ( Controller == None )
return Rotation;
return Controller.GetViewRotation();
}
simulated function SetViewRotation(rotator NewRotation )
{
if ( Controller != None )
Controller.SetRotation(NewRotation);
}
final function bool InGodMode()
{
return ( (Controller != None) && Controller.bGodMode );
}
function bool NearMoveTarget()
{
if ( (Controller == None) || (Controller.MoveTarget == None) )
return false;
return ReachedDestination(Controller.MoveTarget);
}
simulated final function bool PressingFire()
{
return ( (Controller != None) && (Controller.bFire != 0) );
}
simulated final function bool PressingAltFire()
{
return ( (Controller != None) && (Controller.bAltFire != 0) );
}
function Actor GetMoveTarget()
{
if ( Controller == None )
return None;
return Controller.MoveTarget;
}
function SetMoveTarget(Actor NewTarget )
{
if ( Controller != None )
Controller.MoveTarget = NewTarget;
}
function bool LineOfSightTo(actor Other)
{
return ( (Controller != None) && Controller.LineOfSightTo(Other) );
}
simulated final function rotator AdjustAim(FireProperties FiredAmmunition, vector projStart, int aimerror)
{
if ( Controller == None )
return Rotation;
return Controller.AdjustAim(FiredAmmunition, projStart, aimerror);
}
function Actor ShootSpecial(Actor A)
{
if ( !Controller.bCanDoSpecial || (Weapon == None) )
return None;
SetRotation(rotator(A.Location - Location));
Controller.Focus = A;
Controller.FireWeaponAt(A);
return A;
}
/* return a value (typically 0 to 1) adjusting pawn's perceived strength if under some special influence (like berserk)
*/
function float AdjustedStrength()
{
return 0;
}
function HandlePickup(Pickup pick)
{
MakeNoise(0.2);
if ( Controller != None )
Controller.HandlePickup(pick);
}
function ReceiveLocalizedMessage( class<LocalMessage> Message, optional int Switch, optional PlayerReplicationInfo RelatedPRI_1, optional PlayerReplicationInfo RelatedPRI_2, optional Object OptionalObject )
{
if ( PlayerController(Controller) != None )
PlayerController(Controller).ReceiveLocalizedMessage( Message, Switch, RelatedPRI_1, RelatedPRI_2, OptionalObject );
}
event ClientMessage( coerce string S, optional Name Type )
{
if ( PlayerController(Controller) != None )
PlayerController(Controller).ClientMessage( S, Type );
}
function Trigger( actor Other, pawn EventInstigator )
{
if ( Controller != None )
Controller.Trigger(Other, EventInstigator);
}
//***************************************
function bool CanTrigger(Trigger T)
{
return true;
}
function CreateInventory(string InventoryClassName)
{
}
function GiveWeapon(string aClassName )
{
local class<Weapon> WeaponClass;
local Weapon NewWeapon;
WeaponClass = class<Weapon>(DynamicLoadObject(aClassName, class'Class'));
if( FindInventoryType(WeaponClass) != None )
return;
newWeapon = Spawn(WeaponClass);
if( newWeapon != None )
newWeapon.GiveTo(self);
}
function SetDisplayProperties(ERenderStyle NewStyle, Material NewTexture, bool bLighting )
{
Style = NewStyle;
Texture = NewTexture;
bUnlit = bLighting;
if ( Weapon != None )
Weapon.SetDisplayProperties(Style, Texture, bUnlit);
if ( !bUpdatingDisplay && (Inventory != None) )
{
bUpdatingDisplay = true;
Inventory.SetOwnerDisplay();
}
bUpdatingDisplay = false;
}
function SetDefaultDisplayProperties()
{
Style = Default.Style;
texture = Default.Texture;
bUnlit = Default.bUnlit;
if ( Weapon != None )
Weapon.SetDefaultDisplayProperties();
if ( !bUpdatingDisplay && (Inventory != None) )
{
bUpdatingDisplay = true;
Inventory.SetOwnerDisplay();
}
bUpdatingDisplay = false;
}
function FinishedInterpolation()
{
DropToGround();
}
function JumpOutOfWater(vector jumpDir)
{
Falling();
Velocity = jumpDir * WaterSpeed;
Acceleration = jumpDir * AccelRate;
velocity.Z = FMax(380,JumpZ); //set here so physics uses this for remainder of tick
bUpAndOut = true;
}
/*
Modify velocity called by physics before applying new velocity
for this tick.
Velocity,Acceleration, etc. have been updated by the physics, but location hasn't
*/
simulated event ModifyVelocity(float DeltaTime, vector OldVelocity);
event FellOutOfWorld(eKillZType KillType)
{
if ( Level.NetMode == NM_Client )
return;
if ( (Controller != None) && Controller.AvoidCertainDeath() )
return;
Health = -1;
if( KillType == KILLZ_Lava)
Died( None, class'FellLava', Location );
else if(KillType == KILLZ_Suicide)
Died( None, class'Fell', Location );
else
{
if ( Physics != PHYS_Karma )
SetPhysics(PHYS_None);
Died( None, class'Fell', Location );
}
}
/* ShouldCrouch()
Controller is requesting that pawn crouch
*/
function ShouldCrouch(bool Crouch)
{
if ( bWantsToCrouch != Crouch )
{
bWantsToCrouch = Crouch;
// Have to unpress crawl so you don't automatically go to crouch when you
// stand uncrouch if toggle crouch is on
if( bWantsToCrouch )
{
if( Controller != none )
{
Controller.bCrawl = 0;
}
}
}
}
// if _RO_
/* ShouldProne()
Controller is requesting that pawn prone
*/
function ShouldProne(bool Prone)
{
if ( bWantsToProne != Prone )
{
bWantsToProne = Prone;
// Have to unpress duck so you don't automatically go to crouch when you
// unprone if toggle duck is on
if( bWantsToProne )
{
if( Controller != none )
{
Controller.bDuck = 0;
}
}
}
}
// end if _RO_
// Stub events called when physics actually allows crouch to begin or end
// use these for changing the animation (if script controlled)
event EndCrouch(float HeightAdjust)
{
EyeHeight -= HeightAdjust;
OldZ += HeightAdjust;
BaseEyeHeight = Default.BaseEyeHeight;
}
event StartCrouch(float HeightAdjust)
{
EyeHeight += HeightAdjust;
OldZ -= HeightAdjust;
BaseEyeHeight = FMin(0.8 * CrouchHeight, CrouchHeight - 10);
}
function RestartPlayer();
function AddVelocity( vector NewVelocity)
{
if ( bIgnoreForces || (NewVelocity == vect(0,0,0)) )
return;
if ( (Physics == PHYS_Falling) && (AIController(Controller) != None) )
ImpactVelocity += NewVelocity;
if ( (Physics == PHYS_Walking)
|| (((Physics == PHYS_Ladder) || (Physics == PHYS_Spider)) && (NewVelocity.Z > Default.JumpZ)) )
SetPhysics(PHYS_Falling);
if ( (Velocity.Z > 380) && (NewVelocity.Z > 0) )
NewVelocity.Z *= 0.5;
Velocity += NewVelocity;
}
function KilledBy( pawn EventInstigator )
{
local Controller Killer;
Health = 0;
if ( EventInstigator != None )
Killer = EventInstigator.Controller;
Died( Killer, class'Suicided', Location );
}
function TakeFallingDamage()
{
local float Shake, EffectiveSpeed;
if (Velocity.Z < -0.5 * MaxFallSpeed)
{
if ( Role == ROLE_Authority )
{
MakeNoise(1.0);
if (Velocity.Z < -1 * MaxFallSpeed)
{
EffectiveSpeed = Velocity.Z;
if ( TouchingWaterVolume() )
EffectiveSpeed = FMin(0, EffectiveSpeed + 100);
if ( EffectiveSpeed < -1 * MaxFallSpeed )
TakeDamage(-100 * (EffectiveSpeed + MaxFallSpeed)/MaxFallSpeed, None, Location, vect(0,0,0), class'Fell');
}
}
if ( Controller != None )
{
Shake = FMin(1, -1 * Velocity.Z/MaxFallSpeed);
Controller.DamageShake(Shake);
}
}
else if (Velocity.Z < -1.4 * JumpZ)
MakeNoise(0.5);
}
function ClientReStart()
{
Velocity = vect(0,0,0);
Acceleration = vect(0,0,0);
BaseEyeHeight = Default.BaseEyeHeight;
EyeHeight = BaseEyeHeight;
PlayWaiting();
}
function ClientSetLocation( vector NewLocation, rotator NewRotation )
{
if ( Controller != None )
Controller.ClientSetLocation(NewLocation, NewRotation);
}
function ClientSetRotation( rotator NewRotation )
{
if ( Controller != None )
Controller.ClientSetRotation(NewRotation);
}
simulated function FaceRotation( rotator NewRotation, float DeltaTime )
{
if ( Physics == PHYS_Ladder )
SetRotation(OnLadder.Walldir);
else
{
if ( (Physics == PHYS_Walking) || (Physics == PHYS_Falling) )
NewRotation.Pitch = 0;
SetRotation(NewRotation);
}
}
// if _RO_
// Added deltatime here so we could do some smooth pitch interpolations
function int LimitPitch(int pitch, optional float DeltaTime)
// else
//function int LimitPitch(int pitch)
{
pitch = pitch & 65535;
if (pitch > PitchUpLimit && pitch < PitchDownLimit)
{
if (pitch - PitchUpLimit < PitchDownLimit - pitch)
pitch = PitchUpLimit;
else
pitch = PitchDownLimit;
}
return pitch;
}
function ClientDying(class<DamageType> DamageType, vector HitLocation)
{
if ( Controller != None )
Controller.ClientDying(DamageType, HitLocation);
}
function DoComboName( string ComboClassName );
function bool InCurrentCombo()
{
return false;
}
//=============================================================================
// UDamage stub.
function EnableUDamage(float Amount);
function DisableUDamage();
//=============================================================================
// Shield stubs.
function float GetShieldStrengthMax();
function float GetShieldStrength();
function bool AddShieldStrength(int Amount);
function int CanUseShield(int Amount);
//=============================================================================
// Inventory related functions.
// check before throwing
simulated function bool CanThrowWeapon()
{
return ( (Weapon != None) && Weapon.CanThrow() && Level.Game.bAllowWeaponThrowing );
}
// toss out a weapon
function TossWeapon(Vector TossVel)
{
local Vector X,Y,Z;
Weapon.Velocity = TossVel;
GetAxes(Rotation,X,Y,Z);
Weapon.DropFrom(Location + 0.8 * CollisionRadius * X - 0.5 * CollisionRadius * Y);
}
exec function SwitchToLastWeapon()
{
if ( (Weapon != None) && (Weapon.OldWeapon != None) && Weapon.OldWeapon.HasAmmo() )
{
PendingWeapon = Weapon.OldWeapon;
Weapon.PutDown();
}
}
/* PrevWeapon()
- switch to previous inventory group weapon
*/
simulated function PrevWeapon()
{
if ( Level.Pauser != None )
return;
if ( Weapon == None && Controller != None )
{
Controller.SwitchToBestWeapon();
return;
}
if ( PendingWeapon != None )
{
if ( PendingWeapon.bForceSwitch )
return;
PendingWeapon = Inventory.PrevWeapon(None, PendingWeapon);
}
else
PendingWeapon = Inventory.PrevWeapon(None, Weapon);
if ( PendingWeapon != None )
Weapon.PutDown();
}
/* NextWeapon()
- switch to next inventory group weapon
*/
simulated function NextWeapon()
{
if ( Level.Pauser != None )
return;
if ( Weapon == None && Controller != None )
{
Controller.SwitchToBestWeapon();
return;
}
if ( PendingWeapon != None )
{
if ( PendingWeapon.bForceSwitch )
return;
PendingWeapon = Inventory.NextWeapon(None, PendingWeapon);
}
else
PendingWeapon = Inventory.NextWeapon(None, Weapon);
if ( PendingWeapon != None )
Weapon.PutDown();
}
// The player wants to switch to weapon group number F.
simulated function SwitchWeapon(byte F)
{
local weapon newWeapon;
if ( (Level.Pauser!=None) || (Inventory == None) )
return;
if ( (Weapon != None) && (Weapon.Inventory != None) )
newWeapon = Weapon.Inventory.WeaponChange(F, false);
else
newWeapon = None;
if ( newWeapon == None )
newWeapon = Inventory.WeaponChange(F, true);
if ( newWeapon == None )
{
if ( F == 10 )
ServerNoTranslocator();
return;
}
if ( PendingWeapon != None && PendingWeapon.bForceSwitch )
return;
if ( Weapon == None )
{
PendingWeapon = newWeapon;
ChangedWeapon();
}
else if ( Weapon != newWeapon || PendingWeapon != None )
{
PendingWeapon = newWeapon;
Weapon.PutDown();
}
else if ( Weapon == newWeapon )
Weapon.Reselect(); // sjs
}
function ServerNoTranslocator()
{
if ( Level.Game != None )
Level.Game.NoTranslocatorKeyPressed( PlayerController(Controller) );
}
// The player/bot wants to select next item
exec function NextItem()
{
if (SelectedItem==None) {
SelectedItem = Inventory.SelectNext();
Return;
}
if (SelectedItem.Inventory!=None)
SelectedItem = SelectedItem.Inventory.SelectNext();
else
SelectedItem = Inventory.SelectNext();
if ( SelectedItem == None )
SelectedItem = Inventory.SelectNext();
}
// FindInventoryType()
// returns the inventory item of the requested class
// if it exists in this pawn's inventory
function Inventory FindInventoryType( class DesiredClass )
{
local Inventory Inv;
local int Count;
for( Inv=Inventory; Inv!=None && Count < 1000; Inv=Inv.Inventory )
{
if ( Inv.class == DesiredClass )
return Inv;
Count++;
}
// Search for subclasses if exact class wasn't found
Count = 0;
for ( Inv = Inventory; Inv != None && Count < 1000; Inv = Inv.Inventory )
{
if ( ClassIsChildOf(Inv.Class, DesiredClass) )
return Inv;
Count++;
}
return None;
}
// Add Item to this pawn's inventory.
// Returns true if successfully added, false if not.
function bool AddInventory( inventory NewItem )
{
// Skip if already in the inventory.
local inventory Inv;
local actor Last, Prev;
local bool bAddedInOrder;
Last = self;
// The item should not have been destroyed if we get here.
if (NewItem ==None )
log("tried to add none inventory to "$self);
NewItem.SetOwner(Self);
NewItem.NetUpdateTime = Level.TimeSeconds - 1;
// order weapons based on priority
if ( Weapon(NewItem) != None )
{
Prev = self;
for( Inv=Inventory; Inv!=None; Inv=Inv.Inventory )
{
if ( (Inv.InventoryGroup == NewItem.InventoryGroup) && (Weapon(Inv) != None) )
{
if( (Weapon(Inv).Priority < Weapon(NewItem).Priority) )
{
bAddedInOrder = true;
break;
}
}
else if ( (Weapon(Prev) != None) && (Weapon(Prev).InventoryGroup == NewItem.InventoryGroup) )
{
bAddedInOrder = true;
break;
}
if ( !bAddedInOrder )
Prev = Inv;
}
if ( bAddedInOrder )
{
NewItem.Inventory = Prev.Inventory;
Prev.Inventory = NewItem;
Prev.NetUpdateTime = Level.TimeSeconds - 1;
}
}
if ( !bAddedInOrder )
{
for( Inv=Inventory; Inv!=None; Inv=Inv.Inventory )
{
if( Inv == NewItem )
return false;
Last = Inv;
}
// Add to back of inventory chain (so minimizes net replication effect).
NewItem.Inventory = None;
Last.Inventory = NewItem;
Last.NetUpdateTime = Level.TimeSeconds - 1;
}
if ( Controller != None )
Controller.NotifyAddInventory(NewItem);
return true;
}
// Remove Item from this pawn's inventory, if it exists.
function DeleteInventory( inventory Item )
{
// If this item is in our inventory chain, unlink it.
local actor Link;
local int Count;
if ( Item == Weapon )
Weapon = None;
if ( Item == SelectedItem )
SelectedItem = None;
for( Link = Self; Link!=None; Link=Link.Inventory )
{
if( Link.Inventory == Item )
{
Link.Inventory = Item.Inventory;
Item.Inventory = None;
Link.NetUpdateTime = Level.TimeSeconds - 1;
Item.NetUpdateTime = Level.TimeSeconds - 1;
break;
}
if ( Level.NetMode == NM_Client )
{
Count++;
if ( Count > 1000 )
break;
}
}
Item.SetOwner(None);
}
// Just changed to pendingWeapon
simulated function ChangedWeapon()
{
local Weapon OldWeapon;
ServerChangedWeapon(Weapon, PendingWeapon);
if (Role < ROLE_Authority)
{
OldWeapon = Weapon;
Weapon = PendingWeapon;
PendingWeapon = None;
if ( Controller != None )
Controller.ChangedWeapon();
if (Weapon != None)
Weapon.BringUp(OldWeapon);
}
}
function name GetOffhandBoneFor(Inventory I)
{
return '';
}
function name GetWeaponBoneFor(Inventory I)
{
return 'righthand';
}
function ServerChangedWeapon(Weapon OldWeapon, Weapon NewWeapon)
{
Weapon = NewWeapon;
if ( Controller != None )
Controller.ChangedWeapon();
PendingWeapon = None;
if ( OldWeapon != None )
{
OldWeapon.SetDefaultDisplayProperties();
OldWeapon.DetachFromPawn(self);
OldWeapon.GotoState('Hidden');
OldWeapon.NetUpdateFrequency = 2;
}
if ( Weapon != None )
{
Weapon.NetUpdateFrequency = 100;
Weapon.AttachToPawn(self);
Weapon.BringUp(OldWeapon);
PlayWeaponSwitch(NewWeapon);
}
if ( Inventory != None )
Inventory.OwnerEvent('ChangedWeapon'); // tell inventory that weapon changed (in case any effect was being applied)
}
function bool IsHeadShot(vector loc, vector ray, float AdditionalScale)
{
local coords C;
local vector HeadLoc, B, M, diff;
local float t, DotMM, Distance;
local int look;
if (HeadBone == '')
return False;
// If we are a dedicated server estimate what animation is most likely playing on the client
if (Level.NetMode == NM_DedicatedServer)
{
if (Physics == PHYS_Falling)
PlayAnim(AirAnims[0], 1.0, 0.0);
else if (Physics == PHYS_Walking)
{
if (bIsCrouched)
PlayAnim(IdleCrouchAnim, 1.0, 0.0);
else
PlayAnim(IdleWeaponAnim, 1.0, 0.0);
if ( bDoTorsoTwist )
{
SmoothViewYaw = Rotation.Yaw;
SmoothViewPitch = ViewPitch;
look = (256 * ViewPitch) & 65535;
if (look > 32768)
look -= 65536;
SetTwistLook(0, look);
}
}
else if (Physics == PHYS_Swimming)
PlayAnim(SwimAnims[0], 1.0, 0.0);
SetAnimFrame(0.5);
}
C = GetBoneCoords(HeadBone);
HeadLoc = C.Origin + (HeadHeight * HeadScale * AdditionalScale * C.XAxis);
// Express snipe trace line in terms of B + tM
B = loc;
M = ray * (2.0 * CollisionHeight + 2.0 * CollisionRadius);
// Find Point-Line Squared Distance
diff = HeadLoc - B;
t = M Dot diff;
if (t > 0)
{
DotMM = M dot M;
if (t < DotMM)
{
t = t / DotMM;
diff = diff - (t * M);
}
else
{
t = 1;
diff -= M;
}
}
else
t = 0;
Distance = Sqrt(diff Dot diff);
return (Distance < (HeadRadius * HeadScale * AdditionalScale));
}
//==============
// Encroachment
event bool EncroachingOn( actor Other )
{
if ( Other.bWorldGeometry || Other.bBlocksTeleport )
return true;
if ( (Vehicle(Other) != None) && (Weapon != None) && Weapon.IsA('Translauncher') )
return true;
if ( ((Controller == None) || !Controller.bIsPlayer || bWarping) && (Pawn(Other) != None) )
return true;
return false;
}
event EncroachedBy( actor Other )
{
// Allow encroachment by Vehicles so they can push the pawn out of the way
if ( Pawn(Other) != None && Vehicle(Other) == None )
gibbedBy(Other);
}
function gibbedBy(actor Other)
{
if ( Role < ROLE_Authority )
return;
if ( Pawn(Other) != None )
Died(Pawn(Other).Controller, class'DamTypeTelefragged', Location);
else
Died(None, class'Gibbed', Location);
}
//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
function JumpOffPawn()
{
Velocity += (100 + CollisionRadius) * VRand();
Velocity.Z = 200 + CollisionHeight;
SetPhysics(PHYS_Falling);
bNoJumpAdjust = true;
if ( Controller != None )
Controller.SetFall();
}
singular event BaseChange()
{
local float decorMass;
if ( bInterpolating )
return;
if ( (base == None) && (Physics == PHYS_None) )
SetPhysics(PHYS_Falling);
// Pawns can only set base to non-pawns, or pawns which specifically allow it.
// Otherwise we do some damage and jump off.
else if ( Pawn(Base) != None && Base != DrivenVehicle )
{
if ( !Pawn(Base).bCanBeBaseForPawns )
{
Base.TakeDamage( (1-Velocity.Z/400)* Mass/Base.Mass, Self,Location,0.5 * Velocity , class'Crushed');
JumpOffPawn();
}
}
else if ( (Decoration(Base) != None) && (Velocity.Z < -400) )
{
decorMass = FMax(Decoration(Base).Mass, 1);
Base.TakeDamage((-2* Mass/decorMass * Velocity.Z/400), Self, Location, 0.5 * Velocity, class'Crushed');
}
}
event UpdateEyeHeight( float DeltaTime )
{
local float smooth, MaxEyeHeight;
local float OldEyeHeight;
local Actor HitActor;
local vector HitLocation,HitNormal;
if ( Controller == None )
{
EyeHeight = 0;
return;
}
if ( bTearOff )
{
EyeHeight = Default.BaseEyeheight;
bUpdateEyeHeight = false;
return;
}
HitActor = trace(HitLocation,HitNormal,Location + (CollisionHeight + MAXSTEPHEIGHT + 14) * vect(0,0,1),
Location + CollisionHeight * vect(0,0,1),true);
if ( HitActor == None )
MaxEyeHeight = CollisionHeight + MAXSTEPHEIGHT;
else
MaxEyeHeight = HitLocation.Z - Location.Z - 14;
if ( abs(Location.Z - OldZ) > 15 )
{
bJustLanded = false;
bLandRecovery = false;
}
// smooth up/down stairs
if ( !bJustLanded )
{
smooth = FMin(0.9, 10.0 * DeltaTime/Level.TimeDilation);
LandBob *= (1 - smooth);
if( Controller.WantsSmoothedView() )
{
OldEyeHeight = EyeHeight;
EyeHeight = FClamp((EyeHeight - Location.Z + OldZ) * (1 - smooth) + BaseEyeHeight * smooth,
-0.5 * CollisionHeight, MaxEyeheight);
}
else
EyeHeight = FMin(EyeHeight * ( 1 - smooth) + BaseEyeHeight * smooth, MaxEyeHeight);
}
else if ( bLandRecovery )
{
smooth = FMin(0.9, 10.0 * DeltaTime);
OldEyeHeight = EyeHeight;
EyeHeight = FMin(EyeHeight * ( 1 - 0.6*smooth) + BaseEyeHeight * 0.6*smooth, BaseEyeHeight);
LandBob *= (1 - smooth);
if ( Eyeheight >= BaseEyeheight - 1)
{
bJustLanded = false;
bLandRecovery = false;
Eyeheight = BaseEyeheight;
}
}
else
{
smooth = FMin(0.65, 10.0 * DeltaTime);
OldEyeHeight = EyeHeight;
EyeHeight = FMin(EyeHeight * (1 - 1.5*smooth), MaxEyeHeight);
LandBob += 0.03 * (OldEyeHeight - Eyeheight);
if ( (Eyeheight < 0.25 * BaseEyeheight + 1) || (LandBob > 3) )
{
bLandRecovery = true;
Eyeheight = 0.25 * BaseEyeheight + 1;
}
}
Controller.AdjustView(DeltaTime);
}
/* EyePosition()
Called by PlayerController to determine camera position in first person view. Returns
the offset from the Pawn's location at which to place the camera
*/
simulated function vector EyePosition()
{
return EyeHeight * vect(0,0,1) + WalkBob;
}
//=============================================================================
simulated event Destroyed()
{
if ( Shadow != None )
Shadow.Destroy();
if ( Controller != None )
Controller.PawnDied(self);
if ( Level.NetMode == NM_Client )
return;
while ( Inventory != None )
Inventory.Destroy();
Weapon = None;
Super.Destroyed();
}
//=============================================================================
//
// Called immediately before gameplay begins.
//
event PreBeginPlay()
{
Super.PreBeginPlay();
Instigator = self;
DesiredRotation = Rotation;
if ( bDeleteMe )
return;
if ( BaseEyeHeight == 0 )
BaseEyeHeight = 0.8 * CollisionHeight;
EyeHeight = BaseEyeHeight;
if ( menuname == "" )
menuname = GetItemName(string(class));
}
event PostBeginPlay()
{
local AIScript A;
Super.PostBeginPlay();
SplashTime = 0;
SpawnTime = Level.TimeSeconds;
EyeHeight = BaseEyeHeight;
OldRotYaw = Rotation.Yaw;
// automatically add controller to pawns which were placed in level
// NOTE: pawns spawned during gameplay are not automatically possessed by a controller
if ( Level.bStartup && (Health > 0) && !bDontPossess )
{
// check if I have an AI Script
if ( AIScriptTag != '' )
{
ForEach AllActors(class'AIScript',A,AIScriptTag)
break;
// let the AIScript spawn and init my controller
if ( A != None )
{
A.SpawnControllerFor(self);
if ( Controller != None )
return;
}
}
if ( (ControllerClass != None) && (Controller == None) )
Controller = spawn(ControllerClass);
if ( Controller != None )
{
Controller.Possess(self);
AIController(Controller).Skill += SkillModifier;
}
}
}
// called after PostBeginPlay on net client
simulated event PostNetBeginPlay()
{
local playercontroller P;
if ( Level.bDropDetail || (Level.DetailMode == DM_Low) )
MaxLights = Min(4,MaxLights);
if ( Role == ROLE_Authority )
return;
if ( (Controller != None) && (Controller.Pawn == None) )
{
Controller.Pawn = self;
if ( (PlayerController(Controller) != None)
&& (PlayerController(Controller).ViewTarget == Controller) )
PlayerController(Controller).SetViewTarget(self);
}
if ( Role == ROLE_AutonomousProxy )
bUpdateEyeHeight = true;
if ( (PlayerReplicationInfo != None)
&& (PlayerReplicationInfo.Owner == None) )
{
PlayerReplicationInfo.SetOwner(Controller);
if ( left(PlayerReplicationInfo.PlayerName, 5) ~= "PRESS" )
{
P = Level.GetLocalPlayerController();
if ( (P.PlayerReplicationInfo != None) && !(left(PlayerReplicationInfo.PlayerName, 5) ~= "PRESS") )
bScriptPostRender = true;
}
}
PlayWaiting();
}
simulated function SetMesh()
{
if (Mesh != None)
return;
LinkMesh( default.mesh );
}
function Gasp();
function SetMovementPhysics();
function bool GiveHealth(int HealAmount, int HealMax)
{
if (Health < HealMax)
{
Health = Min(HealMax, Health + HealAmount);
return true;
}
return false;
}
function bool HasUDamage()
{
return false;
}
function int ShieldAbsorb( int damage )
{
return damage;
}
// if _RO_
function TakeDamage(int Damage, Pawn InstigatedBy, vector HitLocation, vector Momentum, class<DamageType> DamageType, optional int HitIndex)
// else UT
// function TakeDamage(int Damage, Pawn InstigatedBy, vector HitLocation, vector Momentum, class<DamageType> DamageType);
{
local int actualDamage;
local Controller Killer;
if ( damagetype == None )
{
if ( InstigatedBy != None )
warn("No damagetype for damage by "$instigatedby$" with weapon "$InstigatedBy.Weapon);
DamageType = class'DamageType';
}
if ( Role < ROLE_Authority )
{
log(self$" client damage type "$damageType$" by "$instigatedBy);
return;
}
if ( Health <= 0 )
return;
if ((instigatedBy == None || instigatedBy.Controller == None) && DamageType.default.bDelayedDamage && DelayedDamageInstigatorController != None)
instigatedBy = DelayedDamageInstigatorController.Pawn;
if ( (Physics == PHYS_None) && (DrivenVehicle == None) )
SetMovementPhysics();
if (Physics == PHYS_Walking && damageType.default.bExtraMomentumZ)
momentum.Z = FMax(momentum.Z, 0.4 * VSize(momentum));
if ( instigatedBy == self )
momentum *= 0.6;
momentum = momentum/Mass;
if (Weapon != None)
Weapon.AdjustPlayerDamage( Damage, InstigatedBy, HitLocation, Momentum, DamageType );
if (DrivenVehicle != None)
DrivenVehicle.AdjustDriverDamage( Damage, InstigatedBy, HitLocation, Momentum, DamageType );
if ( (InstigatedBy != None) && InstigatedBy.HasUDamage() )
Damage *= 2;
actualDamage = Level.Game.ReduceDamage(Damage, self, instigatedBy, HitLocation, Momentum, DamageType);
if( DamageType.default.bArmorStops && (actualDamage > 0) )
actualDamage = ShieldAbsorb(actualDamage);
Health -= actualDamage;
if ( HitLocation == vect(0,0,0) )
HitLocation = Location;
PlayHit(actualDamage,InstigatedBy, hitLocation, damageType, Momentum);
if ( Health <= 0 )
{
// pawn died
if ( DamageType.default.bCausedByWorld && (instigatedBy == None || instigatedBy == self) && LastHitBy != None )
Killer = LastHitBy;
else if ( instigatedBy != None )
Killer = instigatedBy.GetKillerController();
if ( Killer == None && DamageType.Default.bDelayedDamage )
Killer = DelayedDamageInstigatorController;
// if _KF_
if ( bPhysicsAnimUpdate )
SetTearOffMomemtum(momentum);
//else
// if ( bPhysicsAnimUpdate )
// TearOffMomentum = momentum;
// endif _KF_
Died(Killer, damageType, HitLocation);
}
else
{
AddVelocity( momentum );
if ( Controller != None )
Controller.NotifyTakeHit(instigatedBy, HitLocation, actualDamage, DamageType, Momentum);
if ( instigatedBy != None && instigatedBy != self )
LastHitBy = instigatedBy.Controller;
}
MakeNoise(1.0);
}
function SetDelayedDamageInstigatorController(Controller C)
{
DelayedDamageInstigatorController = C;
}
simulated function int GetTeamNum()
{
if ( Controller != None )
return Controller.GetTeamNum();
if ( (DrivenVehicle != None) && (DrivenVehicle.Controller != None) )
return DrivenVehicle.Controller.GetTeamNum();
if ( (PlayerReplicationInfo == None) || (PlayerReplicationInfo.Team == None) )
return 255;
return PlayerReplicationInfo.Team.TeamIndex;
}
function TeamInfo GetTeam()
{
if ( PlayerReplicationInfo != None )
return PlayerReplicationInfo.Team;
if ( (DrivenVehicle != None) && (DrivenVehicle.PlayerReplicationInfo != None) )
return DrivenVehicle.PlayerReplicationInfo.Team;
return None;
}
function Controller GetKillerController()
{
return Controller;
}
function Died(Controller Killer, class<DamageType> damageType, vector HitLocation)
{
local Vector TossVel;
local Trigger T;
local NavigationPoint N;
if ( bDeleteMe || Level.bLevelChange || Level.Game == None )
return; // already destroyed, or level is being cleaned up
if ( DamageType.default.bCausedByWorld && (Killer == None || Killer == Controller) && LastHitBy != None )
Killer = LastHitBy;
// mutator hook to prevent deaths
// WARNING - don't prevent bot suicides - they suicide when really needed
if ( Level.Game.PreventDeath(self, Killer, damageType, HitLocation) )
{
Health = max(Health, 1); //mutator should set this higher
return;
}
Health = Min(0, Health);
if ( Weapon != None && (DrivenVehicle == None || DrivenVehicle.bAllowWeaponToss) )
{
if ( Controller != None )
Controller.LastPawnWeapon = Weapon.Class;
Weapon.HolderDied();
TossVel = Vector(GetViewRotation());
TossVel = TossVel * ((Velocity Dot TossVel) + 500) + Vect(0,0,200);
TossWeapon(TossVel);
}
if ( DrivenVehicle != None )
{
Velocity = DrivenVehicle.Velocity;
DrivenVehicle.DriverDied();
}
if ( Controller != None )
{
Controller.WasKilledBy(Killer);
Level.Game.Killed(Killer, Controller, self, damageType);
}
else
Level.Game.Killed(Killer, Controller(Owner), self, damageType);
DrivenVehicle = None;
if ( Killer != None )
TriggerEvent(Event, self, Killer.Pawn);
else
TriggerEvent(Event, self, None);
// make sure to untrigger any triggers requiring player touch
if ( IsPlayerPawn() || WasPlayerPawn() )
{
PhysicsVolume.PlayerPawnDiedInVolume(self);
ForEach TouchingActors(class'Trigger',T)
T.PlayerToucherDied(self);
// event for HoldObjectives
//for ( N=Level.NavigationPointList; N!=None; N=N.NextNavigationPoint )
// if ( N.bStatic && N.bReceivePlayerToucherDiedNotify )
ForEach TouchingActors(class'NavigationPoint', N)
if ( N.bReceivePlayerToucherDiedNotify )
N.PlayerToucherDied( Self );
}
// remove powerup effects, etc.
RemovePowerups();
Velocity.Z *= 1.3;
if ( IsHumanControlled() )
PlayerController(Controller).ForceDeathUpdate();
if ( (DamageType != None) && DamageType.default.bAlwaysGibs )
ChunkUp( Rotation, DamageType.default.GibPerterbation );
else
{
NetUpdateFrequency = Default.NetUpdateFrequency;
PlayDying(DamageType, HitLocation);
if ( Level.Game.bGameEnded )
return;
if ( !bPhysicsAnimUpdate && !IsLocallyControlled() )
ClientDying(DamageType, HitLocation);
}
}
function RemovePowerups();
event Falling()
{
//SetPhysics(PHYS_Falling); //Note - physics changes type to PHYS_Falling by default
if ( Controller != None )
Controller.SetFall();
}
//#ifdef _KF_
// A section of the PickWallAdjust function has a hardcoded jump. This can override that.
event PickWallAdjustInLowGravity( vector WallHitNormal, actor HitActor );
//#endif
event HitWall(vector HitNormal, actor Wall);
event Landed(vector HitNormal)
{
ImpactVelocity = vect(0,0,0);
TakeFallingDamage();
if ( Health > 0 )
PlayLanded(Velocity.Z);
if ( (Velocity.Z < -200) && (PlayerController(Controller) != None) )
{
bJustLanded = PlayerController(Controller).bLandingShake;
OldZ = Location.Z;
}
LastHitBy = None;
}
event HeadVolumeChange(PhysicsVolume newHeadVolume)
{
if ( (Level.NetMode == NM_Client) || (Controller == None) )
return;
if ( HeadVolume.bWaterVolume )
{
if (!newHeadVolume.bWaterVolume)
{
if ( Controller.bIsPlayer && (BreathTime > 0) && (BreathTime < 8) )
Gasp();
BreathTime = -1.0;
}
}
else if ( newHeadVolume.bWaterVolume )
BreathTime = UnderWaterTime;
}
function bool TouchingWaterVolume()
{
local PhysicsVolume V;
ForEach TouchingActors(class'PhysicsVolume',V)
if ( V.bWaterVolume )
return true;
return false;
}
//Pain timer just expired.
//Check what zone I'm in (and which parts are)
//based on that cause damage, and reset BreathTime
function bool IsInPain()
{
local PhysicsVolume V;
ForEach TouchingActors(class'PhysicsVolume',V)
if ( V.bPainCausing && (V.DamageType != ReducedDamageType)
&& (V.DamagePerSec > 0) )
return true;
return false;
}
event BreathTimer()
{
if ( (Health < 0) || (Level.NetMode == NM_Client) || (DrivenVehicle != None) )
return;
TakeDrowningDamage();
if ( Health > 0 )
BreathTime = 2.0;
}
function TakeDrowningDamage();
function bool CheckWaterJump(out vector WallNormal)
{
local actor HitActor;
local vector HitLocation, HitNormal, checkpoint, start, checkNorm;
if ( AIController(Controller) != None )
{
checkpoint = Acceleration;
checkpoint.Z = 0.0;
}
if ( checkpoint == vect(0,0,0))
checkpoint = vector(Rotation);
checkpoint.Z = 0.0;
checkNorm = Normal(checkpoint);
checkPoint = Location + 1.2 * CollisionRadius * checkNorm;
HitActor = Trace(HitLocation, HitNormal, checkpoint, Location, true, GetCollisionExtent());
if ( (HitActor != None) && (Pawn(HitActor) == None) )
{
WallNormal = -1 * HitNormal;
start = Location;
start.Z += 1.1 * MAXSTEPHEIGHT;
checkPoint = start + 2 * CollisionRadius * checkNorm;
HitActor = Trace(HitLocation, HitNormal, checkpoint, start, true);
if ( (HitActor == None) || (HitNormal.Z > 0.7) )
return true;
}
return false;
}
function DoDoubleJump( bool bUpdating );
function bool CanDoubleJump();
function bool CanMultiJump();
function UpdateRocketAcceleration(float DeltaTime, float YawChange, float PitchChange);
// if _RO_
function HandleTurretRotation(float DeltaTime, float YawChange, float PitchChange);
// end _RO_
function ProcessMove(float DeltaTime, vector NewAccel, eDoubleClickDir DoubleClickMove, rotator DeltaRot);
function bool Dodge(eDoubleClickDir DoubleClickMove)
{
return false;
}
//#ifdef _KF_
// Alternate way to handle jumping that's level-designer controlled since they define the start and end positions with JumpSpot actors.
// Placed in Engine.Pawn because actors from 3 different packages can call this function.
function vector ComputeTrajectoryByTime( vector StartPosition, vector EndPosition, float fTimeEnd )
{
local vector NewVelocity;
local float ZAccel;
fTimeEnd = fTimeEnd * ( 1.1/Level.TimeDilation );
ZAccel = PhysicsVolume.Gravity.Z;
fTimeEnd = FMax( 0.0001f, fTimeEnd );
NewVelocity = ( EndPosition - StartPosition ) / fTimeEnd;
NewVelocity.z = ( ( EndPosition.z - StartPosition.z ) - ( 0.5f * ZAccel * ( fTimeEnd*fTimeEnd ) ) ) / fTimeEnd;
// return the inital velocity required to hit EndPosition at t = fTimeEnd
return NewVelocity;
}
//#endif
//Player Jumped
function bool DoJump( bool bUpdating )
{
if ( !bIsCrouched && !bWantsToCrouch && ((Physics == PHYS_Walking) || (Physics == PHYS_Ladder) || (Physics == PHYS_Spider)) )
{
if ( Role == ROLE_Authority )
{
if ( (Level.Game != None) && (Level.Game.GameDifficulty > 2) )
MakeNoise(0.1 * Level.Game.GameDifficulty);
if ( bCountJumps && (Inventory != None) )
Inventory.OwnerEvent('Jumped');
}
if ( Physics == PHYS_Spider )
Velocity = JumpZ * Floor;
else if ( Physics == PHYS_Ladder )
Velocity.Z = 0;
else if ( bIsWalking )
Velocity.Z = Default.JumpZ;
else
Velocity.Z = JumpZ;
if ( (Base != None) && !Base.bWorldGeometry )
Velocity.Z += Base.Velocity.Z;
SetPhysics(PHYS_Falling);
return true;
}
return false;
}
/* PlayMoverHitSound()
Mover Hit me, play appropriate sound if any
*/
function PlayMoverHitSound();
function PlayDyingSound();
function PlayHit(float Damage, Pawn InstigatedBy, vector HitLocation, class<DamageType> damageType, vector Momentum, optional int HitIndex)
{
local vector BloodOffset, Mo, HitNormal;
local class<Effects> DesiredEffect;
local class<Emitter> DesiredEmitter;
local PlayerController Hearer;
if ( DamageType == None )
return;
if ( (Damage <= 0) && ((Controller == None) || !Controller.bGodMode) )
return;
if (Damage > DamageType.Default.DamageThreshold) //spawn some blood
{
HitNormal = Normal(HitLocation - Location);
// Play any set effect
if ( EffectIsRelevant(Location,true) )
{
DesiredEffect = DamageType.static.GetPawnDamageEffect(HitLocation, Damage, Momentum, self, (Level.bDropDetail || Level.DetailMode == DM_Low));
if ( DesiredEffect != None )
{
BloodOffset = 0.2 * CollisionRadius * HitNormal;
BloodOffset.Z = BloodOffset.Z * 0.5;
Mo = Momentum;
if ( Mo.Z > 0 )
Mo.Z *= 0.5;
spawn(DesiredEffect,self,,HitLocation + BloodOffset, rotator(Mo));
}
// Spawn any preset emitter
DesiredEmitter = DamageType.Static.GetPawnDamageEmitter(HitLocation, Damage, Momentum, self, (Level.bDropDetail || Level.DetailMode == DM_Low));
if (DesiredEmitter != None)
spawn(DesiredEmitter,,,HitLocation+HitNormal, Rotator(HitNormal));
}
}
if ( Health <= 0 )
{
if ( PhysicsVolume.bDestructive && (PhysicsVolume.ExitActor != None) )
Spawn(PhysicsVolume.ExitActor);
return;
}
if ( Level.TimeSeconds - LastPainTime > 0.1 )
{
if ( InstigatedBy != None && (DamageType != None) && DamageType.default.bDirectDamage )
Hearer = PlayerController(InstigatedBy.Controller);
if ( Hearer != None )
Hearer.bAcuteHearing = true;
PlayTakeHit(HitLocation,Damage,damageType);
if ( Hearer != None )
Hearer.bAcuteHearing = false;
LastPainTime = Level.TimeSeconds;
}
}
/*
Pawn was killed - detach any controller, and die
*/
// blow up into little pieces (implemented in subclass)
simulated function ChunkUp( Rotator HitRotation, float ChunkPerterbation )
{
if ( (Level.NetMode != NM_Client) && (Controller != None) )
{
if ( Controller.bIsPlayer )
Controller.PawnDied(self);
else
Controller.Destroy();
}
destroy();
}
simulated function TurnOff()
{
//ifdef _RO_
if ( PlayerReplicationInfo != none && PlayerReplicationInfo.SteamStatsAndAchievements != none )
{
PlayerReplicationInfo.SteamStatsAndAchievements.PlayerDied();
}
//endif
SetCollision(true,false);
AmbientSound = None;
bNoWeaponFiring = true;
Velocity = vect(0,0,0);
SetPhysics(PHYS_None);
bPhysicsAnimUpdate = false;
bIsIdle = true;
bWaitForAnim = false;
StopAnimating();
bIgnoreForces = true;
}
/* IsInLoadout()
return true if InventoryClass is part of required or optional equipment
*/
function bool IsInLoadout(class<Inventory> InventoryClass)
{
return true;
}
State Dying
{
ignores Trigger, Bump, HitWall, HeadVolumeChange, PhysicsVolumeChange, Falling, BreathTimer;
event ChangeAnimation() {}
event StopPlayFiring() {}
function PlayFiring(float Rate, name FiringMode) {}
function PlayWeaponSwitch(Weapon NewWeapon) {}
function PlayTakeHit(vector HitLoc, int Damage, class<DamageType> damageType) {}
simulated function PlayNextAnimation() {}
function Died(Controller Killer, class<DamageType> damageType, vector HitLocation)
{
}
event FellOutOfWorld(eKillZType KillType)
{
if(KillType == KILLZ_Lava || KillType == KILLZ_Suicide )
return;
Destroy();
}
function Timer()
{
if ( !PlayerCanSeeMe() )
Destroy();
else
SetTimer(2.0, false);
}
function Landed(vector HitNormal)
{
local rotator finalRot;
if( Velocity.Z < -500 )
TakeDamage( (1-Velocity.Z/30),Instigator,Location,vect(0,0,0) , class'Crushed');
finalRot = Rotation;
finalRot.Roll = 0;
finalRot.Pitch = 0;
setRotation(finalRot);
SetPhysics(PHYS_None);
SetCollision(true, false);
if ( !IsAnimating(0) )
LieStill();
}
/* ReduceCylinder() made obsolete by ragdoll deaths */
function ReduceCylinder()
{
SetCollision(false,false);
}
function LandThump()
{
// animation notify - play sound if actually landed, and animation also shows it
if ( Physics == PHYS_None)
bThumped = true;
}
event AnimEnd(int Channel)
{
if ( Channel != 0 )
return;
if ( Physics == PHYS_None )
LieStill();
else if ( PhysicsVolume.bWaterVolume )
{
bThumped = true;
LieStill();
}
}
function LieStill()
{
if ( !bThumped )
LandThump();
ReduceCylinder();
}
singular function BaseChange()
{
if( base == None )
SetPhysics(PHYS_Falling);
else if ( Pawn(base) != None ) // don't let corpse ride around on someone's head
ChunkUp( Rotation, 1.0 );
}
function TakeDamage( int Damage, Pawn instigatedBy, Vector hitlocation,
Vector momentum, class<DamageType> damageType, optional int HitIndex)
{
SetPhysics(PHYS_Falling);
if ( (Physics == PHYS_None) && (Momentum.Z < 0) )
Momentum.Z *= -1;
Velocity += 3 * momentum/(Mass + 200);
if ( bInvulnerableBody )
return;
Damage *= DamageType.Default.GibModifier;
Health -=Damage;
if ( ((Damage > 30) || !IsAnimating()) && (Health < -80) )
ChunkUp( Rotation, DamageType.default.GibPerterbation );
}
function BeginState()
{
local int i;
//log(self$" dying");
if ( bTearOff && (Level.NetMode == NM_DedicatedServer) )
LifeSpan = 1.0;
else
SetTimer(12.0, false);
SetPhysics(PHYS_Falling);
bInvulnerableBody = true;
if ( Controller != None )
{
if ( Controller.bIsPlayer )
Controller.PawnDied(self);
else
Controller.Destroy();
}
for (i = 0; i < Attached.length; i++)
if (Attached[i] != None)
Attached[i].PawnBaseDied();
}
Begin:
Sleep(0.2);
bInvulnerableBody = false;
PlayDyingSound();
}
//=============================================================================
// Animation interface for controllers
simulated event SetAnimAction(name NewAction);
/* PlayXXX() function called by controller to play transient animation actions
*/
simulated event PlayDying(class<DamageType> DamageType, vector HitLoc)
{
AmbientSound = None;
GotoState('Dying');
if ( bPhysicsAnimUpdate )
{
bReplicateMovement = false;
bTearOff = true;
Velocity += TearOffMomentum;
SetPhysics(PHYS_Falling);
}
bPlayedDeath = true;
}
simulated function PlayFiring(optional float Rate, optional name FiringMode);
function PlayWeaponSwitch(Weapon NewWeapon);
simulated event StopPlayFiring()
{
bSteadyFiring = false;
}
function PlayTakeHit(vector HitLoc, int Damage, class<DamageType> damageType)
{
local Sound DesiredSound;
if (Damage==0)
return;
//
// Play a hit sound according to the DamageType
DesiredSound = DamageType.Static.GetPawnDamageSound();
if (DesiredSound != None)
PlayOwnedSound(DesiredSound,SLOT_Misc);
}
//=============================================================================
// Pawn internal animation functions
simulated event ChangeAnimation()
{
if ( (Controller != None) && Controller.bControlAnimations )
return;
// player animation - set up new idle and moving animations
PlayWaiting();
PlayMoving();
}
simulated event AnimEnd(int Channel)
{
if ( Channel == 0 )
PlayWaiting();
}
// Animation group checks (usually implemented in subclass)
function bool CannotJumpNow()
{
return false;
}
simulated event PlayJump();
simulated event PlayFalling();
simulated function PlayMoving();
simulated function PlayWaiting();
function PlayLanded(float impactVel)
{
if ( !bPhysicsAnimUpdate )
PlayLandingAnimation(impactvel);
}
simulated event PlayLandingAnimation(float ImpactVel);
function PlayVictoryAnimation();
function Vehicle GetVehicleBase()
{
return Vehicle(Base);
}
function int GetSpree()
{
return 0;
}
function IncrementSpree();
// Allows a pawn to process the raw input from the controller
simulated function RawInput(float DeltaTime,
float aBaseX, float aBaseY, float aBaseZ, float aMouseX, float aMouseY,
float aForward, float aTurn, float aStrafe, float aUp, float aLookUp)
{
}
function Suicide()
{
KilledBy(self);
}
// Cheats - invoked by CheatManager
function bool CheatWalk()
{
UnderWaterTime = Default.UnderWaterTime;
SetCollision(true, true , true);
SetPhysics(PHYS_Walking);
bCollideWorld = true;
return true;
}
function bool CheatGhost()
{
UnderWaterTime = -1.0;
SetCollision(false, false, false);
bCollideWorld = false;
return true;
}
function bool CheatFly()
{
UnderWaterTime = Default.UnderWaterTime;
SetCollision(true, true , true);
bCollideWorld = true;
return true;
}
function float RangedAttackTime()
{
if ( Weapon != None )
return Weapon.RangedAttackTime();
return 0;
}
simulated function vector GetTargetLocation()
{
return Location;
}
defaultproperties
{
bCanBeDamaged=true
bNoRepMesh=true
bJumpCapable=true
bCanJump=true
bCanWalk=true
bCanSwim=false
bCanFly=false
bUpdateSimulatedPosition=true
BaseEyeHeight=+00064.000000
EyeHeight=+00054.000000
CollisionRadius=+00034.000000
CollisionHeight=+00078.000000
GroundSpeed=+00440.000000
AirSpeed=+00440.000000
WaterSpeed=+00300.000000
AccelRate=+02048.000000
JumpZ=+00420.000000
MaxFallSpeed=+1200.0
DrawType=DT_Mesh
bLOSHearing=true
HearingThreshold=+2800.0
Health=100
HealthMax=100
SuperHealthMax=199
Visibility=128
LadderSpeed=+200.0
noise1time=-00010.000000
noise2time=-00010.000000
AvgPhysicsTime=+00000.100000
SoundDampening=+00001.000000
DamageScaling=+00001.000000
bDirectional=True
bCanTeleport=True
bStasis=True
SoundRadius=160
SoundVolume=255
bCollideActors=True
bCollideWorld=True
bBlockActors=True
bProjTarget=True
bRotateToDesired=True
bCanCrouch=False
// if _RO_
bCanProne=False
// endif _RO_
RotationRate=(Pitch=4096,Yaw=20000,Roll=3072)
Texture=S_Pawn
RemoteRole=ROLE_SimulatedProxy
NetPriority=+00002.000000
AirControl=+0.05
ControllerClass=class'AIController'
CrouchHeight=+40.0
CrouchRadius=+34.0
MaxDesiredSpeed=+00001.000000
DesiredSpeed=+00001.000000
LandMovementState=PlayerWalking
WaterMovementState=PlayerSwimming
SightRadius=+05000.000000
bOwnerNoSee=true
bAcceptsProjectors=True
BlendChangeTime=0.25
WalkingPct=+0.5
CrouchedPct=+0.5
bTravel=true
ForwardStrafeBias=+0.0
BackwardStrafeBias=+0.0
bShouldBaseAtStartup=true
Bob=0.0060
bDisturbFluidSurface=true
bBlockKarma=False
bWeaponBob=true
bUseCompressedPosition=true
bCanDoubleJump=true
bSimulateGravity=true
HeadScale=+1.0
bServerMoveSetPawnRot=true
bNoCoronas=true
bSetPCRotOnPossess=true
DrivingHeight=+20
DrivingRadius=+22.0
HeadRadius=+9.0
HeadHeight=6.0
PitchUpLimit=18000
PitchDownLimit=49153
bCanUse=true
bAutoActivate=true
bUseDynamicLights=true
// if _KF_
LedgeCheckThreshold=4.0 // This is the engine's default value, but now it's configurable rather than hardcoded
AmbientSoundScaling=+6.83 // This is 100% volume at 255 now, instead of being clamped at like .11
//else
// AmbientSoundScaling=+0.8
// endif _KF_
// if _RO_
// RO Defaults
SprintPct=1.500000
CrouchedSprintPct=1.25
ProneIronPct=0.05
PronePct=0.260000
ProneHeight=15.0
ProneRadius=22.0
CustomAmbientRelevancyScale=1.0
}