793 lines
28 KiB
C++
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
|
|
|
|
|