diff --git a/sp/src/game/server/ai_basenpc.h b/sp/src/game/server/ai_basenpc.h index 97d74a1e..71b340cf 100644 --- a/sp/src/game/server/ai_basenpc.h +++ b/sp/src/game/server/ai_basenpc.h @@ -1180,6 +1180,11 @@ public: void SetDeathPose( const int &iDeathPose ) { m_iDeathPose = iDeathPose; } void SetDeathPoseFrame( const int &iDeathPoseFrame ) { m_iDeathFrame = iDeathPoseFrame; } + +#ifdef MAPBASE + int GetDeathPose() { return m_iDeathPose; } + int GetDeathPoseFrame() { return m_iDeathFrame; } +#endif void SelectDeathPose( const CTakeDamageInfo &info ); virtual bool ShouldPickADeathPose( void ) { return true; } diff --git a/sp/src/game/server/physics_prop_ragdoll.cpp b/sp/src/game/server/physics_prop_ragdoll.cpp index e208e620..772f9e31 100644 --- a/sp/src/game/server/physics_prop_ragdoll.cpp +++ b/sp/src/game/server/physics_prop_ragdoll.cpp @@ -22,6 +22,7 @@ #include "hierarchy.h" #ifdef MAPBASE #include "decals.h" +#include "death_pose.h" #endif // memdbgon must be the last include file in a .cpp file!!! @@ -29,6 +30,7 @@ #ifdef MAPBASE ConVar ragdoll_autointeractions("ragdoll_autointeractions", "1", FCVAR_NONE, "Controls whether we should rely on hardcoded keyvalues or automatic flesh checks for ragdoll physgun interactions."); +ConVar ai_death_pose_server_enabled("ai_death_pose_server_enabled", "1", FCVAR_NONE, "Toggles the death pose fix code, but for server ragdolls."); #define IsBody() VPhysicsIsFlesh() ConVar ragdoll_always_allow_use( "ragdoll_always_allow_use", "0", FCVAR_NONE, "Allows all ragdolls to be used and, if they aren't explicitly set to prevent pickup, picked up." ); @@ -788,7 +790,11 @@ void CRagdollProp::SetOverlaySequence( Activity activity ) } } +#ifdef MAPBASE +void CRagdollProp::InitRagdoll( const Vector& forceVector, int forceBone, const Vector& forcePos, matrix3x4_t* pPrevBones, matrix3x4_t* pBoneToWorld, float dt, int collisionGroup, bool activateRagdoll, bool bWakeRagdoll, bool bDeathPose ) +#else void CRagdollProp::InitRagdoll( const Vector &forceVector, int forceBone, const Vector &forcePos, matrix3x4_t *pPrevBones, matrix3x4_t *pBoneToWorld, float dt, int collisionGroup, bool activateRagdoll, bool bWakeRagdoll ) +#endif { SetCollisionGroup( collisionGroup ); @@ -811,7 +817,11 @@ void CRagdollProp::InitRagdoll( const Vector &forceVector, int forceBone, const params.forceVector = forceVector; params.forceBoneIndex = forceBone; params.forcePosition = forcePos; +#ifdef MAPBASE + params.pCurrentBones = bDeathPose ? pPrevBones : pBoneToWorld; +#else params.pCurrentBones = pBoneToWorld; +#endif params.jointFrictionScale = 1.0; params.allowStretch = HasSpawnFlags(SF_RAGDOLLPROP_ALLOW_STRETCH); #ifdef MAPBASE @@ -1492,6 +1502,43 @@ CBaseEntity *CreateServerRagdoll( CBaseAnimating *pAnimating, int forceBone, con float fPreviousCycle = clamp(pAnimating->GetCycle()-( dt * ( 1 / fSequenceDuration ) ),0.f,1.f); float fCurCycle = pAnimating->GetCycle(); + +#ifdef MAPBASE + int deathpose = ACT_INVALID; + int deathframe = 0; + if (ai_death_pose_server_enabled.GetBool() && pAnimating->IsNPC()) { + CAI_BaseNPC* npc = (CAI_BaseNPC*)pAnimating; + if (npc) { + deathpose = Activity(npc->GetDeathPose()); + deathframe = npc->GetDeathPoseFrame(); + } + } + if (deathpose != ACT_INVALID) { + int currentSequence = pAnimating->GetSequence(); + + //Force pAnimating to position the deathpose + pAnimating->SetSequence(deathpose); + pAnimating->SetCycle((float)deathframe / MAX_DEATHPOSE_FRAMES); + + //Store the position + pAnimating->SetupBones(pBoneToWorldNext, BONE_USED_BY_ANYTHING); + + //Restore the current sequence and cycle + pAnimating->SetSequence(currentSequence); + + pAnimating->SetCycle(fCurCycle); + pAnimating->SetupBones(pBoneToWorld, BONE_USED_BY_ANYTHING); + } + else { + // Get current bones positions + pAnimating->SetupBones(pBoneToWorldNext, BONE_USED_BY_ANYTHING); + // Get previous bones positions + pAnimating->SetCycle(fPreviousCycle); + pAnimating->SetupBones(pBoneToWorld, BONE_USED_BY_ANYTHING); + // Restore current cycle + pAnimating->SetCycle(fCurCycle); + } +#else // Get current bones positions pAnimating->SetupBones( pBoneToWorldNext, BONE_USED_BY_ANYTHING ); // Get previous bones positions @@ -1499,6 +1546,7 @@ CBaseEntity *CreateServerRagdoll( CBaseAnimating *pAnimating, int forceBone, con pAnimating->SetupBones( pBoneToWorld, BONE_USED_BY_ANYTHING ); // Restore current cycle pAnimating->SetCycle( fCurCycle ); +#endif // Reset previous bone flags pAnimating->ClearBoneCacheFlags( BCF_NO_ANIMATION_SKIP ); @@ -1573,7 +1621,11 @@ CBaseEntity *CreateServerRagdoll( CBaseAnimating *pAnimating, int forceBone, con } else { +#ifdef MAPBASE + pRagdoll->InitRagdoll(info.GetDamageForce(), forceBone, info.GetDamagePosition(), pBoneToWorld, pBoneToWorldNext, dt, collisionGroup, true, true, deathpose != ACT_INVALID); +#else pRagdoll->InitRagdoll( info.GetDamageForce(), forceBone, info.GetDamagePosition(), pBoneToWorld, pBoneToWorldNext, dt, collisionGroup, true ); +#endif } // Are we dissolving? diff --git a/sp/src/game/server/physics_prop_ragdoll.h b/sp/src/game/server/physics_prop_ragdoll.h index 82a3d77a..134cfec1 100644 --- a/sp/src/game/server/physics_prop_ragdoll.h +++ b/sp/src/game/server/physics_prop_ragdoll.h @@ -75,7 +75,11 @@ public: // locals void InitRagdollAnimation( void ); +#ifdef MAPBASE + void InitRagdoll( const Vector& forceVector, int forceBone, const Vector& forcePos, matrix3x4_t* pPrevBones, matrix3x4_t* pBoneToWorld, float dt, int collisionGroup, bool activateRagdoll, bool bWakeRagdoll = true, bool bDeathPose = false ); +#else void InitRagdoll( const Vector &forceVector, int forceBone, const Vector &forcePos, matrix3x4_t *pPrevBones, matrix3x4_t *pBoneToWorld, float dt, int collisionGroup, bool activateRagdoll, bool bWakeRagdoll = true ); +#endif void RecheckCollisionFilter( void ); void SetDebrisThink();