Team Fortress 2 Source Code as on 22/4/2020
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.

346 lines
8.5 KiB

  1. //========= Copyright Valve Corporation, All rights reserved. ============//
  2. //
  3. // Purpose:
  4. //
  5. //=============================================================================//
  6. #include "cbase.h"
  7. #include "basecsgrenade_projectile.h"
  8. float GetCurrentGravity( void );
  9. #ifdef CLIENT_DLL
  10. #include "c_cs_player.h"
  11. #else
  12. #include "bot_manager.h"
  13. #include "cs_player.h"
  14. #include "soundent.h"
  15. #include "te_effect_dispatch.h"
  16. #include "KeyValues.h"
  17. BEGIN_DATADESC( CBaseCSGrenadeProjectile )
  18. DEFINE_THINKFUNC( DangerSoundThink ),
  19. END_DATADESC()
  20. #endif
  21. IMPLEMENT_NETWORKCLASS_ALIASED( BaseCSGrenadeProjectile, DT_BaseCSGrenadeProjectile )
  22. BEGIN_NETWORK_TABLE( CBaseCSGrenadeProjectile, DT_BaseCSGrenadeProjectile )
  23. #ifdef CLIENT_DLL
  24. RecvPropVector( RECVINFO( m_vInitialVelocity ) )
  25. #else
  26. SendPropVector( SENDINFO( m_vInitialVelocity ),
  27. 20, // nbits
  28. 0, // flags
  29. -3000, // low value
  30. 3000 // high value
  31. )
  32. #endif
  33. END_NETWORK_TABLE()
  34. #ifdef CLIENT_DLL
  35. void CBaseCSGrenadeProjectile::PostDataUpdate( DataUpdateType_t type )
  36. {
  37. BaseClass::PostDataUpdate( type );
  38. if ( type == DATA_UPDATE_CREATED )
  39. {
  40. // Now stick our initial velocity into the interpolation history
  41. CInterpolatedVar< Vector > &interpolator = GetOriginInterpolator();
  42. interpolator.ClearHistory();
  43. float changeTime = GetLastChangeTime( LATCH_SIMULATION_VAR );
  44. // Add a sample 1 second back.
  45. Vector vCurOrigin = GetLocalOrigin() - m_vInitialVelocity;
  46. interpolator.AddToHead( changeTime - 1.0, &vCurOrigin, false );
  47. // Add the current sample.
  48. vCurOrigin = GetLocalOrigin();
  49. interpolator.AddToHead( changeTime, &vCurOrigin, false );
  50. }
  51. }
  52. int CBaseCSGrenadeProjectile::DrawModel( int flags )
  53. {
  54. // During the first half-second of our life, don't draw ourselves if he's
  55. // still playing his throw animation.
  56. // (better yet, we could draw ourselves in his hand).
  57. if ( GetThrower() != C_BasePlayer::GetLocalPlayer() )
  58. {
  59. if ( gpGlobals->curtime - m_flSpawnTime < 0.5 )
  60. {
  61. C_CSPlayer *pPlayer = dynamic_cast<C_CSPlayer*>( GetThrower() );
  62. if ( pPlayer && pPlayer->m_PlayerAnimState->IsThrowingGrenade() )
  63. {
  64. return 0;
  65. }
  66. }
  67. }
  68. return BaseClass::DrawModel( flags );
  69. }
  70. void CBaseCSGrenadeProjectile::Spawn()
  71. {
  72. m_flSpawnTime = gpGlobals->curtime;
  73. BaseClass::Spawn();
  74. }
  75. #else
  76. void CBaseCSGrenadeProjectile::PostConstructor( const char *className )
  77. {
  78. BaseClass::PostConstructor( className );
  79. TheBots->AddGrenade( this );
  80. }
  81. CBaseCSGrenadeProjectile::~CBaseCSGrenadeProjectile()
  82. {
  83. TheBots->RemoveGrenade( this );
  84. }
  85. void CBaseCSGrenadeProjectile::Spawn( void )
  86. {
  87. BaseClass::Spawn();
  88. SetSolidFlags( FSOLID_NOT_STANDABLE );
  89. SetMoveType( MOVETYPE_FLYGRAVITY, MOVECOLLIDE_FLY_CUSTOM );
  90. SetSolid( SOLID_BBOX ); // So it will collide with physics props!
  91. // smaller, cube bounding box so we rest on the ground
  92. SetSize( Vector ( -2, -2, -2 ), Vector ( 2, 2, 2 ) );
  93. }
  94. void CBaseCSGrenadeProjectile::DangerSoundThink( void )
  95. {
  96. if (!IsInWorld())
  97. {
  98. Remove( );
  99. return;
  100. }
  101. if( gpGlobals->curtime > m_flDetonateTime )
  102. {
  103. Detonate();
  104. return;
  105. }
  106. CSoundEnt::InsertSound ( SOUND_DANGER, GetAbsOrigin() + GetAbsVelocity() * 0.5, GetAbsVelocity().Length( ), 0.2 );
  107. SetNextThink( gpGlobals->curtime + 0.2 );
  108. if (GetWaterLevel() != 0)
  109. {
  110. SetAbsVelocity( GetAbsVelocity() * 0.5 );
  111. }
  112. }
  113. //Sets the time at which the grenade will explode
  114. void CBaseCSGrenadeProjectile::SetDetonateTimerLength( float timer )
  115. {
  116. m_flDetonateTime = gpGlobals->curtime + timer;
  117. }
  118. void CBaseCSGrenadeProjectile::ResolveFlyCollisionCustom( trace_t &trace, Vector &vecVelocity )
  119. {
  120. //Assume all surfaces have the same elasticity
  121. float flSurfaceElasticity = 1.0;
  122. //Don't bounce off of players with perfect elasticity
  123. if( trace.m_pEnt && trace.m_pEnt->IsPlayer() )
  124. {
  125. flSurfaceElasticity = 0.3;
  126. }
  127. // if its breakable glass and we kill it, don't bounce.
  128. // give some damage to the glass, and if it breaks, pass
  129. // through it.
  130. bool breakthrough = false;
  131. if( trace.m_pEnt && FClassnameIs( trace.m_pEnt, "func_breakable" ) )
  132. {
  133. breakthrough = true;
  134. }
  135. if( trace.m_pEnt && FClassnameIs( trace.m_pEnt, "func_breakable_surf" ) )
  136. {
  137. breakthrough = true;
  138. }
  139. if (breakthrough)
  140. {
  141. CTakeDamageInfo info( this, this, 10, DMG_CLUB );
  142. trace.m_pEnt->DispatchTraceAttack( info, GetAbsVelocity(), &trace );
  143. ApplyMultiDamage();
  144. if( trace.m_pEnt->m_iHealth <= 0 )
  145. {
  146. // slow our flight a little bit
  147. Vector vel = GetAbsVelocity();
  148. vel *= 0.4;
  149. SetAbsVelocity( vel );
  150. return;
  151. }
  152. }
  153. float flTotalElasticity = GetElasticity() * flSurfaceElasticity;
  154. flTotalElasticity = clamp( flTotalElasticity, 0.0f, 0.9f );
  155. // NOTE: A backoff of 2.0f is a reflection
  156. Vector vecAbsVelocity;
  157. PhysicsClipVelocity( GetAbsVelocity(), trace.plane.normal, vecAbsVelocity, 2.0f );
  158. vecAbsVelocity *= flTotalElasticity;
  159. // Get the total velocity (player + conveyors, etc.)
  160. VectorAdd( vecAbsVelocity, GetBaseVelocity(), vecVelocity );
  161. float flSpeedSqr = DotProduct( vecVelocity, vecVelocity );
  162. // Stop if on ground.
  163. if ( trace.plane.normal.z > 0.7f ) // Floor
  164. {
  165. // Verify that we have an entity.
  166. CBaseEntity *pEntity = trace.m_pEnt;
  167. Assert( pEntity );
  168. SetAbsVelocity( vecAbsVelocity );
  169. if ( flSpeedSqr < ( 30 * 30 ) )
  170. {
  171. if ( pEntity->IsStandable() )
  172. {
  173. SetGroundEntity( pEntity );
  174. }
  175. // Reset velocities.
  176. SetAbsVelocity( vec3_origin );
  177. SetLocalAngularVelocity( vec3_angle );
  178. //align to the ground so we're not standing on end
  179. QAngle angle;
  180. VectorAngles( trace.plane.normal, angle );
  181. // rotate randomly in yaw
  182. angle[1] = random->RandomFloat( 0, 360 );
  183. // TODO: rotate around trace.plane.normal
  184. SetAbsAngles( angle );
  185. }
  186. else
  187. {
  188. Vector vecDelta = GetBaseVelocity() - vecAbsVelocity;
  189. Vector vecBaseDir = GetBaseVelocity();
  190. VectorNormalize( vecBaseDir );
  191. float flScale = vecDelta.Dot( vecBaseDir );
  192. VectorScale( vecAbsVelocity, ( 1.0f - trace.fraction ) * gpGlobals->frametime, vecVelocity );
  193. VectorMA( vecVelocity, ( 1.0f - trace.fraction ) * gpGlobals->frametime, GetBaseVelocity() * flScale, vecVelocity );
  194. PhysicsPushEntity( vecVelocity, &trace );
  195. }
  196. }
  197. else
  198. {
  199. // If we get *too* slow, we'll stick without ever coming to rest because
  200. // we'll get pushed down by gravity faster than we can escape from the wall.
  201. if ( flSpeedSqr < ( 30 * 30 ) )
  202. {
  203. // Reset velocities.
  204. SetAbsVelocity( vec3_origin );
  205. SetLocalAngularVelocity( vec3_angle );
  206. }
  207. else
  208. {
  209. SetAbsVelocity( vecAbsVelocity );
  210. }
  211. }
  212. BounceSound();
  213. // tell the bots a grenade has bounced
  214. CCSPlayer *player = ToCSPlayer(GetThrower());
  215. if ( player )
  216. {
  217. IGameEvent * event = gameeventmanager->CreateEvent( "grenade_bounce" );
  218. if ( event )
  219. {
  220. event->SetInt( "userid", player->GetUserID() );
  221. event->SetFloat( "x", GetAbsOrigin().x );
  222. event->SetFloat( "y", GetAbsOrigin().y );
  223. event->SetFloat( "z", GetAbsOrigin().z );
  224. gameeventmanager->FireEvent( event );
  225. }
  226. }
  227. }
  228. void CBaseCSGrenadeProjectile::SetupInitialTransmittedGrenadeVelocity( const Vector &velocity )
  229. {
  230. m_vInitialVelocity = velocity;
  231. }
  232. #define MAX_WATER_SURFACE_DISTANCE 512
  233. void CBaseCSGrenadeProjectile::Splash()
  234. {
  235. Vector centerPoint = GetAbsOrigin();
  236. Vector normal( 0, 0, 1 );
  237. // Find our water surface by tracing up till we're out of the water
  238. trace_t tr;
  239. Vector vecTrace( 0, 0, MAX_WATER_SURFACE_DISTANCE );
  240. UTIL_TraceLine( centerPoint, centerPoint + vecTrace, MASK_WATER, NULL, COLLISION_GROUP_NONE, &tr );
  241. // If we didn't start in water, we're above it
  242. if ( tr.startsolid == false )
  243. {
  244. // Look downward to find the surface
  245. vecTrace.Init( 0, 0, -MAX_WATER_SURFACE_DISTANCE );
  246. UTIL_TraceLine( centerPoint, centerPoint + vecTrace, MASK_WATER, NULL, COLLISION_GROUP_NONE, &tr );
  247. // If we hit it, setup the explosion
  248. if ( tr.fraction < 1.0f )
  249. {
  250. centerPoint = tr.endpos;
  251. }
  252. else
  253. {
  254. //NOTENOTE: We somehow got into a splash without being near water?
  255. Assert( 0 );
  256. }
  257. }
  258. else if ( tr.fractionleftsolid )
  259. {
  260. // Otherwise we came out of the water at this point
  261. centerPoint = centerPoint + (vecTrace * tr.fractionleftsolid);
  262. }
  263. else
  264. {
  265. // Use default values, we're really deep
  266. }
  267. CEffectData data;
  268. data.m_vOrigin = centerPoint;
  269. data.m_vNormal = normal;
  270. data.m_flScale = random->RandomFloat( 1.0f, 2.0f );
  271. if ( GetWaterType() & CONTENTS_SLIME )
  272. {
  273. data.m_fFlags |= FX_WATER_IN_SLIME;
  274. }
  275. DispatchEffect( "gunshotsplash", data );
  276. }
  277. #endif // !CLIENT_DLL