Files
GTASource/game/vehicleAi/task/TaskVehicleGotoBoat.cpp
expvintl 419f2e4752 init
2025-02-23 17:40:52 +08:00

793 lines
28 KiB
C++

//
// boat cruise
// April 17, 2013
//
#include "math/vecmath.h"
#include "VehicleAi/task/TaskVehicleGoToBoat.h"
#include "VehicleAi/task/TaskVehicleGoToAutomobile.h"
#include "VehicleAi/Task/TaskVehiclePark.h"
#include "VehicleAi/VehicleIntelligence.h"
#include "Task/System/TaskHelpers.h"
#include "Peds/ped.h"
AI_OPTIMISATIONS()
AI_VEHICLE_OPTIMISATIONS()
CTaskVehicleGoToBoat::Tunables CTaskVehicleGoToBoat::sm_Tunables;
IMPLEMENT_VEHICLE_AI_TASK_TUNABLES(CTaskVehicleGoToBoat, 0xba1b001f);
// Constructor/destructor
CTaskVehicleGoToBoat::CTaskVehicleGoToBoat(const sVehicleMissionParams& params, const fwFlags16 uConfigFlags)
: CTaskVehicleMissionBase(params)
, m_fTimeBlocked(0.0f)
, m_fTimeBlockThreePointTurn(0.0f)
, m_fTimeRanRouteSearch(0.0f)
, m_uConfigFlags(uConfigFlags)
, m_bWasBlockedForThreePointTurn(false)
{
Assertf(m_Params.GetTargetEntity().GetEntity() == NULL || m_uConfigFlags.IsFlagSet(CF_NeverNavMesh), "Can't have a target entity and use navmesh pathing for boats" );
SetInternalTaskType(CTaskTypes::TASK_VEHICLE_GOTO_BOAT);
}
CTaskVehicleGoToBoat::CTaskVehicleGoToBoat(const CTaskVehicleGoToBoat& in_rhs)
: CTaskVehicleMissionBase(in_rhs.m_Params)
, m_fTimeBlocked(in_rhs.m_fTimeBlocked)
, m_fTimeBlockThreePointTurn(in_rhs.m_fTimeBlockThreePointTurn)
, m_uConfigFlags(in_rhs.m_uConfigFlags)
, m_uRunningFlags(in_rhs.m_uRunningFlags)
, m_fTimeRanRouteSearch(in_rhs.m_fTimeRanRouteSearch)
, m_bWasBlockedForThreePointTurn(in_rhs.m_bWasBlockedForThreePointTurn)
{
SetInternalTaskType(CTaskTypes::TASK_VEHICLE_GOTO_BOAT);
}
CTaskVehicleGoToBoat::~CTaskVehicleGoToBoat()
{
}
void CTaskVehicleGoToBoat::SetTargetPosition(const Vector3 *pTargetPosition)
{
CTaskVehicleMissionBase::SetTargetPosition(pTargetPosition);
m_uRunningFlags.ClearFlag(RF_IsRunningRouteSearch);
m_fTimeRanRouteSearch = 0.0f;
}
aiTask::FSM_Return CTaskVehicleGoToBoat::ProcessPreFSM()
{
const Vector3 vStartCoords = VEC3V_TO_VECTOR3(CVehicleFollowRouteHelper::GetVehicleBonnetPosition(GetVehicle(), IsDrivingFlagSet(DF_DriveInReverse)));
Vector3 vTargetPosition;
m_Params.GetDominantTargetPosition(vTargetPosition);
float length = (vTargetPosition - vStartCoords).XYMag();
GetVehicle()->GetIntelligence()->GetBoatAvoidanceHelper()->SetAvoidanceFeelerMaxLength(Max(length, 2.0f));
if ( GetVehicle()->GetIntelligence()->GetBoatAvoidanceHelper()->IsBlocked() )
{
m_fTimeBlocked += GetTimeStep();
}
m_fTimeBlockThreePointTurn -= GetTimeStep();
UpdateSearchRoute(*GetVehicle());
UpdateFollowRoute(*GetVehicle());
return FSM_Continue;
}
aiTask::FSM_Return CTaskVehicleGoToBoat::UpdateFSM(const s32 iState, const FSM_Event iEvent)
{
CVehicle* pVehicle = GetVehicle();
FSM_Begin
// FindRoute state
FSM_State(State_Init)
FSM_OnUpdate
return Init_OnUpdate(*pVehicle);
FSM_State(State_GotoStraightLine)
FSM_OnEnter
GotoStraightLine_OnEnter(*pVehicle);
FSM_OnUpdate
return GotoStraightLine_OnUpdate(*pVehicle);
FSM_State(State_GotoNavmesh)
FSM_OnEnter
GotoNavmesh_OnEnter(*pVehicle);
FSM_OnUpdate
return GotoNavmesh_OnUpdate(*pVehicle);
FSM_OnExit
GotoNavmesh_OnExit(*pVehicle);
FSM_State(State_ThreePointTurn)
FSM_OnEnter
ThreePointTurn_OnEnter(*pVehicle);
FSM_OnUpdate
return ThreePointTurn_OnUpdate(*pVehicle);
FSM_OnExit
ThreePointTurn_OnExit(*pVehicle);
FSM_State(State_PauseForRoadRoute)
FSM_OnEnter
PauseForRoadRoute_OnEnter(*pVehicle);
FSM_OnUpdate
return PauseForRoadRoute_OnUpdate(*pVehicle);
FSM_State(State_Stop)
FSM_OnEnter
Stop_OnEnter();
FSM_OnUpdate
return Stop_OnUpdate();
FSM_End
}
static float s_MaxSpeedToThreePointTurn = 10.0f;
static float s_MaxTimeBlocked = 0.5f;
static float s_AngleToThreePointTurn = 0.5f;
static float s_AngleToStopThreePointTurn = 0.6f;
bool CTaskVehicleGoToBoat::ShouldUseThreePointTurn(CVehicle& in_Vehicle, const Vector3& in_Target ) const
{
const Vector3 vStartCoords = VEC3V_TO_VECTOR3(CVehicleFollowRouteHelper::GetVehicleBonnetPosition(GetVehicle(), IsDrivingFlagSet(DF_DriveInReverse)));
const Vector3 vBoatFwd = VEC3V_TO_VECTOR3(in_Vehicle.GetTransform().GetForward());
const Vector3 vBoatVel = in_Vehicle.GetVelocity();
Vector3 vDirectionToTarget = in_Target - vStartCoords;
vDirectionToTarget.z = 0.0f;
vDirectionToTarget.NormalizeSafe();
CPed* pDriver = in_Vehicle.GetDriver();
bool bOnlyTurnForBlocked = false;
if(pDriver)
{
//commender this flag to prevent pickup boats turning around the large yachts when picking up player
bOnlyTurnForBlocked = pDriver->GetPedConfigFlag(ePedConfigFlags::CPED_CONFIG_FLAG_AIDriverAllowFriendlyPassengerSeatEntry);
}
float fAngleToThreePointTurn = bOnlyTurnForBlocked ? -10.0f : (m_uConfigFlags.IsFlagSet(CF_PreferForward) ? 0.0f : s_AngleToThreePointTurn);
if ( m_fTimeBlockThreePointTurn < 0
&& ( m_fTimeBlocked > s_MaxTimeBlocked
|| (vDirectionToTarget.Dot(vBoatFwd) <= fAngleToThreePointTurn
&& vBoatVel.XYMag() <= s_MaxSpeedToThreePointTurn
&& ( !CPathServer::IsNavMeshLoadedAtPosition(VEC3V_TO_VECTOR3(in_Vehicle.GetTransform().GetPosition()), kNavDomainRegular) || in_Vehicle.GetIntelligence()->GetBoatAvoidanceHelper()->IsAvoiding()) ) ) )
{
return true;
}
return false;
}
void CTaskVehicleGoToBoat::UpdateFollowRoute(CVehicle& in_Vehicle)
{
m_uRunningFlags.ClearFlag(RF_HasUpdatedSegmentThisFrame);
if ( m_RouteFollowHelper.Progress(in_Vehicle, sm_Tunables.m_RouteLookAheadDistance ) )
{
if ( m_RouteFollowHelper.IsLastSegment() && m_uRunningFlags.IsFlagSet(RF_RouteIsPartial) && m_uRunningFlags.IsFlagSet(RF_HasValidRoute) )
{
m_uRunningFlags.ClearFlag(RF_HasValidRoute);
m_fTimeRanRouteSearch = 0.0f;
}
m_uRunningFlags.SetFlag(RF_HasUpdatedSegmentThisFrame);
}
}
void CTaskVehicleGoToBoat::UpdateSearchRoute(CVehicle& in_Vehicle)
{
m_uRunningFlags.ClearFlag(RF_HasUpdatedRouteThisFrame);
if ( !m_uConfigFlags.IsFlagSet(CF_NeverRoute) )
{
if ( m_uRunningFlags.IsFlagSet(RF_IsRunningRouteSearch) )
{
if( m_RouteSearchHelper.Update() == CTaskHelperFSM::FSM_Quit )
{
m_uRunningFlags.ClearFlag(RF_IsRunningRouteSearch);
m_uRunningFlags.ClearFlag(RF_HasValidRoute);
m_uRunningFlags.ClearFlag(RF_RouteIsPartial);
m_uRunningFlags.SetFlag(RF_HasUpdatedRouteThisFrame);
if ( m_RouteSearchHelper.GetState() == CPathNodeRouteSearchHelper::State_ValidRoute )
{
if ( m_RouteSearchHelper.GetCurrentNumNodes() >= CVehicleNodeList::CAR_MAX_NUM_PATHNODES_STORED )
{
m_uRunningFlags.SetFlag(RF_RouteIsPartial);
}
m_uRunningFlags.SetFlag(RF_HasValidRoute);
Vector3 vTargetPosition;
m_Params.GetDominantTargetPosition(vTargetPosition);
m_RouteFollowHelper.ConstructFromNodeList(in_Vehicle, m_RouteSearchHelper.GetNodeList(), vTargetPosition);
}
}
}
else
{
Vector3 vTargetCoords;
FindTargetCoors(&in_Vehicle, vTargetCoords);
const Vector3 vStartPos = VEC3V_TO_VECTOR3(CVehicleFollowRouteHelper::GetVehicleBonnetPosition(&in_Vehicle, IsDrivingFlagSet(DF_DriveInReverse)));
const float fSearchMinX = Min(vStartPos.x, vTargetCoords.x);
const float fSearchMinY = Min(vStartPos.y, vTargetCoords.y);
const float fSearchMaxX = Max(vStartPos.x, vTargetCoords.x);
const float fSearchMaxY = Max(vStartPos.y, vTargetCoords.y);
if (ThePaths.AreNodesLoadedForArea(fSearchMinX, fSearchMaxX, fSearchMinY, fSearchMaxY))
{
if ( !m_uRunningFlags.IsFlagSet(RF_HasValidRoute) || m_uConfigFlags.IsFlagSet(CF_UseWanderRoute) || m_uConfigFlags.IsFlagSet(CF_UseFleeRoute) )
{
m_fTimeRanRouteSearch -= GetTimeStep();
if ( m_fTimeRanRouteSearch < 0 )
{
static float s_RouteSearchTime = 5.0f;
m_fTimeRanRouteSearch = s_RouteSearchTime;
u32 iSearchFlags = CPathNodeRouteSearchHelper::Flag_IncludeWaterNodes;
if (IsDrivingFlagSet(DF_AvoidTargetCoors))
{
iSearchFlags |= CPathNodeRouteSearchHelper::Flag_FindRouteAwayFromTarget;
}
if (IsDrivingFlagSet(DF_DriveIntoOncomingTraffic))
{
iSearchFlags |= CPathNodeRouteSearchHelper::Flag_DriveIntoOncomingTraffic;
}
if (IsDrivingFlagSet(DF_UseSwitchedOffNodes))
{
iSearchFlags |= CPathNodeRouteSearchHelper::Flag_UseSwitchedOffNodes;
}
if (IsDrivingFlagSet(DF_UseShortCutLinks))
{
iSearchFlags |= CPathNodeRouteSearchHelper::Flag_UseShortcutLinks;
}
if (m_uConfigFlags.IsFlagSet(CF_UseWanderRoute))
{
iSearchFlags |= CPathNodeRouteSearchHelper::Flag_WanderRoute;
}
if ( m_uConfigFlags.IsFlagSet(CF_UseFleeRoute) )
{
static u32 s_Flags = CPathNodeRouteSearchHelper::Flag_FindWanderRouteTowardsTarget | CPathNodeRouteSearchHelper::Flag_WanderRoute | CPathNodeRouteSearchHelper::Flag_JoinRoadInDirection;
iSearchFlags |= s_Flags;
}
m_RouteSearchHelper.StartSearch(vStartPos, vTargetCoords, VEC3V_TO_VECTOR3(in_Vehicle.GetVehicleForwardDirection()), in_Vehicle.GetAiVelocity(), iSearchFlags, NULL);
m_uRunningFlags.ClearFlag(RF_HasValidRoute);
m_uRunningFlags.SetFlag(RF_IsRunningRouteSearch);
}
}
}
else
{
static float s_Padding = 10.0f;
ThePaths.AddNodesRequiredRegionThisFrame(CPathFind::CPathNodeRequiredArea::CONTEXT_GAME, Vector3(fSearchMinX - s_Padding, fSearchMinY - s_Padding, 0.0f), Vector3(fSearchMaxX + s_Padding, fSearchMaxY + s_Padding, 0.0f), "Goto Boat");
}
}
}
}
aiTask::FSM_Return CTaskVehicleGoToBoat::Init_OnUpdate(CVehicle& in_Vehicle)
{
Vector3 vTargetPosition;
m_Params.GetDominantTargetPosition(vTargetPosition);
m_RouteFollowHelper.ConstructFromStartEnd(in_Vehicle, vTargetPosition);
m_RouteFollowHelper.ComputeTarget(vTargetPosition, in_Vehicle);
const Vector3 vStartCoords = VEC3V_TO_VECTOR3(CVehicleFollowRouteHelper::GetVehicleBonnetPosition(GetVehicle(), IsDrivingFlagSet(DF_DriveInReverse)));
const Vector3 vBoatVel = in_Vehicle.GetVelocity();
Vector3 vDirectionToTarget = vTargetPosition - vStartCoords;
vDirectionToTarget.z = 0.0f;
vDirectionToTarget.NormalizeSafe();
float dirToTargetOrientation = fwAngle::GetATanOfXY(vDirectionToTarget.x, vDirectionToTarget.y);
dirToTargetOrientation = fwAngle::LimitRadianAngleSafe(dirToTargetOrientation);
m_fTimeBlocked = 0.0f;
in_Vehicle.GetIntelligence()->GetBoatAvoidanceHelper()->SetSteeringEnabled(m_uConfigFlags.IsFlagSet(CF_AvoidShore));
in_Vehicle.GetIntelligence()->GetBoatAvoidanceHelper()->SetAvoidanceOrientation(dirToTargetOrientation);
in_Vehicle.GetIntelligence()->GetBoatAvoidanceHelper()->SetDesiredOrientation(dirToTargetOrientation);
if ( ShouldUseThreePointTurn(in_Vehicle, vTargetPosition) )
{
SetState(State_ThreePointTurn);
}
else
{
SetState(State_GotoStraightLine);
}
return FSM_Continue;
}
void CTaskVehicleGoToBoat::GotoStraightLine_OnEnter(CVehicle& in_Vehicle)
{
m_fTimeBlocked = 0.0f;
sVehicleMissionParams params = m_Params;
params.m_fTargetArriveDist = sm_Tunables.m_RouteArrivalDistance;
m_RouteFollowHelper.ComputeTarget(params, in_Vehicle);
m_uRunningFlags.ClearFlag(RF_HasUpdatedSegmentThisFrame);
m_uRunningFlags.ClearFlag(RF_HasUpdatedRouteThisFrame);
#if __ASSERT
Vector3 vTargetPosition;
m_Params.GetDominantTargetPosition(vTargetPosition);
Assertf(vTargetPosition.Dist2(ORIGIN) > SMALL_FLOAT, "CTaskVehicleGoToBoat::GotoStraightLine_OnEnter");
#endif // __ASSERT
SetNewTask( rage_new CTaskVehicleGoToPointWithAvoidanceAutomobile(params, true, false));
CBoatAvoidanceHelper * pBoatAvoidHelper = in_Vehicle.GetIntelligence()->GetBoatAvoidanceHelper();
pBoatAvoidHelper->SetMaxAvoidanceOrientationLeft(-CBoatAvoidanceHelper::ms_DefaultMaxAvoidanceOrientation);
pBoatAvoidHelper->SetMaxAvoidanceOrientationRight(CBoatAvoidanceHelper::ms_DefaultMaxAvoidanceOrientation);
}
aiTask::FSM_Return CTaskVehicleGoToBoat::GotoStraightLine_OnUpdate(CVehicle& in_Vehicle)
{
bool bEndState = true;
if ( ( !m_uRunningFlags.IsFlagSet(RF_HasValidRoute) || m_RouteFollowHelper.IsLastSegment() )
&& !CPathServer::IsNavMeshLoadedAtPosition(VEC3V_TO_VECTOR3(in_Vehicle.GetTransform().GetPosition()), kNavDomainRegular)
&& !m_uConfigFlags.IsFlagSet(CF_NeverRoute)
&& !m_uConfigFlags.IsFlagSet(CF_NeverPause))
{
SetState(State_PauseForRoadRoute);
return FSM_Continue;
}
if ( !m_uRunningFlags.IsFlagSet(RF_HasUpdatedRouteThisFrame)
&& !m_uRunningFlags.IsFlagSet(RF_HasUpdatedSegmentThisFrame) )
{
if (GetSubTask() && GetSubTask()->GetTaskType()==CTaskTypes::TASK_VEHICLE_GOTO_POINT_WITH_AVOIDANCE_AUTOMOBILE )
{
bEndState = false;
Vector3 vSegmentTarget;
m_Params.GetDominantTargetPosition(vSegmentTarget);
CTaskVehicleGoToPointWithAvoidanceAutomobile* pTaskVehicleGoToPointWithAvoidanceAutomobile = static_cast<CTaskVehicleGoToPointWithAvoidanceAutomobile*>(GetSubTask());
pTaskVehicleGoToPointWithAvoidanceAutomobile->SetCruiseSpeed(ComputeDesiredSpeed());
pTaskVehicleGoToPointWithAvoidanceAutomobile->SetTargetPosition(&m_RouteFollowHelper.ComputeSegmentTarget(vSegmentTarget, in_Vehicle));
//
// limit boat avoidance when following a valid road route
//
if ( m_uRunningFlags.IsFlagSet(RF_HasValidRoute) )
{
if ( in_Vehicle.GetIntelligence()->GetBoatAvoidanceHelper() )
{
const float fSegmentWidth = m_RouteFollowHelper.ComputeSegmentWidth();
if ( fSegmentWidth > 0.0f )
{
Vec2V vDirection = in_Vehicle.GetVehicleForwardDirectionForDriving().GetXY();
m_RouteFollowHelper.ComputeSegmentDirection(vDirection);
Vec2V vRight = Vec2V(vDirection.GetY(), Negate(vDirection.GetX()));
const Vector3 vStartCoords = VEC3V_TO_VECTOR3(CVehicleFollowRouteHelper::GetVehicleBonnetPosition(GetVehicle(), IsDrivingFlagSet(DF_DriveInReverse)));
Vec2V vBoatPos = VECTOR3_TO_VEC3V(vStartCoords).GetXY();
Vec2V vCurrent = VECTOR3_TO_VEC3V(vSegmentTarget).GetXY();
Vec2V vTargetRight = vCurrent + vRight * ScalarV(fSegmentWidth);
Vec2V vTargetLeft = vCurrent - vRight * ScalarV(fSegmentWidth);
float fDistSqrFromSegment = geomDistances::Distance2LineToPoint(vSegmentTarget, Vector3(vDirection.GetXf(), vDirection.GetYf(), 0.0f), vStartCoords);
//don't limit if we're really far away from our desired segment
if(fDistSqrFromSegment < square(fSegmentWidth*3.0f))
{
// grcDebugDraw::Sphere(Vector3(vTargetRight.GetXf(), vTargetRight.GetYf(), vStartCoords.z), 1.0f, Color_blue, true, -1);
// grcDebugDraw::Sphere(Vector3(vTargetLeft.GetXf(), vTargetLeft.GetYf(), vStartCoords.z), 1.0f, Color_blue, true, -1);
Vec2V vDirToTarget = NormalizeSafe(vCurrent - vBoatPos, vDirection);
Vec2V vDirToLeftTarget = NormalizeSafe(vTargetLeft - vBoatPos, vDirection);
Vec2V vDirToRightTarget = NormalizeSafe(vTargetRight - vBoatPos, vDirection);
ScalarV angleLeft = Angle(vDirToTarget, vDirToLeftTarget);
ScalarV angleRight = Angle(vDirToTarget, vDirToRightTarget);
ScalarV fAngleLeft = FPIsFinite(angleLeft.Getf()) ? (angleLeft * ScalarV(RtoD) * ScalarV(Sign(Dot(vRight, vDirToLeftTarget).Getf()))) : ScalarV(V_ZERO);
ScalarV fAngleRight = FPIsFinite(angleRight.Getf()) ? (angleRight * ScalarV(RtoD) * ScalarV(Sign(Dot(vRight, vDirToRightTarget).Getf()))) : ScalarV(V_ZERO);
in_Vehicle.GetIntelligence()->GetBoatAvoidanceHelper()->SetMaxAvoidanceOrientationLeftThisFrame(fAngleLeft.Getf());
in_Vehicle.GetIntelligence()->GetBoatAvoidanceHelper()->SetMaxAvoidanceOrientationRightThisFrame(fAngleRight.Getf());
}
}
}
}
if ( in_Vehicle.GetIntelligence()->GetBoatAvoidanceHelper() )
{
if ( in_Vehicle.GetIntelligence()->GetBoatAvoidanceHelper()->IsAvoiding() )
{
Vector3 vTargetCoords;
m_Params.GetDominantTargetPosition(vTargetCoords);
const Vector3 vStartCoords = VEC3V_TO_VECTOR3(CVehicleFollowRouteHelper::GetVehicleBonnetPosition(GetVehicle(), IsDrivingFlagSet(DF_DriveInReverse)));
if ( CanUseNavmeshToReachPoint(vStartCoords, vTargetCoords) )
{
// don't go back if we already failed
if (!m_uRunningFlags.IsFlagSet(RF_IsUnableToFindNavPath) )
{
SetState(State_GotoNavmesh);
return FSM_Continue;
}
}
}
if ( ShouldUseThreePointTurn(in_Vehicle, *pTaskVehicleGoToPointWithAvoidanceAutomobile->GetTargetPosition() ) )
{
SetState(State_ThreePointTurn);
return FSM_Continue;
}
else if ( m_fTimeBlocked > s_MaxTimeBlocked )
{
pTaskVehicleGoToPointWithAvoidanceAutomobile->SetCruiseSpeed(Min(ComputeDesiredSpeed(), 5.0f));
}
}
}
}
bool bReachedDestination = HasReachedDestination(in_Vehicle);
if ( bEndState || bReachedDestination )
{
if ( bReachedDestination && !m_uConfigFlags.IsFlagSet(CF_NeverStop) )
{
SetState(State_Stop);
if ( !m_uConfigFlags.IsFlagSet(CF_StopAtEnd) )
{
m_bMissionAchieved = true;
}
}
else
{
m_uRunningFlags.ClearFlag(RF_IsUnableToFindNavPath);
SetFlag(aiTaskFlags::RestartCurrentState);
}
}
return FSM_Continue;
}
void CTaskVehicleGoToBoat::GotoNavmesh_OnEnter(CVehicle& in_Vehicle)
{
m_fTimeBlocked = 0.0f;
sVehicleMissionParams params = m_Params;
params.m_fTargetArriveDist = sm_Tunables.m_RouteArrivalDistance;
m_RouteFollowHelper.ComputeTarget(params, in_Vehicle);
SetNewTask(rage_new CTaskVehicleGoToNavmesh(params));
static float s_MaxAvoidanceAngle = 45.0f;
CBoatAvoidanceHelper * pBoatAvoidHelper = in_Vehicle.GetIntelligence()->GetBoatAvoidanceHelper();
pBoatAvoidHelper->SetMaxAvoidanceOrientationLeft(-s_MaxAvoidanceAngle);
pBoatAvoidHelper->SetMaxAvoidanceOrientationRight(s_MaxAvoidanceAngle);
}
aiTask::FSM_Return CTaskVehicleGoToBoat::GotoNavmesh_OnUpdate(CVehicle& in_Vehicle)
{
bool bEndState = true;
if ( ( !m_uRunningFlags.IsFlagSet(RF_HasValidRoute) || m_RouteFollowHelper.IsLastSegment() )
&& !CPathServer::IsNavMeshLoadedAtPosition(VEC3V_TO_VECTOR3(in_Vehicle.GetTransform().GetPosition()), kNavDomainRegular)
&& !m_uConfigFlags.IsFlagSet(CF_NeverRoute)
&& !m_uConfigFlags.IsFlagSet(CF_NeverPause))
{
SetState(State_PauseForRoadRoute);
return FSM_Continue;
}
if ( !m_uRunningFlags.IsFlagSet(RF_HasUpdatedRouteThisFrame)
&& !m_uRunningFlags.IsFlagSet(RF_HasUpdatedSegmentThisFrame) )
{
if (GetSubTask() && GetSubTask()->GetTaskType()==CTaskTypes::TASK_VEHICLE_GOTO_NAVMESH)
{
CTaskVehicleGoToNavmesh* pNavmeshTask = static_cast<CTaskVehicleGoToNavmesh*>(GetSubTask());
bEndState = false;
Vector3 vTargetPos = pNavmeshTask->GetClosestPointFoundToTarget();
pNavmeshTask->SetCruiseSpeed(ComputeDesiredSpeed());
pNavmeshTask->SetTargetPosition(&vTargetPos);
if ( m_RouteFollowHelper.IsLastSegment() )
{
// @TODO: How does this work with an entity target?
m_RouteFollowHelper.OverrideTarget(vTargetPos);
m_Params.SetTargetPosition(vTargetPos);
}
if ( pNavmeshTask->GetSubTask() && pNavmeshTask->GetSubTask()->GetTaskType()==CTaskTypes::TASK_VEHICLE_GOTO_POINT_WITH_AVOIDANCE_AUTOMOBILE )
{
CTaskVehicleGoToPointWithAvoidanceAutomobile* pGotoTask = static_cast<CTaskVehicleGoToPointWithAvoidanceAutomobile*>(pNavmeshTask->GetSubTask());
if ( ShouldUseThreePointTurn(in_Vehicle, *pGotoTask->GetTargetPosition() ) )
{
if ( !m_RouteFollowHelper.IsLastSegment() || !m_uConfigFlags.IsFlagSet(CF_ForceBeached) )
{
SetState(State_ThreePointTurn);
}
}
}
if ( HasReachedDestination(in_Vehicle) && !m_uConfigFlags.IsFlagSet(CF_NeverStop))
{
SetState(State_Stop);
}
}
if (bEndState)
{
m_uRunningFlags.SetFlag(RF_IsUnableToFindNavPath);
if ( m_RouteFollowHelper.IsLastSegment() )
{
if ( m_Params.m_fTargetArriveDist > 0.0f )
{
m_Params.m_fTargetArriveDist += in_Vehicle.GetBoundRadius();
}
}
SetState(State_GotoStraightLine);
}
}
return FSM_Continue;
}
void CTaskVehicleGoToBoat::GotoNavmesh_OnExit(CVehicle& in_Vehicle)
{
in_Vehicle.GetIntelligence()->GetBoatAvoidanceHelper()->SetMaxAvoidanceOrientationLeft(-CBoatAvoidanceHelper::ms_DefaultMaxAvoidanceOrientation);
in_Vehicle.GetIntelligence()->GetBoatAvoidanceHelper()->SetMaxAvoidanceOrientationRight(CBoatAvoidanceHelper::ms_DefaultMaxAvoidanceOrientation);
//GetVehicle()->GetIntelligence()->GetBoatAvoidanceHelper()->SetSteeringEnabled(true);
//GetVehicle()->GetIntelligence()->GetBoatAvoidanceHelper()->SetAvoidanceFeelerScale(1.0f);
}
static float s_BackupAngle = 80.0f;
static float s_BackupDistance = 25.0f;
static float s_BackupSpeed = 15.0f;
void CTaskVehicleGoToBoat::ThreePointTurn_OnEnter(CVehicle& in_Vehicle)
{
m_bWasBlockedForThreePointTurn = m_fTimeBlocked > s_MaxTimeBlocked;
m_fTimeBlocked = 0.0f;
in_Vehicle.GetIntelligence()->GetBoatAvoidanceHelper()->SetReverse(true);
in_Vehicle.GetIntelligence()->GetBoatAvoidanceHelper()->SetSlowDownEnabled(false);
//in_Vehicle.GetIntelligence()->GetBoatAvoidanceHelper()->SetSteeringEnabled(false);
sVehicleMissionParams params = m_Params;
Vector3 vTargetPosition;
m_Params.GetDominantTargetPosition(vTargetPosition);
const Vector3 vStartCoords = VEC3V_TO_VECTOR3(CVehicleFollowRouteHelper::GetVehicleBonnetPosition(GetVehicle(), IsDrivingFlagSet(DF_DriveInReverse)));
const Vector3 vBoatFwd = VEC3V_TO_VECTOR3(in_Vehicle.GetTransform().GetForward());
const Vector3 vBoatRight = VEC3V_TO_VECTOR3(in_Vehicle.GetTransform().GetRight());
Vector3 vBoatBack = -vBoatFwd;
Vector3 vDestination;
m_Params.GetDominantTargetPosition(vDestination);
m_RouteFollowHelper.ComputeTarget(vDestination, in_Vehicle);
Vector3 vDirectionToTarget = vDestination - vStartCoords;
vDirectionToTarget.z = 0.0f;
vDirectionToTarget.NormalizeSafe();
float fBackupAngle = s_BackupAngle;
if ( vBoatRight.Dot(vDirectionToTarget) > 0.0f )
{
fBackupAngle = -fBackupAngle;
}
vBoatBack.RotateZ(fBackupAngle * DtoR);
float dirToTargetOrientation = fwAngle::GetATanOfXY(vBoatBack.x, vBoatBack.y);
dirToTargetOrientation = fwAngle::LimitRadianAngleSafe(dirToTargetOrientation);
in_Vehicle.GetIntelligence()->GetBoatAvoidanceHelper()->SetAvoidanceOrientation(dirToTargetOrientation);
in_Vehicle.GetIntelligence()->GetBoatAvoidanceHelper()->SetDesiredOrientation(dirToTargetOrientation);
params.m_fCruiseSpeed = s_BackupSpeed;
params.SetTargetPosition(vStartCoords + vBoatBack * s_BackupDistance);
params.m_fTargetArriveDist = 5.0f;
params.m_iDrivingFlags.SetFlag(DF_DriveInReverse);
SetNewTask( rage_new CTaskVehicleGoToPointWithAvoidanceAutomobile(params, true, false));
}
aiTask::FSM_Return CTaskVehicleGoToBoat::ThreePointTurn_OnUpdate(CVehicle& in_Vehicle)
{
if (GetSubTask() && GetSubTask()->GetTaskType()==CTaskTypes::TASK_VEHICLE_GOTO_POINT_WITH_AVOIDANCE_AUTOMOBILE )
{
CTaskVehicleGoToPointWithAvoidanceAutomobile* pTaskVehicleGoToPointWithAvoidanceAutomobile = static_cast<CTaskVehicleGoToPointWithAvoidanceAutomobile*>(GetSubTask());
const Vector3 vStartCoords = VEC3V_TO_VECTOR3(CVehicleFollowRouteHelper::GetVehicleBonnetPosition(GetVehicle(), IsDrivingFlagSet(DF_DriveInReverse)));
const Vector3 vBoatFwd = VEC3V_TO_VECTOR3(in_Vehicle.GetTransform().GetForward());
const Vector3 vBoatRight = VEC3V_TO_VECTOR3(in_Vehicle.GetTransform().GetRight());
Vector3 vBoatBack = -vBoatFwd;
Vector3 vDestination;
m_Params.GetDominantTargetPosition(vDestination);
m_RouteFollowHelper.ComputeTarget(vDestination, in_Vehicle);
Vector3 vDirectionToTarget = vDestination - vStartCoords;
vDirectionToTarget.z = 0.0f;
vDirectionToTarget.NormalizeSafe();
float fBackupAngle = s_BackupAngle;
if ( vBoatRight.Dot(vDirectionToTarget) > 0.0f )
{
fBackupAngle = -fBackupAngle;
}
vBoatBack.RotateZ(fBackupAngle * DtoR);
Vector3 vTargetPosition = vStartCoords + vBoatBack * s_BackupDistance;
pTaskVehicleGoToPointWithAvoidanceAutomobile->SetTargetPosition(&vTargetPosition);
pTaskVehicleGoToPointWithAvoidanceAutomobile->SetCruiseSpeed(s_BackupSpeed);
float fAngleToStopThreePointTurn = m_uConfigFlags.IsFlagSet(CF_PreferForward) ? 0.1f : s_AngleToStopThreePointTurn;
bool bCanGoForward = vDirectionToTarget.Dot(vBoatFwd) > fAngleToStopThreePointTurn;
if(m_bWasBlockedForThreePointTurn)
{
bCanGoForward = GetTimeInState() > 2.0f;
}
if ( bCanGoForward || m_fTimeBlocked > s_MaxTimeBlocked )
{
static float s_TimeToBlockThreePointTurn = 3.0f;
m_fTimeBlockThreePointTurn = s_TimeToBlockThreePointTurn;
SetState(State_GotoStraightLine);
}
if ( HasReachedDestination(in_Vehicle) && !m_uConfigFlags.IsFlagSet(CF_NeverStop))
{
SetState(State_Stop);
}
}
else
{
SetState(State_GotoStraightLine);
}
return FSM_Continue;
}
void CTaskVehicleGoToBoat::ThreePointTurn_OnExit(CVehicle& in_Vehicle)
{
in_Vehicle.GetIntelligence()->GetBoatAvoidanceHelper()->SetReverse(false);
in_Vehicle.GetIntelligence()->GetBoatAvoidanceHelper()->SetSlowDownEnabled(true);
const Vector3 vStartCoords = VEC3V_TO_VECTOR3(CVehicleFollowRouteHelper::GetVehicleBonnetPosition(GetVehicle(), IsDrivingFlagSet(DF_DriveInReverse)));
Vector3 vTargetPosition;
m_Params.GetDominantTargetPosition(vTargetPosition);
Vector3 vDirectionToTarget = vTargetPosition - vStartCoords;
vDirectionToTarget.z = 0.0f;
vDirectionToTarget.NormalizeSafe();
float dirToTargetOrientation = fwAngle::GetATanOfXY(vDirectionToTarget.x, vDirectionToTarget.y);
dirToTargetOrientation = fwAngle::LimitRadianAngleSafe(dirToTargetOrientation);
in_Vehicle.GetIntelligence()->GetBoatAvoidanceHelper()->SetAvoidanceOrientation(dirToTargetOrientation);
in_Vehicle.GetIntelligence()->GetBoatAvoidanceHelper()->SetDesiredOrientation(dirToTargetOrientation);
//in_Vehicle.GetIntelligence()->GetBoatAvoidanceHelper()->SetSteeringEnabled(true);
}
void CTaskVehicleGoToBoat::PauseForRoadRoute_OnEnter(CVehicle& UNUSED_PARAM(in_Vehicle))
{
SetNewTask(rage_new CTaskVehicleStop());
}
aiTask::FSM_Return CTaskVehicleGoToBoat::PauseForRoadRoute_OnUpdate(CVehicle& in_Vehicle)
{
if ( (m_uRunningFlags.IsFlagSet(RF_HasValidRoute) && !m_RouteFollowHelper.IsLastSegment())
|| CPathServer::IsNavMeshLoadedAtPosition(VEC3V_TO_VECTOR3(in_Vehicle.GetTransform().GetPosition()), kNavDomainRegular))
{
SetState(State_GotoStraightLine);
return FSM_Continue;
}
return FSM_Continue;
}
void CTaskVehicleGoToBoat::Stop_OnEnter()
{
SetNewTask(rage_new CTaskVehicleStop());
}
aiTask::FSM_Return CTaskVehicleGoToBoat::Stop_OnUpdate()
{
if (GetIsSubtaskFinished(CTaskTypes::TASK_VEHICLE_STOP))
{
m_bMissionAchieved = true;
return FSM_Quit;
}
return FSM_Continue;
}
bool CTaskVehicleGoToBoat::HasReachedDestination(CVehicle& in_Vehicle) const
{
const Vector3 vStartCoords = VEC3V_TO_VECTOR3(CVehicleFollowRouteHelper::GetVehicleBonnetPosition(&in_Vehicle, IsDrivingFlagSet(DF_DriveInReverse)));
if ( m_Params.m_fTargetArriveDist > 0 )
{
Vector3 vTargetPosition;
m_Params.GetDominantTargetPosition(vTargetPosition);
if ( (vTargetPosition - vStartCoords).XYMag2() < square(m_Params.m_fTargetArriveDist) )
{
return true;
}
}
return false;
}
float CTaskVehicleGoToBoat::ComputeDesiredSpeed() const
{
const Vector3 vStartCoords = VEC3V_TO_VECTOR3(CVehicleFollowRouteHelper::GetVehicleBonnetPosition(GetVehicle(), IsDrivingFlagSet(DF_DriveInReverse)));
Vector3 vTargetPosition;
m_Params.GetDominantTargetPosition(vTargetPosition);
const Vector3 vDelta = vTargetPosition - vStartCoords;
float scalar = Min(vDelta.XYMag() / sm_Tunables.m_SlowdownDistance, 1.0f);
return m_Params.m_fCruiseSpeed * scalar;
}
bool CTaskVehicleGoToBoat::CanUseNavmeshToReachPoint(const Vector3& in_vStartCoords, const Vector3& in_vTargetCoords ) const
{
if ( !m_uConfigFlags.IsFlagSet(CF_NeverNavMesh) )
{
if (CPathServer::IsNavMeshLoadedAtPosition(in_vStartCoords, kNavDomainRegular)
&& CPathServer::IsNavMeshLoadedAtPosition(in_vTargetCoords, kNavDomainRegular))
{
return true;
}
}
return false;
}
#if !__FINAL
const char* CTaskVehicleGoToBoat::GetStaticStateName( s32 iState )
{
Assert(iState>=State_Init&&iState<=State_Stop);
static const char* aStateNames[] =
{
"State_Init",
"State_GotoStraightLine",
"State_GotoNavmesh",
"State_ThreePointTurn",
"State_PauseForRoadRoute",
"State_Stop",
};
return aStateNames[iState];
}
void CTaskVehicleGoToBoat::Debug() const
{
#if DEBUG_DRAW
Vector3 vTargetPosition;
m_Params.GetDominantTargetPosition(vTargetPosition);
const Vector3 vStartCoords = VEC3V_TO_VECTOR3(CVehicleFollowRouteHelper::GetVehicleBonnetPosition(GetVehicle(), IsDrivingFlagSet(DF_DriveInReverse)));
grcDebugDraw::Sphere(vStartCoords + ZAXIS, 0.5f, Color_green, false);
grcDebugDraw::Sphere(vTargetPosition + ZAXIS, Max(m_Params.m_fTargetArriveDist, 0.5f), Color_green, false);
grcDebugDraw::Arrow(VECTOR3_TO_VEC3V(vStartCoords + ZAXIS), VECTOR3_TO_VEC3V(vTargetPosition + ZAXIS), 1.0f, Color_OrangeRed);
m_RouteFollowHelper.Debug(*GetVehicle());
#endif
}
#endif //!__FINAL