mirror of
https://github.com/nillerusr/source-engine.git
synced 2025-01-27 15:24:28 +00:00
316 lines
9.7 KiB
C++
316 lines
9.7 KiB
C++
#include "cbase.h"
|
|
#include "asw_alien_shared_classmembers.h"
|
|
#include "c_asw_clientragdoll.h"
|
|
#include "asw_util_shared.h"
|
|
#include "c_asw_fx.h"
|
|
#include "c_asw_player.h"
|
|
#include "asw_input.h"
|
|
#include "props_shared.h"
|
|
#include "c_asw_alien.h"
|
|
|
|
// memdbgon must be the last include file in a .cpp file!!!
|
|
#include "tier0/memdbgon.h"
|
|
|
|
BEGIN_DATADESC( C_ASW_ClientRagdoll )
|
|
DEFINE_FIELD( m_fASWGibTime, FIELD_TIME ),
|
|
DEFINE_FIELD( m_iSourceEntityIndex, FIELD_INTEGER ),
|
|
END_DATADESC()
|
|
|
|
ConVar asw_drone_ridiculous( "asw_drone_ridiculous", "0", FCVAR_CHEAT, "If true, hurl drone ragdolls at camera in a ridiculous fashion." );
|
|
ConVar asw_drone_gib_velocity( "asw_drone_gib_velocity", "1.75", FCVAR_CHEAT, "Drone gibs will inherit the velocity of the parent ragdoll scaled by this" );
|
|
extern ConVar asw_breakable_aliens;
|
|
extern ConVar asw_alien_debug_death_style;
|
|
|
|
C_ASW_ClientRagdoll::C_ASW_ClientRagdoll( bool bRestoring ) : BaseClass( bRestoring )
|
|
{
|
|
m_nDeathStyle = 0;
|
|
m_bElectroShock = false;
|
|
m_bHurled = false;
|
|
|
|
pszGibParticleEffect = NULL;
|
|
}
|
|
|
|
/// @brief given an origin point, a destination, and a gravity, return a
|
|
/// velocity that will apex exactly at the destination.
|
|
/// @param flGravity should be positive, assumed to be aimed down -z
|
|
Vector ComputeParabolicTrajectoryToApex( const Vector &vOrigin, const Vector &vDestination, const float flGravity )
|
|
{
|
|
// transform everything so the object's origin is at 0,0,0
|
|
const Vector vApex = vDestination - vOrigin;
|
|
/*
|
|
V = <x,z> // z is up, x out in this formulation
|
|
x(t) = tVx
|
|
y(t) = tVy
|
|
z(t) = tVz - 0.5gt^2
|
|
|V| = sqrt(Vx^2 + Vz^2)
|
|
at apex,
|
|
0 = Vz - gt -> t = Vz/g
|
|
X1 = tVx for t = Vz/g
|
|
Y1 = tVy for t = Vz/g
|
|
Z1 = tVz - 0.5gt^2 for t=Vz/g
|
|
solving the linear system gets you
|
|
Vz^2 = 2*Z1*g
|
|
Vx = g * X1 / Vz
|
|
Vy = g * Y1 / Vz
|
|
*/
|
|
|
|
// return value
|
|
float flX, flY, flZ;
|
|
|
|
float flZSquared = 2.0f * vApex.z * flGravity;
|
|
float flRecipZ = FastRSqrt( flZSquared ); // 1/vZ
|
|
flZ = flRecipZ * flZSquared; // Vz^2 / Vz = Vz
|
|
flX = flRecipZ * flGravity * vApex.x;
|
|
flY = flRecipZ * flGravity * vApex.y;
|
|
|
|
return Vector( flX, flY, flZ );
|
|
}
|
|
|
|
extern ConVar cl_ragdoll_gravity;
|
|
void ASWHurlRagdollAtCamera( C_ASW_ClientRagdoll * RESTRICT pEntity, const Vector &vCameraPosition, const QAngle &vCameraAngles )
|
|
{
|
|
Assert( pEntity );
|
|
// AssertMsg1( pEntity->VPhysicsGetObject(), "Tried to throw %s at camera but it has no VPhysics\n", pEntity->GetDebugName() );
|
|
pEntity->SetAbsVelocity( Vector(0,0,0) );
|
|
|
|
Vector vViewForward; // =CurrentViewForward();
|
|
AngleVectors( vCameraAngles, &vViewForward );
|
|
|
|
float radius = MAX(pEntity->BoundingRadius(), 20.0f );
|
|
Vector vApex = vCameraPosition + ( vViewForward * ( radius * 2 ) );
|
|
// NDebugOverlay::Sphere( vApex, vCamAngles , pEntity->BoundingRadius() * 0.5f, 255, 0, 0, 255, false, 1.0f );
|
|
// NDebugOverlay::Box( vApex, Vector(-6,-6,-6), Vector(6,6,6), 255, 0, 0, 55, 1.0f );
|
|
|
|
// pEntity->ApplyAbsVelocityImpulse( ComputeParabolicTrajectoryToApex( pEntity->GetAbsOrigin(), vApex, cl_ragdoll_gravity.GetFloat() ) );
|
|
Vector vel = ComputeParabolicTrajectoryToApex( pEntity->GetAbsOrigin(), vApex, cl_ragdoll_gravity.GetFloat() );
|
|
if ( !vel.IsValid() )
|
|
return;
|
|
|
|
IPhysicsObject *ppPhysObjs[ VPHYSICS_MAX_OBJECT_LIST_COUNT ];
|
|
int nNumPhysObjs = pEntity->VPhysicsGetObjectList( ppPhysObjs, VPHYSICS_MAX_OBJECT_LIST_COUNT );
|
|
if ( nNumPhysObjs > 0 )
|
|
{
|
|
{
|
|
AngularImpulse spin = RandomAngularImpulse(-720, 720);
|
|
ppPhysObjs[ 0 ]->SetVelocity( &vel, &spin );
|
|
}
|
|
|
|
for ( int i = 1; i < nNumPhysObjs; i++ )
|
|
{
|
|
ppPhysObjs[ i ]->SetVelocity( &vel, NULL );
|
|
}
|
|
}
|
|
|
|
}
|
|
|
|
void ASWHurlRagdollAtCamera( C_ASW_ClientRagdoll * RESTRICT pEntity )
|
|
{
|
|
// Verify that we have input.
|
|
Assert( ASWInput() != NULL );
|
|
if ( !ASWInput() )
|
|
return;
|
|
|
|
HACK_GETLOCALPLAYER_GUARD( "HurlObjectAtCamera needs to care about which camera" );
|
|
Vector vCamPos; QAngle vCamAngles;
|
|
int omx, omy;
|
|
// const Vector vCamPos = CurrentViewOrigin();
|
|
ASWInput()->ASW_GetCameraLocation( C_ASW_Player::GetLocalASWPlayer(), vCamPos, vCamAngles, omx, omy, false );
|
|
return ASWHurlRagdollAtCamera( pEntity, vCamPos, vCamAngles );
|
|
}
|
|
|
|
|
|
void ASWMeleeThrowRagdoll( C_ASW_ClientRagdoll * RESTRICT pEntity )
|
|
{
|
|
Assert( pEntity );
|
|
pEntity->SetAbsVelocity( Vector(0,0,0) );
|
|
|
|
Vector vecThrowDir = pEntity->GetDeathForce();
|
|
vecThrowDir.z = 0;
|
|
vecThrowDir.NormalizeInPlace();
|
|
|
|
Vector vApex = pEntity->GetAbsOrigin() + vecThrowDir * 170.0f + Vector( 0, 0, 50 );
|
|
|
|
Vector vel = ComputeParabolicTrajectoryToApex( pEntity->GetAbsOrigin(), vApex, cl_ragdoll_gravity.GetFloat() );
|
|
if ( !vel.IsValid() )
|
|
return;
|
|
|
|
IPhysicsObject *ppPhysObjs[ VPHYSICS_MAX_OBJECT_LIST_COUNT ];
|
|
int nNumPhysObjs = pEntity->VPhysicsGetObjectList( ppPhysObjs, VPHYSICS_MAX_OBJECT_LIST_COUNT );
|
|
if ( nNumPhysObjs > 0 )
|
|
{
|
|
{
|
|
AngularImpulse spin = RandomAngularImpulse(-720, 720);
|
|
ppPhysObjs[ 0 ]->SetVelocity( &vel, &spin );
|
|
}
|
|
|
|
for ( int i = 1; i < nNumPhysObjs; i++ )
|
|
{
|
|
ppPhysObjs[ i ]->SetVelocity( &vel, NULL );
|
|
}
|
|
}
|
|
}
|
|
|
|
void C_ASW_ClientRagdoll::BreakRagdoll()
|
|
{
|
|
|
|
IPhysicsObject *pPhysics = VPhysicsGetObject();
|
|
|
|
Vector velocity;
|
|
velocity = m_vecForce / 140.0f;
|
|
if ( velocity == vec3_origin )
|
|
velocity = Vector( RandomFloat( 1, 15 ), RandomFloat( 1, 15 ), 75.0f );
|
|
velocity.z += 100.0;
|
|
AngularImpulse angVelocity = RandomAngularImpulse( -500.0f, 500.0f );
|
|
breakablepropparams_t params( GetAbsOrigin(), GetAbsAngles(), velocity, angVelocity );
|
|
params.impactEnergyScale = 1.25f;
|
|
params.defBurstScale = 125.0f;
|
|
params.defCollisionGroup = COLLISION_GROUP_DEBRIS;
|
|
params.useThisRawVelocity = true;
|
|
PropBreakableCreateAll( GetModelIndex(), pPhysics, params, this, -1, true, true );
|
|
|
|
SUB_Remove(); // destroy ragdoll
|
|
}
|
|
|
|
//ConVar test_hurl( "test_hurl", "0.25" );
|
|
void C_ASW_ClientRagdoll::ClientThink( void )
|
|
{
|
|
// if parent is going to delete us, make sure we do nothing else
|
|
if ( m_bReleaseRagdoll )
|
|
{
|
|
BaseClass::ClientThink();
|
|
return;
|
|
}
|
|
|
|
BaseClass::ClientThink();
|
|
|
|
// OLD STUFF
|
|
/*
|
|
if ( m_fASWGibTime > 0 && gpGlobals->curtime > m_fASWGibTime )
|
|
{
|
|
// should gib this
|
|
CLocalPlayerFilter filter;
|
|
C_BaseEntity::EmitSound( filter, entindex(), "ASW_Drone.GibSplatLight" );
|
|
UTIL_ASW_ClientsideGib(this);
|
|
Release();
|
|
}
|
|
*/
|
|
|
|
if ( !m_pRagdoll || IsFadingOut() )
|
|
return;
|
|
|
|
// force-reset the velocity one frame after spawning in case the grenade explosion
|
|
// has somehow accumulated again on top of it even though we told it not to.
|
|
if ( m_nDeathStyle == kDIE_HURL && !m_bHurled && ( ( SpawnTime() + 0.05f ) < gpGlobals->curtime ) )
|
|
{
|
|
// SetMoveType( MOVETYPE_VPHYSICS );
|
|
ASWHurlRagdollAtCamera( this );
|
|
m_bHurled = true;
|
|
}
|
|
else if ( m_nDeathStyle == kDIE_MELEE_THROW && !m_bHurled && ( ( SpawnTime() + 0.05f ) < gpGlobals->curtime ) )
|
|
{
|
|
ASWMeleeThrowRagdoll( this );
|
|
m_bHurled = true;
|
|
}
|
|
|
|
if ( m_fASWGibTime > 0 && gpGlobals->curtime > m_fASWGibTime )
|
|
{
|
|
if ( asw_alien_debug_death_style.GetBool() )
|
|
Msg( "C_ASW_ClientRagdoll::ClientThink: m_nDeathStyle = %d\n", m_nDeathStyle );
|
|
|
|
if ( m_nDeathStyle == kDIE_BREAKABLE && asw_breakable_aliens.GetBool() )
|
|
{
|
|
BreakRagdoll();
|
|
return;
|
|
}
|
|
// if we die and are on fire, the ragdoll burns away
|
|
if ( GetFlags() & FL_ONFIRE )
|
|
{
|
|
CUtlReference<CNewParticleEffect> pBurnEffect = ParticleProp()->Create( "burned_alien_death", PATTACH_ABSORIGIN_FOLLOW );
|
|
|
|
EmitSound( "ASW_Alien.Flame_Death_Flash" );
|
|
|
|
// this tells the ragdoll to fade out.
|
|
SUB_Remove();
|
|
return;
|
|
}
|
|
|
|
// if we're set to fade, MAKE IT SO
|
|
if ( m_nDeathStyle == kDIE_RAGDOLLFADE )
|
|
{
|
|
// this tells the ragdoll to fade out.
|
|
SUB_Remove();
|
|
|
|
//if ( pszGibParticleEffect )
|
|
// ParticleProp()->Create( pszGibParticleEffect, PATTACH_ABSORIGIN_FOLLOW );
|
|
|
|
return;
|
|
}
|
|
|
|
// we might use this code int he future, but for now, we're using models in the particle system to spawn the instagib effects
|
|
/*
|
|
KeyValues * modelKeyValues = new KeyValues("");
|
|
if ( modelKeyValues->LoadFromBuffer( GetModelName(), modelinfo->GetModelKeyValueText( GetModel() ) ) )
|
|
{
|
|
KeyValues *pkvMeshParticleEffect = modelKeyValues->FindKey("MeshParticles");
|
|
if ( pkvMeshParticleEffect )
|
|
{
|
|
|
|
for ( KeyValues *pSingleEffect = pkvMeshParticleEffect->GetFirstSubKey(); pSingleEffect; pSingleEffect = pSingleEffect->GetNextKey() )
|
|
{
|
|
const char *pszParticleEffect = pSingleEffect->GetString( "effectName", "" );
|
|
const char *pszModelName = pSingleEffect->GetString( "modelName", "" );
|
|
const char *pszBoneName = pSingleEffect->GetString( "boneName", "" );
|
|
//const char *pszBoneAxis = pSingleEffect->GetString( "boneAxis", "0 1 0" );
|
|
|
|
Vector vGibOrigin;
|
|
QAngle aGibAngles;
|
|
|
|
int iBoneIdx = -1;
|
|
if ( pszBoneName )
|
|
{
|
|
iBoneIdx = LookupBone( pszBoneName );
|
|
}
|
|
|
|
// See if we can find the appropriate bone
|
|
if ( iBoneIdx > -1 )
|
|
{
|
|
GetBonePosition( iBoneIdx, vGibOrigin, aGibAngles );
|
|
}
|
|
else
|
|
{
|
|
//if no bone was specified, pop a warning and then use the ragdoll's centre, or the worldspace origin...
|
|
Warning("Failed to find the bone specified for particle effect in model '%s' keyvalues section. Trying to spawn effect '%s' on attachment named '%s'. Spawning effect at origin of ragdoll.\n", GetModelName(), pszParticleEffect, pszBoneName );
|
|
|
|
Vector vMins, vMaxs;
|
|
if ( m_pRagdoll )
|
|
{
|
|
m_pRagdoll->GetRagdollBounds( vMins, vMaxs );
|
|
vGibOrigin = m_pRagdoll->GetRagdollOrigin() + ( ( vMins + vMaxs ) / 2.0f );
|
|
}
|
|
else
|
|
{
|
|
vGibOrigin = WorldSpaceCenter();
|
|
}
|
|
}
|
|
|
|
Vector vGibVelocity(0,0,0);
|
|
if ( m_pRagdoll )
|
|
{
|
|
m_pRagdoll->GetElement(0)->GetVelocity(&vGibVelocity,NULL);
|
|
}
|
|
|
|
FX_GibMeshEmitter( pszModelName, pszParticleEffect, vGibOrigin, vGibVelocity * asw_drone_gib_velocity.GetFloat(), GetSkin() );
|
|
}
|
|
}
|
|
else
|
|
{
|
|
UTIL_ASW_ClientsideGib( this );
|
|
}
|
|
|
|
modelKeyValues->deleteThis();
|
|
}
|
|
*/
|
|
|
|
Release();
|
|
}
|
|
} |