css_enhanced_waf/game/shared/cstrike/basecsgrenade_projectile.cpp
Kamay Xutax 854991ab8c Fixed lag compensation for animations
The problem is that we still trust the client, although now we have a
good base to start with; The key difference here is that we don't need
to use anymore the cs player animestate client side anymore
because server side values are used

There are minor bugs like fire effect but they can be fixed
2024-07-11 02:12:51 +02:00

348 lines
8.6 KiB
C++

//========= Copyright Valve Corporation, All rights reserved. ============//
//
// Purpose:
//
//=============================================================================//
#include "cbase.h"
#include "basecsgrenade_projectile.h"
float GetCurrentGravity( void );
#ifdef CLIENT_DLL
#include "c_cs_player.h"
#else
#include "bot_manager.h"
#include "cs_player.h"
#include "soundent.h"
#include "te_effect_dispatch.h"
#include "KeyValues.h"
BEGIN_DATADESC( CBaseCSGrenadeProjectile )
DEFINE_THINKFUNC( DangerSoundThink ),
END_DATADESC()
#endif
IMPLEMENT_NETWORKCLASS_ALIASED( BaseCSGrenadeProjectile, DT_BaseCSGrenadeProjectile )
BEGIN_NETWORK_TABLE( CBaseCSGrenadeProjectile, DT_BaseCSGrenadeProjectile )
#ifdef CLIENT_DLL
RecvPropVector( RECVINFO( m_vInitialVelocity ) )
#else
SendPropVector( SENDINFO( m_vInitialVelocity ),
20, // nbits
0, // flags
-3000, // low value
3000 // high value
)
#endif
END_NETWORK_TABLE()
#ifdef CLIENT_DLL
void CBaseCSGrenadeProjectile::PostDataUpdate( DataUpdateType_t type )
{
BaseClass::PostDataUpdate( type );
if ( type == DATA_UPDATE_CREATED )
{
// Now stick our initial velocity into the interpolation history
CInterpolatedVar< Vector > &interpolator = GetOriginInterpolator();
interpolator.ClearHistory();
float changeTime = GetLastChangeTime( LATCH_SIMULATION_VAR );
// Add a sample 1 second back.
Vector vCurOrigin = GetLocalOrigin() - m_vInitialVelocity;
interpolator.AddToHead( changeTime - 1.0, &vCurOrigin, false );
// Add the current sample.
vCurOrigin = GetLocalOrigin();
interpolator.AddToHead( changeTime, &vCurOrigin, false );
}
}
int CBaseCSGrenadeProjectile::DrawModel( int flags )
{
// During the first half-second of our life, don't draw ourselves if he's
// still playing his throw animation.
// (better yet, we could draw ourselves in his hand).
#ifndef CLIENT_DLL
if ( GetThrower() != C_BasePlayer::GetLocalPlayer() )
{
if ( gpGlobals->curtime - m_flSpawnTime < 0.5 )
{
C_CSPlayer *pPlayer = dynamic_cast<C_CSPlayer*>( GetThrower() );
if ( pPlayer && pPlayer->m_PlayerAnimState->IsThrowingGrenade() )
{
return 0;
}
}
}
#endif
return BaseClass::DrawModel( flags );
}
void CBaseCSGrenadeProjectile::Spawn()
{
m_flSpawnTime = gpGlobals->curtime;
BaseClass::Spawn();
}
#else
void CBaseCSGrenadeProjectile::PostConstructor( const char *className )
{
BaseClass::PostConstructor( className );
TheBots->AddGrenade( this );
}
CBaseCSGrenadeProjectile::~CBaseCSGrenadeProjectile()
{
TheBots->RemoveGrenade( this );
}
void CBaseCSGrenadeProjectile::Spawn( void )
{
BaseClass::Spawn();
SetSolidFlags( FSOLID_NOT_STANDABLE );
SetMoveType( MOVETYPE_FLYGRAVITY, MOVECOLLIDE_FLY_CUSTOM );
SetSolid( SOLID_BBOX ); // So it will collide with physics props!
// smaller, cube bounding box so we rest on the ground
SetSize( Vector ( -2, -2, -2 ), Vector ( 2, 2, 2 ) );
}
void CBaseCSGrenadeProjectile::DangerSoundThink( void )
{
if (!IsInWorld())
{
Remove( );
return;
}
if( gpGlobals->curtime > m_flDetonateTime )
{
Detonate();
return;
}
CSoundEnt::InsertSound ( SOUND_DANGER, GetAbsOrigin() + GetAbsVelocity() * 0.5, GetAbsVelocity().Length( ), 0.2 );
SetNextThink( gpGlobals->curtime + 0.2 );
if (GetWaterLevel() != 0)
{
SetAbsVelocity( GetAbsVelocity() * 0.5 );
}
}
//Sets the time at which the grenade will explode
void CBaseCSGrenadeProjectile::SetDetonateTimerLength( float timer )
{
m_flDetonateTime = gpGlobals->curtime + timer;
}
void CBaseCSGrenadeProjectile::ResolveFlyCollisionCustom( trace_t &trace, Vector &vecVelocity )
{
//Assume all surfaces have the same elasticity
float flSurfaceElasticity = 1.0;
//Don't bounce off of players with perfect elasticity
if( trace.m_pEnt && trace.m_pEnt->IsPlayer() )
{
flSurfaceElasticity = 0.3;
}
// if its breakable glass and we kill it, don't bounce.
// give some damage to the glass, and if it breaks, pass
// through it.
bool breakthrough = false;
if( trace.m_pEnt && FClassnameIs( trace.m_pEnt, "func_breakable" ) )
{
breakthrough = true;
}
if( trace.m_pEnt && FClassnameIs( trace.m_pEnt, "func_breakable_surf" ) )
{
breakthrough = true;
}
if (breakthrough)
{
CTakeDamageInfo info( this, this, 10, DMG_CLUB );
trace.m_pEnt->DispatchTraceAttack( info, GetAbsVelocity(), &trace );
ApplyMultiDamage();
if( trace.m_pEnt->m_iHealth <= 0 )
{
// slow our flight a little bit
Vector vel = GetAbsVelocity();
vel *= 0.4;
SetAbsVelocity( vel );
return;
}
}
float flTotalElasticity = GetElasticity() * flSurfaceElasticity;
flTotalElasticity = clamp( flTotalElasticity, 0.0f, 0.9f );
// NOTE: A backoff of 2.0f is a reflection
Vector vecAbsVelocity;
PhysicsClipVelocity( GetAbsVelocity(), trace.plane.normal, vecAbsVelocity, 2.0f );
vecAbsVelocity *= flTotalElasticity;
// Get the total velocity (player + conveyors, etc.)
VectorAdd( vecAbsVelocity, GetBaseVelocity(), vecVelocity );
float flSpeedSqr = DotProduct( vecVelocity, vecVelocity );
// Stop if on ground.
if ( trace.plane.normal.z > 0.7f ) // Floor
{
// Verify that we have an entity.
CBaseEntity *pEntity = trace.m_pEnt;
Assert( pEntity );
SetAbsVelocity( vecAbsVelocity );
if ( flSpeedSqr < ( 30 * 30 ) )
{
if ( pEntity->IsStandable() )
{
SetGroundEntity( pEntity );
}
// Reset velocities.
SetAbsVelocity( vec3_origin );
SetLocalAngularVelocity( vec3_angle );
//align to the ground so we're not standing on end
QAngle angle;
VectorAngles( trace.plane.normal, angle );
// rotate randomly in yaw
angle[1] = random->RandomFloat( 0, 360 );
// TODO: rotate around trace.plane.normal
SetAbsAngles( angle );
}
else
{
Vector vecDelta = GetBaseVelocity() - vecAbsVelocity;
Vector vecBaseDir = GetBaseVelocity();
VectorNormalize( vecBaseDir );
float flScale = vecDelta.Dot( vecBaseDir );
VectorScale( vecAbsVelocity, ( 1.0f - trace.fraction ) * gpGlobals->frametime, vecVelocity );
VectorMA( vecVelocity, ( 1.0f - trace.fraction ) * gpGlobals->frametime, GetBaseVelocity() * flScale, vecVelocity );
PhysicsPushEntity( vecVelocity, &trace );
}
}
else
{
// If we get *too* slow, we'll stick without ever coming to rest because
// we'll get pushed down by gravity faster than we can escape from the wall.
if ( flSpeedSqr < ( 30 * 30 ) )
{
// Reset velocities.
SetAbsVelocity( vec3_origin );
SetLocalAngularVelocity( vec3_angle );
}
else
{
SetAbsVelocity( vecAbsVelocity );
}
}
BounceSound();
// tell the bots a grenade has bounced
CCSPlayer *player = ToCSPlayer(GetThrower());
if ( player )
{
IGameEvent * event = gameeventmanager->CreateEvent( "grenade_bounce" );
if ( event )
{
event->SetInt( "userid", player->GetUserID() );
event->SetFloat( "x", GetAbsOrigin().x );
event->SetFloat( "y", GetAbsOrigin().y );
event->SetFloat( "z", GetAbsOrigin().z );
gameeventmanager->FireEvent( event );
}
}
}
void CBaseCSGrenadeProjectile::SetupInitialTransmittedGrenadeVelocity( const Vector &velocity )
{
m_vInitialVelocity = velocity;
}
#define MAX_WATER_SURFACE_DISTANCE 512
void CBaseCSGrenadeProjectile::Splash()
{
Vector centerPoint = GetAbsOrigin();
Vector normal( 0, 0, 1 );
// Find our water surface by tracing up till we're out of the water
trace_t tr;
Vector vecTrace( 0, 0, MAX_WATER_SURFACE_DISTANCE );
UTIL_TraceLine( centerPoint, centerPoint + vecTrace, MASK_WATER, NULL, COLLISION_GROUP_NONE, &tr );
// If we didn't start in water, we're above it
if ( tr.startsolid == false )
{
// Look downward to find the surface
vecTrace.Init( 0, 0, -MAX_WATER_SURFACE_DISTANCE );
UTIL_TraceLine( centerPoint, centerPoint + vecTrace, MASK_WATER, NULL, COLLISION_GROUP_NONE, &tr );
// If we hit it, setup the explosion
if ( tr.fraction < 1.0f )
{
centerPoint = tr.endpos;
}
else
{
//NOTENOTE: We somehow got into a splash without being near water?
Assert( 0 );
}
}
else if ( tr.fractionleftsolid )
{
// Otherwise we came out of the water at this point
centerPoint = centerPoint + (vecTrace * tr.fractionleftsolid);
}
else
{
// Use default values, we're really deep
}
CEffectData data;
data.m_vOrigin = centerPoint;
data.m_vNormal = normal;
data.m_flScale = random->RandomFloat( 1.0f, 2.0f );
if ( GetWaterType() & CONTENTS_SLIME )
{
data.m_fFlags |= FX_WATER_IN_SLIME;
}
DispatchEffect( "gunshotsplash", data );
}
#endif // !CLIENT_DLL