//============================================================================= // Controller, the base class of players or AI. // // Controllers are non-physical actors that can be attached to a pawn to control // its actions. PlayerControllers are used by human players to control pawns, while // AIControFllers implement the artificial intelligence for the pawns they control. // Controllers take control of a pawn using their Possess() method, and relinquish // control of the pawn by calling UnPossess(). // // Controllers receive notifications for many of the events occuring for the Pawn they // are controlling. This gives the controller the opportunity to implement the behavior // in response to this event, intercepting the event and superceding the Pawn's default // behavior. // // Copyright 1998-2013 Epic Games, Inc. All Rights Reserved. //============================================================================= class Controller extends Actor native(Controller) nativereplication implements(Interface_NavigationHandle) abstract; //============================================================================= // BASE VARIABLES /** Pawn currently being controlled by this controller. Use Pawn.Possess() to take control of a pawn */ var editinline repnotify Pawn Pawn; /** PlayerReplicationInfo containing replicated information about the player using this controller (only exists if bIsPlayer is true). */ var editinline repnotify PlayerReplicationInfo PlayerReplicationInfo; var const int PlayerNum; // The player number - per-match player number. var const private Controller NextController; // chained Controller list var bool bIsPlayer; // Pawn is a player or a player-bot. var bool bGodMode; // cheat - when true, can't be killed or hurt `if(`__TW_) var bool bDemiGodMode; /** It forces the pawn to not be able to die */ `endif var bool bSoaking; // pause and focus on pawn controlled by this controller if it encounters a problem var bool bSlowerZAcquire; // AI acquires targets above or below more slowly than at same height // Input buttons. var input byte bFire; /** If true, the controlled pawn will attempt to alt fire */ var input byte bAltFire; //============================================================================= // PHYSICS VARIABLES var bool bNotifyPostLanded; // if true, event NotifyPostLanded() after pawn lands after falling. var bool bNotifyApex; // if true, event NotifyJumpApex() when at apex of jump var float MinHitWall; // Minimum HitNormal dot Velocity.Normal to get a HitWall event from the physics //============================================================================= // NAVIGATION VARIABLES /** Navigation handle used for pathing when using NavMesh */ var class NavigationHandleClass; var editinline NavigationHandle NavigationHandle; /** Override search start position for navhandle path cache info */ var bool bOverrideSearchStart; var Vector OverrideSearchStart; var bool bAdvancedTactics; // serpentine movement between pathnodes var bool bCanDoSpecial; // are we able to traverse R_SPECIAL reach specs? var bool bAdjusting; // adjusting around obstacle var bool bPreparingMove; // set true while pawn sets up for a latent move /** Used by AI, set true to force AI to use serpentine/strafing movement when possible. */ var bool bForceStrafe; var float MoveTimer; // internal timer for latent moves, useful for setting a max duration var Actor MoveTarget; // actor being moved toward var BasedPosition DestinationPosition; // destination controlled pawn is moving toward var BasedPosition FocalPosition; // position controlled pawn is looking at var Actor Focus; // actor being looked at var Actor GoalList[4]; // used by navigation AI - list of intermediate goals var BasedPosition AdjustPosition; // intermediate destination used while adjusting around obstacle (bAdjusting is true) var NavigationPoint StartSpot; // where player started the match /** Cached list of nodes filled in by the last call to FindPathXXX */ var array RouteCache; var ReachSpec CurrentPath; // Current path being moved along var ReachSpec NextRoutePath; // Next path in route to destination var vector CurrentPathDir; // direction vector of current path var Actor RouteGoal; // final destination for current route var float RouteDist; // total distance for current route var float LastRouteFind; // time at which last route finding occured var InterpActor PendingMover; // InterpActor that controller is currently waiting on (e.g. door or lift) /** used for discovering navigation failures */ var Actor FailedMoveTarget; var int MoveFailureCount; var float GroundPitchTime; var Pawn ShotTarget; // Target most recently aimed at var const Actor LastFailedReach; // cache to avoid trying failed actorreachable more than once per frame var const float FailedReachTime; var const vector FailedReachLocation; const LATENT_MOVETOWARD = 503; // LatentAction number for Movetoward() latent function //============================================================================= // AI VARIABLES var const bool bLOSflag; // used for alternating LineOfSight traces var bool bSkipExtraLOSChecks; // Skip viewport nudging checks for LOS var bool bNotifyFallingHitWall; // If true, controller gets NotifyFallingHitWall() when pawn hits wall while falling var float SightCounter; // Used to keep track of when to check player visibility var float SightCounterInterval; // how often player visibility is checked var bool bEarlyOutOfSighTestsForSameType;// when an AI already has an enemy of this type, early out from sight tests to me `if(`__TW_) var bool bReachedLatentMoveGoal; // Used by APawn::MoveToward() & AKFPawn::MoveToward() var NavigationPoint LastNavGoalReached; // Last NavigationPoint reached via MoveToward() var bool bAdjustFromWalls; // Moved down from AIController to avoid casting `endif /** multiplier to cost of NavigationPoints that another Pawn is currently anchored to */ var float InUseNodeCostMultiplier; /** additive modifier to cost of NavigationPoints that require high jumping */ var int HighJumpNodeCostModifier; /** Max time when moving toward a pawn target before latent movetoward returns (allowing reassessment of movement) */ var float MaxMoveTowardPawnTargetTime; // Enemy information var Pawn Enemy; /** Forces all velocity to be directed towards reaching Destination */ var bool bPreciseDestination; /** Do visibility checks, call SeePlayer events() for pawns on same team as self. Setting to true will result in a lot more AI visibility line checks. */ var bool bSeeFriendly; /** List of destinations whose source portals are visible to this Controller */ struct native VisiblePortalInfo { /** source actor of portal */ var Actor Source; /** destination actor of portal */ var Actor Destination; structcpptext { FVisiblePortalInfo() {} FVisiblePortalInfo(EEventParm) { appMemzero(this, sizeof(FVisiblePortalInfo)); } FVisiblePortalInfo(AActor* InSource, AActor* InDest) : Source(InSource), Destination(InDest) {} UBOOL operator==(const FVisiblePortalInfo& Other) { return Other.Source == Source && Other.Destination == Destination; } } }; var array VisiblePortals; /** indicates that the AI is within a lane in its CurrentPath (like a road) * to avoid ramming other Pawns also using that path * set by MoveToward() when it detects multiple AI pawns using the same path * when this is true, serpentine movement and cutting corners are disabled */ var bool bUsingPathLanes; /** the offset from the center of CurrentPath to the center of the lane in use (the Pawn's CollisionRadius defines the extent) * positive values are to the Pawn's right, negative to the Pawn's left */ var float LaneOffset; /** Used for reversing rejected mover base movement */ var const rotator OldBasedRotation; /** allows easy modification of the search extent provided by setuppathfindingparams() */ var vector NavMeshPath_SearchExtent_Modifier; cpptext { INT* GetOptimizedRepList( BYTE* InDefault, FPropertyRetirement* Retire, INT* Ptr, UPackageMap* Map, UActorChannel* Channel ); UBOOL Tick( FLOAT DeltaTime, enum ELevelTick TickType ); virtual void Spawned(); virtual void BeginDestroy(); virtual UBOOL IsPlayerOwned() { return IsPlayerOwner(); } virtual UBOOL IsPlayerOwner() { return bIsPlayer; } virtual AController* GetAController() { return this; } // Seeing and hearing checks virtual UBOOL CanHear(const FVector& NoiseLoc, FLOAT Loudness, AActor *Other); virtual void ShowSelf(); virtual UBOOL ShouldCheckVisibilityOf(AController* C); virtual DWORD SeePawn(APawn *Other, UBOOL bMaySkipChecks = TRUE); virtual DWORD LineOfSightTo(const AActor* Other, INT bUseLOSFlag=0, const FVector* chkLocation = NULL, UBOOL bTryAlternateTargetLoc = FALSE); void CheckEnemyVisible(); virtual void HearNoise(AActor* NoiseMaker, FLOAT Loudness, FName NoiseType); AActor* HandleSpecial(AActor *bestPath); virtual INT AcceptNearbyPath(AActor* goal); virtual UReachSpec* PrepareForMove( ANavigationPoint *NavGoal, UReachSpec* Path ); UReachSpec* GetNextRoutePath( ANavigationPoint *NavGoal ); virtual void AdjustFromWall(FVector HitNormal, AActor* HitActor); void SetRouteCache( ANavigationPoint *EndPath, FLOAT StartDist, FLOAT EndDist ); AActor* FindPath(const FVector& Point, AActor* Goal, UBOOL bWeightDetours, INT MaxPathLength, UBOOL bReturnPartial); /** given the passed in goal for pathfinding, set bTransientEndPoint on all NavigationPoints that are acceptable * destinations on the path network * @param EndAnchor the Anchor for the goal on the navigation network * @param Goal the goal actor we're pathfinding toward (may be NULL) * @param GoalLocation the goal world location we're pathfinding toward */ virtual void MarkEndPoints(ANavigationPoint* EndAnchor, AActor* Goal, const FVector& GoalLocation); /** gives the Controller a chance to pre-empt pathfinding with its own result (if a cached path is still valid, for example) * called just before navigation network traversal, after Anchor determination and NavigationPoint transient properties are set up * only called when using the 'FindEndPoint' node evaluator * @param EndAnchor - Anchor for Goal on the path network * @param Goal - Destination Actor we're trying to path to (may be NULL) * @param GoalLocation - the goal world location we're pathfinding toward * @param bWeightDetours - whether we should consider short detours for pickups and such * @param BestWeight - weighting value for best node on path - if this function returns true, findPathToward() will return this value * @return whether the normal pathfinding should be skipped */ virtual UBOOL OverridePathTo(ANavigationPoint* EndAnchor, AActor* Goal, const FVector& GoalLocation, UBOOL bWeightDetours, FLOAT& BestWeight) { return FALSE; } AActor* SetPath(INT bInitialPath=1); virtual UBOOL WantsLedgeCheck(); virtual UBOOL StopAtLedge(); virtual void PrePollMove() {} virtual void PostPollMove() {} virtual void PollMoveComplete(); virtual AActor* GetViewTarget(); virtual void UpdateEnemyInfo(APawn* AcquiredEnemy) {}; #if __TW_ virtual void JumpOverWall(FVector WallNormal, AActor* Wall); #else virtual void JumpOverWall(FVector WallNormal); #endif virtual void UpdatePawnRotation(); virtual UBOOL ForceReached(ANavigationPoint *Nav, const FVector& TestPosition); virtual FRotator SetRotationRate(FLOAT deltaTime); virtual FVector DesiredDirection(); /** activates path lanes for this Controller's current movement and adjusts its destination accordingly * @param DesiredLaneOffset the offset from the center of the Controller's CurrentPath that is desired * the Controller sets its LaneOffset as close as it can get to it without * allowing any part of the Pawn's cylinder outside of the CurrentPath */ #if __TW_PATHFINDING_ virtual void SetPathLane(FLOAT InPathOffset); #else void SetPathLane(FLOAT InPathOffset); #endif #if __TW_AIDEBUGGING_ virtual void FailMove( const FString& Reason ); #else virtual void FailMove(); #endif // falling physics AI hooks virtual void PreAirSteering(FLOAT DeltaTime) {}; virtual void PostAirSteering(FLOAT DeltaTime) {}; virtual void PostPhysFalling(FLOAT DeltaTime) {}; virtual void PostPhysWalking(FLOAT DeltaTime) {}; virtual void PostPhysSpider(FLOAT DeltaTime) {}; virtual UBOOL AirControlFromWall(float DeltaTime, FVector& RealAcceleration) { return FALSE; }; virtual void NotifyJumpApex(); virtual void PostBeginPlay(); virtual void PostScriptDestroyed(); virtual void ClearCrossLevelPaths(ULevel *Level); // Natives. DECLARE_FUNCTION(execPollWaitForLanding); virtual DECLARE_FUNCTION(execPollMoveTo); virtual DECLARE_FUNCTION(execPollMoveToward); DECLARE_FUNCTION(execPollFinishRotation); virtual UBOOL ShouldOffsetCorners() { return TRUE; } virtual UBOOL ShouldUsePathLanes() { return TRUE; } virtual UBOOL ShouldIgnoreNavigationBlockingFor(const AActor* Other){ return !Other->bBlocksNavigation; } // AnimControl Matinee Track support /** Used to provide information on the slots that this Actor provides for animation to Matinee. */ virtual void GetAnimControlSlotDesc(TArray& 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& 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); /** Used by Matinee playback to start a FaceFX animation playing. */ // WWISEMODIF_START 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& SlotInfos ); /** base function called to kick off moveto latent action (called from execMoveTo and execMoveToDirectNonPathPos) */ virtual void MoveTo(const FVector& Dest, AActor* ViewFocus, FLOAT DesiredOffset, UBOOL bShouldWalk); /** base function called to kick off movetoward latent action (called from execMoveToward) */ virtual void MoveToward(AActor* goal, AActor* viewfocus, FLOAT DesiredOffset, UBOOL bStrafe, UBOOL bShouldWalk); /** IMPLEMENT Interface_NavigationHandle */ virtual UBOOL CanCoverSlip(ACoverLink* Link, INT SlotIdx); virtual void SetupPathfindingParams( FNavMeshPathParams& out_ParamCache ); virtual void InitForPathfinding() {} virtual INT ExtraEdgeCostToAddWhenActive(FNavMeshEdgeBase* Edge) { return 0; } virtual FVector GetEdgeZAdjust(FNavMeshEdgeBase* Edge); /** END */ virtual FLOAT GetMaxDropHeight(); } replication { if (bNetDirty && Role==ROLE_Authority) PlayerReplicationInfo, Pawn; } /** returns whether this Controller is a locally controlled PlayerController * @note not valid until the Controller is completely spawned (i.e, unusable in Pre/PostBeginPlay()) */ native function bool IsLocalPlayerController(); /** returns whether this controller is a local controller. * @RETURN true always for non-playercontroller */ native function bool IsLocalController(); /** Route Cache Operations * Allows operations on nodes in the route while modifying route (ie before emptying the cache) * Should override in subclasses as needed */ native function RouteCache_Empty(); native function RouteCache_AddItem( NavigationPoint Nav ); native function RouteCache_InsertItem( NavigationPoint Nav, int Idx=0 ); native function RouteCache_RemoveItem( NavigationPoint Nav ); native function RouteCache_RemoveIndex( int InIndex, int Count=1 ); /** Set FocalPoint as absolute position or offset from base */ native final function SetFocalPoint( Vector FP, optional bool bOffsetFromBase ); /** Retrive the final position that controller should be looking at */ native final function Vector GetFocalPoint(); /** Set Destination as absolute position or offset from base */ native final function SetDestinationPosition( Vector Dest, optional bool bOffsetFromBase ); /** Retrive the final position that controller should be moving to */ native final function Vector GetDestinationPosition(); native final virtual function SetAdjustLocation( Vector NewLoc, bool bAdjust, optional bool bOffsetFromBase ); native final function Vector GetAdjustLocation(); /** * this event is called when an edge is deleted that this controller's handle is actively using */ event NotifyPathChanged(); `if(`__TW_PATHFINDING_) event FailedToFindAnchor(); event JumpedOverWall( vector WallHitNormal, optional actor Wall ); event NotifyFailMove( string Reason ); event AILog_Internal( coerce string LogText, optional Name LogCategory, optional bool bForce, optional bool BugIt, optional bool bSkipExtraInfo ); event PauseAndShowMsg( optional string MsgTxt, optional vector TeleportToLocation ); `endif /** 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) { Pawn.BeginAnimControl(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) { Pawn.SetAnimPosition(SlotName, ChannelIndex, InAnimSeqName, InPosition, bFireNotifies, bLooping, bEnableRootMotion); } /** Called when we are done with the AnimControl track. */ simulated event FinishAnimControl(InterpGroup InInterpGroup) { Pawn.FinishAnimControl(InInterpGroup); } /** * Play FaceFX animations on this Actor. * Returns TRUE if succeeded, if failed, a log warning will be issued. */ // WWISEMODIF_START event bool PlayActorFaceFXAnim(FaceFXAnimSet AnimSet, String GroupName, String SeqName, SoundCue SoundCueToPlay, AkEvent AkEventToPlay) { return Pawn.PlayActorFaceFXAnim(AnimSet, GroupName, SeqName, SoundCueToPlay, AkEventToPlay); } // WWISEMODIF_END /** Stop any matinee FaceFX animations on this Actor. */ event StopActorFaceFXAnim() { Pawn.StopActorFaceFXAnim(); } /** Called each frame by Matinee to update the weight of a particular MorphNodeWeight. */ event SetMorphWeight(name MorphNodeName, float MorphWeight) { Pawn.SetMorphweight(MorphNodeName, MorphWeight); } /** Called each frame by Matinee to update the scaling on a SkelControl. */ event SetSkelControlScale(name SkelControlName, float Scale) { Pawn.SetSkelControlScale(SkelControlName, Scale); } /* epic =============================================== * ::PostBeginPlay * * Overridden to create the player replication info and * perform other mundane initialization tasks. * * ===================================================== */ event PostBeginPlay() { Super.PostBeginPlay(); if ( !bDeleteMe && (WorldInfo.NetMode != NM_Client) ) { if( bIsPlayer ) { // create a new player replication info InitPlayerReplicationInfo(); } InitNavigationHandle(); } // randomly offset the sight counter to avoid hitches SightCounter = SightCounterInterval * FRand(); } /* epic =============================================== * ::Reset * * Resets various properties to their default state, used * for round resetting, etc. * * ===================================================== */ function Reset() { super.Reset(); Enemy = None; StartSpot = None; bAdjusting = false; bPreparingMove = false; MoveTimer = -1; MoveTarget = None; CurrentPath = None; RouteGoal = None; } /* epic =============================================== * ::ClientSetLocation * * Replicated function to set the pawn location and * rotation, allowing server to force (ex. teleports). * * ===================================================== */ reliable client function ClientSetLocation( vector NewLocation, rotator NewRotation ) { SetRotation(NewRotation); if ( Pawn != None ) { if ( (Rotation.Pitch > Pawn.MaxPitchLimit) && (Rotation.Pitch < 65536 - Pawn.MaxPitchLimit) ) { If (Rotation.Pitch < 32768) NewRotation.Pitch = Pawn.MaxPitchLimit; else NewRotation.Pitch = 65536 - Pawn.MaxPitchLimit; } NewRotation.Roll = 0; Pawn.SetRotation( NewRotation ); Pawn.SetLocation( NewLocation ); } } /* epic =============================================== * ::ClientSetRotation * * Replicated function to set the pawn rotation, allowing * the server to force. * * ===================================================== */ reliable client function ClientSetRotation( rotator NewRotation, optional bool bResetCamera ) { SetRotation(NewRotation); if ( Pawn != None ) { NewRotation.Pitch = 0; NewRotation.Roll = 0; Pawn.SetRotation( NewRotation ); } } /* epic =============================================== * ::ReplicatedEvent * * Called when a variable with the property flag "RepNotify" is replicated * * ===================================================== */ simulated event ReplicatedEvent(name VarName) { if (VarName == 'PlayerReplicationInfo') { if (PlayerReplicationInfo != None) { PlayerReplicationInfo.ClientInitialize(self); } } else { Super.ReplicatedEvent(VarName); } } /** Kismet Action to possess a Pawn or a vehicle */ function OnPossess(SeqAct_Possess inAction) { local Pawn OldPawn; local Vehicle V; // if we're driving a vehicle, and we should try to get out first. V = Vehicle(Pawn); if( inAction.bTryToLeaveVehicle && V != None ) { V.DriverLeave( TRUE ); } if( inAction.PawnToPossess != None ) { V = Vehicle(inAction.PawnToPossess); if( Pawn!= None && V != None ) { V.TryToDrive( Pawn ); } else { OldPawn = Pawn; UnPossess(); Possess( inAction.PawnToPossess, FALSE ); if( inAction.bKillOldPawn && OldPawn != None ) { OldPawn.Destroy(); } } } } /* epic =============================================== * ::Possess * * Handles attaching this controller to the specified * pawn. * * ===================================================== */ event Possess(Pawn inPawn, bool bVehicleTransition) { if (inPawn.Controller != None) { inPawn.Controller.UnPossess(); } inPawn.PossessedBy(self, bVehicleTransition); Pawn = inPawn; // preserve Pawn's rotation initially for placed Pawns SetFocalPoint( Pawn.Location + 512*vector(Pawn.Rotation), TRUE ); Restart(bVehicleTransition); if( Pawn.Weapon == None ) { ClientSwitchToBestWeapon(); } } /* epic =============================================== * ::UnPossess * * Called to unpossess our pawn for any reason that is not death * (death handled by PawnDied()) * * ===================================================== */ event UnPossess() { if ( Pawn != None ) { Pawn.UnPossessed(); Pawn = None; } } /* epic =============================================== * ::PawnDied * * Called to unpossess our pawn because it has died * (other unpossession handled by UnPossess()) * * ===================================================== */ function PawnDied(Pawn inPawn) { local int idx; if ( inPawn != Pawn ) { // if that's not our current pawn, leave return; } // abort any latent actions TriggerEventClass(class'SeqEvent_Death',self); for (idx = 0; idx < LatentActions.Length; idx++) { if (LatentActions[idx] != None) { LatentActions[idx].AbortFor(self); } } LatentActions.Length = 0; if ( Pawn != None ) { SetLocation(Pawn.Location); Pawn.UnPossessed(); } Pawn = None; // if we are a player, transition to the dead state if ( bIsPlayer ) { // only if the game hasn't ended, if ( !GamePlayEndedState() ) { // so that we can respawn GotoState('Dead'); } } // otherwise destroy this controller else { Destroy(); } } function bool GamePlayEndedState() { return false; } /* epic =============================================== * ::NotifyPostLanded * * Called after pawn lands after falling if bNotifyPostLanded is true * * ===================================================== */ event NotifyPostLanded(); /* epic =============================================== * ::Destroyed * * Called once this controller has been deleted, overridden * to cleanup any lingering references, etc. * * ===================================================== */ event Destroyed() { if (Role == ROLE_Authority) { // if we are a player, log out if ( bIsPlayer && (WorldInfo.Game != None) ) { WorldInfo.Game.logout(self); } if ( PlayerReplicationInfo != None ) { // remove from team if applicable if ( !PlayerReplicationInfo.bOnlySpectator && PlayerReplicationInfo.Team != None ) { PlayerReplicationInfo.Team.RemoveFromTeam(self); } CleanupPRI(); } } Super.Destroyed(); } /* epic =============================================== * ::CleanupPRI * * Called from Destroyed(). Cleans up PlayerReplicationInfo. * * ===================================================== */ function CleanupPRI() { PlayerReplicationInfo.Destroy(); PlayerReplicationInfo = None; } /* epic =============================================== * ::Restart * * Called upon possessing a new pawn, perform any specific * cleanup/initialization here. * * ===================================================== */ function Restart(bool bVehicleTransition) { Pawn.Restart(); if ( !bVehicleTransition ) { Enemy = None; } // if not vehicle transition, clear controller information if ( bVehicleTransition == FALSE && Pawn.InvManager != None ) { Pawn.InvManager.UpdateController(); } } /* epic =============================================== * ::BeyondFogDistance * * Returns true if OtherPoint is occluded by fog when viewed from ViewPoint. * * ===================================================== */ final native function bool BeyondFogDistance(vector ViewPoint, vector OtherPoint); /* epic =============================================== * ::EnemyJustTeleported * * Notification that Enemy just went through a teleporter. * * ===================================================== */ function EnemyJustTeleported() { LineOfSightTo(Enemy); } /* epic =============================================== * ::NotifyTakeHit * * Notification from pawn that it has received damage * via TakeDamage(). * * ===================================================== */ function NotifyTakeHit(Controller InstigatedBy, vector HitLocation, int Damage, class damageType, vector Momentum); /** spawns and initializes the PlayerReplicationInfo for this Controller */ function InitPlayerReplicationInfo() { PlayerReplicationInfo = Spawn(WorldInfo.Game.PlayerReplicationInfoClass, self,, vect(0,0,0),rot(0,0,0)); // force a default player name if necessary if (PlayerReplicationInfo.PlayerName == "") { // don't call SetPlayerName() as that will broadcast entry messages but the GameInfo hasn't had a chance // to potentionally apply a player/bot name yet PlayerReplicationInfo.PlayerName = class'GameInfo'.default.DefaultPlayerName; } } /* * Queries the PRI and returns our current team index. */ simulated native function byte GetTeamNum(); /* epic =============================================== * ::ServerRestartPlayer * * Attempts to restart this player, generally called from * the client upon respawn request. * * ===================================================== */ reliable server function ServerRestartPlayer() { if (WorldInfo.NetMode != NM_Client && Pawn != None) { ServerGivePawn(); } } /* epic =============================================== * ::ServerGivePawn * * Requests a pawn from the server for this controller, * as part of the respawn process. * * ===================================================== */ function ServerGivePawn(); /* epic =============================================== * ::SetCharacter * * Sets the character for this controller for future * pawn spawns. * * ===================================================== */ function SetCharacter(string inCharacter); /* epic =============================================== * ::GameHasEnded * * Called from game info upon end of the game, used to * transition to proper state. * * ===================================================== */ function GameHasEnded(optional Actor EndGameFocus, optional bool bIsWinner) { // and transition to the game ended state GotoState('RoundEnded'); } /* epic =============================================== * ::NotifyKilled * * Notification from game that a pawn has been killed. * * ===================================================== */ function NotifyKilled(Controller Killer, Controller Killed, pawn KilledPawn, class damageTyp) { if( Pawn != None ) { Pawn.TriggerEventClass( class'SeqEvent_SeeDeath', KilledPawn ); } if (Enemy == KilledPawn) { Enemy = None; } } function NotifyProjLanded( Projectile Proj ) { if( Proj != None && Pawn != None ) { Pawn.TriggerEventClass( class'SeqEvent_ProjectileLanded', Proj ); } } /** * Notification from given projectil that it is about to explode */ function WarnProjExplode( Projectile Proj ); //============================================================================= // INVENTORY FUNCTIONS /* epic =============================================== * ::RatePickup * * Callback from PickupFactory that allows players to * additionally weight certain pickups. * * ===================================================== */ event float RatePickup(Actor PickupHolder, class inPickup); /* epic =============================================== * ::FireWeaponAt * * Should cause this player to fire a weapon at the given * actor. * * ===================================================== */ function bool FireWeaponAt(Actor inActor); /* epic =============================================== * ::StopFiring * * Stop firing of our current weapon. * * ===================================================== */ event StopFiring() { bFire = 0; if ( Pawn != None ) Pawn.StopFiring(); } /* epic =============================================== * ::RoundHasEnded * * * ===================================================== */ function RoundHasEnded(optional Actor EndRoundFocus) { GotoState('RoundEnded'); } /* epic =============================================== * ::HandlePickup * * Called whenever our pawn runs over a new pickup. * * ===================================================== */ function HandlePickup(Inventory Inv); /** * Adjusts weapon aiming direction. * Gives controller a chance to modify the aiming of the pawn. 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. */ function Rotator GetAdjustedAimFor( Weapon W, vector StartFireLoc ) { // by default, return Rotation. This is the standard aim for controllers // see implementation for PlayerController. if ( Pawn != None ) { return Pawn.GetBaseAimRotation(); } return Rotation; } /* epic =============================================== * ::InstantWarnTarget * * Warn a target it is about to be shot at with an instant hit * weapon. * * ===================================================== */ function InstantWarnTarget(Actor InTarget, Weapon FiredWeapon, vector FireDir) { local Pawn P; P = Pawn(InTarget); if (P != None && P.Controller != None) { P.Controller.ReceiveWarning(Pawn, -1, FireDir); } } /* epic =============================================== * ::ReceiveWarning * * Notification that the pawn is about to be shot by a * trace hit weapon. * * ===================================================== */ function ReceiveWarning(Pawn shooter, float projSpeed, vector FireDir); /* epic =============================================== * ::ReceiveProjectileWarning * * Notification that the pawn is about to be shot by a * projectile. * * ===================================================== */ function ReceiveProjectileWarning(Projectile Proj); /* epic =============================================== * ::SwitchToBestWeapon * * Rates the pawn's weapon loadout and chooses the best * weapon, bringing it up as the active weapon. * * ===================================================== */ exec function SwitchToBestWeapon(optional bool bForceNewWeapon, optional bool check_9mm_logic = false) { if ( Pawn == None || Pawn.InvManager == None ) return; Pawn.InvManager.SwitchToBestWeapon(bForceNewWeapon, check_9mm_logic); } /* epic =============================================== * ::ClientSwitchToBestWeapon * * Forces the client to switch to a new weapon, allowing * the server control. * * ===================================================== */ reliable client function ClientSwitchToBestWeapon(optional bool bForceNewWeapon) { local bool check_9mm_logic; check_9mm_logic = true; SwitchToBestWeapon(bForceNewWeapon, check_9mm_logic); } /* epic =============================================== * ::NotifyChangedWeapon * * Notification from pawn that the current weapon has * changed. * Network: LocalPlayer * ===================================================== */ function NotifyChangedWeapon( Weapon PrevWeapon, Weapon NewWeapon ); //============================================================================= // AI FUNCTIONS /* epic =============================================== * ::LineOfSightTo * * Returns true if the specified actor has line of sight * to our pawn. * * NOTE: No FOV is accounted for, use CanSee(). * * ===================================================== */ native(514) noexport final function bool LineOfSightTo(Actor Other, optional vector chkLocation, optional bool bTryAlternateTargetLoc); /* epic =============================================== * ::CanSee * * Returns true if the specified pawn is visible within * our peripheral vision. If the pawn is not our current * enemy then LineOfSightTo() will be called instead. * * ===================================================== */ native(533) final function bool CanSee(Pawn Other); /* epic =============================================== * ::CanSee * * Returns true if the test location is visible within * our peripheral vision (from view location). * * ===================================================== */ native(537) final function bool CanSeeByPoints( Vector ViewLocation, Vector TestLocation, Rotator ViewRotation ); /* epic =============================================== * ::PickTarget * * Evaluates pawns in the local area and returns the * one that is closest to the specified FireDir. * * ===================================================== */ `if(`__TW_) native(531) final function Pawn PickTarget(class TargetClass, out float bestAim, out float bestDist, vector FireDir, vector projStart, float MaxRange, optional bool bTargetTeammates = False); `else native(531) final function Pawn PickTarget(class TargetClass, out float bestAim, out float bestDist, vector FireDir, vector projStart, float MaxRange); `endif /* epic =============================================== * ::HearNoise * * Counterpart to the Actor::MakeNoise() function, called * whenever this player is within range of a given noise. * Used as AI audio cues, instead of processing actual * sounds. * * ===================================================== */ event HearNoise( float Loudness, Actor NoiseMaker, optional Name NoiseType ); /* epic =============================================== * ::SeePlayer * * Called whenever Seen is within of our line of sight * if Seen.bIsPlayer==true. * * ===================================================== */ event SeePlayer( Pawn Seen ); /* epic =============================================== * ::SeeMonster * * Called whenever Seen is within of our line of sight * if Seen.bIsPlayer==false. * * ===================================================== */ event SeeMonster( Pawn Seen ); /* epic =============================================== * ::EnemyNotVisible * * Called whenever Enemy is no longer within of our line * of sight. * * ===================================================== */ event EnemyNotVisible(); //============================================================================= // NAVIGATION FUNCTIONS /* epic =============================================== * ::MoveTo * * Latently moves our pawn to the desired location, which * is cached in Destination. * * ===================================================== */ native(500) noexport final latent function MoveTo(vector NewDestination, optional Actor ViewFocus, optional float DestinationOffset, optional bool bShouldWalk = (Pawn != None) ? Pawn.bIsWalking : false); /* epic =============================================== * ::MoveToDirectNonPathPos * * Latently moves our pawn to the desired location, which * is cached in Destination. * NOTE: this function should be used only when moving directly to a final goal (e.g. not following a path) * it will properly set the final destination on the navhandle (and ensure things are cleared out which would normally be set by GetNextMoveLocation) * @Param NewDestination - destination to move to * @param ViewFocus - actor to look at while moving * @param DestinationOffset - distance from goal we would like to get within * @param bShouldWalk - should the AI walk for this move? * ===================================================== */ native noexport final latent function MoveToDirectNonPathPos(vector NewDestination, optional Actor ViewFocus, optional float DestinationOffset, optional bool bShouldWalk = (Pawn != None) ? Pawn.bIsWalking : false); /* epic =============================================== * ::MoveToward * * Latently moves our pawn to the desired actor, which * is cached in MoveTarget. Takes advantage of the * navigation network anchors when moving to other Pawn * and Inventory actors. * * ===================================================== */ native(502) noexport final latent function MoveToward(Actor NewTarget, optional Actor ViewFocus, optional float DestinationOffset, optional bool bUseStrafing, optional bool bShouldWalk = (Pawn != None) ? Pawn.bIsWalking : false); /* epic =============================================== * ::SetupSpecialPathAbilities * * Called before path finding to allow setup of transient * navigation flags. * * ===================================================== */ event SetupSpecialPathAbilities(); /* epic =============================================== * ::FinishRotation * * Latently waits for our pawn's rotation to match the * pawn's DesiredRotation. * * ===================================================== */ native(508) final latent function FinishRotation(); /* epic =============================================== * ::FindPathTo * * Searches the navigation network for a path to the * node closest to the given point. * * ===================================================== */ native(518) final function Actor FindPathTo( Vector aPoint, optional int MaxPathLength, optional bool bReturnPartial ); /* epic =============================================== * ::FindPathToward * * Searches the navigation network for a path to the * node closest to the given actor. * * ===================================================== */ native(517) final function Actor FindPathToward( Actor anActor, optional bool bWeightDetours, optional int MaxPathLength, optional bool bReturnPartial ); /* epic =============================================== * ::FindPathTowardNearest * * Searches the navigation network for a path to the * closest node of the specified type. * * ===================================================== */ native final function Actor FindPathTowardNearest(class GoalClass, optional bool bWeightDetours, optional int MaxPathLength, optional bool bReturnPartial ); /* epic =============================================== * ::FindRandomDest * * Returns a random node on the network. * * ===================================================== */ native(525) final function NavigationPoint FindRandomDest(); native final function Actor FindPathToIntercept(Pawn P, Actor InRouteGoal, optional bool bWeightDetours, optional int MaxPathLength, optional bool bReturnPartial ); /* epic =============================================== * ::PointReachable * * Returns true if the given point is directly reachable * given our pawn's current movement capabilities. * * NOTE: This function is potentially expensive and should * be used sparingly. If at all possible, use ActorReachable() * instead, since that has more possible optimizations * over PointReachable(). * * ===================================================== */ native(521) final function bool PointReachable(vector aPoint); /* epic =============================================== * ::ActorReachable * * Returns true if the given actor is directly reachable * given our pawn's current movement capabilities. Takes * advantage of the navigation network anchors when * possible. * * NOTE: This function is potentially expensive and should * be used sparingly. * * ===================================================== */ native(520) final function bool ActorReachable(actor anActor); /** * Called by APawn::moveToward when the point is unreachable * due to obstruction or height differences. */ event MoveUnreachable(vector AttemptedDest, Actor AttemptedTarget) { } /* epic =============================================== * ::PickWallAdjust * * Checks if we could jump over obstruction (if within * knee height), or attempts to move to either side of * the obstruction. * * ===================================================== */ native(526) final function bool PickWallAdjust(vector HitNormal); /* epic =============================================== * ::WaitForLanding * * Latently waits until the pawn has landed. Only valid * with PHYS_Falling. Optionally specify the max amount * of time to wait, which defaults to 4 seconds. * * NOTE: If the pawn hasn't landed before the duration * is exceeded, it will abort and call LongFall(). * * ===================================================== */ native(527) noexport final latent function WaitForLanding(optional float waitDuration); /* epic =============================================== * ::LongFall * * Called once the duration for WaitForLanding has been * exceeded without hitting ground. * * ===================================================== */ event LongFall(); /* epic =============================================== * ::EndClimbLadder * * Aborts a latent move action if the MoveTarget is * currently a ladder. * * ===================================================== */ native function EndClimbLadder(); /* epic =============================================== * ::MayFall * * Called when a pawn is about to fall off a ledge, and * allows the controller to prevent a fall by toggling * bCanJump. * This event is also passed if a floor is found over the edge, and the normal of the floor if so. * * ===================================================== */ event MayFall(bool bFloor, vector FloorNormal); /* epic =============================================== * ::AllowDetourTo * * Return true to allow a detour to a given point, or * false to avoid it. Called during any sort of path * finding (FindPathXXX() functions). * * ===================================================== */ event bool AllowDetourTo(NavigationPoint N) { return true; } /* epic =============================================== * ::WaitForMover * * Used to notify AI controller that it needs to wait * at its current position for an interpActor to * become properly positioned. * * ===================================================== */ function WaitForMover(InterpActor M) { PendingMover = M; M.bMonitorMover = true; bPreparingMove = true; Pawn.Acceleration = vect(0,0,0); } /* epic =============================================== * ::MoverFinished * * Called by InterpActor when it stops * if this controller has it set as its PendingMover * * ===================================================== */ event bool MoverFinished() { if (Pawn == None || PendingMover.MyMarker == None || PendingMover.MyMarker.ProceedWithMove(Pawn)) { PendingMover = None; bPreparingMove = false; return true; } return false; } /** Called when the this Controller's Pawn gets hit by an InterpActor interpolating downward while this Controller has Lift * set as its PendingMover * @param Lift the LiftCenter associated with the InterpActor that hit the Pawn */ function UnderLift(LiftCenter Lift); /** called when a ReachSpec the AI wants to use is blocked by a dynamic obstruction * gives the AI an opportunity to do something to get rid of it instead of trying to find another path * @note MoveTarget is the actor the AI wants to move toward, CurrentPath the ReachSpec it wants to use * @param BlockedBy the object blocking the path * @return true if the AI did something about the obstruction and should use the path anyway, false if the path * is unusable and the bot must find some other way to go */ event bool HandlePathObstruction(Actor BlockedBy); //============================================================================= // CAMERA FUNCTIONS /** * Returns Player's Point of View * For the AI this means the Pawn's 'Eyes' ViewPoint * For a Human player, this means the Camera's ViewPoint * * @output out_Location, view location of player * @output out_rotation, view rotation of player */ simulated event GetPlayerViewPoint( out vector out_Location, out Rotator out_rotation ) { out_Location = Location; out_Rotation = Rotation; } /** * 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 ) { // If we have a Pawn, this is our view point. if ( Pawn != None ) { Pawn.GetActorEyesViewPoint( out_Location, out_Rotation ); } else { // Otherwise controller location/rotation is our view point. out_Location = Location; out_Rotation = Rotation; } } /** * This will return whether or not this controller is aiming at the passed in actor. * We are defining AIMing to mean that you are attempting to target the actor. Not just looking in the * direction of the actor. * **/ simulated function bool IsAimingAt( Actor ATarget, float Epsilon ) { local Vector Loc; local Rotator Rot; // grab camera location/rotation for checking Dist GetPlayerViewPoint( Loc, Rot ); // a decent epsilon value is 0.98f as that allows a for a little bit of slop // NOTE: if you want to aim DIRECTLY at something then you would want ~= 1.0f return ( (Normal(ATarget.Location - Loc) dot vector(Rot)) >= Epsilon ); } /** LandingShake() returns true if controller wants landing view shake */ simulated function bool LandingShake() { return false; } //============================================================================= // PHYSICS FUNCTIONS /* epic =============================================== * ::NotifyPhysicsVolumeChange * * Called when our pawn enters a new physics volume. * * ===================================================== */ event NotifyPhysicsVolumeChange(PhysicsVolume NewVolume); /* epic =============================================== * ::NotifyHeadVolumeChange * * Called when our pawn's head enters a new physics * volume. * return true to prevent HeadVolumeChange() notification on the pawn. * * ===================================================== */ event bool NotifyHeadVolumeChange(PhysicsVolume NewVolume); /* epic =============================================== * ::NotifyLanded * * Called when our pawn has landed from a fall, return * true to prevent Landed() notification on the pawn. * * ===================================================== */ event bool NotifyLanded(vector HitNormal, Actor FloorActor); /* epic =============================================== * ::NotifyHitWall * * Called when our pawn has collided with a blocking * piece of world geometry, return true to prevent * HitWall() notification on the pawn. * * ===================================================== */ event bool NotifyHitWall(vector HitNormal, actor Wall); /* epic =============================================== * ::NotifyFallingHitWall * * Called when our pawn has collided with a blocking * piece of world geometry while falling, only called if * bNotifyFallingHitWall is true * ===================================================== */ event NotifyFallingHitWall(vector HitNormal, actor Wall); /* epic =============================================== * ::NotifyBump * * Called when our pawn has collided with a blocking player, * return true to prevent Bump() notification on the pawn. * * ===================================================== */ event bool NotifyBump(Actor Other, Vector HitNormal); /* epic =============================================== * ::NotifyJumpApex * * Called when our pawn has reached the apex of a jump. * * ===================================================== */ event NotifyJumpApex(); /* epic =============================================== * ::NotifyMissedJump * * Called when our pawn misses a jump while performing * latent movement (ie MoveToward()). * * ===================================================== */ event NotifyMissedJump(); /** Called when our pawn reaches Controller.Destination after setting bPreciseDestination = TRUE */ event ReachedPreciseDestination(); //============================================================================= // MISC FUNCTIONS /* epic =============================================== * ::InLatentExecution * * Returns true if currently in the specified latent * action. * * ===================================================== */ native final function bool InLatentExecution(int LatentActionNumber); /* epic =============================================== * ::StopLatentExecution * * Stops any active latent action. * * ===================================================== */ native final function StopLatentExecution(); /** * list important Controller 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 Canvas Canvas; Canvas = HUD.Canvas; if ( Pawn == None ) { if ( PlayerReplicationInfo == None ) { Canvas.DrawText("NO PLAYERREPLICATIONINFO", false); } else { PlayerReplicationInfo.DisplayDebug(HUD,out_YL,out_YPos); } out_YPos += out_YL; Canvas.SetPos(4,out_YPos); super.DisplayDebug(HUD,out_YL,out_YPos); return; } Canvas.SetDrawColor(255,0,0); Canvas.DrawText("CONTROLLER "$GetItemName(string(Self))$" Pawn "$GetItemName(string(Pawn))); out_YPos += out_YL; Canvas.SetPos(4,out_YPos); Canvas.DrawText(" bPreciseDestination:" @ bPreciseDestination); out_YPos += out_YL; Canvas.SetPos(4,out_YPos); if (HUD.ShouldDisplayDebug('AI')) { if ( Enemy != None ) { Canvas.DrawText(" STATE: "$GetStateName()$" Enemy "$Enemy.GetHumanReadableName(), false); } else { Canvas.DrawText(" STATE: "$GetStateName()$" NO Enemy ", false); } out_YPos += out_YL; Canvas.SetPos(4,out_YPos); } } /* epic =============================================== * ::GetHumanReadableName * * Returns the PRI player name if available, or of this * controller object. * * ===================================================== */ simulated function String GetHumanReadableName() { if ( PlayerReplicationInfo != None ) { return PlayerReplicationInfo.PlayerName; } else { return GetItemName(String(self)); } } //============================================================================= // CONTROLLER STATES function bool IsDead(); /* epic =============================================== * state Dead * * Base state entered upon pawn death, if bIsPlayer is * set to true. * * ===================================================== */ State Dead { ignores SeePlayer, HearNoise, KilledBy; function bool IsDead() { return TRUE; } function PawnDied(Pawn P) { if ( WorldInfo.NetMode != NM_Client ) { `warn( Self @ "Pawndied while dead" ); ScriptTrace(); } } /* epic =============================================== * ::ServerRestartPlayer * * Attempts to restart the player if not a client. * * ===================================================== */ reliable server function ServerReStartPlayer() { if ( WorldInfo.NetMode == NM_Client ) return; // If we're still attached to a Pawn, leave it if ( Pawn != None ) { UnPossess(); } WorldInfo.Game.RestartPlayer( Self ); } } /* epic =============================================== * state RoundEnded * * Base state entered upon the end of a game round, instigated * by the * * ===================================================== */ state RoundEnded { ignores SeePlayer, HearNoise, KilledBy, NotifyBump, HitWall, NotifyPhysicsVolumeChange, NotifyHeadVolumeChange, Falling, TakeDamage, ReceiveWarning; function bool GamePlayEndedState() { return true; } event BeginState(Name PreviousStateName) { // if we still have a valid pawn, if ( Pawn != None ) { // stop it in midair and detach Pawn.TurnOff(); StopFiring(); if (!bIsPlayer) { Pawn.UnPossessed(); Pawn = None; } } if ( !bIsPlayer ) { Destroy(); } } } /** * Overridden to redirect to pawn, since teleporting the controller * would be useless. * If Action == None, this was called from the Pawn already */ simulated function OnTeleport(SeqAct_Teleport Action) { if( Action != None ) { if (Pawn != None) { Pawn.OnTeleport(Action); } else { Super.OnTeleport(Action); } } } function OnAttachToActor(SeqAct_AttachToActor Action) { if (Pawn != None) { Pawn.OnAttachToActor(Action); } else { Super.OnAttachToActor(Action); } } /** * Sets god mode based on the activated link. */ function OnToggleGodMode(SeqAct_ToggleGodMode inAction) { if (inAction.InputLinks[0].bHasImpulse) { bGodMode = true; } else if (inAction.InputLinks[1].bHasImpulse) { bGodMode = false; } else { bGodMode = !bGodMode; } } /** Redirects SetPhysics kismet action to the pawn */ simulated function OnSetPhysics(SeqAct_SetPhysics Action) { if( Pawn != None ) { Pawn.OnSetPhysics(Action); } else { Super.OnSetPhysics(Action); } } /** Redirects SetVelocity kismet action to the pawn */ simulated function OnSetVelocity( SeqAct_SetVelocity Action ) { if( Pawn != None ) { Pawn.OnSetVelocity(Action); } else { Super.OnSetVelocity(Action); } } /** * Called when a slot is disabled with this controller as the current owner. */ simulated function NotifyCoverDisabled( CoverLink Link, int SlotIdx, optional bool bAdjacentIdx ); /** * Called when a slot is adjusted with this controller as the current owner. */ simulated event NotifyCoverAdjusted() { // do nothing. intended to be overloaded, but needs a body because it's an event. } /** * Called when cover that AI had claimed is claimed forceably by someone else (usually a player) */ simulated function bool NotifyCoverClaimViolation( Controller NewClaim, CoverLink Link, int SlotIdx ); /** * Redirect to pawn. */ simulated function OnModifyHealth(SeqAct_ModifyHealth Action) { if (Pawn != None) { Pawn.OnModifyHealth(Action); } } /** * Called when an inventory item is given to our Pawn * (owning client only) * @param NewItem the Inventory item that was added */ function NotifyAddInventory(Inventory NewItem); /** * Overridden to redirect to the pawn if available. */ simulated function OnToggleHidden(SeqAct_ToggleHidden Action) { if (Pawn != None) { Pawn.OnToggleHidden(Action); } } /** Returns true if controller is spectating */ event bool IsSpectating() { return false; } /** Returns if controller is in combat */ event bool IsInCombat( optional bool bForceCheck ); /** * Called when the level this controller is in is unloaded via streaming. */ event CurrentLevelUnloaded(); function SendMessage(PlayerReplicationInfo Recipient, name MessageType, float Wait, optional class DamageType); function ReadyForLift(); /** spawn and init Navigation Handle */ simulated function InitNavigationHandle() { if( NavigationHandleClass != None ) { NavigationHandle = new(self) NavigationHandleClass; } } simulated event InterpolationStarted(SeqAct_Interp InterpAction, InterpGroupInst GroupInst) { if (Pawn!=none) { Pawn.InterpolationStarted(InterpAction, GroupInst); } Super.InterpolationStarted( InterpAction, GroupInst ); } /** called when a SeqAct_Interp action finished interpolating this Actor * @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) { if (Pawn!=none) { Pawn.InterpolationFinished(InterpAction); } Super.InterpolationFinished( InterpAction ); } event bool GeneratePathToActor( Actor Goal, optional float WithinDistance, optional bool bAllowPartialPath ); event bool GeneratePathToLocation( Vector Goal, optional float WithinDistance, optional bool bAllowPartialPath ); defaultproperties { RotationRate=(Pitch=30000,Yaw=30000,Roll=2048) bHidden=TRUE bHiddenEd=TRUE MinHitWall=-1.f bSlowerZAcquire=TRUE RemoteRole=ROLE_None bOnlyRelevantToOwner=TRUE SightCounterInterval=0.2 MaxMoveTowardPawnTargetTime=1.2 NavigationHandleClass=class'NavigationHandle' }