Files
GTASource/game/task/Physics/TaskNMSlungOverShoulder.cpp

211 lines
6.6 KiB
C++
Raw Normal View History

2025-02-23 17:40:52 +08:00
// Filename : TaskNMSlungOverShoulder.cpp
// Description: Natural Motion SlungOverShoulder class (FSM version)
// --- Include Files ------------------------------------------------------------
// C headers
// Rage headers
#include "crskeleton\Skeleton.h"
#include "fragment\Cache.h"
#include "fragment\Instance.h"
#include "fragment\Type.h"
#include "fragment\TypeChild.h"
#include "fragmentnm\messageparams.h"
#include "pharticulated/articulatedcollider.h"
#include "physics/shapetest.h"
#include "Physics/constrainthinge.h"
#include "physics/simulator.h"
#include "phbound/boundcomposite.h"
// Framework headers
#include "grcore/debugdraw.h"
// Game headers
#include "Peds\Ped.h"
#include "Task/Physics/NmDebug.h"
#include "Task/Physics/TaskNMSlungOverShoulder.h"
#include "task/motion/TaskMotionBase.h"
#include "Physics/physics.h"
#include "physics/gtaInst.h"
#include "physics/constraintfixed.h"
AI_OPTIMISATIONS()
CTaskNMSlungOverShoulder::CTaskNMSlungOverShoulder(CPed *slungPed, CPed *carrierPed)
: CTaskNMBehaviour(30000, 30000),
m_slungPed(slungPed),
m_carrierPed(carrierPed),
m_bCarryClipsLoaded(false)
{
m_Handle.Reset();
SetInternalTaskType(CTaskTypes::TASK_NM_SLUNG_OVER_SHOULDER);
}
CTaskNMSlungOverShoulder::~CTaskNMSlungOverShoulder()
{
PHLEVEL->AddInstanceIncludeFlags(m_slungPed->GetRagdollInst()->GetLevelIndex(), ArchetypeFlags::GTA_PED_TYPE);
if (m_Handle.IsValid())
{
CPhysics::GetSimulator()->GetConstraintMgr()->Remove(m_Handle);
m_Handle.Reset();
}
// reset the motion state
if (m_carrierPed && m_carrierPed->GetPrimaryMotionTask())
{
m_carrierPed->GetPrimaryMotionTask()->ResetOnFootClipSet();
}
}
CTaskInfo* CTaskNMSlungOverShoulder::CreateQueriableState() const
{
// this task is not networked yet
Assert(!NetworkInterface::IsGameInProgress());
return rage_new CTaskInfo();
}
void CTaskNMSlungOverShoulder::StartBehaviour(CPed* /*pPed*/)
{
// Have slung Ped only collider with carrier Ped's ragdoll bounds
//phArchetypeDamp * slungArch = m_slungPed->GetRagdollInst()->GetCacheEntry()->GetPhysArchetype();
ASSERT_ONLY(phArchetypeDamp * carrierArchRagdoll = m_carrierPed->GetRagdollInst()->GetCacheEntry()->GetPhysArchetype());
ASSERT_ONLY(phArchetype * carrierArchClip = m_carrierPed->GetAnimatedInst()->GetArchetype());
Assert(carrierArchRagdoll->GetTypeFlag(ArchetypeFlags::GTA_RAGDOLL_TYPE));
Assert(carrierArchRagdoll->GetIncludeFlag(ArchetypeFlags::GTA_RAGDOLL_TYPE));
Assert(carrierArchClip->GetTypeFlag(ArchetypeFlags::GTA_PED_TYPE));
//Assert(slungArch->GetTypeFlag(ArchetypeFlags::GTA_RAGDOLL_TYPE));
//Assert(slungArch->GetIncludeFlag(ArchetypeFlags::GTA_PED_TYPE));
//Assert(slungArch->GetIncludeFlag(ArchetypeFlags::GTA_OBJECT_TYPE));
//Assert(slungArch->GetIncludeFlag(ArchetypeFlags::GTA_RAGDOLL_TYPE));
PHLEVEL->ClearInstanceIncludeFlags(m_slungPed->GetRagdollInst()->GetLevelIndex(), ArchetypeFlags::GTA_PED_TYPE);
ART::MessageParams msg;
msg.addBool(NMSTR_PARAM(NM_START), true);
m_slungPed->GetRagdollInst()->PostARTMessage(NMSTR_MSG(NM_CARRIED_MSG), &msg);
// Stream in the carrying clips
fwMvClipSetId clipSet = CLIP_SET_ID_INVALID;
const char *szClipGroupName = "MOVE_CARRY_PED";
if (fwClipSetManager::GetClipSet(fwMvClipSetId(szClipGroupName)))
clipSet.SetFromString(szClipGroupName);
if (clipSet.GetHash() && fwClipSetManager::Request_DEPRECATED(clipSet))
{
m_carrierPed->GetPrimaryMotionTask()->SetOnFootClipSet(clipSet);
m_bCarryClipsLoaded = true;
}
else
m_bCarryClipsLoaded = false;
// Pin ped to the carrier
Assert(!m_Handle.IsValid());
phConstraintFixed::Params constraint;
constraint.instanceA = m_slungPed->GetRagdollInst();
constraint.instanceB = m_carrierPed->GetRagdollInst();
constraint.componentA = RAGDOLL_BUTTOCKS;
constraint.componentB = RAGDOLL_CLAVICLE_LEFT;
m_Handle = PHCONSTRAINT->Insert(constraint);
// Don't let the constraint activate the carrier
if (m_Handle.IsValid())
{
phConstraintFixed* constraintFixed = static_cast<phConstraintFixed*>( PHCONSTRAINT->GetTemporaryPointer(m_Handle) );
if (constraintFixed)
constraintFixed->SetAllowForceActivation(false);
}
}
void CTaskNMSlungOverShoulder::ControlBehaviour(CPed* pPed)
{
if (!m_bCarryClipsLoaded)
{
fwMvClipSetId clipSet = CLIP_SET_ID_INVALID;
const char *szClipGroupName = "MOVE_CARRY_PED";
if (fwClipSetManager::GetClipSet(fwMvClipSetId(szClipGroupName)))
clipSet.SetFromString(szClipGroupName);
if (clipSet.GetHash() && fwClipSetManager::Request_DEPRECATED(clipSet))
{
m_carrierPed->GetPrimaryMotionTask()->SetOnFootClipSet(clipSet);
m_bCarryClipsLoaded = true;
}
}
// make sure the ragdoll bounds for the animated ped are up to date before the physics update (so the constraint processes more accurately)
m_carrierPed->GetAnimDirector()->WaitForPrePhysicsUpdateToComplete();
m_carrierPed->UpdateRagdollBoundsFromAnimatedSkel();
CTaskNMBehaviour::ControlBehaviour(pPed);
}
CTask::FSM_Return CTaskNMSlungOverShoulder::ProcessPreFSM()
{
CPed *pPed = GetPed();
pPed->SetPedResetFlag( CPED_RESET_FLAG_ProcessPhysicsTasks, true );
pPed->SetPedResetFlag( CPED_RESET_FLAG_ProcessPostMovement, true );
return CTaskNMBehaviour::ProcessPreFSM();
}
bool CTaskNMSlungOverShoulder::ProcessPhysics( float /*fTimeStep*/, int UNUSED_PARAM(nTimeSlice) )
{
return true;
}
bool CTaskNMSlungOverShoulder::ProcessPostMovement()
{
// HACK HACK HACK
// Because the slung peds ragdoll inst is attached to the
// carrier ped's ragdoll inst by a physical constraint,
// we can't currently give the physics update an up to date
// position for the carrier peds radgoll inst (the ragdoll inst is not active,
// and the physics update itself will do the work to move the animated inst.)
// For now, we'll live with the position being an update out and fake update the
// slung peds entity position based on the final physical velocity of the carrier ped
if (m_slungPed && m_carrierPed)
{
Vec3V oldPosition = m_slungPed->GetMatrix().d();
Vector3 newPosition = m_carrierPed->GetVelocity();
newPosition *= fwTimer::GetTimeStep();
newPosition+=RC_VECTOR3(oldPosition);
m_slungPed->SetPosition(newPosition, true, false, false);
return true;
}
return false;
}
bool CTaskNMSlungOverShoulder::FinishConditions(CPed* pPed)
{
if (pPed->IsDead() || pPed->GetIsSwimming())
return true;
if (m_carrierPed && m_carrierPed->GetRagdollState() >= RAGDOLL_STATE_PHYS_ACTIVATE)
{
if (m_Handle.IsValid())
{
CPhysics::GetSimulator()->GetConstraintMgr()->Remove(m_Handle);
m_Handle.Reset();
}
// reset the motion state
if (m_carrierPed->GetPrimaryMotionTask())
{
m_carrierPed->GetPrimaryMotionTask()->ResetOnFootClipSet();
}
return true;
}
return false;
}