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

220 lines
5.6 KiB
C++

// FILE : TaskAnimatedHitByExplosion.cpp
// CREATED : 07/02/2012
//rage headers
#include "math/angmath.h"
// game headers
#include "Peds/ped.h"
#include "Task/Combat/TaskAnimatedHitByExplosion.h"
#include "task/Combat/TaskDamageDeath.h"
#include "Task/Movement/Jumping/TaskFallGetUp.h"
#include "event/Events.h"
AI_OPTIMISATIONS()
CTaskAnimatedHitByExplosion::Tunables CTaskAnimatedHitByExplosion::sm_Tunables;
IMPLEMENT_COMBAT_TASK_TUNABLES(CTaskAnimatedHitByExplosion, 0x228bf772);
//////////////////////////////////////////////////////////////////////////
// CtaskAnimatedHitByExplosion
//////////////////////////////////////////////////////////////////////////
CTaskAnimatedHitByExplosion::CTaskAnimatedHitByExplosion(const fwMvClipSetId& clipSetId, const fwMvClipId& clipId, float startPhase)
: m_clipSetId(clipSetId),
m_clipId(clipId),
m_startPhase(startPhase)
{
SetInternalTaskType(CTaskTypes::TASK_ANIMATED_HIT_BY_EXPLOSION);
m_ragdollBlockingFlags.BitSet().Reset();
}
CTaskAnimatedHitByExplosion::~CTaskAnimatedHitByExplosion()
{
}
bool CTaskAnimatedHitByExplosion::ShouldAbort(const AbortPriority iPriority, const aiEvent* pEvent)
{
//Check if the priority is not immediate.
if(iPriority != ABORT_PRIORITY_IMMEDIATE)
{
//Check if the event is valid.
if(pEvent)
{
//Check the event type.
switch(((CEvent *)pEvent)->GetEventType())
{
case EVENT_SCRIPT_COMMAND:
{
//Don't allow scripters to interrupt. The blend looks like crap.
return false;
}
default:
{
break;
}
}
}
}
return CTask::ShouldAbort(iPriority, pEvent);
}
#if !__FINAL
void CTaskAnimatedHitByExplosion::Debug() const
{
#if DEBUG_DRAW && __DEV
grcDebugDraw::Axis(m_lastMatrix, 1.0f, true);
#endif
}
#endif // !__FINAL
#if !__FINAL
const char* CTaskAnimatedHitByExplosion::GetStaticStateName(s32 iState)
{
Assert(iState >= State_Dive && iState <= State_Finish);
static const char* aStateNames[] =
{
"State_Dive",
"State_GetUp",
"State_Finish"
};
return aStateNames[iState];
}
#endif // !__FINAL
CTask::FSM_Return CTaskAnimatedHitByExplosion::ProcessPreFSM()
{
//Ensure the ped is valid.
CPed* pPed = GetPed();
if(!pPed)
{
return FSM_Quit;
}
if (m_ragdollBlockingFlags.BitSet().AreAnySet() && GetTimeRunning()>=sm_Tunables.m_InitialRagdollDelay)
{
pPed->ClearRagdollBlockingFlags(m_ragdollBlockingFlags);
m_ragdollBlockingFlags.BitSet().Reset();
}
return FSM_Continue;
}
void CTaskAnimatedHitByExplosion::CleanUp()
{
CPed* pPed = GetPed();
pPed->ClearBound();
}
CTask::FSM_Return CTaskAnimatedHitByExplosion::UpdateFSM(const s32 iState, const FSM_Event iEvent)
{
CPed *pPed = GetPed(); //Get the ped ptr.
FSM_Begin
FSM_State(State_Dive)
FSM_OnEnter
Dive_OnEnter(pPed);
FSM_OnUpdate
return Dive_OnUpdate(pPed);
FSM_State(State_GetUp)
FSM_OnUpdate
return GetUp_OnUpdate(pPed);
FSM_State(State_Finish)
FSM_OnUpdate
return FSM_Quit;
FSM_End
}
void CTaskAnimatedHitByExplosion::Dive_OnEnter(CPed* pPed)
{
if (sm_Tunables.m_InitialRagdollDelay>0.0f)
{
m_ragdollBlockingFlags.BitSet().SetBits(BIT(RBF_EXPLOSION) | BIT(RBF_IMPACT_OBJECT) | BIT(RBF_ALLOW_BLOCK_DEAD_PED));
m_ragdollBlockingFlags.BitSet().IntersectNegate(pPed->GetRagdollBlockingFlags().BitSet());
pPed->ApplyRagdollBlockingFlags(m_ragdollBlockingFlags);
}
// Detach from a vehicle or anything else
pPed->SetPedOutOfVehicle();
pPed->DetachFromParent(0);
// B* 1582472: Pass the reaction clip we're using up to the parent dead task if one exists, so it can use it to wait for a ragdoll settle.
CTaskDyingDead* pDeadTask = static_cast<CTaskDyingDead*>(FindParentTaskOfType(CTaskTypes::TASK_DYING_DEAD));
if (pDeadTask != NULL)
{
pDeadTask->SetDeathAnimationBySet(m_clipSetId, m_clipId);
}
CTaskFallAndGetUp* pNewTask = rage_new CTaskFallAndGetUp(m_clipSetId, m_clipId, 3.0f, m_startPhase);
pNewTask->SetRunningLocally(true);
SetNewTask(pNewTask);
FreeMoverCapsule();
}
void CTaskAnimatedHitByExplosion::FreeMoverCapsule()
{
CPed* pPed = GetPed();
pPed->SetPedResetFlag( CPED_RESET_FLAG_DisablePedCapsuleControl, true );
if (!NetworkInterface::IsGameInProgress() || !pPed->IsNetworkClone())
{
if (sm_Tunables.m_AllowPitchAndRoll)
pPed->RemoveRotationalConstraint();
}
else
{
NetworkInterface::UseAnimatedRagdollFallbackBlending(*pPed);
}
//// Reduce angular inertia on the sides (to override a hack to force spherical inertia)
//if (pPed->GetCollider())
//{
// m_SavedAngInertia = pPed->GetCollider()->GetAngInertia();
// float inertia = m_SavedAngInertia.GetXf();
// static float mult1 = 1.0f;
// static float mult2 = 1.0f;
// static float mult3 = 0.5f;
// Vec3V newInertia(inertia*mult1, inertia*mult2, inertia*mult3);
// pPed->GetCollider()->SetInertia(m_SavedAngInertia.GetW().GetIntrin128ConstRef(), newInertia.GetIntrin128ConstRef());
//}
}
CTask::FSM_Return CTaskAnimatedHitByExplosion::Dive_OnUpdate(CPed* pPed)
{
pPed->SetPedResetFlag( CPED_RESET_FLAG_DisablePedCapsuleControl, true );
if (pPed->IsNetworkClone())
{
NetworkInterface::UseAnimatedRagdollFallbackBlending(*pPed);
}
//the dying clip is finished, progress to the dead animated state
if (GetIsSubtaskFinished(CTaskTypes::TASK_FALL_AND_GET_UP) || static_cast<CTaskFallAndGetUp*>(GetSubTask())->GetClipPhase() >= 1.0f)
{
SetState(State_GetUp);
SetFlag(aiTaskFlags::KeepCurrentSubtaskAcrossTransition);
return FSM_Continue;
}
return FSM_Continue;
}
CTask::FSM_Return CTaskAnimatedHitByExplosion::GetUp_OnUpdate(CPed* pPed)
{
if (GetIsSubtaskFinished(CTaskTypes::TASK_FALL_AND_GET_UP) ||
(pPed->IsNetworkClone() && FindParentTaskOfType(CTaskTypes::TASK_DYING_DEAD) && pPed->IsDead()))
{
SetState(State_Finish);
}
return FSM_Continue;
}