//============================================================================= // AIPluginMovement //============================================================================= // A proxy/parent class for all specific movement implementations //============================================================================= // Killing Floor 2 // Copyright (C) 2015 Tripwire Interactive LLC //============================================================================= class AIPluginMovement extends AITickablePlugin within BaseAIController native(Plugin) dependson(NavigationPath) abstract; struct native MoveParameters { var EBaseMoveMood MoveMood; var EBaseMoveType MoveType; // var EStridePose EndStridePose; var Actor RotateAtEndToMatch; /** When path is actually for following actor. */ var Actor FollowingActor; /** Movement can be inaccurate. Useful when character ends up around < 2m away and it is not needed for it cover distance. */ var bool bMovementCanBeInaccurate; /** Don't stop at the end of path. Useful for charge attacks etc. when character is not expected to stop at the end of path. Doesn't apply for entering cover. */ var bool bMoveThroughLastPoint; /** Indicates whether movement needs to start/end with shooting animation. */ var bool bStartPathFollowingShooting; var bool bEndPathFollowingShooting; /** makes sure AI will do any move even if destination is close enough */ var bool bForceAnyMove; var bool bAllowedToFire; structcpptext { FMoveParameters() { Reset(); } void Reset() { appMemzero(this, sizeof(FMoveParameters)); // copied from structdefaultproperties MoveMood = BMM_Fast; MoveType = BMT_Normal; bStartPathFollowingShooting = TRUE; bEndPathFollowingShooting = FALSE; } } structdefaultproperties { // BodyStance=NBS_Stand MoveMood=BMM_Fast MoveType=BMT_Normal bStartPathFollowingShooting=true } }; enum EMoveRequestDestinationType { MRDT_Invalid, MRDT_Vector, MRDT_Actor, }; struct native MoveRequestDestination { var vector VectorDest; var Actor ActorDest; var EMoveRequestDestinationType Type; structcpptext { FMoveRequestDestination() { appMemzero(this, sizeof(FMoveRequestDestination)); } FMoveRequestDestination(const class FVector& vDestination) { VectorDest = vDestination; Type = MRDT_Vector; } FMoveRequestDestination(class AActor* Actor) : Type(MRDT_Invalid) { if(Actor != NULL) { ActorDest = Actor; Type = MRDT_Actor; } } void Reset() { Type = MRDT_Invalid; } void Set(const class FVector& vDestination) { VectorDest = vDestination; Type = MRDT_Vector; } void Set(class AActor* Actor) { if(Actor != NULL) { ActorDest = Actor; Type = MRDT_Actor; } else { Type = MRDT_Invalid; } } //void Set(struct FCoverInfo& inCoverInfo) //{ // if(inCoverInfo.IsSet() == TRUE) // { // CoverInfoDest = inCoverInfo; // Type = MRDT_Cover; // } // else // { // Type = MRDT_Invalid; // } //} UBOOL IsActor() const { return Type == MRDT_Actor; } UBOOL IsVector() const { return Type == MRDT_Vector; } //UBOOL IsCover() const //{ // return Type == MRDT_Cover; //} class AActor* GetAsActor() { return Type == MRDT_Actor ? ActorDest : NULL; } const class AActor* GetAsActor() const { return Type == MRDT_Actor ? ActorDest : NULL; } //struct FCoverInfo GetAsCoverInfo() const //{ // return Type == MRDT_Cover ? CoverInfoDest : FCoverInfo(); //} FVector GetPosition() const { switch(Type) { case MRDT_Vector: return VectorDest; break; //case MRDT_Cover: // return CoverInfoDest.Link ? CoverInfoDest.Link->GetSlotLocation(CoverInfoDest.SlotIdx) : FVector(0.f); // break; case MRDT_Actor: return ActorDest ? ActorDest->Location : FVector(0.f); break; default: // MRDT_Invalid break; } return FVector(0.0f); } } }; struct native MovementRequest { var native MoveParameters MoveParams; var float AcceptableDistance; var vector DestOffset; var vector MidPointOffset; /** a struct type with union inside representing move destination. It seems * ok to have a native only access to it - script will only be able to modify means * of execution, but not destination itself. */ var native MoveRequestDestination Destination; var native NavigationPath PreComputedPath; var EActionPriority Priority; var const object Observer; var bool bStickToNavmesh; var bool bStickToActionArea; var bool bDynamicDestOffset; // not used at the moment. Added for consistence var bool bDynamicMidPoint; var bool bPostProcessPath; var int QueryID; structcpptext { FMovementRequest() { appMemzero(this, sizeof(FMovementRequest)); Reset(); } FMovementRequest(FMovementRequest* pOther) { if(pOther != NULL) { appMemCopy(*this, *pOther); } else { appMemzero(this, sizeof(FMovementRequest)); Reset(); } } FString GetDescription() const; void Reset() { MoveParams.Reset(); AcceptableDistance=0.0f; Destination.Reset(); PreComputedPath = NULL; Priority = AP_Invalid; bStickToNavmesh = TRUE; bStickToActionArea = FALSE; bPostProcessPath = FALSE; Observer = NULL; } } }; var MovementRequest MoveRequest; var transient float GoalDistanceSq; var const public{protected} EActionPriority ActionPriority; var const public{private} EActionPriority MovementLock; var const transient bool bObserverNotified; var const transient bool bDontNotifyObserver; var transient bool bDontRestartByKismet; var float MinimumSuccessDistance; cpptext { UBOOL IsMovementLocked(const EActionPriority Priority = AP_Logic) const // AP_Locic, i.e. AP_Invalid + 1. { return MovementLock >= Priority; } EActionPriority GetMovementLock() const { return (EActionPriority)MovementLock; } UBOOL CanAcceptNewMoveRequest(EActionPriority NewRequestPriority) const { return NewRequestPriority >= ActionPriority; } FORCEINLINE EActionPriority GetActionPriority() const { return (EActionPriority)ActionPriority; } FVector GetDestination(struct FMovementRequest& Request) const { return Request.Destination.GetPosition(); } } /** overrideable only in native code (no-exported as virtual) */ native function bool MoveToRequest(out MovementRequest Request); native function bool MoveToPointRequest(vector InDestLocation, EActionPriority CommandPriority, optional object ActionObserver, optional bool bStopAtEnd=true, optional bool bStickToNavmesh = true, optional float AcceptableDistance, optional Actor RotateAtEndToMatch); native function bool MoveToActorRequest(Actor inPawnGoal, EActionPriority CommandPriority, optional object ActionObserver, optional bool bInAllowedToFire=true, optional float AcceptableDistance, optional vector DestOffset, optional vector MidPointOffset, optional bool bDynamicMidPoint, optional bool bStopAtEnd=true, optional bool bStickToNavmesh=true); native function bool FollowPlugInsPath(NavigationPath InPath, EActionPriority CommandPriority, optional object ActionObserver, optional bool bStopAtEnd=true, optional Actor RotateAtEndToMatch, optional Float AcceptableDistance); native function bool AbortMove(bool bNewRequest); /** * @param bNewRequest if set to false (default) then if there was a move * task paused while lock was being set, then this task will be resumed. * If true, it will not. This param makes sense only for bLock == true */ native function SetMovementLock(bool bLock, optional EActionPriority Priority = AP_Logic, optional bool bNewRequest); native function protected Success(); native function protected Failure(); native function bool RePath(); /** Script interface to get location of destination point from given MovementRequest. * no-exported to make inline. */ final native noexport function vector GetDestination(out MovementRequest Request) const; final function EMoveRequestDestinationType GetDestinationType() { return MoveRequest.Destination.Type; } function StopMovement() { //@todo fill it! } /** Called from native code during latent movement when current move is considered unreachable */ function bool MoveUnreachable( Vector AttemptedDest, Actor AttemptedTarget ) { if( AttemptedTarget != none ) { `AILog( GetFuncName()$" AttemptedTarget: "$AttemptedTarget, 'PathWarning' ); } return false; } state Succeeding `DEBUGSTATE { Begin: `AILog("Moving - END:"@GetStateName(), 'Move'); Success(); } state Failing `DEBUGSTATE { Begin: `AILog("Moving - END:"@GetStateName(), 'Move'); Failure(); } /* this state does nothing. It's here to leave other states when move is aborted, * and to indicate that it happened */ state Aborting `DEBUGSTATE { Begin: `AILog("Moving - Aborted", 'Move'); //AbortMove(false); StopMovement(); } /* this state does nothing. It's here to leave other states when move is aborted, * and to indicate that it happened */ state Idling `DEBUGSTATE { Begin: `AILog("Idling", 'Move'); StopMovement(); } defaultproperties { // mz> this change is a little bit hacky and will need further changes. AnimSys accepts path success if destination to cover < 150.0f; //MinimumSuccessDistance=8100.0f //90 units MinimumSuccessDistance=160.0f //90 units }