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

  1. //========= Copyright � 1996-2005, Valve Corporation, All rights reserved. ============//
  2. //
  3. // Purpose:
  4. //
  5. //=============================================================================//
  6. #include "cbase.h"
  7. #include "sensorgrenade_projectile.h"
  8. #include "engine/IEngineSound.h"
  9. #include "keyvalues.h"
  10. #include "weapon_csbase.h"
  11. #include "particle_parse.h"
  12. #if defined( CLIENT_DLL )
  13. #include "c_cs_player.h"
  14. #else
  15. #include "sendproxy.h"
  16. #include "cs_player.h"
  17. #include "bot_manager.h"
  18. #include "cs_bot.h"
  19. #endif
  20. // NOTE: This has to be the last file included!
  21. #include "tier0/memdbgon.h"
  22. #if defined( CLIENT_DLL )
  23. IMPLEMENT_CLIENTCLASS_DT( C_SensorGrenadeProjectile, DT_SensorGrenadeProjectile, CSensorGrenadeProjectile )
  24. END_RECV_TABLE()
  25. //--------------------------------------------------------------------------------------------------------
  26. void C_SensorGrenadeProjectile::OnNewParticleEffect( const char *pszParticleName, CNewParticleEffect *pNewParticleEffect )
  27. {
  28. if ( FStrEq( pszParticleName, "weapon_sensorgren_detlight" ) )
  29. {
  30. m_sensorgrenadeParticleEffect = pNewParticleEffect;
  31. }
  32. }
  33. //--------------------------------------------------------------------------------------------------------
  34. void C_SensorGrenadeProjectile::OnParticleEffectDeleted( CNewParticleEffect *pParticleEffect )
  35. {
  36. if ( m_sensorgrenadeParticleEffect == pParticleEffect )
  37. {
  38. m_sensorgrenadeParticleEffect = NULL;
  39. }
  40. }
  41. //--------------------------------------------------------------------------------------------------------
  42. bool C_SensorGrenadeProjectile::Simulate( void )
  43. {
  44. // we are still moving
  45. if ( GetAbsVelocity().Length() > 0.1f )
  46. {
  47. return true;
  48. }
  49. if ( !m_sensorgrenadeParticleEffect.IsValid() )
  50. {
  51. DispatchParticleEffect( "weapon_sensorgren_detlight", PATTACH_POINT_FOLLOW, this, "Wick" );
  52. }
  53. else
  54. {
  55. m_sensorgrenadeParticleEffect->SetSortOrigin( GetAbsOrigin() );
  56. m_sensorgrenadeParticleEffect->SetNeedsBBoxUpdate( true );
  57. }
  58. BaseClass::Simulate();
  59. return true;
  60. }
  61. #else // GAME_DLL
  62. #define GRENADE_MODEL "models/Weapons/w_eq_sensorgrenade_thrown.mdl"
  63. LINK_ENTITY_TO_CLASS( tagrenade_projectile, CSensorGrenadeProjectile );
  64. PRECACHE_REGISTER( tagrenade_projectile );
  65. IMPLEMENT_SERVERCLASS_ST( CSensorGrenadeProjectile, DT_SensorGrenadeProjectile )
  66. END_SEND_TABLE()
  67. BEGIN_DATADESC( CSensorGrenadeProjectile )
  68. DEFINE_THINKFUNC( Think_Arm ),
  69. DEFINE_THINKFUNC( Think_Remove ),
  70. DEFINE_THINKFUNC( SensorThink )
  71. END_DATADESC()
  72. // --------------------------------------------------------------------------------------------------- //
  73. // CFlashbangProjectile implementation.
  74. // --------------------------------------------------------------------------------------------------- //
  75. CSensorGrenadeProjectile* CSensorGrenadeProjectile::Create(
  76. const Vector &position,
  77. const QAngle &angles,
  78. const Vector &velocity,
  79. const AngularImpulse &angVelocity,
  80. CBaseCombatCharacter *pOwner,
  81. const CCSWeaponInfo& weaponInfo )
  82. {
  83. CSensorGrenadeProjectile *pGrenade = ( CSensorGrenadeProjectile* )CBaseEntity::Create( "tagrenade_projectile", position, angles, pOwner );
  84. // Set the timer for 1 second less than requested. We're going to issue a SOUND_DANGER
  85. // one second before detonation.
  86. pGrenade->SetTimer( 2.0f );
  87. pGrenade->SetAbsVelocity( velocity );
  88. pGrenade->SetupInitialTransmittedGrenadeVelocity( velocity );
  89. pGrenade->SetThrower( pOwner );
  90. pGrenade->m_flDamage = 1.0f; // 25 = 1/4 of HEGrenade Damage
  91. pGrenade->m_DmgRadius = pGrenade->m_flDamage * 3.5f; // Changing damage will change the radius
  92. pGrenade->ChangeTeam( pOwner->GetTeamNumber() );
  93. pGrenade->SetAbsAngles( pOwner->EyeAngles() + QAngle( -80, 40, 0 ) );
  94. QAngle angRotationVel = QAngle( RandomFloat(100,200), RandomFloat(-100,200), RandomFloat(-100,200) );
  95. pGrenade->SetLocalAngularVelocity( angRotationVel );
  96. pGrenade->SetTouch( &CSensorGrenadeProjectile::BounceTouch );
  97. pGrenade->SetGravity( BaseClass::GetGrenadeGravity() );
  98. pGrenade->SetFriction( BaseClass::GetGrenadeFriction() );
  99. pGrenade->SetElasticity( BaseClass::GetGrenadeElasticity() );
  100. pGrenade->m_pWeaponInfo = &weaponInfo;
  101. ASSERT(pOwner != NULL);
  102. //pGrenade->SetCollisionGroup( COLLISION_GROUP_PROJECTILE );
  103. return pGrenade;
  104. }
  105. void CSensorGrenadeProjectile::SetTimer( float timer )
  106. {
  107. SetThink( &CSensorGrenadeProjectile::Think_Arm );
  108. SetNextThink( gpGlobals->curtime + timer );
  109. m_fNextDetectPlayerSound = gpGlobals->curtime;
  110. TheBots->SetGrenadeRadius( this, 0.0f );
  111. }
  112. void CSensorGrenadeProjectile::Think_Arm( void )
  113. {
  114. #if 1
  115. if ( GetAbsVelocity().Length() > 0.2f )
  116. {
  117. // Still moving. Don't detonate yet.
  118. SetNextThink( gpGlobals->curtime + 0.2f );
  119. return;
  120. }
  121. #endif // 0
  122. m_fExpireTime = gpGlobals->curtime + 2.0f; // TODO: Make this Data Driven
  123. SetThink( &CSensorGrenadeProjectile::SensorThink );
  124. //TheBots->SetGrenadeRadius( this, SensorGrenadeGrenadeRadius );
  125. SensorThink(); // This will handling the 'Detonate'
  126. }
  127. void CSensorGrenadeProjectile::Think_Remove( void )
  128. {
  129. UTIL_Remove( this );
  130. }
  131. void CSensorGrenadeProjectile::Detonate( void )
  132. {
  133. // [mlowrance] The SensorGrenade is handling it's own detonate.
  134. Assert(!"SensorGrenade grenade handles its own detonation");
  135. }
  136. void CSensorGrenadeProjectile::SensorThink( void )
  137. {
  138. // tell the bots about the gunfire
  139. CCSPlayer *pThrower = ToCSPlayer( GetThrower() );
  140. if ( !pThrower )
  141. return;
  142. if ( gpGlobals->curtime > m_fNextDetectPlayerSound )
  143. {
  144. EmitSound( "Sensor.WarmupBeep" );
  145. m_fNextDetectPlayerSound = gpGlobals->curtime + 1.0f; // TODO: Make this Data Driven
  146. }
  147. if ( gpGlobals->curtime < m_fExpireTime )
  148. {
  149. SetNextThink( gpGlobals->curtime + 0.1f );
  150. }
  151. else
  152. {
  153. // [mlowrance] Do the damage on Despawn and post event
  154. CCSPlayer *player = ToCSPlayer( GetThrower() );
  155. if ( player )
  156. {
  157. IGameEvent * event = gameeventmanager->CreateEvent( "tagrenade_detonate" );
  158. if ( event )
  159. {
  160. event->SetInt( "userid", player->GetUserID() );
  161. event->SetInt( "entityid", this->entindex() );
  162. event->SetFloat( "x", GetAbsOrigin().x );
  163. event->SetFloat( "y", GetAbsOrigin().y );
  164. event->SetFloat( "z", GetAbsOrigin().z );
  165. gameeventmanager->FireEvent( event );
  166. }
  167. }
  168. TheBots->RemoveGrenade( this );
  169. DispatchParticleEffect( "weapon_sensorgren_detonate", PATTACH_POINT, this, "Wick" );
  170. EmitSound( "Sensor.Detonate" );
  171. DoDetectWave();
  172. //BaseClass::Detonate();
  173. }
  174. }
  175. void CSensorGrenadeProjectile::DoDetectWave( void )
  176. {
  177. // tell the bots about the gunfire
  178. CCSPlayer *pThrower = ToCSPlayer( GetThrower() );
  179. if ( !pThrower )
  180. return;
  181. for ( int i = 1; i <= MAX_PLAYERS; i++ )
  182. {
  183. CCSPlayer *pPlayer = ToCSPlayer( UTIL_PlayerByIndex( i ) );
  184. if ( !pPlayer || !pPlayer->IsAlive() || !pThrower->IsOtherEnemy( pPlayer ) )
  185. continue;
  186. Vector vDelta = pPlayer->EyePosition() - GetAbsOrigin();
  187. float flDistance = vDelta.Length();
  188. float flMaxTraceDist = 1600;
  189. if ( flDistance <= flMaxTraceDist )
  190. {
  191. trace_t tr;
  192. //if ( pCSPlayer->IsAlive() && ( flTargetIDCone > flViewCone ) && !bShowAllNamesForSpec )
  193. {
  194. if ( TheCSBots()->IsLineBlockedBySmoke( pPlayer->EyePosition(), GetAbsOrigin(), 1.0f ) )
  195. {
  196. // if we are outside half the max dist and don't trace, dont show
  197. if ( flDistance > (flMaxTraceDist/2) )
  198. continue;
  199. }
  200. UTIL_TraceLine( pPlayer->EyePosition(), GetAbsOrigin(), MASK_VISIBLE, pPlayer, COLLISION_GROUP_DEBRIS, &tr );
  201. if ( tr.fraction != 1 )
  202. {
  203. trace_t tr2;
  204. UTIL_TraceLine( pPlayer->GetAbsOrigin() + Vector( 0, 0, 16 ), GetAbsOrigin(), MASK_VISIBLE, pPlayer, COLLISION_GROUP_DEBRIS, &tr2 );
  205. if ( tr2.fraction != 1 )
  206. {
  207. // if we are outside half the max dist and don't trace, dont show
  208. if ( flDistance > (flMaxTraceDist/2) )
  209. continue;
  210. }
  211. }
  212. int nThrowerIndex = 0;
  213. for ( int i = 1; i <= MAX_PLAYERS; i++ )
  214. {
  215. CCSPlayer *pPlayer = ToCSPlayer( UTIL_PlayerByIndex( i ) );
  216. if ( pPlayer == pThrower )
  217. {
  218. nThrowerIndex = i;
  219. break;
  220. }
  221. }
  222. DebugDrawLine( WorldSpaceCenter(), pPlayer->WorldSpaceCenter(), 90, 0, 0, true, 1.5f );
  223. pPlayer->SetIsSpotted( true );
  224. pPlayer->SetIsSpottedBy( nThrowerIndex );
  225. pPlayer->m_flDetectedByEnemySensorTime = gpGlobals->curtime;
  226. pPlayer->Blind( 0.02f, 1.0f, 128 );
  227. pPlayer->EmitSound( "Sensor.WarmupBeep" );
  228. }
  229. }
  230. }
  231. SetNextThink( gpGlobals->curtime + 0.25f );
  232. SetThink( &CSensorGrenadeProjectile::Think_Remove );
  233. }
  234. void CSensorGrenadeProjectile::Spawn( void )
  235. {
  236. SetModel( GRENADE_MODEL );
  237. BaseClass::Spawn();
  238. SetSolid( SOLID_BBOX );
  239. AddSolidFlags( FSOLID_NOT_STANDABLE );
  240. }
  241. void CSensorGrenadeProjectile::Precache( void )
  242. {
  243. PrecacheModel( GRENADE_MODEL );
  244. PrecacheScriptSound( "Sensor.Detonate" );
  245. PrecacheScriptSound( "Sensor.WarmupBeep" );
  246. PrecacheScriptSound( "Sensor.Activate" );
  247. PrecacheScriptSound( "Flashbang.Bounce" );
  248. //PrecacheParticleSystem( "weapon_sen_active" );
  249. PrecacheParticleSystem( "weapon_sensorgren_detlight" );
  250. PrecacheParticleSystem( "weapon_sensorgren_detonate" );
  251. BaseClass::Precache();
  252. }
  253. void CSensorGrenadeProjectile::BounceTouch( CBaseEntity *other )
  254. {
  255. if ( other->IsSolidFlagSet( FSOLID_TRIGGER | FSOLID_VOLUME_CONTENTS ) )
  256. return;
  257. // don't hit the guy that launched this grenade
  258. if ( other == GetThrower() )
  259. return;
  260. if ( FClassnameIs( other, "func_breakable" ) )
  261. {
  262. return;
  263. }
  264. if ( FClassnameIs( other, "func_breakable_surf" ) )
  265. {
  266. return;
  267. }
  268. // don't detonate on ladders
  269. if ( FClassnameIs( other, "func_ladder" ) )
  270. {
  271. return;
  272. }
  273. // Deal car alarms direct damage to set them off - flames won't do so
  274. if ( FClassnameIs( other, "prop_car_alarm" ) || FClassnameIs( other, "prop_car_glass" ) )
  275. {
  276. CTakeDamageInfo info( this, GetThrower(), 10, DMG_GENERIC );
  277. other->OnTakeDamage( info );
  278. }
  279. const trace_t &hitTrace = GetTouchTrace();
  280. if ( hitTrace.m_pEnt && hitTrace.m_pEnt->MyCombatCharacterPointer() )
  281. {
  282. // don't break if we hit an actor - wait until we hit the environment
  283. return;
  284. }
  285. else
  286. {
  287. SetAbsVelocity( Vector( 0, 0, 0) );
  288. SetMoveType(MOVETYPE_NONE);
  289. SetNextThink( gpGlobals->curtime + 1.0f );
  290. SetThink( &CSensorGrenadeProjectile::Think_Arm );
  291. EmitSound( "Sensor.Activate" );
  292. m_fExpireTime = gpGlobals->curtime + 15.0f; // TODO: Make this Data Driven
  293. // stick the grenade onto the target surface using the closest rotational alignment to match the in-flight orientation,
  294. // ( like breach charges )
  295. Vector vecSurfNormal = hitTrace.plane.normal.Normalized();
  296. Vector vecProjectileZ = EntityToWorldTransform().GetColumn(Z_AXIS);
  297. // 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'.
  298. if ( DotProduct( vecSurfNormal, vecProjectileZ ) < 0 )
  299. vecSurfNormal = -vecSurfNormal;
  300. QAngle angSurface;
  301. MatrixAngles( ConcatTransforms( QuaternionMatrix( RotateBetween( vecProjectileZ, vecSurfNormal ) ), EntityToWorldTransform() ), angSurface );
  302. SetAbsAngles( angSurface );
  303. //if ( fabs(hitTrace.plane.normal.Dot(Vector(0,0,1))) > 0.65f )
  304. {
  305. //get the player forward vector
  306. // Vector vecFlatForward;
  307. // VectorCopy( pPlayer->Forward(), vecFlatForward );
  308. // vecFlatForward.z = 0;
  309. //
  310. // //derive c4 forward and right
  311. // Vector vecC4Right = CrossProduct( vecFlatForward.Normalized(), hitTrace.plane.normal );
  312. // Vector vecC4Forward = CrossProduct( vecC4Right, trPlant.plane.normal );
  313. //QAngle angle;
  314. //VectorAngles( hitTrace.plane.normal, angle );
  315. //SetAbsAngles( angle );
  316. //m_hDisplayGrenade = CreatePhysicsProp( GRENADE_MODEL, GetAbsOrigin(), GetAbsOrigin(), NULL, false, "prop_physics_multiplayer" );
  317. /*
  318. m_hDisplayGrenade = ( CBreakableProp * )CBaseEntity::CreateNoSpawn( "prop_physics", GetAbsOrigin(), angle );
  319. CBreakableProp *pDisplay = dynamic_cast< CBreakableProp* >( m_hDisplayGrenade.Get() );
  320. if ( pDisplay )
  321. {
  322. pDisplay->KeyValue( "fademindist", "-1" );
  323. pDisplay->KeyValue( "fademaxdist", "0" );
  324. pDisplay->KeyValue( "fadescale", "1" );
  325. pDisplay->KeyValue( "inertiaScale", "1.0" );
  326. pDisplay->KeyValue( "physdamagescale", "0.1" );
  327. //pDisplay->SetPhysicsMode( PHYSICS_MULTIPLAYER_SOLID );
  328. pDisplay->SetModel( GRENADE_MODEL );
  329. pDisplay->SetSolid( SOLID_BBOX );
  330. pDisplay->AddSolidFlags( FSOLID_NOT_STANDABLE );
  331. pDisplay->AddSpawnFlags( SF_PHYSPROP_MOTIONDISABLED );
  332. pDisplay->Precache();
  333. DispatchSpawn( pDisplay );
  334. pDisplay->Activate();
  335. // disable the parent model
  336. SetModelName( NULL_STRING );//invisible
  337. SetSolid( SOLID_NONE );
  338. }
  339. */
  340. }
  341. /*
  342. // only detonate on surfaces less steep than this
  343. const float kMinCos = cosf( DEG2RAD( weapon_molotov_maxdetonateslope.GetFloat() ) );
  344. if ( hitTrace.plane.normal.z >= kMinCos )
  345. {
  346. //Stick();
  347. }
  348. */
  349. }
  350. }
  351. //TODO: Let physics handle the sound!
  352. void CSensorGrenadeProjectile::BounceSound( void )
  353. {
  354. EmitSound( "Flashbang.Bounce" );
  355. }
  356. #endif // GAME_DLL