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

293 lines
6.8 KiB
C++

// File header
#include "vehicleAi/task/TaskVehicleShotTire.h"
AI_OPTIMISATIONS()
AI_VEHICLE_OPTIMISATIONS()
//=========================================================================
// CTaskVehicleShotTire
//=========================================================================
CTaskVehicleShotTire::Tunables CTaskVehicleShotTire::ms_Tunables;
IMPLEMENT_VEHICLE_AI_TASK_TUNABLES(CTaskVehicleShotTire, 0xdbc31abf);
CTaskVehicleShotTire::CTaskVehicleShotTire(eHierarchyId nTire)
: m_SwerveControls()
, m_vInitialVehicleForward(V_ZERO)
, m_fTorque(0.0f)
, m_nTire(nTire)
, m_uRunningFlags(0)
{
SetInternalTaskType(CTaskTypes::TASK_VEHICLE_SHOT_TIRE);
}
CTaskVehicleShotTire::~CTaskVehicleShotTire()
{
}
aiTask* CTaskVehicleShotTire::Copy() const
{
return rage_new CTaskVehicleShotTire(m_nTire);
}
#if !__FINAL
const char* CTaskVehicleShotTire::GetStaticStateName(s32 iState)
{
Assert(iState >= State_Start && iState <= State_Finish);
static const char* aStateNames[] =
{
"State_Start",
"State_Swerve",
"State_Finish"
};
return aStateNames[iState];
}
#endif
CTask::FSM_Return CTaskVehicleShotTire::ProcessPreFSM()
{
//Ensure the vehicle is valid.
CVehicle* pVehicle = GetVehicle();
if(!pVehicle)
{
return FSM_Quit;
}
//Ensure the wheel is valid.
CWheel* pWheel = pVehicle->GetWheelFromId(m_nTire);
if(!pWheel)
{
return FSM_Quit;
}
return FSM_Continue;
}
CTask::FSM_Return CTaskVehicleShotTire::UpdateFSM(const s32 iState, const FSM_Event iEvent)
{
FSM_Begin
FSM_State(State_Start)
FSM_OnUpdate
return Start_OnUpdate();
FSM_State(State_Swerve)
FSM_OnEnter
Swerve_OnEnter();
FSM_OnUpdate
return Swerve_OnUpdate();
FSM_State(State_Finish)
FSM_OnUpdate
return FSM_Quit;
FSM_End
}
CTask::FSM_Return CTaskVehicleShotTire::Start_OnUpdate()
{
//Grab the vehicle.
CVehicle* pVehicle = GetVehicle();
//Grab the wheel.
const CWheel* pWheel = pVehicle->GetWheelFromId(m_nTire);
taskAssertf(pWheel, "Wheel is invalid.");
//Ensure the wheel is touching.
if(!pWheel->GetIsTouching())
{
return FSM_Quit;
}
//Grab the vehicle position.
Vec3V vVehiclePosition = pVehicle->GetTransform().GetPosition();
//Grab the vehicle forward vector.
m_vInitialVehicleForward = pVehicle->GetTransform().GetForward();
//Grab the vehicle right vector.
Vec3V vVehicleRight = pVehicle->GetTransform().GetRight();
//Grab the wheel position.
Vec3V vWheelPosition;
pWheel->GetWheelPosAndRadius(RC_VECTOR3(vWheelPosition));
//Generate a vector from the vehicle to the wheel.
Vec3V vVehicleToWheel = Subtract(vWheelPosition, vVehiclePosition);
//Check if the wheel is on the right.
ScalarV scDot = Dot(vVehicleRight, vVehicleToWheel);
if(IsGreaterThanAll(scDot, ScalarV(V_ZERO)))
{
m_uRunningFlags.SetFlag(VSTRF_WheelIsOnRight);
}
else
{
m_uRunningFlags.ClearFlag(VSTRF_WheelIsOnRight);
}
//Calculate the torque to apply.
{
//Grab the vehicle speed.
float fVehicleSpeed = pVehicle->GetVelocity().Mag();
//Grab the vehicle mass.
float fVehicleMass = pVehicle->GetMass();
//Calculate the torque.
m_fTorque = fVehicleSpeed * fVehicleMass * ms_Tunables.m_TorqueMultiplier;
//Negate the torque when the wheel is on the right.
if(m_uRunningFlags.IsFlagSet(VSTRF_WheelIsOnRight))
{
m_fTorque = -m_fTorque;
}
}
//Move to the swerve state.
SetState(State_Swerve);
return FSM_Continue;
}
void CTaskVehicleShotTire::Swerve_OnEnter()
{
//Set the steer angle based on the wheel position.
if(m_uRunningFlags.IsFlagSet(VSTRF_WheelIsOnRight))
{
m_SwerveControls.SetSteerAngle(-1.0f);
}
else
{
m_SwerveControls.SetSteerAngle(1.0f);
}
//Set the throttle.
m_SwerveControls.SetThrottle(0.0f);
//Set the brake.
m_SwerveControls.SetBrake(false);
//Set the hand brake.
m_SwerveControls.SetHandBrake(true);
}
CTask::FSM_Return CTaskVehicleShotTire::Swerve_OnUpdate()
{
//Grab the vehicle.
CVehicle* pVehicle = GetVehicle();
//Apply the swerve controls to the vehicle.
{
//Copy the swerve controls.
m_vehicleControls.Copy(m_SwerveControls);
//Determine if the vehicle is going slowly.
static float sfMaxVelocitySq = square(5.0f);
float fVelocitySq = pVehicle->GetVelocity().Mag2();
bool bGoingSlowly = (fVelocitySq < sfMaxVelocitySq);
//Humanize the controls.
HumaniseCarControlInput(pVehicle, &m_vehicleControls, true, bGoingSlowly);
}
//Apply gradual torque to the car to flip it.
if(ShouldApplyTorque())
{
//Grab the vehicle's forward vector.
Vector3 vVehicleForward = VEC3V_TO_VECTOR3(pVehicle->GetTransform().GetForward());
//The torque should be applied around the forward vector.
Vector3 vTorque = vVehicleForward * m_fTorque;
//Apply the torque.
pVehicle->ApplyTorque(vTorque);
//Note that torque should be applied.
m_uRunningFlags.SetFlag(VSTRF_ApplyTorque);
}
//Check if the swerve is complete.
if(IsSwerveComplete())
{
//Finish the task.
SetState(State_Finish);
}
return FSM_Continue;
}
bool CTaskVehicleShotTire::IsSwerveComplete() const
{
//Ensure the time has not exceeded the threshold.
if(GetTimeInState() > ms_Tunables.m_MaxTimeInSwerve)
{
return true;
}
//Grab the vehicle.
const CVehicle* pVehicle = GetVehicle();
//Grab the vehicle speed.
float fVehicleSpeedSq = pVehicle->GetVelocity().Mag2();
//Ensure the speed is above the threshold.
float fMinVehicleSpeedSq = square(ms_Tunables.m_MinSpeedInSwerve);
if(fVehicleSpeedSq < fMinVehicleSpeedSq)
{
return true;
}
return false;
}
bool CTaskVehicleShotTire::ShouldApplyTorque() const
{
//Check if the torque should be applied.
if(m_uRunningFlags.IsFlagSet(VSTRF_ApplyTorque))
{
return true;
}
//Grab the vehicle.
const CVehicle* pVehicle = GetVehicle();
//Ensure the vehicle is not bulky.
if(pVehicle->GetVehicleModelInfo()->GetVehicleFlag(CVehicleModelInfoFlags::FLAG_IS_BULKY))
{
return false;
}
//Ensure the vehicle's velocity exceeds the threshold.
float fSpeedSq = pVehicle->GetVelocity().XYMag2();
float fMinSpeedSq = square(ms_Tunables.m_MinSpeedToApplyTorque);
if(fSpeedSq < fMinSpeedSq)
{
return false;
}
//Grab the vehicle's forward vector.
Vec3V vVehicleForward = pVehicle->GetTransform().GetForward();
vVehicleForward.SetZ(ScalarV(V_ZERO));
vVehicleForward = NormalizeFastSafe(vVehicleForward, Vec3V(V_ZERO));
//Grab the vehicle's initial forward vector.
Vec3V vInitialVehicleForward = m_vInitialVehicleForward;
vInitialVehicleForward.SetZ(ScalarV(V_ZERO));
vInitialVehicleForward = NormalizeFastSafe(vInitialVehicleForward, Vec3V(V_ZERO));
//Ensure the difference in the initial and current forward vectors exceeds the threshold.
ScalarV scDot = Dot(vInitialVehicleForward, vVehicleForward);
ScalarV scMaxDot = ScalarVFromF32(ms_Tunables.m_MaxDotToApplyTorque);
if(IsGreaterThanAll(scDot, scMaxDot))
{
return false;
}
return true;
}