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

689 lines
22 KiB
C++

//
// PlaneChase
// Designed for following some sort of entity
//
// File header
#include "TaskVehiclePlaneChase.h"
// Game headers
#include "grcore/debugdraw.h"
#include "math/angmath.h"
#include "Peds/Ped.h"
#include "Peds/PedIntelligence.h"
#include "task/Vehicle/TaskCar.h"
#include "vehicleAi/VehicleIntelligence.h"
#include "vehicleAi/task/TaskVehicleGoToPlane.h"
#include "Vehicles/planes.h"
#include "Vehicles/vehicle.h"
VEHICLE_OPTIMISATIONS()
AI_OPTIMISATIONS()
AI_VEHICLE_OPTIMISATIONS()
//=========================================================================
// CTaskVehiclePlaneChase
//=========================================================================
CTaskVehiclePlaneChase::Tunables CTaskVehiclePlaneChase::sm_Tunables;
IMPLEMENT_VEHICLE_AI_TASK_TUNABLES(CTaskVehiclePlaneChase, 0x2deab7c0);
static float s_fSlowTargetSpeedThreshold = 25.0f;
//static float s_fSlowTargetDistanceThreshold = 500.0f;
static float s_fMinSpeedSlowTargets = 60.0f;
static float s_fMinSpeedSlowTargetsNetwork = 40.0f;
static float s_MinRadiusPadding = 75.0f;
CTaskVehiclePlaneChase::CTaskVehiclePlaneChase(const sVehicleMissionParams& params, const CAITarget& rTarget)
: CTaskVehicleGoTo(params)
, m_Target(rTarget)
, m_bWasDiveBombingLastFrame(false)
, m_fTimeBeingPursued(0)
, m_fTargetAvgSpeed(0)
{
// mission params mostly use cruise speed so lets base min and max on that
// not the best but unless I want scripters to redo the game it's what we have
static float s_CruiseSpeedWindowMin = 0.4f;
m_fMinSpeed = Max(sm_Tunables.MinSpeed, params.m_fCruiseSpeed * s_CruiseSpeedWindowMin );
m_fMaxSpeed = sm_Tunables.MaxSpeed;
Vec3V vTargetVelocity = CalculateTargetVelocity();
m_fTargetAvgSpeed = Mag(vTargetVelocity).Getf();
SetInternalTaskType(CTaskTypes::TASK_VEHICLE_PLANE_CHASE);
}
CTaskVehiclePlaneChase::~CTaskVehiclePlaneChase()
{
}
void CTaskVehiclePlaneChase::SetMinChaseSpeed(float in_Speed)
{
m_fMinSpeed = in_Speed;
}
void CTaskVehiclePlaneChase::SetMaxChaseSpeed(float in_Speed)
{
m_fMaxSpeed = in_Speed;
}
const CEntity* CTaskVehiclePlaneChase::GetTargetEntity() const
{
//Ensure the target is valid.
if(!m_Target.GetIsValid())
{
return NULL;
}
return m_Target.GetEntity();
}
CTask::FSM_Return CTaskVehiclePlaneChase::ProcessPreFSM()
{
//Ensure the target entity is valid.
if(!m_Target.GetIsValid())
{
return FSM_Quit;
}
//SPARR have this enabled by default in the future
if(GetVehicle()->GetDriver() && GetVehicle()->GetDriver()->GetPedIntelligence()->GetCombatBehaviour().IsFlagSet(CCombatData::BF_AllowDogFighting))
{
UpdateTargetPursuingUs();
}
return FSM_Continue;
}
CTask::FSM_Return CTaskVehiclePlaneChase::UpdateFSM(const s32 iState, const FSM_Event iEvent)
{
FSM_Begin
FSM_State(State_Start)
FSM_OnUpdate
return Start_OnUpdate();
FSM_State(State_Pursue)
FSM_OnEnter
Pursue_OnEnter();
FSM_OnUpdate
return Pursue_OnUpdate();
FSM_State(State_EscapePursuer)
FSM_OnEnter
EscapePursuer_OnEnter();
FSM_OnUpdate
return EscapePursuer_OnUpdate();
FSM_OnExit
EscapePursuer_OnExit();
FSM_State(State_Finish)
FSM_OnUpdate
return FSM_Quit;
FSM_End
}
CTask::FSM_Return CTaskVehiclePlaneChase::Start_OnUpdate()
{
//Move to the pursue state.
SetState(State_Pursue);
return FSM_Continue;
}
bool CTaskVehiclePlaneChase::IsTargetInAir() const
{
//Grab the target entity.
const CEntity* pTargetEntity = GetTargetEntity();
if ( pTargetEntity )
{
if ( pTargetEntity->GetIsTypePed() )
{
const CPed* pPed = static_cast<const CPed*>(pTargetEntity);
const CVehicle* pVehicle = pPed->GetVehiclePedInside();
if ( pVehicle )
{
return const_cast<CVehicle*>(pVehicle)->IsInAir();
}
}
else if ( pTargetEntity->GetIsTypeVehicle() )
{
const CVehicle* pVehicle = static_cast<const CVehicle*>(pTargetEntity);
return const_cast<CVehicle*>(pVehicle)->IsInAir();
}
}
return false;
}
float ComputeFlightLengthToTarget(CPlane& in_Plane, Vec3V_In in_Target, float in_Radius )
{
Vec2V vTargetPos = in_Target.GetXY();
Vec2V vPlanePos = in_Plane.GetVehiclePosition().GetXY();
Vec2V vPlaneRight = in_Plane.GetTransform().GetA().GetXY();
vPlaneRight = Normalize(vPlaneRight);
Vec2V vCircleCenter = vPlanePos + ( vPlaneRight * ScalarV(-in_Radius));
Vec2V vCircleCenterToPlane = vPlanePos - vCircleCenter;
Vec2V vCircleCenterToTarget = vTargetPos - vCircleCenter;
float theta1 = Atan2f(vCircleCenterToPlane.GetYf(), vCircleCenterToPlane.GetXf());
float theta2 = Atan2f(vCircleCenterToTarget.GetYf(), vCircleCenterToTarget.GetXf());
float theta = fabs(SubtractAngleShorter(theta1, theta2));
float arcLength = TWO_PI * fabs(in_Radius) * (theta / (TWO_PI));
float distance = arcLength;
return distance;
}
float ComputeTimeToTarget(CPlane& in_Plane, Vec3V_In in_Target, float in_Radius, float in_Speed )
{
if ( in_Speed > 0 )
{
float distance = ComputeFlightLengthToTarget(in_Plane, in_Target, in_Radius );
float time = distance / in_Speed;
return time;
}
// some big value to represent we will never catchup
return 10000000.0f;
}
float NormalDot(Vec3V_In in_a, Vec3V_In in_b)
{
return ((Dot(in_a, in_b) + ScalarV(V_ONE)) * ScalarV(V_HALF)).Getf();
}
float PositiveDot(Vec3V_In in_a, Vec3V_In in_b)
{
return (Clamp( Dot(in_a, in_b), ScalarV(V_ZERO), ScalarV(V_ONE))).Getf();
}
void CTaskVehiclePlaneChase::Pursue_OnEnter()
{
//Create the params.
sVehicleMissionParams params;
params.SetTargetEntity(const_cast<CEntity *>(GetTargetEntity()));
params.SetTargetPosition(VEC3V_TO_VECTOR3(CalculateTargetPosition()));
params.m_iDrivingFlags = DF_DontTerminateTaskWhenAchieved|DF_TargetPositionOverridesEntity;
params.m_fTargetArriveDist = 0.0f;
params.m_fCruiseSpeed = 20.0f;
CTaskVehicleGoToPlane* pVehicleTask = rage_new CTaskVehicleGoToPlane(params);
pVehicleTask->SetMaxThrottle(10.0f); // chase gets more throttle so it can catch up
SetNewTask(pVehicleTask);
m_PreviousTargetPosition = params.GetTargetPosition();
}
CTask::FSM_Return CTaskVehiclePlaneChase::Pursue_OnUpdate()
{
if(m_fTimeBeingPursued > 3.0f)
{
SetState(State_EscapePursuer);
return FSM_Continue;
}
//Ensure the active task is valid.
CTaskVehicleGoToPlane* pTask = static_cast<CTaskVehicleGoToPlane*>(GetSubTask());
if(pTask)
{
CPlane* pPlane = static_cast<CPlane*>(GetVehicle());
// CPlane* plane = static_cast<CPlane*>(GetVehicle());
// plane->SetDesiredVerticalFlightModeRatio(0.0f);
Vec3V vTargetPosition = CalculateTargetPosition();
Vec3V vTargetFuturePosition = CalculateTargetFuturePosition();
Vec3V vTargetVelocity = CalculateTargetVelocity();
Vec3V vPlanePos = pPlane->GetVehiclePosition();
Vec3V vPlaneFwd = pPlane->GetTransform().GetB();
Vec3V vPlaneToTarget = vTargetPosition-vPlanePos;
Vec3V vDirPlaneToTarget = Normalize(vPlaneToTarget);
ScalarV vTargetSpeed = Mag(vTargetVelocity);
ScalarV vPlaneSpeed = ScalarV(pPlane->GetVelocity().Mag());
ScalarV vDistanceToTargetXY = MagXY(vPlaneToTarget);
// smooth the avg speed over time
m_fTargetAvgSpeed = (vTargetSpeed.Getf() * .1f + m_fTargetAvgSpeed * .9f);
// tweak different between single/multiplayer
bool bTargetIsSlow = NetworkInterface::IsGameInProgress() ? m_fTargetAvgSpeed < s_fSlowTargetSpeedThreshold : vTargetSpeed.Getf() < s_fSlowTargetSpeedThreshold;
float fSlowMinSpeed = NetworkInterface::IsGameInProgress() ? s_fMinSpeedSlowTargetsNetwork : s_fMinSpeedSlowTargets;
float fTurnRadiusPadding = !bTargetIsSlow ? s_MinRadiusPadding : m_Params.m_fTargetArriveDist/2.0f;
float fMinSpeed = bTargetIsSlow ? fSlowMinSpeed : m_fMinSpeed;
//don't go less than half our minimum air speed, as it just looks really stupid
fMinSpeed = rage::Max(fMinSpeed, CTaskVehicleGoToPlane::GetMinAirSpeed(pPlane) * 0.5f);
Vec3V vTargetDirection = !bTargetIsSlow ? Normalize(vTargetVelocity) : vDirPlaneToTarget;
#if !__FINAL
m_fComputedMinSpeed = fMinSpeed;
#endif // !__FINAL
Vector3 modifiedTargetPosition = VEC3V_TO_VECTOR3(vTargetPosition);
float maxRoll = CTaskVehicleGoToPlane::ComputeMaxRollForPitch(pTask->GetDesiredPitch(), pTask->GetMaxRoll());
float fDesiredSpeed = fMinSpeed;
if ( (MagXY(vTargetDirection) >= ScalarV(0.0f)).Getb() )
{
if ( CTaskVehicleGoToPlane::ComputeApproachTangentPosition(modifiedTargetPosition, pPlane, VEC3V_TO_VECTOR3(vTargetFuturePosition), VEC3V_TO_VECTOR3(vTargetDirection), fDesiredSpeed, maxRoll, true, false) )
{
static float s_SpeedMatchTime = 8.0f;
static float s_AngleToAccelerate = 15.0f;
static float s_SpeedMatchDistance = 40.0f;
Vec3V vPlaneModifiedTarget = VECTOR3_TO_VEC3V(modifiedTargetPosition);
Vec3V vPlaneToModifiedTarget = vPlaneModifiedTarget-vPlanePos;
Vec3V vDirPlaneToModifiedTarget = Normalize(vPlaneToModifiedTarget);
float fRadiusToLocalTarget = CTaskVehicleGoToPlane::ComputeTurnRadiusForTarget(pPlane, VEC3V_TO_VECTOR3(vPlaneModifiedTarget), 0.0f );
float fMaxSpeed = CTaskVehicleGoToPlane::ComputeSpeedForRadiusAndRoll(*pPlane, fabsf(fRadiusToLocalTarget), maxRoll);
float fPosDotToTarget = PositiveDot(vDirPlaneToTarget, vPlaneFwd);
float fPosDotToModifiedTarget = PositiveDot( vDirPlaneToModifiedTarget, vPlaneFwd);
float fTValueMinMaxSpeed = Clamp( (fPosDotToTarget * fPosDotToModifiedTarget) / cos(s_AngleToAccelerate * DtoR), 0.0f, 1.0f);
float fTimeToTarget = ComputeTimeToTarget(*pPlane, vPlaneModifiedTarget, fRadiusToLocalTarget, vPlaneSpeed.Getf() - vTargetSpeed.Getf() );
float fDesiredSpeedMinMax = Lerp(fTValueMinMaxSpeed, fMinSpeed, fMaxSpeed);
float fSpeedMatchTValue = Clamp( fTimeToTarget / s_SpeedMatchTime, 0.0f, 1.0f);
fDesiredSpeed = Min( Lerp(fSpeedMatchTValue, vTargetSpeed.Getf(), fDesiredSpeedMinMax), fDesiredSpeedMinMax );
fDesiredSpeed = Clamp(fDesiredSpeed, fMinSpeed, m_fMaxSpeed);
if ( vDistanceToTargetXY.Getf() > s_SpeedMatchDistance && fTimeToTarget > s_SpeedMatchTime )
{
// don't do thrust falloff. Let our plane catch up
pPlane->SetEnableThrustFallOffThisFrame(false);
}
}
// do dive bomb logic
bool bWasDiveBombingLastFrame = m_bWasDiveBombingLastFrame;
m_bWasDiveBombingLastFrame = false;
if ( !IsTargetInAir() )
{
static float s_fMaxDistanceToDiveBomb = 1000.0f;
float xyDist = vDistanceToTargetXY.Getf();
if ( xyDist <= s_fMaxDistanceToDiveBomb )
{
static int s_MaxHeight = 120;
static int s_MinHeight = 15;
static float s_ForwardThreshold = 0.707f;
//static float s_SlopeThreshold = -0.2f;
pTask->SetMinHeightAboveTerrain(s_MaxHeight);
modifiedTargetPosition.z += s_MaxHeight;
// dive bomb chase
if ( Dot(vDirPlaneToTarget, vPlaneFwd).Getf() >= s_ForwardThreshold )
{
m_bWasDiveBombingLastFrame = true;
//sparr - don't do this it causes planes not to avoid terrain
//pTask->SetAvoidTerrainMaxZThisFrame(false);
float zDelta = ( vPlaneToTarget.GetZf() + s_MinHeight );
if ( xyDist > 0 || bWasDiveBombingLastFrame )
{
if ( bWasDiveBombingLastFrame || zDelta / xyDist )
{
modifiedTargetPosition.z -= s_MaxHeight;
modifiedTargetPosition.z += s_MinHeight;
pTask->SetMinHeightAboveTerrain(s_MinHeight);
}
}
}
}
}
}
static float s_fWeight = 2.0f;
float tValue = Clamp(GetTimeStep() * s_fWeight, 0.0f, 1.0f);
m_PreviousTargetPosition = Lerp(tValue, m_PreviousTargetPosition, modifiedTargetPosition);
m_PreviousTargetPosition = VEC3V_TO_VECTOR3(Clamp(VECTOR3_TO_VEC3V(m_PreviousTargetPosition), Vec3V(WORLDLIMITS_XMIN, WORLDLIMITS_YMIN,WORLDLIMITS_ZMIN), Vec3V(WORLDLIMITS_XMAX,WORLDLIMITS_YMAX,WORLDLIMITS_ZMAX)));
pTask->SetTargetPosition(&m_PreviousTargetPosition);
pTask->SetCruiseSpeed(Min(fDesiredSpeed, CTaskVehicleMissionBase::MAX_CRUISE_SPEED - 1.0f));
pTask->SetMinTurnRadiusPadding(fTurnRadiusPadding);
}
//Check if the sub-task has finished.
if(GetIsFlagSet(aiTaskFlags::SubTaskFinished))
{
//Finish the task.
SetState(State_Finish);
}
return FSM_Continue;
}
//very basic system to make us get out of being pursued
//would be nice to turn this into a dog fighting system in the future
void CTaskVehiclePlaneChase::UpdateTargetPursuingUs()
{
const CVehicle* pTargetVehicle = GetTargetVehicle();
if ( pTargetVehicle )
{
if(pTargetVehicle->InheritsFromPlane() && pTargetVehicle->IsInAir())
{
Vec3V vTargetPos = pTargetVehicle->GetTransform().GetPosition();
Vec3V vOurPos = GetVehicle()->GetTransform().GetPosition();
//within 200 meters
//if(IsLessThanAll(DistSquared(vTargetPos, vOurPos), ScalarV(40000.0f)))
{
Vec3V vOurForward = GetVehicle()->GetTransform().GetForward();
Vec3V vTargetToUs = vOurPos - vTargetPos;
vTargetToUs = Normalize(vTargetToUs);
ScalarV fPosDot = Dot(vTargetToUs, vOurForward);
//in front of target and orientations similar
Vec3V vTargetForward = pTargetVehicle->GetTransform().GetForward();
ScalarV fForwardDot = Dot(vTargetForward, vOurForward);
if(IsGreaterThanAll(fForwardDot, ScalarV(0.8f)) && IsGreaterThanAll(fPosDot, ScalarV(0.8f)))
{
//velocities similar
float fTargetSpeed = pTargetVehicle->GetAiXYSpeed();
float fOurSpeed = GetVehicle()->GetAiXYSpeed();
if(Abs(fOurSpeed - fTargetSpeed) < 20.0f)
{
m_fTimeBeingPursued += fwTimer::GetTimeStep();
return;
}
}
}
}
}
m_fTimeBeingPursued = 0.0f;
}
Vec3V_Out CTaskVehiclePlaneChase::CalculateTargetPosition() const
{
Vector3 targetPosition;
m_Target.GetPosition(targetPosition);
Vec3V vTargetPosition = VECTOR3_TO_VEC3V(targetPosition);
return vTargetPosition;
}
const CVehicle* CTaskVehiclePlaneChase::GetTargetVehicle() const
{
const CVehicle* pVehicle = NULL;
const CEntity* pTargetEntity = GetTargetEntity();
if ( pTargetEntity )
{
if ( pTargetEntity->GetIsTypePed() )
{
const CPed* pPed = static_cast<const CPed*>(pTargetEntity);
pVehicle = pPed->GetVehiclePedInside();
}
if ( pTargetEntity->GetIsTypeVehicle() )
{
pVehicle = static_cast<const CVehicle*>(pTargetEntity);
}
}
return pVehicle;
};
Vec3V_Out CTaskVehiclePlaneChase::CalculateTargetFuturePosition(float in_fTimeAhead) const
{
Vector3 targetPosition;
m_Target.GetPosition(targetPosition);
Vec3V vTargetPosition = VECTOR3_TO_VEC3V(targetPosition);
Vec3V vTargetVelocity = CalculateTargetVelocity();
const CVehicle* pTargetVehicle = GetTargetVehicle();
bool bLinearProjection = true;
if ( pTargetVehicle )
{
if ( pTargetVehicle && const_cast<CVehicle*>(pTargetVehicle)->IsInAir() && pTargetVehicle->InheritsFromPlane() )
{
const CPlane* pPlane = static_cast<const CPlane*>(pTargetVehicle);
float fPlaneRoll = pTargetVehicle->GetTransform().GetRoll() * RtoD;
float fPlaneSpeed = Mag(vTargetVelocity).Getf();
float fTurnRadius = CTaskVehicleGoToPlane::ComputeTurnRadiusForRoll(pPlane, fPlaneSpeed, fPlaneRoll );
if ( fabsf(fTurnRadius) > 0.0f )
{
Vector3 vPlanePos = VEC3V_TO_VECTOR3(vTargetPosition);
Vector3 vPlaneRight = VEC3V_TO_VECTOR3(pPlane->GetTransform().GetA());
vPlaneRight.z = 0;
vPlaneRight.Normalize();
Vector3 vCircleCenter = vPlanePos + ( vPlaneRight * -fTurnRadius);
Vector3 vCircleCenterToPlane = vPlanePos - vCircleCenter;
float angleToPlane = Atan2f(vCircleCenterToPlane.y, vCircleCenterToPlane.x) * RtoD;
// using arclength equation to get angle
// arclength = 2 * PI * radius * (angle/360.0f)
float arclengh = fPlaneSpeed * in_fTimeAhead;
float relAngle = (360.0f * arclengh) / ( 2 * PI * fTurnRadius);
// convert local angle to world
float angle = fmod(relAngle + angleToPlane, 360.0f);
// compute offset given the angle, radius and center of the circle
Vector3 vOffsetWorld = Vector3::ZeroType;
vOffsetWorld.x = rage::Cosf(angle * DtoR) * fabsf(fTurnRadius);
vOffsetWorld.y = rage::Sinf(angle * DtoR) * fabsf(fTurnRadius);
vTargetPosition = VECTOR3_TO_VEC3V(vCircleCenter + vOffsetWorld);
}
bLinearProjection = false;
}
}
if ( bLinearProjection )
{
vTargetPosition += vTargetVelocity * ScalarV(in_fTimeAhead);
}
return vTargetPosition;
}
Vec3V_Out CTaskVehiclePlaneChase::CalculateTargetVelocity() const
{
//Grab the target entity.
const CEntity* pTargetEntity = GetTargetEntity();
if ( pTargetEntity )
{
if ( pTargetEntity->GetIsTypePed() )
{
const CPed* pPed = static_cast<const CPed*>(pTargetEntity);
const CVehicle* pVehicle = pPed->GetVehiclePedInside();
if ( pVehicle )
{
return VECTOR3_TO_VEC3V(pVehicle->GetVelocity());
}
return VECTOR3_TO_VEC3V(pPed->GetVelocity());
}
if ( pTargetEntity->GetIsPhysical() )
{
const CPhysical* pTargetPhysical = static_cast<const CPhysical*>(pTargetEntity);
return VECTOR3_TO_VEC3V(pTargetPhysical->GetVelocity());
}
}
return Vec3V(V_ZERO);
}
void CTaskVehiclePlaneChase::EscapePursuer_OnEnter()
{
CalculateEvadeTargetPosition();
//Create the params.
sVehicleMissionParams params;
params.SetTargetPosition(m_evadeData.m_vCurrentTarget);
params.m_iDrivingFlags = DF_DontTerminateTaskWhenAchieved;
params.m_fTargetArriveDist = 0.0f;
params.m_fCruiseSpeed = 100.0f;
CTaskVehicleGoToPlane* pVehicleTask = rage_new CTaskVehicleGoToPlane(params);
pVehicleTask->OverrideMaxRoll(90.0f);
pVehicleTask->SetMaxThrottle(10.0f); // chase gets more throttle so it can catch up
SetNewTask(pVehicleTask);
}
//basic avoidance at the moment
//we set a target position to the left/right of the plane and allow it to roll sharply towards it
//reevaluate every now and then to keep it moving
CTask::FSM_Return CTaskVehiclePlaneChase::EscapePursuer_OnUpdate()
{
if(m_fTimeBeingPursued == 0.0f)
{
//stay evading for a short time so we don't instantly reenter escape
m_evadeData.m_beingPursuedTimer.Set(fwTimer::GetTimeInMilliseconds(), 3000);
}
else
{
m_evadeData.m_beingPursuedTimer.Unset();
}
if(GetTimeInState() > 10.0f || (m_evadeData.m_beingPursuedTimer.IsSet() && m_evadeData.m_beingPursuedTimer.IsOutOfTime()))
{
SetState(State_Pursue);
}
//Ensure the active task is valid.
CTaskVehicleGoToPlane* pTask = static_cast<CTaskVehicleGoToPlane*>(GetSubTask());
if(pTask)
{
m_evadeData.m_fReavaluateTime -= fwTimer::GetTimeStep();
if(m_evadeData.m_fReavaluateTime < 0.0f)
{
CalculateEvadeTargetPosition();
}
const CPlane* pPlane = static_cast<const CPlane*>(GetVehicle());
const CVehicle* pTargetPlane = GetTargetVehicle();
float fTargetSpeed = pTargetPlane->GetVelocity().Mag();
//want to go faster than them
float fMinSpeed = rage::Max(CTaskVehicleGoToPlane::GetMinAirSpeed(pPlane), fTargetSpeed + 10.0f);
pTask->SetCruiseSpeed(fMinSpeed);
pTask->SetTargetPosition(&m_evadeData.m_vCurrentTarget);
pTask->SetMinTurnRadiusPadding(1000000.0f); //magic, make the plane just try and get here, even if it can't
}
//somehow we made it to our target, just resume pursue
if(GetIsFlagSet(aiTaskFlags::SubTaskFinished))
{
SetState(State_Pursue);
}
return FSM_Continue;
}
void CTaskVehiclePlaneChase::EscapePursuer_OnExit()
{
CTaskVehicleGoToPlane* pTask = static_cast<CTaskVehicleGoToPlane*>(GetSubTask());
if(pTask)
{
pTask->OverrideMaxRoll(-1.0f);
}
}
void CTaskVehiclePlaneChase::CalculateEvadeTargetPosition()
{
const CVehicle* pTargetPlane = GetTargetVehicle();
if ( pTargetPlane )
{
Vec3V vTargetPos = pTargetPlane->GetTransform().GetPosition();
Vec3V vOurPos = GetVehicle()->GetTransform().GetPosition();
Vec3V vToTarget = vOurPos- vTargetPos;
vToTarget = Normalize(vToTarget);
bool bIsOnRight = IsGreaterThanAll(Dot(vToTarget, pTargetPlane->GetTransform().GetRight()), ScalarV(V_ZERO)) > 0;
m_evadeData.m_bIsRollingRight = bIsOnRight;
float fTargetOffsetDist = 200.0f;
Vector3 vLocalTargetOffset(cos(60.0f) * (bIsOnRight ? -fTargetOffsetDist : fTargetOffsetDist), sin(60.0f) * -fTargetOffsetDist, 0.0f);
//transform into world space
m_evadeData.m_vCurrentTarget = GetVehicle()->TransformIntoWorldSpace(vLocalTargetOffset);
m_evadeData.m_fReavaluateTime = 3.0f;
}
}
#if !__FINAL
void CTaskVehiclePlaneChase::Debug() const
{
#if DEBUG_DRAW
const CPlane* pPlane = static_cast<const CPlane*>(GetVehicle());
Vec3V vPlanePos = pPlane->GetVehiclePosition();
if(GetState() == State_Pursue)
{
Vec3V vTargetPosition = CalculateTargetPosition();
Vec3V vTargetFuturePosition = CalculateTargetFuturePosition();
grcDebugDraw::Sphere(vTargetPosition, 1.0f, Color_yellow );
grcDebugDraw::Sphere(vTargetFuturePosition, 1.0f, Color_brown );
Vec3V vTargetVelocity = CalculateTargetVelocity();
//Vec3V vPlaneFwd = pPlane->GetTransform().GetB();
Vec3V vPlaneToTarget = vTargetPosition-vPlanePos;
Vec3V vDirPlaneToTarget = Normalize(vPlaneToTarget);
//ScalarV vDistance = Mag(vPlaneToTarget);
ScalarV vTargetSpeed = Mag(vTargetVelocity);
Vec3V vTargetDirection = (vTargetSpeed > ScalarV(s_fSlowTargetSpeedThreshold)).Getb() ? Normalize(vTargetVelocity) : vDirPlaneToTarget;
//Ensure the active task is valid.
const CTaskVehicleGoToPlane* pTask = static_cast<const CTaskVehicleGoToPlane*>(GetSubTask());
if(pTask)
{
bool bDebugDraw = true;
Vector3 vModifiedTarget(0.0f, 0.0f, 0.0f);
float maxRoll = CTaskVehicleGoToPlane::ComputeMaxRollForPitch(pTask->GetDesiredPitch(), pTask->GetMaxRoll());
CTaskVehicleGoToPlane::ComputeApproachTangentPosition(vModifiedTarget, pPlane, VEC3V_TO_VECTOR3(vTargetFuturePosition), VEC3V_TO_VECTOR3(vTargetDirection), m_fComputedMinSpeed, maxRoll, true, bDebugDraw);
}
char debugText[128];
sprintf(debugText, "Target Speed: %.3f", Mag(CalculateTargetVelocity()).Getf());
grcDebugDraw::Text(vPlanePos, Color_black, 0, 80, debugText);
}
else
{
grcDebugDraw::Sphere(m_evadeData.m_vCurrentTarget, 2.0f, Color_yellow );
char debugText[128];
sprintf(debugText, "Reevalute time: %.3f", m_evadeData.m_fReavaluateTime);
grcDebugDraw::Text(vPlanePos, Color_black, 0, 80, debugText);
}
#endif
CTask::Debug();
}
const char* CTaskVehiclePlaneChase::GetStaticStateName(s32 iState)
{
Assert(iState >= State_Start && iState <= State_Finish);
static const char* aStateNames[] =
{
"State_Start",
"State_Pursue",
"State_EscapePursuer",
"State_Finish"
};
return aStateNames[iState];
}
#endif // !__FINAL