|
|
//========= 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).
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; } } }
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
|