Counter Strike : Global Offensive Source Code
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 

439 lines
13 KiB

//========= Copyright © 1996-2005, Valve Corporation, All rights reserved. ============//
//
// Purpose:
//
//=============================================================================//
#include "cbase.h"
#include "sensorgrenade_projectile.h"
#include "engine/IEngineSound.h"
#include "keyvalues.h"
#include "weapon_csbase.h"
#include "particle_parse.h"
#if defined( CLIENT_DLL )
#include "c_cs_player.h"
#else
#include "sendproxy.h"
#include "cs_player.h"
#include "bot_manager.h"
#include "cs_bot.h"
#endif
// NOTE: This has to be the last file included!
#include "tier0/memdbgon.h"
#if defined( CLIENT_DLL )
IMPLEMENT_CLIENTCLASS_DT( C_SensorGrenadeProjectile, DT_SensorGrenadeProjectile, CSensorGrenadeProjectile )
END_RECV_TABLE()
//--------------------------------------------------------------------------------------------------------
void C_SensorGrenadeProjectile::OnNewParticleEffect( const char *pszParticleName, CNewParticleEffect *pNewParticleEffect )
{
if ( FStrEq( pszParticleName, "weapon_sensorgren_detlight" ) )
{
m_sensorgrenadeParticleEffect = pNewParticleEffect;
}
}
//--------------------------------------------------------------------------------------------------------
void C_SensorGrenadeProjectile::OnParticleEffectDeleted( CNewParticleEffect *pParticleEffect )
{
if ( m_sensorgrenadeParticleEffect == pParticleEffect )
{
m_sensorgrenadeParticleEffect = NULL;
}
}
//--------------------------------------------------------------------------------------------------------
bool C_SensorGrenadeProjectile::Simulate( void )
{
// we are still moving
if ( GetAbsVelocity().Length() > 0.1f )
{
return true;
}
if ( !m_sensorgrenadeParticleEffect.IsValid() )
{
DispatchParticleEffect( "weapon_sensorgren_detlight", PATTACH_POINT_FOLLOW, this, "Wick" );
}
else
{
m_sensorgrenadeParticleEffect->SetSortOrigin( GetAbsOrigin() );
m_sensorgrenadeParticleEffect->SetNeedsBBoxUpdate( true );
}
BaseClass::Simulate();
return true;
}
#else // GAME_DLL
#define GRENADE_MODEL "models/Weapons/w_eq_sensorgrenade_thrown.mdl"
LINK_ENTITY_TO_CLASS( tagrenade_projectile, CSensorGrenadeProjectile );
PRECACHE_REGISTER( tagrenade_projectile );
IMPLEMENT_SERVERCLASS_ST( CSensorGrenadeProjectile, DT_SensorGrenadeProjectile )
END_SEND_TABLE()
BEGIN_DATADESC( CSensorGrenadeProjectile )
DEFINE_THINKFUNC( Think_Arm ),
DEFINE_THINKFUNC( Think_Remove ),
DEFINE_THINKFUNC( SensorThink )
END_DATADESC()
// --------------------------------------------------------------------------------------------------- //
// CFlashbangProjectile implementation.
// --------------------------------------------------------------------------------------------------- //
CSensorGrenadeProjectile* CSensorGrenadeProjectile::Create(
const Vector &position,
const QAngle &angles,
const Vector &velocity,
const AngularImpulse &angVelocity,
CBaseCombatCharacter *pOwner,
const CCSWeaponInfo& weaponInfo )
{
CSensorGrenadeProjectile *pGrenade = ( CSensorGrenadeProjectile* )CBaseEntity::Create( "tagrenade_projectile", position, angles, pOwner );
// Set the timer for 1 second less than requested. We're going to issue a SOUND_DANGER
// one second before detonation.
pGrenade->SetTimer( 2.0f );
pGrenade->SetAbsVelocity( velocity );
pGrenade->SetupInitialTransmittedGrenadeVelocity( velocity );
pGrenade->SetThrower( pOwner );
pGrenade->m_flDamage = 1.0f; // 25 = 1/4 of HEGrenade Damage
pGrenade->m_DmgRadius = pGrenade->m_flDamage * 3.5f; // Changing damage will change the radius
pGrenade->ChangeTeam( pOwner->GetTeamNumber() );
pGrenade->SetAbsAngles( pOwner->EyeAngles() + QAngle( -80, 40, 0 ) );
QAngle angRotationVel = QAngle( RandomFloat(100,200), RandomFloat(-100,200), RandomFloat(-100,200) );
pGrenade->SetLocalAngularVelocity( angRotationVel );
pGrenade->SetTouch( &CSensorGrenadeProjectile::BounceTouch );
pGrenade->SetGravity( BaseClass::GetGrenadeGravity() );
pGrenade->SetFriction( BaseClass::GetGrenadeFriction() );
pGrenade->SetElasticity( BaseClass::GetGrenadeElasticity() );
pGrenade->m_pWeaponInfo = &weaponInfo;
ASSERT(pOwner != NULL);
//pGrenade->SetCollisionGroup( COLLISION_GROUP_PROJECTILE );
return pGrenade;
}
void CSensorGrenadeProjectile::SetTimer( float timer )
{
SetThink( &CSensorGrenadeProjectile::Think_Arm );
SetNextThink( gpGlobals->curtime + timer );
m_fNextDetectPlayerSound = gpGlobals->curtime;
TheBots->SetGrenadeRadius( this, 0.0f );
}
void CSensorGrenadeProjectile::Think_Arm( void )
{
#if 1
if ( GetAbsVelocity().Length() > 0.2f )
{
// Still moving. Don't detonate yet.
SetNextThink( gpGlobals->curtime + 0.2f );
return;
}
#endif // 0
m_fExpireTime = gpGlobals->curtime + 2.0f; // TODO: Make this Data Driven
SetThink( &CSensorGrenadeProjectile::SensorThink );
//TheBots->SetGrenadeRadius( this, SensorGrenadeGrenadeRadius );
SensorThink(); // This will handling the 'Detonate'
}
void CSensorGrenadeProjectile::Think_Remove( void )
{
UTIL_Remove( this );
}
void CSensorGrenadeProjectile::Detonate( void )
{
// [mlowrance] The SensorGrenade is handling it's own detonate.
Assert(!"SensorGrenade grenade handles its own detonation");
}
void CSensorGrenadeProjectile::SensorThink( void )
{
// tell the bots about the gunfire
CCSPlayer *pThrower = ToCSPlayer( GetThrower() );
if ( !pThrower )
return;
if ( gpGlobals->curtime > m_fNextDetectPlayerSound )
{
EmitSound( "Sensor.WarmupBeep" );
m_fNextDetectPlayerSound = gpGlobals->curtime + 1.0f; // TODO: Make this Data Driven
}
if ( gpGlobals->curtime < m_fExpireTime )
{
SetNextThink( gpGlobals->curtime + 0.1f );
}
else
{
// [mlowrance] Do the damage on Despawn and post event
CCSPlayer *player = ToCSPlayer( GetThrower() );
if ( player )
{
IGameEvent * event = gameeventmanager->CreateEvent( "tagrenade_detonate" );
if ( event )
{
event->SetInt( "userid", player->GetUserID() );
event->SetInt( "entityid", this->entindex() );
event->SetFloat( "x", GetAbsOrigin().x );
event->SetFloat( "y", GetAbsOrigin().y );
event->SetFloat( "z", GetAbsOrigin().z );
gameeventmanager->FireEvent( event );
}
}
TheBots->RemoveGrenade( this );
DispatchParticleEffect( "weapon_sensorgren_detonate", PATTACH_POINT, this, "Wick" );
EmitSound( "Sensor.Detonate" );
DoDetectWave();
//BaseClass::Detonate();
}
}
void CSensorGrenadeProjectile::DoDetectWave( void )
{
// tell the bots about the gunfire
CCSPlayer *pThrower = ToCSPlayer( GetThrower() );
if ( !pThrower )
return;
for ( int i = 1; i <= MAX_PLAYERS; i++ )
{
CCSPlayer *pPlayer = ToCSPlayer( UTIL_PlayerByIndex( i ) );
if ( !pPlayer || !pPlayer->IsAlive() || !pThrower->IsOtherEnemy( pPlayer ) )
continue;
Vector vDelta = pPlayer->EyePosition() - GetAbsOrigin();
float flDistance = vDelta.Length();
float flMaxTraceDist = 1600;
if ( flDistance <= flMaxTraceDist )
{
trace_t tr;
//if ( pCSPlayer->IsAlive() && ( flTargetIDCone > flViewCone ) && !bShowAllNamesForSpec )
{
if ( TheCSBots()->IsLineBlockedBySmoke( pPlayer->EyePosition(), GetAbsOrigin(), 1.0f ) )
{
// if we are outside half the max dist and don't trace, dont show
if ( flDistance > (flMaxTraceDist/2) )
continue;
}
UTIL_TraceLine( pPlayer->EyePosition(), GetAbsOrigin(), MASK_VISIBLE, pPlayer, COLLISION_GROUP_DEBRIS, &tr );
if ( tr.fraction != 1 )
{
trace_t tr2;
UTIL_TraceLine( pPlayer->GetAbsOrigin() + Vector( 0, 0, 16 ), GetAbsOrigin(), MASK_VISIBLE, pPlayer, COLLISION_GROUP_DEBRIS, &tr2 );
if ( tr2.fraction != 1 )
{
// if we are outside half the max dist and don't trace, dont show
if ( flDistance > (flMaxTraceDist/2) )
continue;
}
}
int nThrowerIndex = 0;
for ( int i = 1; i <= MAX_PLAYERS; i++ )
{
CCSPlayer *pPlayer = ToCSPlayer( UTIL_PlayerByIndex( i ) );
if ( pPlayer == pThrower )
{
nThrowerIndex = i;
break;
}
}
DebugDrawLine( WorldSpaceCenter(), pPlayer->WorldSpaceCenter(), 90, 0, 0, true, 1.5f );
pPlayer->SetIsSpotted( true );
pPlayer->SetIsSpottedBy( nThrowerIndex );
pPlayer->m_flDetectedByEnemySensorTime = gpGlobals->curtime;
pPlayer->Blind( 0.02f, 1.0f, 128 );
pPlayer->EmitSound( "Sensor.WarmupBeep" );
}
}
}
SetNextThink( gpGlobals->curtime + 0.25f );
SetThink( &CSensorGrenadeProjectile::Think_Remove );
}
void CSensorGrenadeProjectile::Spawn( void )
{
SetModel( GRENADE_MODEL );
BaseClass::Spawn();
SetSolid( SOLID_BBOX );
AddSolidFlags( FSOLID_NOT_STANDABLE );
}
void CSensorGrenadeProjectile::Precache( void )
{
PrecacheModel( GRENADE_MODEL );
PrecacheScriptSound( "Sensor.Detonate" );
PrecacheScriptSound( "Sensor.WarmupBeep" );
PrecacheScriptSound( "Sensor.Activate" );
PrecacheScriptSound( "Flashbang.Bounce" );
//PrecacheParticleSystem( "weapon_sen_active" );
PrecacheParticleSystem( "weapon_sensorgren_detlight" );
PrecacheParticleSystem( "weapon_sensorgren_detonate" );
BaseClass::Precache();
}
void CSensorGrenadeProjectile::BounceTouch( CBaseEntity *other )
{
if ( other->IsSolidFlagSet( FSOLID_TRIGGER | FSOLID_VOLUME_CONTENTS ) )
return;
// don't hit the guy that launched this grenade
if ( other == GetThrower() )
return;
if ( FClassnameIs( other, "func_breakable" ) )
{
return;
}
if ( FClassnameIs( other, "func_breakable_surf" ) )
{
return;
}
// don't detonate on ladders
if ( FClassnameIs( other, "func_ladder" ) )
{
return;
}
// Deal car alarms direct damage to set them off - flames won't do so
if ( FClassnameIs( other, "prop_car_alarm" ) || FClassnameIs( other, "prop_car_glass" ) )
{
CTakeDamageInfo info( this, GetThrower(), 10, DMG_GENERIC );
other->OnTakeDamage( info );
}
const trace_t &hitTrace = GetTouchTrace();
if ( hitTrace.m_pEnt && hitTrace.m_pEnt->MyCombatCharacterPointer() )
{
// don't break if we hit an actor - wait until we hit the environment
return;
}
else
{
SetAbsVelocity( Vector( 0, 0, 0) );
SetMoveType(MOVETYPE_NONE);
SetNextThink( gpGlobals->curtime + 1.0f );
SetThink( &CSensorGrenadeProjectile::Think_Arm );
EmitSound( "Sensor.Activate" );
m_fExpireTime = gpGlobals->curtime + 15.0f; // TODO: Make this Data Driven
// stick the grenade onto the target surface using the closest rotational alignment to match the in-flight orientation,
// ( like breach charges )
Vector vecSurfNormal = hitTrace.plane.normal.Normalized();
Vector vecProjectileZ = EntityToWorldTransform().GetColumn(Z_AXIS);
// sensor grenades can stick on either of two sides, unlike the breach charges. So they don't need to flip when they land on their 'backs'.
if ( DotProduct( vecSurfNormal, vecProjectileZ ) < 0 )
vecSurfNormal = -vecSurfNormal;
QAngle angSurface;
MatrixAngles( ConcatTransforms( QuaternionMatrix( RotateBetween( vecProjectileZ, vecSurfNormal ) ), EntityToWorldTransform() ), angSurface );
SetAbsAngles( angSurface );
//if ( fabs(hitTrace.plane.normal.Dot(Vector(0,0,1))) > 0.65f )
{
//get the player forward vector
// Vector vecFlatForward;
// VectorCopy( pPlayer->Forward(), vecFlatForward );
// vecFlatForward.z = 0;
//
// //derive c4 forward and right
// Vector vecC4Right = CrossProduct( vecFlatForward.Normalized(), hitTrace.plane.normal );
// Vector vecC4Forward = CrossProduct( vecC4Right, trPlant.plane.normal );
//QAngle angle;
//VectorAngles( hitTrace.plane.normal, angle );
//SetAbsAngles( angle );
//m_hDisplayGrenade = CreatePhysicsProp( GRENADE_MODEL, GetAbsOrigin(), GetAbsOrigin(), NULL, false, "prop_physics_multiplayer" );
/*
m_hDisplayGrenade = ( CBreakableProp * )CBaseEntity::CreateNoSpawn( "prop_physics", GetAbsOrigin(), angle );
CBreakableProp *pDisplay = dynamic_cast< CBreakableProp* >( m_hDisplayGrenade.Get() );
if ( pDisplay )
{
pDisplay->KeyValue( "fademindist", "-1" );
pDisplay->KeyValue( "fademaxdist", "0" );
pDisplay->KeyValue( "fadescale", "1" );
pDisplay->KeyValue( "inertiaScale", "1.0" );
pDisplay->KeyValue( "physdamagescale", "0.1" );
//pDisplay->SetPhysicsMode( PHYSICS_MULTIPLAYER_SOLID );
pDisplay->SetModel( GRENADE_MODEL );
pDisplay->SetSolid( SOLID_BBOX );
pDisplay->AddSolidFlags( FSOLID_NOT_STANDABLE );
pDisplay->AddSpawnFlags( SF_PHYSPROP_MOTIONDISABLED );
pDisplay->Precache();
DispatchSpawn( pDisplay );
pDisplay->Activate();
// disable the parent model
SetModelName( NULL_STRING );//invisible
SetSolid( SOLID_NONE );
}
*/
}
/*
// only detonate on surfaces less steep than this
const float kMinCos = cosf( DEG2RAD( weapon_molotov_maxdetonateslope.GetFloat() ) );
if ( hitTrace.plane.normal.z >= kMinCos )
{
//Stick();
}
*/
}
}
//TODO: Let physics handle the sound!
void CSensorGrenadeProjectile::BounceSound( void )
{
EmitSound( "Flashbang.Bounce" );
}
#endif // GAME_DLL