2020-12-13 15:01:13 +00:00
//=============================================================================
// 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.
//
// Copyright 1998-2013 Epic Games, Inc. All Rights Reserved.
//=============================================================================
class Pawn extends Actor
abstract
native ( Pawn )
placeable
config ( Game )
dependson ( Controller )
nativereplication
implements ( Interface _Speaker ) ;
var const float MaxStepHeight ,
MaxJumpHeight ;
var const float WalkableFloorZ ; /** minimum z value for floor normal (if less, not a walkable floor for this pawn) */
/** Used in determining if pawn is going off ledge. If the ledge is "shorter" than this value then the pawn will be able to walk off it. **/
var const float LedgeCheckThreshold ;
var const Vector PartialLedgeMoveDir ;
/** Controller currently possessing this Pawn */
var editinline repnotify Controller Controller ;
/** Chained pawn list */
var const Pawn NextPawn ;
/** Used for cacheing net relevancy test */
var float NetRelevancyTime ;
var playerController LastRealViewer ;
var actor LastViewer ;
/** If true, call the script TickSpecial() event. */
var bool bScriptTickSpecial ;
// Physics related flags.
var bool bUpAndOut ; // used by swimming
var bool bIsWalking ; // currently walking (can't jump, affects animations)
/** Physics to use when walking. Typically set to PHYS_Walking or PHYS_NavMeshWalking */
var ( Movement ) EPhysics WalkingPhysics ;
// Crouching
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 const float UncrouchTime ; // when auto-crouch during movement, continually try to uncrouch once this decrements to zero
var float CrouchHeight ; // CollisionHeight when crouching
var float CrouchRadius ; // CollisionRadius when crouching
var const int FullHeight ; // cached for pathfinding
var bool bCrawler ; // crawling - pitch and roll based on surface pawn is on
/** Used by movement natives to slow pawn as it reaches its destination to prevent overshooting */
var const bool bReducedSpeed ;
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 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 bAllowLedgeOverhang ; // if TRUE then allow the pawn to hang off ledges based on the cylinder extent
var const bool bPartiallyOverLedge ; // if TRUE pawn was over a ledge without falling, allows us to handle case if player stops
var const bool bSimulateGravity ; // simulate gravity for this pawn on network clients when predicting position (true if pawn is walking or falling)
var bool bIgnoreForces ; // if true, not affected by external forces
var bool bCanWalkOffLedges ; // Can still fall off ledges, even when walking (for Player Controlled pawns)
var bool bCanBeBaseForPawns ; // all your 'base', are belong to us
var const bool bSimGravityDisabled ; // used on network clients
var bool bDirectHitWall ; // always call pawn hitwall directly (no controller notifyhitwall)
var const bool bPushesRigidBodies ; // Will do a check to find nearby PHYS_RigidBody actors and will give them a 'soft' push.
var bool bForceFloorCheck ; // force the pawn in PHYS_Walking to do a check for a valid floor even if he hasn't moved. Cleared after next floor check.
var bool bForceKeepAnchor ; // Force ValidAnchor function to accept any non-NULL anchor as valid (used to override when we want to set anchor for path finding)
var config bool bCanMantle ; // can this pawn mantle over cover
var config bool bCanClimbUp ; // can this pawn climb up cover wall
var bool bCanClimbCeilings ; // can this pawn climb ceiling nodes
var config bool bCanSwatTurn ; // can this pawn swat turn between cover
var config bool bCanLeap ; // can this pawn use LeapReachSpec
var config bool bCanCoverSlip ; // can this pawn coverslip
/** if set, display "MAP HAS PATHING ERRORS" and message in the log when a Pawn fails a full path search */
var globalconfig bool bDisplayPathErrors ;
// AI related flags
var bool bCanPickupInventory ; // if true, will pickup inventory when touching pickup actors
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 bMuffledHearing ; // can hear sounds through walls (but muffled - sound distance increased to double plus 4x the distance through walls
var ( AI ) bool bDontPossess ; // if true, Pawn won't be possessed at game start
var bool bRollToDesired ; // Update roll when turning to desired rotation (normally false)
var bool bStationary ; // pawn can't move
var bool bCachedRelevant ; // network relevancy caching flag
var bool bNoWeaponFiring ; // TRUE indicates that weapon firing is disabled for this pawn
var bool bModifyReachSpecCost ; // pawn should call virtual function to modify reach spec costs
var bool bModifyNavPointDest ; // pawn should call virtual function to modify destination location when moving to nav point
/** set if Pawn counts as a vehicle for pathfinding checks (so don't use bBlockedForVehicles nodes, etc) */
var bool bPathfindsAsVehicle ;
/** Pawn multiplies cost of NavigationPoints that don't have bPreferredVehiclePath set by this number */
var float NonPreferredVehiclePathMultiplier ;
/** Previously used ShouldBypassSimulatedClientPhysics flag **/
var bool bPrevBypassSimulatedClientPhysics ;
// AI basics.
enum EPathSearchType
{
PST _Default ,
PST _Breadth ,
PST _NewBestPathTo ,
PST _Constraint ,
} ;
var EPathSearchType PathSearchType ;
/** List of search constraints for pathing */
var PathConstraint PathConstraintList ;
var PathGoalEvaluator PathGoalList ;
var float DesiredSpeed ;
var float MaxDesiredSpeed ;
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 const float AvgPhysicsTime ; // Physics updating time monitoring (for AI monitoring reaching destinations)
var float Mass ; // Mass of this pawn.
var float Buoyancy ; // Water buoyancy. A ratio (1.0 = neutral buoyancy, 0.0 = no buoyancy)
var float MeleeRange ; // Max range for melee attack (not including collision radii)
var const NavigationPoint Anchor ; // current nearest path;
var const int AnchorItem ; // Used to index into nav mesh polys
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 float SpawnTime ; // worldinfo time when this pawn was spawned
var int MaxPitchLimit ; // limit on view pitching
// Movement.
var bool bRunPhysicsWithNoController ; // When there is no Controller, Walking Physics abort and force a velocity and acceleration of 0. Set this to TRUE to override.
var bool bForceMaxAccel ; // ignores Acceleration component, and forces max AccelRate to drive Pawn at full velocity.
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 OutofWaterZ ; /** z velocity applied when pawn tries to get out of water */
var float MaxOutOfWaterStepHeight ; /** Maximum step height for getting out of water */
var bool bLimitFallAccel ; // should acceleration be limited (by a factor of GroundSpeed and AirControl) when in PHYS_Falling?
var float AirControl ; // amount of AirControl available to the pawn
var float WalkingPct ; // pct. of running speed that walking speed is
var float MovementSpeedModifier ; // a modifier that can be used to override the movement speed.
var float CrouchedPct ; // pct. of running speed that crouched walking speed is
var float MaxFallSpeed ; // max speed pawn can land without taking damage
/** AI will take paths that require a landing velocity less than (MaxFallSpeed * AIMaxFallSpeedFactor) */
var float AIMaxFallSpeedFactor ;
var ( Camera ) float BaseEyeHeight ; // Base eye height above collision center.
var ( Camera ) 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 transient PhysicsVolume HeadVolume ; // physics volume of head
var ( ) int Health ; /** amount of health this Pawn has */
var ( ) int HealthMax ; /** normal maximum health of Pawn - defaults to default.Health unless explicitly set otherwise */
var bool bReplicateHealthToAll ; /** if true, replicate this Pawn's health to all clients; otherwise, only if owned by or ViewTarget of a client */
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 float KismetDeathDelayTime ;
/** RootMotion derived velocity calculated by APawn::CalcVelocity() (used when replaying client moves in net games (since can't rely on animation when replaying moves)) */
var vector RMVelocity ;
/** this flag forces APawn::CalcVelocity() to just use RMVelocity directly */
var bool bForceRMVelocity ;
/** this flag forces APawn::CalcVelocity() to never use root motion derived velocity */
var bool bForceRegularVelocity ;
// 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 SoundDampening ;
var float DamageScaling ;
var localized string MenuName ; // Name used for this pawn type in menus (e.g. player selection)
var class < AIController > ControllerClass ; // default class to use when pawn is controlled by AI
var editinline RepNotify 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 ;
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 bool bPlayedDeath ; // set when death animation has been played (used in network games)
var ( ) SkeletalMeshComponent Mesh ;
var CylinderComponent CylinderComponent ;
var ( ) float RBPushRadius ; // Unreal units
var ( ) float RBPushStrength ;
var repnotify Vehicle DrivenVehicle ;
var float AlwaysRelevantDistanceSquared ; // always relevant to other clients if closer than this distance to viewer, and have controller
/** replicated to we can see where remote clients are looking */
var const byte RemoteViewPitch ;
/** Radius that is checked for nearby vehicles when pressing use */
var ( ) float VehicleCheckRadius ;
var Controller LastHitBy ; //give kill credit to this guy if hit momentum causes pawn to fall to his death
var ( ) float ViewPitchMin ;
var ( ) float ViewPitchMax ;
/** Max difference between pawn's Rotation.Yaw and DesiredRotation.Yaw for pawn to be considered as having reached its desired rotation */
var int AllowedYawError ;
/** Desired Target Rotation : Physics will smoothly rotate actor to this rotation **/
/** In future I will uncomment this change. Currently Actor has the variable.**/
var ( Movement ) const rotator DesiredRotation ;
/** DesiredRotation is set by somebody - Pawn's default behavior (using direction for desiredrotation) does not work **/
var const private { private } bool bDesiredRotationSet ;
/** Do not overwrite current DesiredRotation **/
var const private { private } bool bLockDesiredRotation ;
/ * * U n l o c k D e s i r e d R o t a t i o n w h e n R e a c h e d t o t h e d e s t i n a t i o n
* This is used when bLockDesiredRotation = TRUE
* This will set bLockDesiredRotation = FALSE when reached to DesiredRotation
* /
var const private { private } bool bUnlockWhenReached ;
/** Inventory Manager */
var class < InventoryManager > InventoryManagerClass ;
var repnotify InventoryManager InvManager ;
/** Weapon currently held by Pawn */
var Weapon Weapon ;
/ * *
* This next group of replicated properties are used to cause 3 rd person effects on
* remote clients . FlashLocation and FlashCount are altered by the weapon to denote that
* a shot has occured and FiringMode is used to determine what type of shot .
* /
/** Hit Location of instant hit weapons. vect(0,0,0) = not firing. */
var repnotify vector FlashLocation ;
/ * * l a s t F l a s h L o c a t i o n t h a t w a s a n a c t u a l s h o t , i . e . n o t c o u n t i n g c l e a r s t o ( 0 , 0 , 0 )
* this is used to make sure we set unique values to FlashLocation for consecutive shots even when there was a clear in between ,
* so that if a client missed the clear due to low net update rate , it still gets the new firing location
* /
var vector LastFiringFlashLocation ;
/** increased when weapon fires. 0 = not firing. 1 - 255 = firing */
var repnotify byte FlashCount ;
/** firing mode used when firing */
var repnotify byte FiringMode ;
/** tracks the number of consecutive shots. Note that this is not replicated, so it's not correct on remote clients. It's only updated when the pawn is relevant. */
var int ShotCount ;
/** set in InitRagdoll() to old CollisionComponent (since it must be Mesh for ragdolls) so that TermRagdoll() can restore it */
var PrimitiveComponent PreRagdollCollisionComponent ;
/** Physics object created to create contacts with physics objects, used to push them around. */
var RB _BodyInstance PhysicsPushBody ;
/ * * @ H A C K : c o u n t o f t i m e s p r o c e s s L a n d e d ( ) w a s c a l l e d b u t i t f a i l e d w i t h o u t c h a n g i n g p h y s i c s f o r s o m e r e a s o n
* so we can detect and avoid a rare case where Pawns get stuck in that state
* /
var int FailedLandingCount ;
/** Controls whether the pawn needs the base ticked before this one can be ticked */
var bool bNeedsBaseTickedFirst ;
/** Array of Slots */
var transient Array < AnimNodeSlot > SlotNodes ;
/** List of Matinee InterpGroup controlling this actor. */
var transient Array < InterpGroup > InterpGroupList ;
/** AudioComponent used by FaceFX */
var transient protected AudioComponent FacialAudioComp ;
/** General material used to control common pawn material parameters (e.g. burning) */
var protected transient MaterialInstanceConstant MIC _PawnMat ;
var protected transient MaterialInstanceConstant MIC _PawnHair ;
/** If TRUE, translation of mesh is updated to match desired floor translation (0 unless special move desired floor conforming) */
var transient repnotify bool bUsedByMatinee ;
struct native ScalarParameterInterpStruct
{
/** Name of parameter to change */
var ( ) Name ParameterName ;
/** Desired Parameter Value */
var ( ) float ParameterValue ;
/** Desired Interpolation Time */
var ( ) float InterpTime ;
/** Time before interpolation starts */
var ( ) float WarmUpTime ;
} ;
var ( ) Array < ScalarParameterInterpStruct > ScalarParameterInterpArray ;
/** Whether root motion should be extracted from the interp curve or not */
/** NOTE: Currently assumes blending isn't altering the root bone */
var bool bRootMotionFromInterpCurve ;
var RootMotionCurve RootMotionInterpCurve ;
var float RootMotionInterpRate ;
var float RootMotionInterpCurrentTime ;
var Vector RootMotionInterpCurveLastValue ;
//debug
var ( Debug ) bool bDebugShowCameraLocation ;
/ * *
* Set this to TRUE if riding on a moving base that you know is clear from non - moving world obstructions .
* This can solve move - order dependencies when riding a mover , and it ' s faster .
* /
var ( ) bool bFastAttachedMove ;
` if( ` _ _TW _ )
var bool bCanJumpOverWalls ;
var bool bDebugCrawlerPhysics ;
` endif
` if( ` _ _TW _LIGHTING _MODIFICATIONS _ ) // Custom lighting channel implementation
/** Keeps track of how many lighting volumes the pawn is currently in */
var transient byte LightingVolumeEnterCount ;
` endif
cpptext
{
// declare type for node evaluation functions
typedef FLOAT ( * NodeEvaluator ) ( ANavigationPoint * , APawn * , FLOAT ) ;
virtual void PostBeginPlay ( ) ;
virtual void PostScriptDestroyed ( ) ;
// AActor interface.
APawn * GetPlayerPawn ( ) const ;
virtual FLOAT GetNetPriority ( const FVector & ViewPos , const FVector & ViewDir , APlayerController * Viewer , UActorChannel * InChannel , FLOAT Time , UBOOL bLowBandwidth ) ;
virtual INT * GetOptimizedRepList ( BYTE * InDefault , FPropertyRetirement * Retire , INT * Ptr , UPackageMap * Map , UActorChannel * Channel ) ;
virtual void NotifyBump ( AActor * Other , UPrimitiveComponent * OtherComp , const FVector & HitNormal ) ;
virtual void TickSimulated ( FLOAT DeltaSeconds ) ;
virtual void TickSpecial ( FLOAT DeltaSeconds ) ;
UBOOL PlayerControlled ( ) ;
virtual void SetBase ( AActor * NewBase , FVector NewFloor = FVector ( 0 , 0 , 1 ) , INT bNotifyActor = 1 , USkeletalMeshComponent * SkelComp = NULL , FName BoneName = NAME _None ) ;
# if WITH _EDITOR
virtual void EditorApplyRotation ( const FRotator & DeltaRotation , UBOOL bAltDown , UBOOL bShiftDown , UBOOL bCtrlDown ) ;
virtual void CheckForErrors ( ) ;
# endif
virtual UBOOL IsNetRelevantFor ( APlayerController * RealViewer , AActor * Viewer , const FVector & SrcLocation ) ;
UBOOL CacheNetRelevancy ( UBOOL bIsRelevant , APlayerController * RealViewer , AActor * Viewer ) ;
virtual UBOOL ShouldTrace ( UPrimitiveComponent * Primitive , AActor * SourceActor , DWORD TraceFlags ) ;
virtual void PreNetReceive ( ) ;
virtual void PostNetReceiveLocation ( ) ;
virtual void SmoothCorrection ( const FVector & OldLocation ) ;
virtual APawn * GetAPawn ( ) { return this ; }
virtual const APawn * GetAPawn ( ) const { return this ; }
/ * *
* Used for SkelControlLimb in BCS _BaseMeshSpace mode .
*
* @ param SkelControlled - the mesh being modified by the skel control
*
* @ return the skeletal mesh component to use for the transform calculation
* /
virtual USkeletalMeshComponent * GetMeshForSkelControlLimbTransform ( const USkeletalMeshComponent * SkelControlled ) { return Mesh ; }
/ * *
* Sets the hard attach flag by first handling the case of already being
* based upon another actor
*
* @ param bNewHardAttach the new hard attach setting
* /
virtual void SetHardAttach ( UBOOL bNewHardAttach ) ;
virtual UBOOL CanCauseFractureOnTouch ( )
{
return TRUE ;
}
// Level functions
void SetZone ( UBOOL bTest , UBOOL bForceRefresh ) ;
// AI sensing
virtual void CheckNoiseHearing ( AActor * NoiseMaker , FLOAT Loudness , FName NoiseType = NAME _None ) ;
virtual FLOAT DampenNoise ( AActor * NoiseMaker , FLOAT Loudness , FName NoiseType = NAME _None ) ;
// Latent movement
virtual void setMoveTimer ( FVector MoveDir ) ;
FLOAT GetMaxSpeed ( ) ;
virtual UBOOL moveToward ( const FVector & Dest , AActor * GoalActor ) ;
virtual UBOOL IsGlider ( ) ;
virtual void rotateToward ( FVector FocalPoint ) ;
void StartNewSerpentine ( const FVector & Dir , const FVector & Start ) ;
void ClearSerpentine ( ) ;
virtual UBOOL SharingVehicleWith ( APawn * P ) ;
# if _ _TW _PATHFINDING _
virtual void InitSerpentine ( ) ;
virtual UBOOL TestWalkFall ( FVector GravDir , FVector & CurrentPosition , FVector CollisionExtent , FCheckResult & Hit , AActor * GoalActor , const FVector StartLocation ) ;
# else
void InitSerpentine ( ) ;
# endif
virtual void HandleSerpentineMovement ( FVector & out _Direction , FLOAT Distance , const FVector & Dest ) ;
// reach tests
virtual UBOOL ReachedDestination ( const FVector & Start , const FVector & Dest , AActor * GoalActor , UBOOL bCheckHandle = FALSE ) ;
virtual int pointReachable ( FVector aPoint , int bKnowVisible = 0 ) ;
virtual int actorReachable ( AActor * Other , UBOOL bKnowVisible = 0 , UBOOL bNoAnchorCheck = 0 ) ;
virtual int Reachable ( FVector aPoint , AActor * GoalActor ) ;
int walkReachable ( const FVector & Dest , const FVector & Start , int reachFlags , AActor * GoalActor ) ;
int flyReachable ( const FVector & Dest , const FVector & Start , int reachFlags , AActor * GoalActor ) ;
int swimReachable ( const FVector & Dest , const FVector & Start , int reachFlags , AActor * GoalActor ) ;
int ladderReachable ( const FVector & Dest , const FVector & Start , int reachFlags , AActor * GoalActor ) ;
INT spiderReachable ( const FVector & Dest , const FVector & Start , INT reachFlags , AActor * GoalActor ) ;
FVector GetGravityDirection ( ) ;
virtual UBOOL TryJumpUp ( FVector Dir , FVector Destination , DWORD TraceFlags , UBOOL bNoVisibility ) ;
virtual UBOOL ReachedBy ( APawn * P , const FVector & TestPosition , const FVector & Dest ) ;
virtual UBOOL ReachThresholdTest ( const FVector & TestPosition , const FVector & Dest , AActor * GoalActor , FLOAT UpThresholdAdjust , FLOAT DownThresholdAdjust , FLOAT ThresholdAdjust ) ;
virtual UBOOL SetHighJumpFlag ( ) { return false ; }
// movement component tests (used by reach tests)
void TestMove ( const FVector & Delta , FVector & CurrentPosition , FCheckResult & Hit , const FVector & CollisionExtent ) ;
FVector GetDefaultCollisionSize ( ) ;
FVector GetCrouchSize ( ) ;
ETestMoveResult walkMove ( FVector Delta , FVector & CurrentPosition , const FVector & CollisionExtent , FCheckResult & Hit , AActor * GoalActor , FLOAT threshold ) ;
ETestMoveResult flyMove ( FVector Delta , FVector & CurrentPosition , AActor * GoalActor , FLOAT threshold ) ;
ETestMoveResult swimMove ( FVector Delta , FVector & CurrentPosition , AActor * GoalActor , FLOAT threshold ) ;
virtual ETestMoveResult FindBestJump ( FVector Dest , FVector & CurrentPosition ) ;
virtual ETestMoveResult FindJumpUp ( FVector Direction , FVector & CurrentPosition ) ;
ETestMoveResult HitGoal ( AActor * GoalActor ) ;
virtual UBOOL HurtByDamageType ( class UClass * DamageType ) ;
UBOOL CanCrouchWalk ( const FVector & StartLocation , const FVector & EndLocation , AActor * HitActor ) ;
/** updates the highest landing Z axis velocity encountered during a reach test */
virtual void SetMaxLandingVelocity ( FLOAT NewLandingVelocity ) { }
// Path finding
UBOOL GeneratePath ( ) ;
FLOAT findPathToward ( AActor * goal , FVector GoalLocation , NodeEvaluator NodeEval , FLOAT BestWeight , UBOOL bWeightDetours , INT MaxPathLength = 0 , UBOOL bReturnPartial = FALSE , INT SoftMaxNodes = 200 ) ;
ANavigationPoint * BestPathTo ( NodeEvaluator NodeEval , ANavigationPoint * start , FLOAT * Weight , UBOOL bWeightDetours , INT MaxPathLength = 0 , INT SoftMaxNodes = 200 ) ;
virtual ANavigationPoint * CheckDetour ( ANavigationPoint * BestDest , ANavigationPoint * Start , UBOOL bWeightDetours ) ;
virtual INT calcMoveFlags ( ) ;
/** returns the maximum falling speed an AI will accept along a path */
FORCEINLINE FLOAT GetAIMaxFallSpeed ( ) { return MaxFallSpeed * AIMaxFallSpeedFactor ; }
virtual void MarkEndPoints ( ANavigationPoint * EndAnchor , AActor * Goal , const FVector & GoalLocation ) ;
virtual FLOAT SecondRouteAttempt ( ANavigationPoint * Anchor , ANavigationPoint * EndAnchor , NodeEvaluator NodeEval , FLOAT BestWeight , AActor * goal , const FVector & GoalLocation , FLOAT StartDist , FLOAT EndDist , INT MaxPathLength , INT SoftMaxNodes ) ;
/ * * f i n d s t h e c l o s e s t N a v i g a t i o n P o i n t w i t h i n M A X P A T H D I S T t h a t i s u s a b l e b y t h i s p a w n a n d d i r e c t l y r e a c h a b l e t o / f r o m T e s t L o c a t i o n
* @ param TestActor the Actor to find an anchor for
* @ param TestLocation the location to find an anchor for
* @ param bStartPoint true if we 're finding the start point for a path search, false if we' re finding the end point
* @ param bOnlyCheckVisible if true , only check visibility - skip reachability test
* @ param Dist ( out ) if an anchor is found , set to the distance TestLocation is from it . Set to 0. f if the anchor overlaps TestLocation
* @ return a suitable anchor on the navigation network for reaching TestLocation , or NULL if no such point exists
* /
ANavigationPoint * FindAnchor ( AActor * TestActor , const FVector & TestLocation , UBOOL bStartPoint , UBOOL bOnlyCheckVisible , FLOAT & Dist ) ;
virtual INT ModifyCostForReachSpec ( UReachSpec * Spec , INT Cost ) { return 0 ; }
virtual void InitForPathfinding ( AActor * Goal , ANavigationPoint * EndAnchor ) { }
// allows pawn subclasses to veto anchor validity
virtual UBOOL IsValidAnchor ( ANavigationPoint * AnchorCandidate ) { return TRUE ; }
/ *
* Route finding notifications ( sent to target )
* /
virtual ANavigationPoint * SpecifyEndAnchor ( APawn * RouteFinder ) ;
virtual UBOOL AnchorNeedNotBeReachable ( ) ;
virtual void NotifyAnchorFindingResult ( ANavigationPoint * EndAnchor , APawn * RouteFinder ) ;
// Pawn physics modes
virtual void setPhysics ( BYTE NewPhysics , AActor * NewFloor = NULL , FVector NewFloorV = FVector ( 0 , 0 , 1 ) ) ;
virtual void performPhysics ( FLOAT DeltaSeconds ) ;
/** Called in PerformPhysics(), after StartNewPhysics() is done moving the Actor, and before the PendingTouch() event is dispatched. */
virtual void PostProcessPhysics ( FLOAT DeltaSeconds , const FVector & OldVelocity ) ;
/** If TRUE, bypass simulated client physics, and run owned/server physics instead. Do not perform simulation/correction. */
virtual UBOOL ShouldBypassSimulatedClientPhysics ( ) ;
virtual FVector CheckForLedges ( FVector AccelDir , FVector Delta , FVector GravDir , int & bCheckedFall , int & bMustJump ) ;
virtual void physWalking ( FLOAT deltaTime , INT Iterations ) ;
virtual void physNavMeshWalking ( FLOAT deltaTime ) ;
virtual void physFlying ( FLOAT deltaTime , INT Iterations ) ;
virtual void physSwimming ( FLOAT deltaTime , INT Iterations ) ;
virtual void physFalling ( FLOAT deltaTime , INT Iterations ) ;
virtual void physSpider ( FLOAT deltaTime , INT Iterations ) ;
virtual void physLadder ( FLOAT deltaTime , INT Iterations ) ;
virtual void startNewPhysics ( FLOAT deltaTime , INT Iterations ) ;
virtual void GetNetBuoyancy ( FLOAT & NetBuoyancy , FLOAT & NetFluidFriction ) ;
virtual void StartFalling ( INT Iterations , FLOAT remainingTime , FLOAT timeTick , const FVector & Delta , const FVector & subLoc ) ;
virtual UBOOL ShouldCatchAir ( const FVector & OldFloor , const FVector & Floor ) ;
void startSwimming ( FVector OldLocation , FVector OldVelocity , FLOAT timeTick , FLOAT remainingTime , INT Iterations ) ;
virtual void physicsRotation ( FLOAT deltaTime , FVector OldVelocity ) ;
void processLanded ( FVector const & HitNormal , AActor * HitActor , FLOAT remainingTime , INT Iterations ) ;
virtual void SetPostLandedPhysics ( AActor * HitActor , FVector HitNormal ) ;
virtual void processHitWall ( FCheckResult const & Hit , FLOAT TimeSlice = 0. f ) ;
virtual void Crouch ( INT bClientSimulation = 0 ) ;
virtual void UnCrouch ( INT bClientSimulation = 0 ) ;
void SmoothHitWall ( FVector const & HitNormal , AActor * HitActor ) ;
virtual FVector NewFallVelocity ( FVector OldVelocity , FVector OldAcceleration , FLOAT timeTick ) ;
void stepUp ( const FVector & GravDir , const FVector & DesiredDir , const FVector & Delta , FCheckResult & Hit ) ;
virtual FLOAT MaxSpeedModifier ( ) ;
virtual FLOAT GetMaxAccel ( FLOAT SpeedModifier = 1. f ) ;
virtual FVector CalculateSlopeSlide ( const FVector & Adjusted , const FCheckResult & Hit ) ;
virtual UBOOL IgnoreBlockingBy ( const AActor * Other ) const ;
virtual void PushedBy ( AActor * Other ) ;
virtual void UpdateBasedRotation ( FRotator & FinalRotation , const FRotator & ReducedRotation ) ;
virtual void ReverseBasedRotation ( ) ;
virtual void InitRBPhys ( ) ;
virtual void TermRBPhys ( FRBPhysScene * Scene ) ;
/** Update information used to detect overlaps between this actor and physics objects, used for 'pushing' things */
virtual void UpdatePushBody ( ) ;
/** Called when the push body 'sensor' overlaps a physics body. Allows you to add a force to that body to move it. */
virtual void ProcessPushNotify ( const FRigidBodyCollisionInfo & PushedInfo , const TArray < FRigidBodyContactInfo > & ContactInfos ) ;
virtual UBOOL HasAudibleAmbientSound ( const FVector & SrcLocation ) { return FALSE ; }
//superville: Chance for pawn to say he has reached a location w/o touching it (ie cover slot)
virtual UBOOL HasReached ( ANavigationPoint * Nav , UBOOL & bFinalDecision ) { return FALSE ; }
virtual FVector GetIdealCameraOrigin ( )
{
return FVector ( Location . X , Location . Y , Location . Z + BaseEyeHeight ) ;
}
/ * *
* Checks whether this pawn needs to have its base ticked first and does so if requested
*
* @ return TRUE if the actor was ticked , FALSE if it was aborted ( e . g . because it ' s in stasis )
* /
virtual UBOOL Tick ( FLOAT DeltaTime , enum ELevelTick TickType ) ;
/** Build AnimSet list, called by UpdateAnimSetList() */
virtual void BuildAnimSetList ( ) ;
void RestoreAnimSetsToDefault ( ) ;
// AnimControl Matinee Track support
/** Used to provide information on the slots that this Actor provides for animation to Matinee. */
virtual void GetAnimControlSlotDesc ( TArray < struct FAnimSlotDesc > & OutSlotDescs ) ;
/ * *
* Called by Matinee when we open it to start controlling animation on this Actor .
* Is also called again when the GroupAnimSets array changes in Matinee , so must support multiple calls .
* /
virtual void PreviewBeginAnimControl ( class UInterpGroup * InInterpGroup ) ;
/** Called each frame by Matinee to update the desired sequence by name and position within it. */
virtual void PreviewSetAnimPosition ( FName SlotName , INT ChannelIndex , FName InAnimSeqName , FLOAT InPosition , UBOOL bLooping , UBOOL bFireNotifies , UBOOL bEnableRootMotion , FLOAT DeltaTime ) ;
/** Called each frame by Matinee to update the desired animation channel weights for this Actor. */
virtual void PreviewSetAnimWeights ( TArray < FAnimSlotInfo > & SlotInfos ) ;
/** Called by Matinee when we close it after we have been controlling animation on this Actor. */
virtual void PreviewFinishAnimControl ( class UInterpGroup * InInterpGroup ) ;
/** Function used to control FaceFX animation in the editor (Matinee). */
virtual void PreviewUpdateFaceFX ( UBOOL bForceAnim , const FString & GroupName , const FString & SeqName , FLOAT InPosition ) ;
// WWISEMODIF_START, alessard, nov-28-2008, WwiseAudioIntegration
/** Used by Matinee playback to start a FaceFX animation playing. */
virtual void PreviewActorPlayFaceFX ( const FString & GroupName , const FString & SeqName , UAkBaseSoundObject * InSoundCue ) ;
// WWISEMODIF_END
/** Used by Matinee to stop current FaceFX animation playing. */
virtual void PreviewActorStopFaceFX ( ) ;
/** Used in Matinee to get the AudioComponent we should play facial animation audio on. */
virtual UAudioComponent * PreviewGetFaceFXAudioComponent ( ) ;
/** Get the UFaceFXAsset that is currently being used by this Actor when playing facial animations. */
virtual class UFaceFXAsset * PreviewGetActorFaceFXAsset ( ) ;
/** Called each frame by Matinee to update the weight of a particular MorphNodeWeight. */
virtual void PreviewSetMorphWeight ( FName MorphNodeName , FLOAT MorphWeight ) ;
/** Called each frame by Matinee to update the scaling on a SkelControl. */
virtual void PreviewSetSkelControlScale ( FName SkelControlName , FLOAT Scale ) ;
/** Called each frame by Matinee to update the controlstrength on a SkelControl. */
virtual void SetSkelControlStrength ( FName SkelControlName , FLOAT ControlStrength ) ;
/** Called each from while the Matinee action is running, to set the animation weights for the actor. */
virtual void SetAnimWeights ( const TArray < struct FAnimSlotInfo > & SlotInfos ) ;
/** Called each frame by Matinee for InterpMoveTrack to adjust their location/rotation **/
virtual void AdjustInterpTrackMove ( FVector & Pos , FRotator & Rot , FLOAT DeltaTime , UBOOL bIgnoreRotation = FALSE ) ;
virtual UBOOL FindInterpMoveTrack ( class UInterpTrackMove * * MoveTrack , class UInterpTrackInstMove * * MoveTrackInst , class USeqAct _Interp * * OutSeq ) ;
void UpdateScalarParameterInterp ( FLOAT DeltaTime ) ;
# if _ _TW _PHYSICS _
virtual void physicsRotationCrawler ( FLOAT deltaTime , FRotator deltaRot , FRotator & NewRotation ) { }
# endif
protected :
virtual void ApplyVelocityBraking ( FLOAT DeltaTime , FLOAT Friction ) ;
virtual void CalcVelocity ( FVector & AccelDir , FLOAT DeltaTime , FLOAT MaxSpeed , FLOAT Friction , INT bFluid , INT bBrake , INT bBuoyant ) ;
# if _ _TW _
int findNewFloor ( FVector OldLocation , FLOAT deltaTime , FLOAT remainingTime , INT Iterations ) ;
# endif
private :
UBOOL Pick3DWallAdjust ( FVector WallHitNormal , AActor * HitActor ) ;
FLOAT Swim ( FVector Delta , FCheckResult & Hit ) ;
FVector findWaterLine ( FVector Start , FVector End ) ;
void SpiderstepUp ( const FVector & DesiredDir , const FVector & Delta , FCheckResult & Hit ) ;
# if ! _ _TW _
int findNewFloor ( FVector OldLocation , FLOAT deltaTime , FLOAT remainingTime , INT Iterations ) ;
# endif
int checkFloor ( FVector Dir , FCheckResult & Hit ) ;
}
replication
{
// Variables the server should send ALL clients.
if ( bNetDirty )
FlashLocation , bSimulateGravity , bIsWalking , PlayerReplicationInfo , HitDamageType ,
TakeHitLocation , DrivenVehicle , bUsedByMatinee , bFastAttachedMove ;
if ( bNetDirty && ( bNetOwner || bReplicateHealthToAll /* || IsViewTargetOfReplicationViewer() */ ) )
Health ;
// variables sent to owning client
if ( bNetDirty && bNetOwner )
InvManager , Controller , GroundSpeed , WaterSpeed , AirSpeed , AccelRate , JumpZ , AirControl ;
if ( bNetDirty && bNetOwner && bNetInitial )
bCanSwatTurn ;
// sent to non owning clients
if ( bNetDirty && ( ! bNetOwner || bDemoRecording ) )
bIsCrouched , FlashCount , FiringMode ;
// variable sent to all clients when Pawn has been torn off. (bTearOff)
if ( bTearOff && bNetDirty )
TearOffMomentum ;
// variables sent to all but the owning client
if ( ( ! bNetOwner || bDemoRecording ) )
RemoteViewPitch ;
if ( bNetInitial && ! bNetOwner )
bRootMotionFromInterpCurve ;
if ( bNetInitial && ! bNetOwner && bRootMotionFromInterpCurve )
RootMotionInterpRate , RootMotionInterpCurrentTime , RootMotionInterpCurveLastValue ;
// Replicated to ALL
if ( ( Role == Role _Authority ) && bNetDirty )
HealthMax ;
}
native final function bool PickWallAdjust ( Vector WallHitNormal , Actor HitActor ) ;
/** DesiredRotation related function **/
/ * * S e t D e s i r e d R o t a t i o n f u n c t i o n
* @ param TargetDesiredRotation : DesiredRotation you want
* @ param InLockDesiredRotation : I 'd like to lock up DesiredRotation, please nobody else can touch it until I say it' s done
* @ param InUnlockWhenReached : When you lock , set this to TRUE if you want it to be auto Unlock when reached desired rotation
* @ param InterpolationTime : Give interpolation time to get to the desired rotation - Ignore default RotationRate , but use this to get there
* @ return TRUE if properly set , otherwise , return FALSE
* * /
native final function bool SetDesiredRotation ( Rotator TargetDesiredRotation , bool InLockDesiredRotation = FALSE , bool InUnlockWhenReached = FALSE , FLOAT InterpolationTime = - 1. f , bool bResetRotationRate = TRUE ) ;
/ * * L o c k D e s i r e d R o t a t i o n f u n c t i o n
* @ param Lock : Lock or Unlock CurrentDesiredRotation
* @ param InUnlockWhenReached : Unlock when reached desired rotation . This is only valid when Lock = true
* /
native final function LockDesiredRotation ( bool Lock , bool InUnlockWhenReached = false /** This is only valid if Lock=true **/ ) ;
/ * * R e s e t D e s i r e d R o t a t i o n f u n c t i o n
* Clear RotationRate / Flag to go back to default behavior
* Unless it ' s locked .
* /
native final function ResetDesiredRotation ( ) ;
/ * * C h e c k D e s i r e d R o t a t i o n f u n c t i o n
* Check to see if DesiredRotation is met , and it need to be clear or not
* This is called by physicsRotation to make sure it needs to be cleared
* /
native final function CheckDesiredRotation ( ) ;
/ * * I s D e s i r e d R o t a t i o n I n U s e ( )
* See if DesiredRotation is used by somebody
* /
native final function bool IsDesiredRotationInUse ( ) ;
/ * * I s D e s i r e d R o t a t i o n L o c k e d ( )
* See if DesiredRotation is locked by somebody
* /
native final function bool IsDesiredRotationLocked ( ) ;
` if( ` _ _TW _ )
native function bool ReachedMyDestination ( const out vector TestPosition , const out vector Dest , actor GoalActor ) ;
` endif
simulated event PostInitAnimTree ( SkeletalMeshComponent SkelComp )
{
Super . PostInitAnimTree ( SkelComp ) ;
// Only refresh anim nodes if our main mesh was updated
if ( SkelComp == Mesh )
{
ClearAnimNodes ( ) ;
CacheAnimNodes ( ) ;
}
}
/** Save off commonly used nodes so the tree doesn't need to be iterated over often */
simulated native event CacheAnimNodes ( ) ;
/** Remove references to the saved nodes */
simulated function ClearAnimNodes ( )
{
SlotNodes . Length = 0 ;
}
/** Update list of AnimSets for this Pawn */
simulated native final function UpdateAnimSetList ( ) ;
/** Build AnimSet list Script version, called by UpdateAnimSetList() */
simulated event BuildScriptAnimSetList ( ) ;
/ * *
* Add a given list of anim sets on the top of the list ( so they override the other ones
* ! ! Only use within BuildScriptAnimSetList ( ) ! !
* /
simulated native final function AddAnimSets ( const out array < AnimSet > CustomAnimSets ) ;
/** Called after UpdateAnimSetList does its job */
simulated event AnimSetListUpdated ( ) ;
simulated event bool RestoreAnimSetsToDefault ( )
{
Mesh . AnimSets = default . Mesh . AnimSets ;
return TRUE ;
}
// Matinee Track Support Start
/** Called when we start an AnimControl track operating on this Actor. Supplied is the set of AnimSets we are going to want to play from. */
simulated event BeginAnimControl ( InterpGroup InInterpGroup )
{
// `log(self@" Begin Anim Control : Rotation:"@Rotation@" Location:"@Location);
MAT _BeginAnimControl ( InInterpGroup ) ;
}
/** Start AnimControl. Add required AnimSets. */
native function MAT _BeginAnimControl ( InterpGroup InInterpGroup ) ;
/** Called when we are done with the AnimControl track. */
simulated event FinishAnimControl ( InterpGroup InInterpGroup )
{
MAT _FinishAnimControl ( InInterpGroup ) ;
}
/** End AnimControl. Release required AnimSets */
native function MAT _FinishAnimControl ( InterpGroup InInterpGroup ) ;
/** Called each from while the Matinee action is running, with the desired sequence name and position we want to be at. */
simulated event SetAnimPosition ( name SlotName , int ChannelIndex , name InAnimSeqName , float InPosition , bool bFireNotifies , bool bLooping , bool bEnableRootMotion )
{
// `log(self@" Slot:"@SlotName@" AnimSeqName:"@InAnimSeqName@" InPosition:"@InPosition@" Rotation:"@Rotation@" Location:"@Location);
MAT _SetAnimPosition ( SlotName , ChannelIndex , InAnimSeqName , InPosition , bFireNotifies , bLooping , bEnableRootMotion ) ;
}
/** Update AnimTree from track info */
native function MAT _SetAnimPosition ( name SlotName , int ChannelIndex , name InAnimSeqName , float InPosition , bool bFireNotifies , bool bLooping , bool bEnableRootMotion ) ;
/** Update AnimTree from track weights */
native function MAT _SetAnimWeights ( Array < AnimSlotInfo > SlotInfos ) ;
native function MAT _SetMorphWeight ( name MorphNodeName , float MorphWeight ) ;
native function MAT _SetSkelControlScale ( name SkelControlName , float Scale ) ;
native function MAT _SetSkelControlStrength ( name SkelControlName , float ControlStrength ) ;
/ * * c a l l e d w h e n a S e q A c t _ I n t e r p a c t i o n s t a r t s i n t e r p o l a t i n g t h i s A c t o r v i a m a t i n e e
* @ note this function is called on clients for actors that are interpolated clientside via MatineeActor
* @ param InterpAction the SeqAct _Interp that is affecting the Actor
* /
simulated event InterpolationStarted ( SeqAct _Interp InterpAction , InterpGroupInst GroupInst )
{
Super . InterpolationStarted ( InterpAction , GroupInst ) ;
}
/ * * c a l l e d w h e n a S e q A c t _ I n t e r p a c t i o n f i n i s h e d i n t e r p o l a t i n g t h i s A c t o r
* @ note this function is called on clients for actors that are interpolated clientside via MatineeActor
* @ param InterpAction the SeqAct _Interp that was affecting the Actor
* /
simulated event InterpolationFinished ( SeqAct _Interp InterpAction )
{
Super . InterpolationFinished ( InterpAction ) ;
}
simulated function BeginAIGroup ( ) ;
simulated function FinishAIGroup ( ) ;
event MAT _BeginAIGroup ( vector StartLoc , rotator StartRot )
{
SetLocation ( StartLoc ) ;
SetRotation ( StartRot ) ;
BeginAIGroup ( ) ;
bUsedByMatinee = true ;
}
event MAT _FinishAIGroup ( )
{
FinishAIGroup ( ) ;
bUsedByMatinee = false ;
}
/ * *
* Play FaceFX animations on this Actor .
* Returns TRUE if succeeded , if failed , a log warning will be issued .
* /
// WWISEMODIF_START
simulated event bool PlayActorFaceFXAnim ( FaceFXAnimSet AnimSet , String GroupName , String SeqName , SoundCue SoundCueToPlay , AkEvent AkEventToPlay )
{
return Mesh . PlayFaceFXAnim ( AnimSet , SeqName , GroupName , SoundCueToPlay , AkEventToPlay ) ;
}
// WWISEMODIF_END
/** Stop any matinee FaceFX animations on this Actor. */
event StopActorFaceFXAnim ( )
{
Mesh . StopFaceFXAnim ( ) ;
}
/** Used to let FaceFX know what component to play dialogue audio on. */
simulated event AudioComponent GetFaceFXAudioComponent ( )
{
return FacialAudioComp ;
}
/ * *
* Returns TRUE if Actor is playing a FaceFX anim .
* Implement in sub - class .
* /
simulated function bool IsActorPlayingFaceFXAnim ( )
{
return ( Mesh != None && Mesh . IsPlayingFaceFXAnim ( ) ) ;
}
/ * *
* Returns FALSE ? ? ? if Actor can play facefx
* Implement in sub - class .
* /
simulated function bool CanActorPlayFaceFXAnim ( )
{
return TRUE ;
}
/** Function for handling the SeqAct_PlayFaceFXAnim Kismet action working on this Actor. */
simulated function OnPlayFaceFXAnim ( SeqAct _PlayFaceFXAnim inAction )
{
//`log("Play FaceFX animation from KismetAction for" @ Self @ "GroupName:" @ inAction.FaceFXGroupName @ "AnimName:" @ inAction.FaceFXAnimName);
// WWISEMODIF_START
Mesh . PlayFaceFXAnim ( inAction . FaceFXAnimSetRef , inAction . FaceFXAnimName , inAction . FaceFXGroupName , inAction . SoundCueToPlay , inAction . AkEventToPlay ) ;
// WWISEMODIF_END
}
/ * *
* Called via delegate when FacialAudioComp is finished .
* /
simulated function FaceFXAudioFinished ( AudioComponent AC )
{
}
/** Used by Matinee in-game to mount FaceFXAnimSets before playing animations. */
event FaceFXAsset GetActorFaceFXAsset ( )
{
if ( Mesh . SkeletalMesh != None && ! Mesh . bDisableFaceFX )
{
return Mesh . SkeletalMesh . FaceFXAsset ;
}
else
{
return None ;
}
}
/** Called each frame by Matinee to update the weight of a particular MorphNodeWeight. */
event SetMorphWeight ( name MorphNodeName , float MorphWeight )
{
MAT _SetMorphweight ( MorphNodeName , MorphWeight ) ;
}
/** Called each frame by Matinee to update the scaling on a SkelControl. */
event SetSkelControlScale ( name SkelControlName , float Scale )
{
MAT _SetSkelControlScale ( SkelControlName , Scale ) ;
}
// Matinee Track Support End
//
/** Check on various replicated data and act accordingly. */
simulated event ReplicatedEvent ( name VarName )
{
//`log( WorldInfo.TimeSeconds @ GetFuncName() @ "VarName:" @ VarName );
super . ReplicatedEvent ( VarName ) ;
if ( VarName == 'FlashCount' ) // FlashCount and FlashLocation are changed when a weapon is fired.
{
FlashCountUpdated ( Weapon , FlashCount , TRUE ) ;
}
else if ( VarName == 'FlashLocation' ) // FlashCount and FlashLocation are changed when a weapon is fired.
{
FlashLocationUpdated ( Weapon , FlashLocation , TRUE ) ;
}
else if ( VarName == 'FiringMode' )
{
FiringModeUpdated ( Weapon , FiringMode , TRUE ) ;
}
else if ( VarName == 'DrivenVehicle' )
{
if ( DrivenVehicle != None )
{
// since pawn doesn't have a PRI while driving, and may become initially relevant while driving,
// we may only be able to ascertain the pawn's team (for team coloring, etc.) through its drivenvehicle
NotifyTeamChanged ( ) ;
}
}
else if ( VarName == 'PlayerReplicationInfo' )
{
NotifyTeamChanged ( ) ;
}
else if ( VarName == 'Controller' )
{
if ( ( Controller != None ) && ( Controller . Pawn == None ) )
{
Controller . Pawn = self ;
if ( ( PlayerController ( Controller ) != None )
&& ( PlayerController ( Controller ) . ViewTarget == Controller ) )
PlayerController ( Controller ) . SetViewTarget ( self ) ;
}
}
else if ( VarName == 'bUsedByMatinee' )
{
if ( bUsedByMatinee )
{
BeginAIGroup ( ) ;
}
else
{
FinishAIGroup ( ) ;
}
}
}
// =============================================================
/** Returns TRUE if Pawn is alive and doing well */
final virtual simulated native function bool IsAliveAndWell ( ) const ;
final native virtual function Vector AdjustDestination ( Actor GoalActor , optional Vector Dest ) ;
/** Is the current anchor valid? */
final native function bool ValidAnchor ( ) ;
/ * *
* SuggestJumpVelocity ( )
* returns true if succesful jump from start to destination is possible
* returns a suggested initial falling velocity in JumpVelocity
* Uses GroundSpeed and JumpZ as limits
*
* @ param JumpVelocity The vector to fill with the calculated jump velocity
* @ param Destination The destination location of the jump
* @ param Start The start location of the jump
* @ param bRequireFallLanding If true , the jump calculated will have a velocity in the negative Z at the destination
* /
native function bool SuggestJumpVelocity ( out vector JumpVelocity , vector Destination , vector Start , optional bool bRequireFallLanding ) ;
/ * *
* GetFallDuration
* returns time before impact if pawn falls from current position with current velocity
* /
native function float GetFallDuration ( ) ;
/ * * r e t u r n s i f w e a r e a v a l i d e n e m y f o r P R I
* checks things like whether we ' re alive , teammates , etc
* works on clients and servers
* /
native function bool IsValidEnemyTargetFor ( const PlayerReplicationInfo PRI , bool bNoPRIisEnemy ) ;
` if( ` _ _TW _ )
/ * * r e t u r n s i f w e a r e a v a l i d t e a m m a t e f o r P R I
* checks things like whether we ' re alive , teammates , etc
* works on clients and servers
* /
native function bool IsValidTeamTargetFor ( const PlayerReplicationInfo PRI ) ;
function bool CanAITargetThisPawn ( Controller TargetingController )
{
return true ;
}
` endif
/ * *
@ RETURN true if pawn is invisible to AI
* /
native function bool IsInvisible ( ) ;
/ * *
* Set Pawn ViewPitch , so we can see where remote clients are looking .
*
* @ param NewRemoteViewPitch Pitch component to replicate to remote ( non owned ) clients .
* /
native final function SetRemoteViewPitch ( int NewRemoteViewPitch ) ;
native function SetAnchor ( NavigationPoint NewAnchor ) ;
native function NavigationPoint GetBestAnchor ( Actor TestActor , Vector TestLocation , bool bStartPoint , bool bOnlyCheckVisible , out float out _Dist ) ;
native function bool ReachedDestination ( Actor Goal ) ;
native function bool ReachedPoint ( Vector Point , Actor NewAnchor ) ;
native function ForceCrouch ( ) ;
native function SetPushesRigidBodies ( bool NewPush ) ;
native final virtual function bool ReachedDesiredRotation ( ) ;
native function GetBoundingCylinder ( out float CollisionRadius , out float CollisionHeight ) const ;
/ * *
* Does the following :
* - Assign the SkeletalMeshComponent 'Mesh' to the CollisionComponent
* - Call InitArticulated on the SkeletalMeshComponent .
* - Change the physics mode to PHYS _RigidBody
* /
native function bool InitRagdoll ( ) ;
/ * * t h e o p p o s i t e o f I n i t R a g d o l l ( ) ; r e s e t s C o l l i s i o n C o m p o n e n t t o t h e d e f a u l t ,
* sets physics to PHYS _Falling , and calls TermArticulated ( ) on the SkeletalMeshComponent
* @ return true on success , false if there is no Mesh , the Mesh is not in ragdoll , or we ' re otherwise not able to terminate the physics
* /
native function bool TermRagdoll ( ) ;
/** Give pawn the chance to do something special moving between points */
function bool SpecialMoveTo ( NavigationPoint Start , NavigationPoint End , Actor Next ) ;
event bool SpecialMoveThruEdge ( ENavMeshEdgeType EdgeType , INT Dir , Vector MoveStart , Vector MoveDest , optional Actor RelActor , optional int RelItem , optional NavigationHandle NavHandle ) ;
simulated function SetBaseEyeheight ( )
{
if ( ! bIsCrouched )
BaseEyeheight = Default . BaseEyeheight ;
else
BaseEyeheight = FMin ( 0.8 * CrouchHeight , CrouchHeight - 10 ) ;
}
function PlayerChangedTeam ( )
{
Died ( None , class 'DamageType' , Location ) ;
}
/ * R e s e t ( )
reset actor to initial state - used when restarting level without reloading .
* /
function Reset ( )
{
if ( ( Controller == None ) || Controller . bIsPlayer )
{
DetachFromController ( ) ;
Destroy ( ) ;
}
else
super . Reset ( ) ;
}
function bool StopFiring ( )
{
if ( Weapon != None )
{
Weapon . StopFire ( Weapon . CurrentFireMode ) ;
}
return TRUE ;
}
/ * *
* Pawn starts firing !
* Called from PlayerController : : StartFiring
* Network : Local Player
*
* @ param FireModeNum fire mode number
* /
simulated function StartFire ( byte FireModeNum )
{
if ( bNoWeaponFIring )
{
return ;
}
if ( Weapon != None )
{
Weapon . StartFire ( FireModeNum ) ;
}
}
/ * *
* Pawn stops firing !
* i . e . player releases fire button , this may not stop weapon firing right away . ( for example press button once for a burst fire )
* Network : Local Player
*
* @ param FireModeNum fire mode number
* /
simulated function StopFire ( byte FireModeNum )
{
if ( Weapon != None )
{
Weapon . StopFire ( FireModeNum ) ;
}
}
/ * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
* Remote Client Firing Magic ...
* @ See Weapon : : IncrementFlashCount ( )
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * /
/** Return FiringMode currently in use by weapon InWeapon */
simulated function byte GetWeaponFiringMode ( Weapon InWeapon )
{
return FiringMode ;
}
/ * *
* Set firing mode replication for remote clients trigger update notification .
* Network : LocalPlayer and Server
* /
simulated function SetFiringMode ( Weapon InWeapon , byte InFiringMode )
{
//`log( WorldInfo.TimeSeconds @ GetFuncName() @ "old:" @ FiringMode @ "new:" @ FiringModeNum );
if ( FiringMode != InFiringMode )
{
FiringMode = InFiringMode ;
bForceNetUpdate = TRUE ;
// call updated event locally
FiringModeUpdated ( InWeapon , FiringMode , FALSE ) ;
}
}
/ * *
* Called when FiringMode has been updated .
*
* Network : ALL
* /
simulated function FiringModeUpdated ( Weapon InWeapon , byte InFiringMode , bool bViaReplication )
{
if ( InWeapon != None )
{
InWeapon . FireModeUpdated ( InFiringMode , bViaReplication ) ;
}
}
/ * *
* This function ' s responsibility is to signal clients that non - instant hit shot
* has been fired . Call this on the server and local player .
*
* Network : Server and Local Player
* /
simulated function IncrementFlashCount ( Weapon InWeapon , byte InFiringMode )
{
bForceNetUpdate = TRUE ; // Force replication
FlashCount ++ ;
// Make sure it's not 0, because it means the weapon stopped firing!
if ( FlashCount == 0 )
{
FlashCount += 2 ;
}
// Make sure firing mode is updated
SetFiringMode ( InWeapon , InFiringMode ) ;
// This weapon has fired.
FlashCountUpdated ( InWeapon , FlashCount , FALSE ) ;
}
/ * *
* Called when FlashCount has been updated .
* Trigger appropritate events based on FlashCount ' s value .
* = 0 means Weapon Stopped firing
* > 0 means Weapon just fired
*
* Network : ALL
* /
simulated function FlashCountUpdated ( Weapon InWeapon , Byte InFlashCount , bool bViaReplication )
{
//`log( WorldInfo.TimeSeconds @ GetFuncName() @ "FlashCount:" @ FlashCount @ "bViaReplication:" @ bViaReplication );
if ( InFlashCount > 0 )
{
WeaponFired ( InWeapon , bViaReplication ) ;
}
else
{
WeaponStoppedFiring ( InWeapon , bViaReplication ) ;
}
}
/ * *
* Clear flashCount variable . and call WeaponStoppedFiring event .
* Call this on the server and local player .
*
* Network : Server or Local Player
* /
simulated function ClearFlashCount ( Weapon InWeapon )
{
if ( FlashCount != 0 )
{
bForceNetUpdate = TRUE ; // Force replication
FlashCount = 0 ;
// This weapon stopped firing
FlashCountUpdated ( InWeapon , FlashCount , FALSE ) ;
}
}
/ * *
* This function sets up the Location of a hit to be replicated to all remote clients .
* It is also responsible for fudging a shot at ( 0 , 0 , 0 ) .
*
* Network : Server only ( unless using client - side hit detection )
* /
simulated function SetFlashLocation ( Weapon InWeapon , byte InFiringMode , vector NewLoc )
{
// Make sure 2 consecutive flash locations are different, for replication
if ( NewLoc == LastFiringFlashLocation )
{
NewLoc += vect ( 0 , 0 , 1 ) ;
}
// If we are aiming at the origin, aim slightly up since we use 0,0,0 to denote
// not firing.
if ( NewLoc == vect ( 0 , 0 , 0 ) )
{
NewLoc = vect ( 0 , 0 , 1 ) ;
}
bForceNetUpdate = TRUE ; // Force replication
FlashLocation = NewLoc ;
LastFiringFlashLocation = NewLoc ;
// Make sure firing mode is updated
SetFiringMode ( InWeapon , InFiringMode ) ;
// This weapon has fired.
FlashLocationUpdated ( InWeapon , FlashLocation , FALSE ) ;
}
/ * *
* Reset flash location variable . and call stop firing .
* Network : Server only
* /
function ClearFlashLocation ( Weapon InWeapon )
{
if ( ! IsZero ( FlashLocation ) )
{
bForceNetUpdate = TRUE ; // Force replication
FlashLocation = vect ( 0 , 0 , 0 ) ;
FlashLocationUpdated ( InWeapon , FlashLocation , FALSE ) ;
}
}
/ * *
* Called when FlashLocation has been updated .
* Trigger appropritate events based on FlashLocation ' s value .
* == ( 0 , 0 , 0 ) means Weapon Stopped firing
* != ( 0 , 0 , 0 ) means Weapon just fired
*
* Network : ALL
* /
simulated function FlashLocationUpdated ( Weapon InWeapon , Vector InFlashLocation , bool bViaReplication )
{
//`log( WorldInfo.TimeSeconds @ GetFuncName() @ "FlashLocation:" @ FlashLocation @ "bViaReplication:" @ bViaReplication );
if ( ! IsZero ( InFlashLocation ) )
{
WeaponFired ( InWeapon , bViaReplication , InFlashLocation ) ;
}
else
{
WeaponStoppedFiring ( InWeapon , bViaReplication ) ;
}
}
/ * *
* Called when a pawn ' s weapon has fired and is responsibile for
* delegating the creation of all of the different effects .
*
* bViaReplication denotes if this call in as the result of the
* flashcount / flashlocation being replicated . It ' s used filter out
* when to make the effects .
*
* Network : ALL
* /
simulated function WeaponFired ( Weapon InWeapon , bool bViaReplication , optional vector HitLocation )
{
// increment number of consecutive shots.
ShotCount ++ ;
// By default we just call PlayFireEffects on the weapon.
if ( InWeapon != None )
{
InWeapon . PlayFireEffects ( GetWeaponFiringMode ( InWeapon ) , HitLocation ) ;
}
}
/ * *
* Called when a pawn ' s weapon has stopped firing and is responsibile for
* delegating the destruction of all of the different effects .
*
* bViaReplication denotes if this call in as the result of the
* flashcount / flashlocation being replicated .
*
* Network : ALL
* /
simulated function WeaponStoppedFiring ( Weapon InWeapon , bool bViaReplication )
{
// reset number of consecutive shots fired.
ShotCount = 0 ;
if ( InWeapon != None )
{
InWeapon . StopFireEffects ( GetWeaponFiringMode ( InWeapon ) ) ;
}
}
/ * *
AI Interface for combat
* * /
function bool BotFire ( bool bFinished )
{
StartFire ( 0 ) ;
return true ;
}
function bool CanAttack ( Actor Other )
{
if ( Weapon == None )
return false ;
return Weapon . CanAttack ( Other ) ;
}
function bool TooCloseToAttack ( Actor Other )
{
return false ;
}
function bool FireOnRelease ( )
{
if ( Weapon != None )
return Weapon . FireOnRelease ( ) ;
return false ;
}
function bool HasRangedAttack ( )
{
return ( Weapon != None ) ;
}
function bool IsFiring ( )
{
if ( Weapon != None )
return Weapon . IsFiring ( ) ;
return false ;
}
/** returns whether we need to turn to fire at the specified location */
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 ) ;
}
simulated function String GetHumanReadableName ( )
{
if ( PlayerReplicationInfo != None )
return PlayerReplicationInfo . PlayerName ;
return MenuName ;
}
function PlayTeleportEffect ( bool bOut , bool bSound )
{
MakeNoise ( 1.0 ) ;
}
/ * * N o t i f y T e a m C h a n g e d ( )
Called when PlayerReplicationInfo is replicated to this pawn , or PlayerReplicationInfo team property changes .
Network : client
* /
simulated function NotifyTeamChanged ( ) ;
/ * P o s s e s s e d B y ( )
Pawn is possessed by Controller
* /
function PossessedBy ( Controller C , bool bVehicleTransition )
{
Controller = C ;
NetPriority = 3 ;
NetUpdateFrequency = 100 ;
bForceNetUpdate = TRUE ;
if ( C . PlayerReplicationInfo != None )
{
PlayerReplicationInfo = C . PlayerReplicationInfo ;
}
UpdateControllerOnPossess ( bVehicleTransition ) ;
SetOwner ( Controller ) ; // for network replication
Eyeheight = BaseEyeHeight ;
if ( C . IsA ( 'PlayerController' ) )
{
if ( WorldInfo . NetMode != NM _Standalone )
{
RemoteRole = ROLE _AutonomousProxy ;
}
// inform client of current weapon
if ( Weapon != None )
{
Weapon . ClientWeaponSet ( FALSE ) ;
}
}
else
{
RemoteRole = Default . RemoteRole ;
}
//Update the AIController cache
if ( Weapon != None )
{
Weapon . CacheAIController ( ) ;
}
}
/ * U p d a t e C o n t r o l l e r O n P o s s e s s ( )
update controller - normally , just change its rotation to match pawn rotation
* /
function UpdateControllerOnPossess ( bool bVehicleTransition )
{
// don't set pawn rotation on possess if was driving vehicle, so face
// same direction when get out as when driving
if ( ! bVehicleTransition )
{
Controller . SetRotation ( Rotation ) ;
}
}
function UnPossessed ( )
{
bForceNetUpdate = TRUE ;
if ( DrivenVehicle != None )
NetUpdateFrequency = 5 ;
PlayerReplicationInfo = None ;
SetOwner ( None ) ;
Controller = None ;
}
/ * *
* returns default camera mode when viewing this pawn .
* Mainly called when controller possesses this pawn .
*
* @ param PlayerController requesting the default camera view
* @ return default camera view player should use when controlling this pawn .
* /
simulated function name GetDefaultCameraMode ( PlayerController RequestedBy )
{
if ( RequestedBy != None && RequestedBy . PlayerCamera != None && RequestedBy . PlayerCamera . CameraStyle == 'Fixed' )
return 'Fixed' ;
return 'FirstPerson' ;
}
function DropToGround ( )
{
bCollideWorld = True ;
if ( Health > 0 )
{
SetCollision ( true , true ) ;
SetPhysics ( PHYS _Falling ) ;
if ( IsHumanControlled ( ) )
Controller . GotoState ( LandMovementState ) ;
}
}
function bool CanGrabLadder ( )
{
return ( bCanClimbLadders
&& ( Controller != None )
&& ( Physics != PHYS _Ladder )
&& ( ( Physics != Phys _Falling ) || ( abs ( Velocity . Z ) <= JumpZ ) ) ) ;
}
function bool RecommendLongRangedAttack ( )
{
return false ;
}
function float RangedAttackTime ( )
{
return 0 ;
}
/ * *
* Called every frame from PlayerInput or PlayerController : : MoveAutonomous ( )
* Sets bIsWalking flag , which defines if the Pawn is walking or not ( affects velocity )
*
* @ param bNewIsWalking , new walking state .
* /
event SetWalking ( bool bNewIsWalking )
{
if ( bNewIsWalking != bIsWalking )
{
bIsWalking = bNewIsWalking ;
}
}
simulated function bool CanSplash ( )
{
if ( ( WorldInfo . TimeSeconds - SplashTime > 0.15 )
&& ( ( Physics == PHYS _Falling ) || ( Physics == PHYS _Flying ) )
&& ( Abs ( Velocity . Z ) > 100 ) )
{
SplashTime = WorldInfo . 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' ) ;
}
/ * *
* list important Pawn variables on canvas . HUD will call DisplayDebug ( ) on the current ViewTarget when
* the ShowDebug exec is used
*
* @ param HUD - HUD with canvas to draw on
* @ input out _YL - Height of the current font
* @ input out _YPos - Y position on Canvas . out _YPos += out _YL , gives position to draw text for next debug line .
* /
simulated function DisplayDebug ( HUD HUD , out float out _YL , out float out _YPos )
{
local string T ;
local Canvas Canvas ;
local AnimTree AnimTreeRootNode ;
local int i ;
Canvas = HUD . Canvas ;
if ( PlayerReplicationInfo == None )
{
Canvas . DrawText ( "NO PLAYERREPLICATIONINFO" , false ) ;
out _YPos += out _YL ;
Canvas . SetPos ( 4 , out _YPos ) ;
}
else
{
PlayerReplicationInfo . DisplayDebug ( HUD , out _YL , out _YPos ) ;
}
super . DisplayDebug ( HUD , out _YL , out _YPos ) ;
Canvas . SetDrawColor ( 255 , 255 , 255 ) ;
Canvas . DrawText ( "Health " $Health ) ;
out _YPos += out _YL ;
Canvas . SetPos ( 4 , out _YPos ) ;
if ( HUD . ShouldDisplayDebug ( 'AI' ) )
{
Canvas . DrawText ( "Anchor " $Anchor$ " Serpentine Dist " $SerpentineDist$ " Time " $SerpentineTime ) ;
out _YPos += out _YL ;
Canvas . SetPos ( 4 , out _YPos ) ;
}
if ( HUD . ShouldDisplayDebug ( 'physics' ) )
{
T = "Floor " $Floor$ " DesiredSpeed " $DesiredSpeed$ " Crouched " $bIsCrouched ;
if ( ( OnLadder != None ) || ( Physics == PHYS _Ladder ) )
T = T$ " on ladder " $OnLadder ;
Canvas . DrawText ( T ) ;
out _YPos += out _YL ;
Canvas . SetPos ( 4 , out _YPos ) ;
T = "Collision Component:" @ CollisionComponent ;
Canvas . DrawText ( T ) ;
out _YPos += out _YL ;
Canvas . SetPos ( 4 , out _YPos ) ;
T = "bForceMaxAccel:" @ bForceMaxAccel ;
Canvas . DrawText ( T ) ;
out _YPos += out _YL ;
Canvas . SetPos ( 4 , out _YPos ) ;
if ( Mesh != None )
{
T = "RootMotionMode:" @ Mesh . RootMotionMode @ "RootMotionVelocity:" @ Mesh . RootMotionVelocity ;
Canvas . DrawText ( T ) ;
out _YPos += out _YL ;
Canvas . SetPos ( 4 , out _YPos ) ;
}
}
if ( HUD . ShouldDisplayDebug ( 'camera' ) )
{
Canvas . DrawText ( "EyeHeight " $Eyeheight$ " BaseEyeHeight " $BaseEyeHeight ) ;
out _YPos += out _YL ;
Canvas . SetPos ( 4 , out _YPos ) ;
}
// Controller
if ( Controller == None )
{
Canvas . SetDrawColor ( 255 , 0 , 0 ) ;
Canvas . DrawText ( "NO CONTROLLER" ) ;
out _YPos += out _YL ;
Canvas . SetPos ( 4 , out _YPos ) ;
HUD . PlayerOwner . DisplayDebug ( HUD , out _YL , out _YPos ) ;
}
else
{
Controller . DisplayDebug ( HUD , out _YL , out _YPos ) ;
}
// Weapon
if ( HUD . ShouldDisplayDebug ( 'weapon' ) )
{
if ( Weapon == None )
{
Canvas . SetDrawColor ( 0 , 255 , 0 ) ;
Canvas . DrawText ( "NO WEAPON" ) ;
out _YPos += out _YL ;
Canvas . SetPos ( 4 , out _YPos ) ;
}
else
Weapon . DisplayDebug ( HUD , out _YL , out _YPos ) ;
}
if ( HUD . ShouldDisplayDebug ( 'animation' ) )
{
if ( Mesh != None && Mesh . Animations != None )
{
AnimTreeRootNode = AnimTree ( Mesh . Animations ) ;
if ( AnimTreeRootNode != None )
{
Canvas . DrawText ( "AnimGroups count:" @ AnimTreeRootNode . AnimGroups . Length ) ;
out _YPos += out _YL ;
Canvas . SetPos ( 4 , out _YPos ) ;
for ( i = 0 ; i < AnimTreeRootNode . AnimGroups . Length ; i ++ )
{
Canvas . DrawText ( " GroupName:" @ AnimTreeRootNode . AnimGroups [ i ] . GroupName @ "NodeCount:" @ AnimTreeRootNode . AnimGroups [ i ] . SeqNodes . Length @ "RateScale:" @ AnimTreeRootNode . AnimGroups [ i ] . RateScale ) ;
out _YPos += out _YL ;
Canvas . SetPos ( 4 , out _YPos ) ;
}
}
}
}
}
//***************************************
// Interface to Pawn's Controller
/ * *
* IsHumanControlled ( )
* @ param PawnController - optional parameter so you can pass a controller that is associated with this pawn but is not attached to it
* @ return - true if controlled by a real live human on the local machine . On client , only local player ' s pawn returns true
* /
simulated final native function bool IsHumanControlled ( optional Controller PawnController ) ;
/ * *
* @ return - true if controlled by local ( not network ) player
* /
simulated native final function bool IsLocallyControlled ( ) ;
/ * * I s P l a y e r P a w n ( )
return true if controlled by a Player ( AI or human ) on local machine ( any controller on server , localclient ' s pawn on client )
* /
simulated native function bool IsPlayerPawn ( ) const ;
// 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 . UsingFirstPersonCamera ( ) ) ;
}
/ * *
* Called from PlayerController UpdateRotation ( ) - > ProcessViewRotation ( ) to ( pre ) process player ViewRotation
* adds delta rot ( player input ) , applies any limits and post - processing
* returns the final ViewRotation set on PlayerController
*
* @ param DeltaTime , time since last frame
* @ param ViewRotation , actual PlayerController view rotation
* @ input out _DeltaRot , delta rotation to be applied on ViewRotation . Represents player ' s input .
* @ return processed ViewRotation to be set on PlayerController .
* /
simulated function ProcessViewRotation ( float DeltaTime , out rotator out _ViewRotation , out Rotator out _DeltaRot )
{
// Add Delta Rotation
out _ViewRotation += out _DeltaRot ;
out _DeltaRot = rot ( 0 , 0 , 0 ) ;
// Limit Player View Pitch
if ( PlayerController ( Controller ) != None )
{
out _ViewRotation = PlayerController ( Controller ) . LimitViewRotation ( out _ViewRotation , ViewPitchMin , ViewPitchMax ) ;
}
}
/ * *
* returns the point of view of the actor .
* note that this doesn 't mean the camera, but the ' eyes ' of the actor .
* For example , for a Pawn , this would define the eye height location ,
* and view rotation ( which is different from the pawn rotation which has a zeroed pitch component ) .
* A camera first person view will typically use this view point . Most traces ( weapon , AI ) will be done from this view point .
*
* @ output out _Location , location of view point
* @ output out _Rotation , view rotation of actor .
* /
simulated event GetActorEyesViewPoint ( out vector out _Location , out Rotator out _Rotation )
{
out _Location = GetPawnViewLocation ( ) ;
out _Rotation = GetViewRotation ( ) ;
}
/ * * @ r e t u r n t h e r o t a t i o n t h e P a w n i s l o o k i n g
* /
simulated native event rotator GetViewRotation ( ) ;
/ * *
* returns the Eye location of the Pawn .
*
* @ return Pawn ' s eye location
* /
simulated native event vector GetPawnViewLocation ( ) ;
/ * *
* Return world location to start a weapon fire trace from .
*
* @ return World location where to start weapon fire traces from
* /
simulated event Vector GetWeaponStartTraceLocation ( optional Weapon CurrentWeapon )
{
local vector POVLoc ;
local rotator POVRot ;
// If we have a controller, by default we start tracing from the player's 'eyes' location
// that is by default Controller.Location for AI, and camera (crosshair) location for human players.
if ( Controller != None )
{
Controller . GetPlayerViewPoint ( POVLoc , POVRot ) ;
return POVLoc ;
}
// If we have no controller, we simply traces from pawn eyes location
return GetPawnViewLocation ( ) ;
}
/ * *
* returns base Aim Rotation without any adjustment ( no aim error , no autolock , no adhesion . . just clean initial aim rotation ! )
*
* @ return base Aim rotation .
* /
simulated singular event Rotator GetBaseAimRotation ( )
{
local vector POVLoc ;
local rotator POVRot ;
// If we have a controller, by default we aim at the player's 'eyes' direction
// that is by default Controller.Rotation for AI, and camera (crosshair) rotation for human players.
if ( Controller != None && ! InFreeCam ( ) )
{
Controller . GetPlayerViewPoint ( POVLoc , POVRot ) ;
return POVRot ;
}
// If we have no controller, we simply use our rotation
POVRot = Rotation ;
// If our Pitch is 0, then use RemoveViewPitch
if ( POVRot . Pitch == 0 )
{
POVRot . Pitch = RemoteViewPitch << 8 ;
}
return POVRot ;
}
/** return true if player is viewing this Pawn in FreeCam */
simulated event bool InFreeCam ( )
{
local PlayerController PC ;
PC = PlayerController ( Controller ) ;
return ( PC != None && PC . PlayerCamera != None && ( PC . PlayerCamera . CameraStyle == 'FreeCam' || PC . PlayerCamera . CameraStyle == 'FreeCam_Default' ) ) ;
}
/ * *
* Adjusts weapon aiming direction .
* Gives Pawn a chance to modify its aiming . For example aim error , auto aiming , adhesion , AI help ...
* Requested by weapon prior to firing .
*
* @ param W , weapon about to fire
* @ param StartFireLoc , world location of weapon fire start trace , or projectile spawn loc .
* @ param BaseAimRot , original aiming rotation without any modifications .
* /
simulated function Rotator GetAdjustedAimFor ( Weapon W , vector StartFireLoc )
{
// If controller doesn't exist or we're a client, get the where the Pawn is aiming at
if ( Controller == None || Role < Role _Authority )
{
return GetBaseAimRotation ( ) ;
}
// otherwise, give a chance to controller to adjust this Aim Rotation
return Controller . GetAdjustedAimFor ( W , StartFireLoc ) ;
}
simulated function SetViewRotation ( rotator NewRotation )
{
if ( Controller != None )
{
Controller . SetRotation ( NewRotation ) ;
}
else
{
SetRotation ( NewRotation ) ;
}
}
function bool InGodMode ( )
{
return ( ( Controller != None ) && Controller . bGodMode ) ;
}
function SetMoveTarget ( Actor NewTarget )
{
if ( Controller != None )
Controller . MoveTarget = NewTarget ;
}
function bool LineOfSightTo ( actor Other )
{
return ( ( Controller != None ) && Controller . LineOfSightTo ( Other ) ) ;
}
function HandlePickup ( Inventory Inv )
{
MakeNoise ( 0.2 ) ;
if ( Controller != None )
Controller . HandlePickup ( Inv ) ;
}
event ClientMessage ( coerce string S , optional Name Type )
{
if ( PlayerController ( Controller ) != None )
PlayerController ( Controller ) . ClientMessage ( S , Type ) ;
}
simulated event FellOutOfWorld ( class < DamageType > dmgType )
{
if ( Role == ROLE _Authority )
{
Health = - 1 ;
Died ( None , dmgType , Location ) ;
if ( dmgType == None )
{
SetPhysics ( PHYS _None ) ;
SetHidden ( True ) ;
LifeSpan = FMin ( LifeSpan , 1.0 ) ;
}
}
}
simulated singular event OutsideWorldBounds ( )
{
// AI pawns on the server just destroy
if ( Role == ROLE _Authority && PlayerController ( Controller ) == None )
{
Destroy ( ) ;
}
else
{
// simply destroying the Pawn could cause synchronization issues with the client controlling it
// so kill it, disable it, and wait a while to give it time to replicate before destroying it
if ( Role == ROLE _Authority )
{
KilledBy ( self ) ;
}
SetPhysics ( PHYS _None ) ;
SetHidden ( True ) ;
LifeSpan = FMin ( LifeSpan , 1.0 ) ;
}
}
/ * *
* Makes sure a Pawn is not crouching , telling it to stand if necessary .
* /
simulated function UnCrouch ( )
{
if ( bIsCrouched || bWantsToCrouch )
{
ShouldCrouch ( false ) ;
}
}
/ * *
* Controller is requesting that pawn crouches .
* This is not guaranteed as it depends if crouching collision cylinder can fit when Pawn is located .
*
* @ param bCrouch true if Pawn should crouch .
* /
function ShouldCrouch ( bool bCrouch )
{
bWantsToCrouch = bCrouch ;
}
/ * *
* Event called from native code when Pawn stops crouching .
* Called on non owned Pawns through bIsCrouched replication .
* Network : ALL
*
* @ param HeightAdjust height difference in unreal units between default collision height , and actual crouched cylinder height .
* /
simulated event EndCrouch ( float HeightAdjust )
{
EyeHeight -= HeightAdjust ;
SetBaseEyeHeight ( ) ;
}
/ * *
* Event called from native code when Pawn starts crouching .
* Called on non owned Pawns through bIsCrouched replication .
* Network : ALL
*
* @ param HeightAdjust height difference in unreal units between default collision height , and actual crouched cylinder height .
* /
simulated event StartCrouch ( float HeightAdjust )
{
EyeHeight += HeightAdjust ;
SetBaseEyeHeight ( ) ;
}
function HandleMomentum ( vector Momentum , Vector HitLocation , class < DamageType > DamageType , optional TraceHitInfo HitInfo )
{
AddVelocity ( Momentum , HitLocation , DamageType , HitInfo ) ;
}
function AddVelocity ( vector NewVelocity , vector HitLocation , class < DamageType > damageType , optional TraceHitInfo HitInfo )
{
if ( bIgnoreForces || ( NewVelocity == vect ( 0 , 0 , 0 ) ) )
return ;
if ( ( Physics == PHYS _Walking )
|| ( ( ( Physics == PHYS _Ladder ) || ( Physics == PHYS _Spider ) ) && ( NewVelocity . Z > Default . JumpZ ) ) )
SetPhysics ( PHYS _Falling ) ;
if ( ( Velocity . Z > Default . JumpZ ) && ( NewVelocity . Z > 0 ) )
NewVelocity . Z *= 0.5 ;
Velocity += NewVelocity ;
}
function KilledBy ( pawn EventInstigator )
{
local Controller Killer ;
Health = 0 ;
if ( EventInstigator != None )
{
Killer = EventInstigator . Controller ;
LastHitBy = None ;
}
Died ( Killer , class 'DmgType_Suicided' , Location ) ;
}
function TakeFallingDamage ( )
{
local float 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 += 100 ;
}
if ( EffectiveSpeed < - 1 * MaxFallSpeed )
{
TakeDamage ( - 100 * ( EffectiveSpeed + MaxFallSpeed ) / MaxFallSpeed , None , Location , vect ( 0 , 0 , 0 ) , class 'DmgType_Fell' ) ;
}
}
}
}
else if ( Velocity . Z < - 1.4 * JumpZ )
MakeNoise ( 0.5 ) ;
else if ( Velocity . Z < - 0.8 * JumpZ )
MakeNoise ( 0.2 ) ;
}
function Restart ( ) ;
simulated function ClientReStart ( )
{
ZeroMovementVariables ( ) ;
SetBaseEyeHeight ( ) ;
}
function ClientSetRotation ( rotator NewRotation )
{
if ( Controller != None )
Controller . ClientSetRotation ( NewRotation ) ;
}
/** Script function callable from C++ to update the Pawn's rotation, and goes through the FaceRotation logic to apply rotation constraints */
final event simulated UpdatePawnRotation ( Rotator NewRotation )
{
FaceRotation ( NewRotation , 0. f ) ;
}
simulated function FaceRotation ( rotator NewRotation , float DeltaTime )
{
// Do not update Pawn's rotation depending on controller's ViewRotation if in FreeCam.
if ( ! InFreeCam ( ) )
{
if ( Physics == PHYS _Ladder )
{
NewRotation = OnLadder . Walldir ;
}
else if ( ( Physics == PHYS _Walking ) || ( Physics == PHYS _Falling ) )
{
NewRotation . Pitch = 0 ;
}
SetRotation ( NewRotation ) ;
}
}
//==============
// Encroachment
event bool EncroachingOn ( actor Other )
{
if ( Other . bWorldGeometry || Other . bBlocksTeleport )
return true ;
if ( ( ( Controller == None ) || ! Controller . bIsPlayer ) && ( 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 'DmgType_Telefragged' , Location ) ;
else
Died ( None , class 'DmgType_Telefragged' , 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 + CylinderComponent . CollisionRadius ) * VRand ( ) ;
if ( VSize2D ( Velocity ) > FMax ( 500.0 , GroundSpeed ) )
{
Velocity = FMax ( 500.0 , GroundSpeed ) * Normal ( Velocity ) ;
}
Velocity . Z = 200 + CylinderComponent . CollisionHeight ;
SetPhysics ( PHYS _Falling ) ;
}
/ * * C a l l e d w h e n p a w n c y l i n d e r e m b e d d e d i n a n o t h e r p a w n . ( C o l l i s i o n b u g t h a t n e e d s t o b e f i x e d ) .
* /
event StuckOnPawn ( Pawn OtherPawn ) ;
/ * *
* Event called after actor ' s base changes .
* /
singular event BaseChange ( )
{
local DynamicSMActor Dyn ;
// Pawns can only set base to non-pawns, or pawns which specifically allow it.
// Otherwise we do some damage and jump off.
if ( Pawn ( Base ) != None && ( DrivenVehicle == None || ! DrivenVehicle . IsBasedOn ( Base ) ) )
{
if ( ! Pawn ( Base ) . CanBeBaseForPawn ( Self ) )
{
Pawn ( Base ) . CrushedBy ( self ) ;
JumpOffPawn ( ) ;
}
}
// If it's a KActor, see if we can stand on it.
Dyn = DynamicSMActor ( Base ) ;
if ( Dyn != None && ! Dyn . CanBasePawn ( self ) )
{
JumpOffPawn ( ) ;
}
}
/ * *
* Are we allowing this Pawn to be based on us ?
* /
simulated function bool CanBeBaseForPawn ( Pawn APawn )
{
return bCanBeBaseForPawns ;
}
/ * * C r u s h e d B y ( )
Called for pawns that have bCanBeBaseForPawns = false when another pawn becomes based on them
* /
function CrushedBy ( Pawn OtherPawn )
{
TakeDamage ( ( 1 - OtherPawn . Velocity . Z / 400 ) * OtherPawn . Mass / Mass , OtherPawn . Controller , Location , vect ( 0 , 0 , 0 ) , class 'DmgType_Crushed' ) ;
}
//=============================================================================
/ * *
* Call this function to detach safely pawn from its controller
*
* @ param bDestroyController if true , then destroy controller . ( only AI Controllers , not players )
* /
function DetachFromController ( optional bool bDestroyController )
{
local Controller OldController ;
// if we have a controller, notify it we're getting destroyed
// be careful with bTearOff, we're authority on client! Make sure our controller and pawn match up.
if ( Controller != None && Controller . Pawn == Self )
{
OldController = Controller ;
Controller . PawnDied ( Self ) ;
if ( Controller != None )
{
Controller . UnPossess ( ) ;
}
if ( bDestroyController && OldController != None && ! OldController . bDeleteMe && ! OldController . bIsPlayer )
{
OldController . Destroy ( ) ;
}
Controller = None ;
}
}
simulated event Destroyed ( )
{
DetachFromController ( ) ;
if ( InvManager != None )
InvManager . Destroy ( ) ;
if ( WorldInfo . NetMode == NM _Client )
return ;
// Clear anchor to avoid checkpoint crash
SetAnchor ( None ) ;
Weapon = None ;
//debug
ClearPathStep ( ) ;
super . Destroyed ( ) ;
}
//=============================================================================
//
// Called immediately before gameplay begins.
//
simulated event PreBeginPlay ( )
{
// important that this comes before Super so mutators can modify it
if ( HealthMax == 0 )
{
HealthMax = default . Health ;
}
Super . PreBeginPlay ( ) ;
Instigator = self ;
SetDesiredRotation ( Rotation ) ;
EyeHeight = BaseEyeHeight ;
}
event PostBeginPlay ( )
{
super . PostBeginPlay ( ) ;
SplashTime = 0 ;
SpawnTime = WorldInfo . TimeSeconds ;
EyeHeight = BaseEyeHeight ;
// automatically add controller to pawns which were placed in level
// NOTE: pawns spawned during gameplay are not automatically possessed by a controller
if ( WorldInfo . bStartup && ( Health > 0 ) && ! bDontPossess )
{
SpawnDefaultController ( ) ;
}
if ( FacialAudioComp != None )
{
FacialAudioComp . OnAudioFinished = FaceFXAudioFinished ;
}
// Spawn Inventory Container
if ( Role == ROLE _Authority && InvManager == None && InventoryManagerClass != None )
{
InvManager = Spawn ( InventoryManagerClass , Self ) ;
if ( InvManager == None )
` log("Warning! Couldn't spawn InventoryManager" @ InventoryManagerClass @ "for" @ Self @ GetHumanReadableName() );
else
InvManager . SetupFor ( Self ) ;
}
//debug
ClearPathStep ( ) ;
}
/ * *
* Spawn default controller for this Pawn , get possessed by it .
* /
function SpawnDefaultController ( )
{
if ( Controller != None )
{
` log("SpawnDefaultController" @ Self @ ", Controller != None" @ Controller );
return ;
}
if ( ControllerClass != None )
{
Controller = Spawn ( ControllerClass ) ;
}
if ( Controller != None )
{
Controller . Possess ( Self , false ) ;
}
}
simulated event ReceivedNewEvent ( SequenceEvent Evt )
{
if ( Controller != None )
{
Controller . ReceivedNewEvent ( Evt ) ;
}
Super . ReceivedNewEvent ( Evt ) ;
}
/ * *
* Deletes the current controller if it exists and creates a new one
* using the specified class .
* Event called from Kismet .
*
* @ param inAction - scripted action that was activated
* /
function OnAssignController ( SeqAct _AssignController inAction )
{
if ( inAction . ControllerClass != None )
{
if ( Controller != None )
{
DetachFromController ( true ) ;
}
Controller = Spawn ( inAction . ControllerClass ) ;
Controller . Possess ( Self , false ) ;
// Set class as the default one if pawn is restarted.
if ( Controller . IsA ( 'AIController' ) )
{
ControllerClass = class < AIController > ( Controller . Class ) ;
}
}
else
{
` warn("Assign controller w/o a class specified!");
}
}
/ * *
* Iterates through the list of item classes specified in the action
* and creates instances that are addeed to this Pawn ' s inventory .
*
* @ param inAction - scripted action that was activated
* /
simulated function OnGiveInventory ( SeqAct _GiveInventory InAction )
{
local int Idx ;
local class < Inventory > InvClass ;
if ( InAction . bClearExisting )
{
InvManager . DiscardInventory ( ) ;
}
if ( InAction . InventoryList . Length > 0 )
{
for ( Idx = 0 ; Idx < InAction . InventoryList . Length ; Idx ++ )
{
InvClass = InAction . InventoryList [ idx ] ;
if ( InvClass != None )
{
// only create if it doesn't already exist
if ( FindInventoryType ( InvClass , FALSE ) == None )
{
CreateInventory ( InvClass ) ;
}
}
else
{
InAction . ScriptLog ( "WARNING: Attempting to give NULL inventory!" ) ;
}
}
}
else
{
InAction . ScriptLog ( "WARNING: Give Inventory without any inventory specified!" ) ;
}
}
function Gasp ( ) ;
function SetMovementPhysics ( )
{
// check for water volume
if ( PhysicsVolume . bWaterVolume )
{
SetPhysics ( PHYS _Swimming ) ;
}
else if ( Physics != PHYS _Falling )
{
SetPhysics ( PHYS _Falling ) ;
}
}
/ * A d j u s t D a m a g e ( )
adjust damage based on inventory , other attributes
* /
function AdjustDamage ( out int InDamage , out vector Momentum , Controller InstigatedBy , vector HitLocation , class < DamageType > DamageType , TraceHitInfo HitInfo , Actor DamageCauser ) ;
` if( ` _ _TW _ )
event bool HealDamage ( int Amount , Controller Healer , class < DamageType > DamageType , optional bool bCanRepairArmor = true , optional bool bMessageHealer = true )
` else
event bool HealDamage ( int Amount , Controller Healer , class < DamageType > DamageType )
` endif
{
// not if already dead or already at full
if ( Health > 0 && Health < HealthMax )
{
Health = Min ( HealthMax , Health + Amount ) ;
return true ;
}
else
{
return false ;
}
}
/** Take a list of bones passed to TakeRadiusDamageOnBones and remove the ones that don't matter */
function PruneDamagedBoneList ( out array < Name > Bones ) ;
/ * *
* Damage radius applied to specific bones on the skeletal mesh
* /
event bool TakeRadiusDamageOnBones
(
Controller InstigatedBy ,
float BaseDamage ,
float DamageRadius ,
class < DamageType > DamageType ,
float Momentum ,
vector HurtOrigin ,
bool bFullDamage ,
Actor DamageCauser ,
array < Name > Bones
)
{
local int Idx ;
local TraceHitInfo HitInfo ;
local bool bResult ;
local float DamageScale , Dist ;
local vector Dir , BoneLoc ;
PruneDamagedBoneList ( Bones ) ;
for ( Idx = 0 ; Idx < Bones . Length ; Idx ++ )
{
HitInfo . BoneName = Bones [ Idx ] ;
HitInfo . HitComponent = Mesh ;
BoneLoc = Mesh . GetBoneLocation ( Bones [ Idx ] ) ;
Dir = BoneLoc - HurtOrigin ;
Dist = VSize ( Dir ) ;
Dir = Normal ( Dir ) ;
if ( bFullDamage )
{
DamageScale = 1. f ;
}
else
{
DamageScale = 1. f - Dist / DamageRadius ;
}
if ( DamageScale > 0. f )
{
TakeDamage
(
DamageScale * BaseDamage ,
InstigatedBy ,
BoneLoc ,
DamageScale * Momentum * Dir ,
DamageType ,
HitInfo ,
DamageCauser
) ;
}
bResult = TRUE ;
}
return bResult ;
}
/** sends any notifications to anything that needs to know this pawn has taken damage */
function NotifyTakeHit ( Controller InstigatedBy , vector HitLocation , int Damage , class < DamageType > DamageType , vector Momentum , Actor DamageCauser )
{
if ( Controller != None )
{
Controller . NotifyTakeHit ( InstigatedBy , HitLocation , Damage , DamageType , Momentum ) ;
}
}
function controller SetKillInstigator ( Controller InstigatedBy , class < DamageType > DamageType )
{
if ( ( InstigatedBy != None ) && ( InstigatedBy != Controller ) )
{
return InstigatedBy ;
}
else if ( DamageType . default . bCausedByWorld && ( LastHitBy != None ) )
{
return LastHitBy ;
}
return InstigatedBy ;
}
event TakeDamage ( int Damage , Controller InstigatedBy , vector HitLocation , vector Momentum , class < DamageType > DamageType , optional TraceHitInfo HitInfo , optional Actor DamageCauser )
{
local int actualDamage ;
local PlayerController PC ;
local Controller Killer ;
if ( ( Role < ROLE _Authority ) || ( Health <= 0 ) )
{
return ;
}
if ( damagetype == None )
{
2023-09-21 19:31:11 +00:00
/ * i f ( I n s t i g a t e d B y = = N o n e )
2020-12-13 15:01:13 +00:00
` warn("No damagetype for damage with no instigator");
else
` warn("No damagetype for damage by " $ instigatedby.pawn $ " with weapon " $ InstigatedBy.Pawn.Weapon);
2023-09-21 19:31:11 +00:00
* /
2020-12-13 15:01:13 +00:00
//scripttrace();
DamageType = class 'DamageType' ;
}
Damage = Max ( Damage , 0 ) ;
if ( Physics == PHYS _None && DrivenVehicle == None )
{
SetMovementPhysics ( ) ;
}
if ( Physics == PHYS _Walking && damageType . default . bExtraMomentumZ )
{
momentum . Z = FMax ( momentum . Z , 0.4 * VSize ( momentum ) ) ;
}
momentum = momentum / Mass ;
if ( DrivenVehicle != None )
{
DrivenVehicle . AdjustDriverDamage ( Damage , InstigatedBy , HitLocation , Momentum , DamageType ) ;
}
ActualDamage = Damage ;
` if( ` _ _TW _ )
WorldInfo . Game . ReduceDamage ( ActualDamage , self , instigatedBy , HitLocation , Momentum , DamageType , DamageCauser , HitInfo ) ;
` else
WorldInfo . Game . ReduceDamage ( ActualDamage , self , instigatedBy , HitLocation , Momentum , DamageType , DamageCauser ) ;
` endif
AdjustDamage ( ActualDamage , Momentum , instigatedBy , HitLocation , DamageType , HitInfo , DamageCauser ) ;
// call Actor's version to handle any SeqEvent_TakeDamage for scripting
Super . TakeDamage ( ActualDamage , InstigatedBy , HitLocation , Momentum , DamageType , HitInfo , DamageCauser ) ;
Health -= actualDamage ;
if ( HitLocation == vect ( 0 , 0 , 0 ) )
{
HitLocation = Location ;
}
if ( Health <= 0 )
{
PC = PlayerController ( Controller ) ;
// play force feedback for death
if ( PC != None )
{
PC . ClientPlayForceFeedbackWaveform ( damageType . default . KilledFFWaveform ) ;
}
// pawn died
Killer = SetKillInstigator ( InstigatedBy , DamageType ) ;
TearOffMomentum = momentum ;
Died ( Killer , damageType , HitLocation ) ;
}
else
{
HandleMomentum ( momentum , HitLocation , DamageType , HitInfo ) ;
NotifyTakeHit ( InstigatedBy , HitLocation , ActualDamage , DamageType , Momentum , DamageCauser ) ;
if ( DrivenVehicle != None )
{
DrivenVehicle . NotifyDriverTakeHit ( InstigatedBy , HitLocation , actualDamage , DamageType , Momentum ) ;
}
if ( instigatedBy != None && instigatedBy != controller )
{
LastHitBy = instigatedBy ;
}
}
PlayHit ( actualDamage , InstigatedBy , hitLocation , damageType , Momentum , HitInfo ) ;
` if( ` _ _TW _ )
// Best to use a noise label whenever possible to make it easier for the AI to identify what they just "heard"
MakeNoise ( 1.0 , 'TakeDamage' ) ;
` else
MakeNoise ( 1.0 ) ;
` endif
}
/ *
* Queries the PRI and returns our current team index .
* /
simulated native function byte GetTeamNum ( ) ;
simulated function TeamInfo GetTeam ( )
{
if ( Controller != None && Controller . PlayerReplicationInfo != None )
{
return Controller . PlayerReplicationInfo . Team ;
}
else if ( PlayerReplicationInfo != None )
{
return PlayerReplicationInfo . Team ;
}
else if ( DrivenVehicle != None && DrivenVehicle . PlayerReplicationInfo != None )
{
return DrivenVehicle . PlayerReplicationInfo . Team ;
}
else
{
return None ;
}
}
/** Returns true of pawns are on the same team, false otherwise */
simulated event bool IsSameTeam ( Pawn Other )
{
return ( Other != None &&
Other . GetTeam ( ) != None &&
Other . GetTeam ( ) == GetTeam ( ) ) ;
}
/** called to throw any weapon(s) that should be thrown on death */
function ThrowWeaponOnDeath ( )
{
ThrowActiveWeapon ( ) ;
}
/ * *
* This pawn has died .
*
* @ param Killer Who killed this pawn
* @ param DamageType What killed it
* @ param HitLocation Where did the hit occur
*
* @ returns true if allowed
* /
function bool Died ( Controller Killer , class < DamageType > DamageType , vector HitLocation )
{
local SeqAct _Latent Action ;
// ensure a valid damagetype
if ( damageType == None )
{
damageType = class 'DamageType' ;
}
// if already destroyed or level transition is occuring then ignore
if ( bDeleteMe || WorldInfo . Game == None || WorldInfo . Game . bLevelChange )
{
return FALSE ;
}
// if this is an environmental death then refer to the previous killer so that they receive credit (knocked into lava pits, etc)
if ( DamageType . default . bCausedByWorld && ( Killer == None || Killer == Controller ) && LastHitBy != None )
{
Killer = LastHitBy ;
}
// gameinfo hook to prevent deaths
// WARNING - don't prevent bot suicides - they suicide when really needed
if ( WorldInfo . Game . PreventDeath ( self , Killer , damageType , HitLocation ) )
{
Health = max ( Health , 1 ) ;
return false ;
}
Health = Min ( 0 , Health ) ;
// activate death events
if ( default . KismetDeathDelayTime > 0 )
{
DelayTriggerDeath ( ) ;
}
else
{
TriggerEventClass ( class 'SeqEvent_Death' , self ) ;
}
KismetDeathDelayTime = default . KismetDeathDelayTime + WorldInfo . TimeSeconds ;
// and abort any latent actions
foreach LatentActions ( Action )
{
Action . AbortFor ( self ) ;
}
LatentActions . Length = 0 ;
// notify the vehicle we are currently driving
if ( DrivenVehicle != None )
{
Velocity = DrivenVehicle . Velocity ;
DrivenVehicle . DriverDied ( DamageType ) ;
}
else if ( Weapon != None )
{
Weapon . HolderDied ( ) ;
ThrowWeaponOnDeath ( ) ;
}
// notify the gameinfo of the death
if ( Controller != None )
{
WorldInfo . Game . Killed ( Killer , Controller , self , damageType ) ;
}
else
{
WorldInfo . Game . Killed ( Killer , Controller ( Owner ) , self , damageType ) ;
}
DrivenVehicle = None ;
// notify inventory manager
if ( InvManager != None )
{
InvManager . OwnerDied ( ) ;
}
` if( ` _ _TW _ )
// push the corpse upward (@fixme - somebody please remove this?)
// Consider yourself removed - Ramm
//Velocity.Z *= 1.3;
` else
// push the corpse upward (@fixme - somebody please remove this?)
Velocity . Z *= 1.3 ;
` endif
// if this is a human player then force a replication update
if ( IsHumanControlled ( ) )
{
PlayerController ( Controller ) . ForceDeathUpdate ( ) ;
}
NetUpdateFrequency = Default . NetUpdateFrequency ;
PlayDying ( DamageType , HitLocation ) ;
return TRUE ;
}
function DelayTriggerDeath ( )
{
TriggerEventClass ( class 'SeqEvent_Death' , self ) ;
}
event Falling ( ) ;
event Landed ( vector HitNormal , Actor FloorActor )
{
TakeFallingDamage ( ) ;
if ( Health > 0 )
PlayLanded ( Velocity . Z ) ;
LastHitBy = None ;
}
/ * *
* Called if bScriptTickSpecial is set
* This tick function is called after physics has executed
* /
event TickSpecial ( float DeltaTime ) ;
event HeadVolumeChange ( PhysicsVolume newHeadVolume )
{
if ( ( WorldInfo . NetMode == NM _Client ) || ( Controller == None ) )
return ;
if ( HeadVolume != None && 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 ;
}
event BreathTimer ( )
{
if ( HeadVolume . bWaterVolume )
{
if ( ( Health < 0 ) || ( WorldInfo . NetMode == NM _Client ) || ( DrivenVehicle != None ) )
return ;
TakeDrowningDamage ( ) ;
if ( Health > 0 )
BreathTime = 2.0 ;
}
else
{
BreathTime = 0.0 ;
}
}
function TakeDrowningDamage ( ) ;
function bool CheckWaterJump ( out vector WallNormal )
{
local actor HitActor ;
local vector HitLocation , HitNormal , Checkpoint , start , checkNorm , Extent ;
if ( AIController ( Controller ) != None )
{
if ( Controller . InLatentExecution ( Controller . LATENT _MOVETOWARD ) && ( Controller . Movetarget != None )
&& ! Controller . MoveTarget . PhysicsVolume . bWaterVolume )
{
CheckPoint = Normal ( Controller . MoveTarget . Location - Location ) ;
}
else
{
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 * CylinderComponent . CollisionRadius * checkNorm ;
Extent = CylinderComponent . CollisionRadius * vect ( 1 , 1 , 0 ) ;
Extent . Z = CylinderComponent . CollisionHeight ;
HitActor = Trace ( HitLocation , HitNormal , Checkpoint , Location , true , Extent , , TRACEFLAG _Blocking ) ;
if ( ( HitActor != None ) && ( Pawn ( HitActor ) == None ) )
{
WallNormal = - 1 * HitNormal ;
start = Location ;
start . Z += MaxOutOfWaterStepHeight ;
checkPoint = start + 3.2 * CylinderComponent . CollisionRadius * WallNormal ;
HitActor = Trace ( HitLocation , HitNormal , Checkpoint , start , true , , , TRACEFLAG _Blocking ) ;
if ( ( HitActor == None ) || ( HitNormal . Z > 0.7 ) )
return true ;
}
return false ;
}
//Player Jumped
function bool DoJump ( bool bUpdating )
{
if ( bJumpCapable && ! bIsCrouched && ! bWantsToCrouch && ( Physics == PHYS _Walking || Physics == PHYS _Ladder || Physics == PHYS _Spider ) )
{
if ( Physics == PHYS _Spider )
` if( ` _ _TW _PATHFINDING _ )
Velocity = Velocity + ( JumpZ * Floor ) ;
` else
Velocity = JumpZ * Floor ;
` endif
else if ( Physics == PHYS _Ladder )
Velocity . Z = 0 ;
else if ( bIsWalking )
Velocity . Z = Default . JumpZ ;
else
Velocity . Z = JumpZ ;
if ( Base != None && ! Base . bWorldGeometry && Base . Velocity . Z > 0. f )
{
Velocity . Z += Base . Velocity . Z ;
}
SetPhysics ( PHYS _Falling ) ;
return true ;
}
return false ;
}
function PlayDyingSound ( ) ;
function PlayHit ( float Damage , Controller InstigatedBy , vector HitLocation , class < DamageType > damageType , vector Momentum , TraceHitInfo HitInfo )
{
if ( ( Damage <= 0 ) && ( ( Controller == None ) || ! Controller . bGodMode ) )
return ;
LastPainTime = WorldInfo . TimeSeconds ;
}
/ * * T u r n O f f ( )
Freeze pawn - stop sounds , animations , physics , weapon firing
* /
simulated function TurnOff ( )
{
if ( Role == ROLE _Authority )
{
RemoteRole = ROLE _SimulatedProxy ;
}
if ( WorldInfo . NetMode != NM _DedicatedServer && Mesh != None )
{
Mesh . bPauseAnims = true ;
if ( Physics == PHYS _RigidBody )
{
Mesh . PhysicsWeight = 1.0 ;
Mesh . bUpdateKinematicBonesFromAnimation = false ;
}
}
SetCollision ( true , false ) ;
bNoWeaponFiring = true ;
Velocity = vect ( 0 , 0 , 0 ) ;
SetPhysics ( PHYS _None ) ;
bIgnoreForces = true ;
if ( Weapon != None )
{
Weapon . StopFire ( Weapon . CurrentFireMode ) ;
}
}
/ * *
* Set physics for dying pawn
* Always set to falling , unless already a ragdoll
* /
function SetDyingPhysics ( )
{
if ( Physics != PHYS _RigidBody )
{
SetPhysics ( PHYS _Falling ) ;
}
}
State Dying
{
ignores Bump , HitWall , HeadVolumeChange , PhysicsVolumeChange , Falling , BreathTimer , FellOutOfWorld ;
simulated function PlayWeaponSwitch ( Weapon OldWeapon , Weapon NewWeapon ) { }
simulated function PlayNextAnimation ( ) { }
singular event BaseChange ( ) { }
event Landed ( vector HitNormal , Actor FloorActor ) { }
function bool Died ( Controller Killer , class < DamageType > damageType , vector HitLocation ) ;
simulated singular event OutsideWorldBounds ( )
{
SetPhysics ( PHYS _None ) ;
SetHidden ( True ) ;
LifeSpan = FMin ( LifeSpan , 1.0 ) ;
}
event Timer ( )
{
if ( ! PlayerCanSeeMe ( ) )
{
Destroy ( ) ;
}
else
{
SetTimer ( 2.0 , false ) ;
}
}
event TakeDamage ( int Damage , Controller EventInstigator , vector HitLocation , vector Momentum , class < DamageType > DamageType , optional TraceHitInfo HitInfo , optional Actor DamageCauser )
{
SetPhysics ( PHYS _Falling ) ;
if ( ( Physics == PHYS _None ) && ( Momentum . Z < 0 ) )
Momentum . Z *= - 1 ;
Velocity += 3 * momentum / ( Mass + 200 ) ;
if ( damagetype == None )
{
// `warn("No damagetype for damage by "$instigatedby.pawn$" with weapon "$InstigatedBy.Pawn.Weapon);
DamageType = class 'DamageType' ;
}
Health -= Damage ;
}
event BeginState ( Name PreviousStateName )
{
local Actor A ;
local array < SequenceEvent > TouchEvents ;
local int i ;
if ( bTearOff && ( WorldInfo . NetMode == NM _DedicatedServer ) )
{
LifeSpan = 2.0 ;
}
else
{
SetTimer ( 5.0 , false ) ;
// add a failsafe termination
LifeSpan = 25. f ;
}
SetDyingPhysics ( ) ;
SetCollision ( true , false ) ;
if ( Controller != None )
{
if ( Controller . bIsPlayer )
{
DetachFromController ( ) ;
}
else
{
` if( ` _ _TW _ )
DetachFromController ( true ) ;
` else
Controller . Destroy ( ) ;
` endif
}
}
foreach TouchingActors ( class 'Actor' , A )
{
if ( A . FindEventsOfClass ( class 'SeqEvent_Touch' , TouchEvents ) )
{
for ( i = 0 ; i < TouchEvents . length ; i ++ )
{
SeqEvent _Touch ( TouchEvents [ i ] ) . NotifyTouchingPawnDied ( self ) ;
}
// clear array for next iteration
TouchEvents . length = 0 ;
}
}
foreach BasedActors ( class 'Actor' , A )
{
A . PawnBaseDied ( ) ;
}
}
Begin :
Sleep ( 0.2 ) ;
PlayDyingSound ( ) ;
}
//=============================================================================
// Animation interface for controllers
/ * P l a y X X X ( ) f u n c t i o n c a l l e d b y c o n t r o l l e r t o p l a y t r a n s i e n t a n i m a t i o n a c t i o n s
* /
/ * P l a y D y i n g ( ) i s c a l l e d o n s e r v e r / s t a n d a l o n e g a m e w h e n k i l l e d
and also on net client when pawn gets bTearOff set to true ( and bPlayedDeath is false )
* /
simulated function PlayDying ( class < DamageType > DamageType , vector HitLoc )
{
GotoState ( 'Dying' ) ;
bReplicateMovement = false ;
bTearOff = true ;
Velocity += TearOffMomentum ;
SetDyingPhysics ( ) ;
bPlayedDeath = true ;
KismetDeathDelayTime = default . KismetDeathDelayTime + WorldInfo . TimeSeconds ;
}
simulated event TornOff ( )
{
// assume dead if bTearOff
if ( ! bPlayedDeath )
{
PlayDying ( HitDamageType , TakeHitLocation ) ;
}
}
/ * *
* PlayFootStepSound ( )
* called by AnimNotify _Footstep
*
* FootDown specifies which foot hit
* /
event PlayFootStepSound ( int FootDown ) ;
//=============================================================================
// Pawn internal animation functions
// Animation group checks (usually implemented in subclass)
function bool CannotJumpNow ( )
{
return false ;
}
function PlayLanded ( float impactVel ) ;
native function Vehicle GetVehicleBase ( ) ;
function Suicide ( )
{
KilledBy ( self ) ;
}
// toss out a weapon
// check before throwing
simulated function bool CanThrowWeapon ( )
{
return ( ( Weapon != None ) && Weapon . CanThrow ( ) ) ;
}
/ * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
* Vehicle driving
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * /
/ * *
* StartDriving ( ) and StopDriving ( ) also called on clients
* on transitions of DrivenVehicle variable .
* Network : ALL
* /
simulated event StartDriving ( Vehicle V )
{
StopFiring ( ) ;
if ( Health <= 0 )
return ;
DrivenVehicle = V ;
bForceNetUpdate = TRUE ;
// Move the driver into position, and attach to car.
ShouldCrouch ( false ) ;
bIgnoreForces = true ;
bCanTeleport = false ;
BreathTime = 0.0 ;
V . AttachDriver ( Self ) ;
}
/ * *
* StartDriving ( ) and StopDriving ( ) also called on clients
* on transitions of DrivenVehicle variable .
* Network : ALL
* /
simulated event StopDriving ( Vehicle V )
{
if ( Mesh != None )
{
Mesh . SetCullDistance ( Default . Mesh . CachedMaxDrawDistance ) ;
Mesh . SetShadowParent ( None ) ;
}
bForceNetUpdate = TRUE ;
if ( V != None )
{
V . StopFiring ( ) ;
}
if ( Physics == PHYS _RigidBody )
{
return ;
}
DrivenVehicle = None ;
bIgnoreForces = false ;
SetHardAttach ( false ) ;
bCanTeleport = true ;
bCollideWorld = true ;
if ( V != None )
{
V . DetachDriver ( Self ) ;
}
SetCollision ( true , true ) ;
if ( Role == ROLE _Authority )
{
if ( PhysicsVolume . bWaterVolume && ( Health > 0 ) )
{
SetPhysics ( PHYS _Swimming ) ;
}
else
{
SetPhysics ( PHYS _Falling ) ;
}
SetBase ( None ) ;
SetHidden ( False ) ;
}
}
//
// Inventory related functions
//
/ * A d d D e f a u l t I n v e n t o r y :
Add Pawn default Inventory .
Called from GameInfo . AddDefaultInventory ( )
* /
function AddDefaultInventory ( ) ;
/ * e p i c = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = =
* : : CreateInventory
*
* Create Inventory Item , adds it to the Pawn ' s Inventory
* And returns it for post processing .
*
* === === === === === === === === === === === === === === === === === ==
* /
event final Inventory CreateInventory ( class < Inventory > NewInvClass , optional bool bDoNotActivate )
{
if ( InvManager != None )
return InvManager . CreateInventory ( NewInvClass , bDoNotActivate ) ;
return None ;
}
/ * F i n d I n v e n t o r y T y p e :
returns the inventory item of the requested class if it exists in this Pawn ' s inventory
* /
simulated final function Inventory FindInventoryType ( class < Inventory > DesiredClass , optional bool bAllowSubclass )
{
return ( InvManager != None ) ? InvManager . FindInventoryType ( DesiredClass , bAllowSubclass ) : None ;
}
/** Hook called from HUD actor. Gives access to HUD and Canvas */
simulated function DrawHUD ( HUD H )
{
if ( InvManager != None )
{
InvManager . DrawHUD ( H ) ;
}
}
/ * *
* Toss active weapon using default settings ( location + velocity ) .
*
* @ param DamageType allows this function to do different behaviors based on the damage type
* /
function ThrowActiveWeapon ( optional bool bDestroyWeap )
{
if ( Weapon != None )
{
TossInventory ( Weapon ) ;
}
}
function TossInventory ( Inventory Inv , optional vector ForceVelocity )
{
local vector POVLoc , TossVel ;
local rotator POVRot ;
local Vector X , Y , Z ;
if ( ForceVelocity != vect ( 0 , 0 , 0 ) )
{
TossVel = ForceVelocity ;
}
else
{
GetActorEyesViewPoint ( POVLoc , POVRot ) ;
TossVel = Vector ( POVRot ) ;
TossVel = TossVel * ( ( Velocity Dot TossVel ) + 500 ) + Vect ( 0 , 0 , 200 ) ;
}
GetAxes ( Rotation , X , Y , Z ) ;
Inv . DropFrom ( Location + 0.8 * CylinderComponent . CollisionRadius * X - 0.5 * CylinderComponent . CollisionRadius * Y , TossVel ) ;
}
/ * S e t A c t i v e W e a p o n
Set this weapon as the Pawn ' s active weapon
* /
simulated function SetActiveWeapon ( Weapon NewWeapon )
{
if ( InvManager != None )
{
InvManager . SetCurrentWeapon ( NewWeapon ) ;
}
}
/ * *
* Player just changed weapon . Called from InventoryManager : : ChangedWeapon ( ) .
* Network : Local Player and Server .
*
* @ param OldWeapon Old weapon held by Pawn .
* @ param NewWeapon New weapon held by Pawn .
* /
simulated function PlayWeaponSwitch ( Weapon OldWeapon , Weapon NewWeapon ) ;
// Cheats - invoked by CheatManager
function bool CheatWalk ( )
{
UnderWaterTime = Default . UnderWaterTime ;
SetCollision ( true , true ) ;
SetPhysics ( PHYS _Falling ) ;
bCollideWorld = true ;
SetPushesRigidBodies ( Default . bPushesRigidBodies ) ;
return true ;
}
function bool CheatGhost ( )
{
UnderWaterTime = - 1.0 ;
SetCollision ( false , false ) ;
bCollideWorld = false ;
SetPushesRigidBodies ( false ) ;
return true ;
}
function bool CheatFly ( )
{
UnderWaterTime = Default . UnderWaterTime ;
SetCollision ( true , true ) ;
bCollideWorld = true ;
return true ;
}
/ * *
* Returns the collision radius of our cylinder
* collision component .
*
* @ return the collision radius of our pawn
* /
simulated function float GetCollisionRadius ( )
{
return ( CylinderComponent != None ) ? CylinderComponent . CollisionRadius : 0. f ;
}
/ * *
* Returns the collision height of our cylinder
* collision component .
*
* @ return collision height of our pawn
* /
simulated function float GetCollisionHeight ( )
{
return ( CylinderComponent != None ) ? CylinderComponent . CollisionHeight : 0. f ;
}
/** @return a vector representing the box around this pawn's cylinder collision component, for use with traces */
simulated final function vector GetCollisionExtent ( )
{
local vector Extent ;
Extent = GetCollisionRadius ( ) * vect ( 1 , 1 , 0 ) ;
Extent . Z = GetCollisionHeight ( ) ;
return Extent ;
}
/ * *
* Pawns by nature are not stationary . Override if you want exact findings
* /
function bool IsStationary ( )
{
return false ;
}
event SpawnedByKismet ( )
{
// notify controller
if ( Controller != None )
{
Controller . SpawnedByKismet ( ) ;
}
}
/** Performs actual attachment. Can be subclassed for class specific behaviors. */
function DoKismetAttachment ( Actor Attachment , SeqAct _AttachToActor Action )
{
local bool bOldCollideActors , bOldBlockActors , bValidBone , bValidSocket ;
// If a bone/socket has been specified, see if it is valid
if ( Mesh != None && Action . BoneName != '' )
{
// See if the bone name refers to an existing socket on the skeletal mesh.
bValidSocket = ( Mesh . GetSocketByName ( Action . BoneName ) != None ) ;
bValidBone = ( Mesh . MatchRefBone ( Action . BoneName ) != INDEX _NONE ) ;
// Issue a warning if we were expecting to attach to a bone/socket, but it could not be found.
if ( ! bValidBone && ! bValidSocket )
{
` log(WorldInfo.TimeSeconds @ class @ GetFuncName() @ "bone or socket" @ Action.BoneName @ "not found on actor" @ Self @ "with mesh" @ Mesh);
}
}
// Special case for handling relative location/rotation w/ bone or socket
if ( bValidBone || bValidSocket )
{
// disable collision, so we can successfully move the attachment
bOldCollideActors = Attachment . bCollideActors ;
bOldBlockActors = Attachment . bBlockActors ;
Attachment . SetCollision ( FALSE , FALSE ) ;
Attachment . SetHardAttach ( Action . bHardAttach ) ;
// Sockets by default move the actor to the socket location.
// This is not the case for bones!
// So if we use relative offsets, then first move attachment to bone's location.
if ( bValidBone && ! bValidSocket )
{
if ( Action . bUseRelativeOffset )
{
Attachment . SetLocation ( Mesh . GetBoneLocation ( Action . BoneName ) ) ;
}
if ( Action . bUseRelativeRotation )
{
Attachment . SetRotation ( QuatToRotator ( Mesh . GetBoneQuaternion ( Action . BoneName ) ) ) ;
}
}
// Attach attachment to base.
Attachment . SetBase ( Self , , Mesh , Action . BoneName ) ;
if ( Action . bUseRelativeRotation )
{
Attachment . SetRelativeRotation ( Attachment . RelativeRotation + Action . RelativeRotation ) ;
}
// if we're using the offset, place attachment relatively to the target
if ( Action . bUseRelativeOffset )
{
Attachment . SetRelativeLocation ( Attachment . RelativeLocation + Action . RelativeOffset ) ;
}
// restore previous collision
Attachment . SetCollision ( bOldCollideActors , bOldBlockActors ) ;
}
else
{
// otherwise base on location
Super . DoKismetAttachment ( Attachment , Action ) ;
}
}
/** returns the amount this pawn's damage should be scaled by */
function float GetDamageScaling ( )
{
return DamageScaling ;
}
function OnSetMaterial ( SeqAct _SetMaterial Action )
{
if ( Mesh != None )
{
Mesh . SetMaterial ( Action . MaterialIndex , Action . NewMaterial ) ;
}
}
/** Kismet teleport handler, overridden so that updating rotation properly updates our Controller as well */
simulated function OnTeleport ( SeqAct _Teleport Action )
{
local array < Object > objVars ;
// find the first supplied actor
Action . GetObjectVars ( objVars , "Destination" ) ;
if ( ! HandleTeleport ( objVars , Action . bUpdateRotation , Action . bCheckOverlap , , Action . TeleportVolumes ) )
{
` warn( "failed to handle teleport kismet action properly"@Action );
}
}
simulated function bool HandleTeleport ( array < Object > DestList , bool bUpdateRotation , bool bCheckOverlap , optional float TeleportDistance , optional array < Volume > TeleportVolumes , optional int PreferredDestIndex )
{
local int idx , cnt ;
local Actor destActor , tempActor , A ;
local Controller C ;
local bool bOccupiedDest , bColliding ;
local Vector Extent ;
Extent = GetCollisionExtent ( ) ;
bOccupiedDest = FALSE ;
// Make sure there's actually a list
if ( DestList . Length > 0 )
{
// Make sure INDEX_NONE (-1) gets resolved before accessing the DestList
idx = ( PreferredDestIndex >= 0 ) ? PreferredDestIndex : 0 ;
if ( idx >= DestList . length )
{
idx = 0 ;
PreferredDestIndex = 0 ;
}
cnt = 0 ;
do
{
tempActor = Actor ( DestList [ idx ] ) ;
if ( tempActor != None )
{
// If its a player variable, teleport to the Pawn not the Controller.
C = Controller ( tempActor ) ;
if ( C != None && C . Pawn != None )
{
tempActor = C . Pawn ;
}
if ( bCheckOverlap )
{
bColliding = FALSE ;
foreach VisibleCollidingActors ( class 'Actor' , A , Extent . X * 2. f , tempActor . Location , FALSE , Extent , TRUE )
{
if ( IsBlockedBy ( A ) )
{
bColliding = TRUE ;
break ;
}
}
bOccupiedDest = bColliding ;
}
destActor = tempActor ;
if ( ( ! bCheckOverlap || ! bOccupiedDest ) && destActor != None )
{
break ;
}
}
// Increment idx
++ idx ;
if ( idx >= DestList . length )
{
idx = 0 ;
}
++ cnt ;
} until ( idx == PreferredDestIndex || cnt >= DestList . Length ) ;
}
else
{
` warn("Unable to teleport - no destination list given");
}
// and set to that actor's location
if ( destActor != None && class 'SeqAct_Teleport' . static . ShouldTeleport ( self , destActor . Location , TeleportDistance , TeleportVolumes ) )
{
if ( SetLocation ( destActor . Location ) )
{
// If the pawn being teleported is a client player we need to tell him to move on his side
if ( ! IsLocallyControlled ( ) && PlayerController ( Controller ) != None )
{
PlayerController ( Controller ) . ClientSetLocation ( destActor . Location , Rotation ) ;
}
PlayTeleportEffect ( false , true ) ;
if ( bUpdateRotation )
{
SetRotation ( destActor . Rotation ) ;
if ( Controller != None )
{
Controller . SetRotation ( destActor . Rotation ) ;
Controller . ClientSetRotation ( destActor . Rotation ) ;
}
}
// Tell controller we teleported (Pass None to avoid recursion)
if ( Controller != None )
{
Controller . OnTeleport ( None ) ;
}
return TRUE ;
}
` warn("Unable to teleport to"@destActor);
return FALSE ;
}
if ( destActor == None )
{
` warn("Unable to teleport - no destination given");
return FALSE ;
}
return TRUE ;
}
/ * *
* For debugging . Causes a string to be displayed on the HUD .
* /
final event MessagePlayer ( coerce String Msg )
{
` if( ` notdefined ( FINAL _RELEASE ) )
local PlayerController PC ;
foreach LocalPlayerControllers ( class 'PlayerController' , PC )
{
PC . ClientMessage ( Msg ) ;
}
` endif
}
simulated event BecomeViewTarget ( PlayerController PC )
{
if ( PhysicsVolume != None )
{
PhysicsVolume . NotifyPawnBecameViewTarget ( self , PC ) ;
}
// if we don't normally replicate health, but will want to do so now to this client, force an update
if ( ! bReplicateHealthToAll && WorldInfo . NetMode != NM _Client )
{
PC . ForceSingleNetUpdateFor ( self ) ;
}
}
/** For AI debugging */
event SoakPause ( )
{
local PlayerController PC ;
ForEach WorldInfo . LocalPlayerControllers ( class 'PlayerController' , PC )
{
PC . SoakPause ( self ) ;
break ;
}
}
native function ClearConstraints ( ) ;
native function AddPathConstraint ( PathConstraint Constraint ) ;
native function AddGoalEvaluator ( PathGoalEvaluator Evaluator ) ;
/ * *
* Path shaping creation functions ...
* these functions by default will just new the class , but this offers a handy
* interface to override for to do things like pool the constraints
* /
function PathConstraint CreatePathConstraint ( class < PathConstraint > ConstraintClass )
{
return new ( self ) ConstraintClass ;
}
function PathGoalEvaluator CreatePathGoalEvaluator ( class < PathGoalEvaluator > GoalEvalClass )
{
return new ( self ) GoalEvalClass ;
}
native function IncrementPathStep ( int Cnt , Canvas C ) ;
native function IncrementPathChild ( int Cnt , Canvas C ) ;
native function DrawPathStep ( Canvas C ) ;
native function ClearPathStep ( ) ;
simulated function ZeroMovementVariables ( )
{
Velocity = vect ( 0 , 0 , 0 ) ;
Acceleration = vect ( 0 , 0 , 0 ) ;
}
simulated function SetCinematicMode ( bool bInCinematicMode ) ;
native function SetRootMotionInterpCurrentTime ( float inTime , optional float DeltaTime , optional bool bUpdateSkelPose ) ;
/** Set a ScalarParameter to Interpolate */
final simulated native function SetScalarParameterInterp ( const out ScalarParameterInterpStruct ScalarParameterInterp ) ;
/** Simple interface for handling pawn dialogue. */
simulated event Speak ( SoundCue Cue )
{
// Trivial implementation for now.
// @TODO: handle things like
// - speaking one line at a time
// - playing facefx if appropriate
// - dialogue-specific soundmodes
// - etc
PlaySound ( Cue , TRUE ) ;
}
/ * *
* Handler for the SeqAct _SetVelocity action . Allows level designer to impart a velocity on the actor .
* /
simulated function OnSetVelocity ( SeqAct _SetVelocity Action )
{
Super . OnSetVelocity ( Action ) ;
// fake acceleration - Assuming default delta time is 0.2f
if ( Action . VelocityMag == 0 )
{
Acceleration = vect ( 0 , 0 , 0 ) ;
}
else
{
Acceleration = Velocity / 0.2 f ;
}
}
` if( ` _ _TW _LIGHTING _MODIFICATIONS _ ) // Custom lighting channel implementation
/** Set the lighting channels on all the appropriate pawn meshes */
simulated function SetMeshLightingChannels ( LightingChannelContainer NewLightingChannels )
{
}
` endif
defaultproperties
{
Begin Object Class = SpriteComponent Name = Sprite
Sprite = Texture2D 'EditorResources.S_Actor'
HiddenGame = True
AlwaysLoadOnClient = False
AlwaysLoadOnServer = False
SpriteCategoryName = "Pawns"
End Object
Components . Add ( Sprite )
// Pawns often manipulate physics components so need to be done pre-async
TickGroup = TG _PreAsyncWork
InventoryManagerClass = class 'InventoryManager'
ControllerClass = class 'AIController'
// Flags
bCanBeDamaged = true
bCanCrouch = false
bCanFly = false
bCanJump = true
bCanSwim = false
bCanTeleport = true
bCanWalk = true
bJumpCapable = true
bProjTarget = true
bSimulateGravity = true
bShouldBaseAtStartup = true
// Locomotion
WalkingPhysics = PHYS _Walking
LandMovementState = PlayerWalking
WaterMovementState = PlayerSwimming
AccelRate = + 02048.000000
DesiredSpeed = + 00001.000000
MaxDesiredSpeed = + 00001.000000
MaxFallSpeed = + 1200.0
AIMaxFallSpeedFactor = 1.0
NonPreferredVehiclePathMultiplier = 1.0
AirSpeed = + 00600.000000
GroundSpeed = + 00600.000000
JumpZ = + 00420.000000
OutofWaterZ = + 420.0
LadderSpeed = + 200.0
WaterSpeed = + 00300.000000
bLimitFallAccel = TRUE
AirControl = + 0.05
CrouchedPct = + 0.5
WalkingPct = + 0.5
MovementSpeedModifier = + 1.0
// Sound
bLOSHearing = true
HearingThreshold = + 2800.0
SoundDampening = + 00001.000000
noise1time = - 00010.000000
noise2time = - 00010.000000
// Physics
AvgPhysicsTime = + 00000.100000
bPushesRigidBodies = false
RBPushRadius = 10.0
RBPushStrength = 50.0
// FOV / Sight
ViewPitchMin = - 16384
ViewPitchMax = 16383
RotationRate = ( Pitch = 20000 , Yaw = 20000 , Roll = 20000 )
MaxPitchLimit = 3072
SightRadius = + 05000.000000
// Network
RemoteRole = ROLE _SimulatedProxy
NetPriority = + 00002.000000
bUpdateSimulatedPosition = true
// GamePlay
DamageScaling = + 00001.000000
Health = 100
bReplicateHealthToAll = false
// Collision
BaseEyeHeight = + 00064.000000
EyeHeight = + 00054.000000
CrouchHeight = + 40.0
CrouchRadius = + 34.0
MaxStepHeight = 35.0
MaxJumpHeight = 96.0
WalkableFloorZ = 0.7 // 0.7 ~= 45 degree angle for floor
LedgeCheckThreshold = 4.0 f
MaxOutOfWaterStepHeight = 40.0
AllowedYawError = 2000
Mass = + 00100.000000
bCollideActors = true
bCollideWorld = true
bBlockActors = true
Begin Object Class = CylinderComponent Name = CollisionCylinder
CollisionRadius = + 0034.000000
CollisionHeight = + 0078.000000
BlockNonZeroExtent = true
BlockZeroExtent = true
BlockActors = true
CollideActors = true
End Object
CollisionComponent = CollisionCylinder
CylinderComponent = CollisionCylinder
Components . Add ( CollisionCylinder )
Begin Object Class = ArrowComponent Name = Arrow
ArrowColor = ( R = 150 , G = 200 , B = 255 )
bTreatAsASprite = True
SpriteCategoryName = "Pawns"
End Object
Components . Add ( Arrow )
VehicleCheckRadius = 150
bAllowLedgeOverhang = TRUE
RootMotionInterpRate = 1. f
bModifyNavPointDest = true
}