//============================================================================= // 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 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 BloodEffect; var class LowGoreBlood; var class 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 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 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 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 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 (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 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 WeaponClass; local Weapon NewWeapon; WeaponClass = class(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, 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, optional int HitIndex) // else UT // function TakeDamage(int Damage, Pawn InstigatedBy, vector HitLocation, vector Momentum, class 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, 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, vector Momentum, optional int HitIndex) { local vector BloodOffset, Mo, HitNormal; local class DesiredEffect; local class 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 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) {} simulated function PlayNextAnimation() {} function Died(Controller Killer, class 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, 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, 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) { 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 }