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.

316 lines
8.7 KiB

  1. //========= Copyright Valve Corporation, All rights reserved. ============//
  2. //
  3. // Purpose: TF Nail Grenade.
  4. //
  5. //=============================================================================//
  6. #include "cbase.h"
  7. #include "tf_weaponbase.h"
  8. #include "tf_gamerules.h"
  9. #include "npcevent.h"
  10. #include "engine/IEngineSound.h"
  11. #include "tf_weapon_grenade_nail.h"
  12. // Server specific.
  13. #ifdef GAME_DLL
  14. #include "tf_player.h"
  15. #include "items.h"
  16. #include "tf_weaponbase_grenadeproj.h"
  17. #include "soundent.h"
  18. #include "KeyValues.h"
  19. #include "tf_projectile_nail.h"
  20. #include "physics_saverestore.h"
  21. #include "phys_controller.h"
  22. #endif
  23. #define GRENADE_NAIL_TIMER 3.0f //Seconds
  24. //=============================================================================
  25. //
  26. // TF Nail Grenade tables.
  27. //
  28. IMPLEMENT_NETWORKCLASS_ALIASED( TFGrenadeNail, DT_TFGrenadeNail )
  29. BEGIN_NETWORK_TABLE( CTFGrenadeNail, DT_TFGrenadeNail )
  30. END_NETWORK_TABLE()
  31. BEGIN_PREDICTION_DATA( CTFGrenadeNail )
  32. END_PREDICTION_DATA()
  33. LINK_ENTITY_TO_CLASS( tf_weapon_grenade_nail, CTFGrenadeNail );
  34. PRECACHE_WEAPON_REGISTER( tf_weapon_grenade_nail );
  35. //=============================================================================
  36. //
  37. // TF Nail Grenade functions.
  38. //
  39. // Server specific.
  40. #ifdef GAME_DLL
  41. BEGIN_DATADESC( CTFGrenadeNail )
  42. END_DATADESC()
  43. //-----------------------------------------------------------------------------
  44. // Purpose:
  45. //-----------------------------------------------------------------------------
  46. CTFWeaponBaseGrenadeProj *CTFGrenadeNail::EmitGrenade( Vector vecSrc, QAngle vecAngles, Vector vecVel,
  47. AngularImpulse angImpulse, CBasePlayer *pPlayer, float flTime, int iflags )
  48. {
  49. return CTFGrenadeNailProjectile::Create( vecSrc, vecAngles, vecVel, angImpulse,
  50. pPlayer, GetTFWpnData(), flTime );
  51. }
  52. #endif
  53. //=============================================================================
  54. //
  55. // TF Nail Grenade Projectile functions (Server specific).
  56. //
  57. #ifdef GAME_DLL
  58. BEGIN_DATADESC( CTFGrenadeNailProjectile )
  59. DEFINE_THINKFUNC( EmitNails ),
  60. DEFINE_EMBEDDED( m_GrenadeController ),
  61. DEFINE_PHYSPTR( m_pMotionController ),
  62. END_DATADESC()
  63. #define GRENADE_MODEL "models/weapons/w_models/w_grenade_nail.mdl"
  64. LINK_ENTITY_TO_CLASS( tf_weapon_grenade_nail_projectile, CTFGrenadeNailProjectile );
  65. PRECACHE_WEAPON_REGISTER( tf_weapon_grenade_nail_projectile );
  66. //-----------------------------------------------------------------------------
  67. // Purpose:
  68. //-----------------------------------------------------------------------------
  69. CTFGrenadeNailProjectile* CTFGrenadeNailProjectile::Create( const Vector &position, const QAngle &angles,
  70. const Vector &velocity, const AngularImpulse &angVelocity,
  71. CBaseCombatCharacter *pOwner, const CTFWeaponInfo &weaponInfo, float timer, int iFlags )
  72. {
  73. // Nail grenades are always thrown like discs
  74. QAngle vecCustomAngles = angles;
  75. vecCustomAngles.x = clamp( vecCustomAngles.x, -10,10 );
  76. vecCustomAngles.z = clamp( vecCustomAngles.x, -10,10 );
  77. Vector vecCustomAngVelocity = vec3_origin;
  78. vecCustomAngVelocity.z = RandomFloat( -600, 600 );
  79. CTFGrenadeNailProjectile *pGrenade = static_cast<CTFGrenadeNailProjectile*>( CTFWeaponBaseGrenadeProj::Create( "tf_weapon_grenade_nail_projectile", position, vecCustomAngles, velocity, vecCustomAngVelocity, pOwner, weaponInfo, timer, iFlags ) );
  80. return pGrenade;
  81. }
  82. CTFGrenadeNailProjectile::~CTFGrenadeNailProjectile()
  83. {
  84. if ( m_pMotionController != NULL )
  85. {
  86. physenv->DestroyMotionController( m_pMotionController );
  87. m_pMotionController = NULL;
  88. }
  89. }
  90. //-----------------------------------------------------------------------------
  91. // Purpose:
  92. //-----------------------------------------------------------------------------
  93. void CTFGrenadeNailProjectile::Spawn()
  94. {
  95. SetModel( GRENADE_MODEL );
  96. m_pMotionController = NULL;
  97. UseClientSideAnimation();
  98. BaseClass::Spawn();
  99. }
  100. //-----------------------------------------------------------------------------
  101. // Purpose:
  102. //-----------------------------------------------------------------------------
  103. void CTFGrenadeNailProjectile::Precache()
  104. {
  105. PrecacheModel( GRENADE_MODEL );
  106. PrecacheScriptSound( "Weapon_Grenade_Nail.Launch" );
  107. BaseClass::Precache();
  108. }
  109. //-----------------------------------------------------------------------------
  110. // Purpose:
  111. //-----------------------------------------------------------------------------
  112. void CTFGrenadeNailProjectile::BounceSound( void )
  113. {
  114. EmitSound( "Weapon_Grenade_Nail.Bounce" );
  115. }
  116. //-----------------------------------------------------------------------------
  117. // Purpose:
  118. //-----------------------------------------------------------------------------
  119. void CTFGrenadeNailProjectile::Detonate()
  120. {
  121. if ( ShouldNotDetonate() )
  122. {
  123. RemoveGrenade();
  124. return;
  125. }
  126. StartEmittingNails();
  127. }
  128. //-----------------------------------------------------------------------------
  129. // Purpose:
  130. //-----------------------------------------------------------------------------
  131. int CTFGrenadeNailProjectile::OnTakeDamage( const CTakeDamageInfo &info )
  132. {
  133. if ( m_pMotionController != NULL )
  134. {
  135. // motioncontroller is animating us, dont take hits that will disorient us
  136. return 0;
  137. }
  138. return BaseClass::OnTakeDamage( info );
  139. }
  140. void CTFGrenadeNailProjectile::StartEmittingNails( void )
  141. {
  142. // 0.4 seconds later, emit nails
  143. IPhysicsObject *pPhysicsObject = VPhysicsGetObject();
  144. if ( pPhysicsObject )
  145. {
  146. m_pMotionController = physenv->CreateMotionController( &m_GrenadeController );
  147. m_pMotionController->AttachObject( pPhysicsObject, true );
  148. pPhysicsObject->EnableGravity( false );
  149. pPhysicsObject->Wake();
  150. }
  151. QAngle ang(0,0,0);
  152. Vector pos = GetAbsOrigin();
  153. pos.z += 32;
  154. m_GrenadeController.SetDesiredPosAndOrientation( pos, ang );
  155. m_flNailAngle = 0;
  156. m_iNumNailBurstsLeft = 40;
  157. int animDesired = SelectWeightedSequence( ACT_RANGE_ATTACK1 );
  158. ResetSequence( animDesired );
  159. SetPlaybackRate( 1.0 );
  160. Vector soundPosition = GetAbsOrigin() + Vector( 0, 0, 5 );
  161. CPASAttenuationFilter filter( soundPosition );
  162. EmitSound( filter, entindex(), "Weapon_Grenade_Nail.Launch" );
  163. #ifdef GAME_DLL
  164. SetThink( &CTFGrenadeNailProjectile::EmitNails );
  165. SetNextThink( gpGlobals->curtime + 0.4 );
  166. #endif
  167. }
  168. void CTFGrenadeNailProjectile::EmitNails( void )
  169. {
  170. m_iNumNailBurstsLeft--;
  171. if ( m_iNumNailBurstsLeft < 0 )
  172. {
  173. BaseClass::Detonate();
  174. return;
  175. }
  176. Vector forward, up;
  177. float flAngleToAdd = random->RandomFloat( 30, 40 );
  178. // else release some nails
  179. for ( int i=0; i < 4 ;i++ )
  180. {
  181. m_flNailAngle = UTIL_AngleMod( m_flNailAngle + flAngleToAdd );
  182. QAngle angNail( random->RandomFloat( -3, 3 ), m_flNailAngle, 0 );
  183. // Emit a nail
  184. CTFProjectile_Nail *pNail = CTFProjectile_Nail::Create( GetAbsOrigin(), angNail, this, GetThrower() );
  185. if ( pNail )
  186. {
  187. pNail->SetDamage( 18 );
  188. }
  189. }
  190. SetNextThink( gpGlobals->curtime + 0.1 );
  191. }
  192. IMotionEvent::simresult_e CNailGrenadeController::Simulate( IPhysicsMotionController *pController, IPhysicsObject *pObject, float deltaTime, Vector &linear, AngularImpulse &angular )
  193. {
  194. // Try to get to m_vecDesiredPosition
  195. // Try to orient ourselves to m_angDesiredOrientation
  196. Vector currentPos;
  197. QAngle currentAng;
  198. pObject->GetPosition( &currentPos, &currentAng );
  199. Vector vecVel;
  200. AngularImpulse angVel;
  201. pObject->GetVelocity( &vecVel, &angVel );
  202. linear.Init();
  203. angular.Init();
  204. if ( m_bReachedPos )
  205. {
  206. // Lock at this height
  207. if ( vecVel.Length() > 1.0 )
  208. {
  209. AngularImpulse nil( 0,0,0 );
  210. pObject->SetVelocityInstantaneous( &vec3_origin, &nil );
  211. // For now teleport to the proper orientation
  212. currentAng.x = 0;
  213. currentAng.y = 0;
  214. currentAng.z = 0;
  215. pObject->SetPosition( currentPos, currentAng, true );
  216. }
  217. }
  218. else
  219. {
  220. // not at the right height yet, keep moving up
  221. linear.z = 50 * ( m_vecDesiredPosition.z - currentPos.z );
  222. if ( currentPos.z > m_vecDesiredPosition.z )
  223. {
  224. // lock into position
  225. m_bReachedPos = true;
  226. }
  227. // Start rotating in the right direction
  228. // we'll lock angles once we reach proper height to stop the oscillating
  229. matrix3x4_t matrix;
  230. // get the object's local to world transform
  231. pObject->GetPositionMatrix( &matrix );
  232. Vector m_worldGoalAxis(0,0,1);
  233. // Get the alignment axis in object space
  234. Vector currentLocalTargetAxis;
  235. VectorIRotate( m_worldGoalAxis, matrix, currentLocalTargetAxis );
  236. float invDeltaTime = (1/deltaTime);
  237. float m_angularLimit = 10;
  238. angular = ComputeRotSpeedToAlignAxes( m_worldGoalAxis, currentLocalTargetAxis, angVel, 1.0, invDeltaTime * invDeltaTime, m_angularLimit * invDeltaTime );
  239. }
  240. return SIM_GLOBAL_ACCELERATION;
  241. }
  242. void CNailGrenadeController::SetDesiredPosAndOrientation( Vector pos, QAngle orientation )
  243. {
  244. m_vecDesiredPosition = pos;
  245. m_angDesiredOrientation = orientation;
  246. m_bReachedPos = false;
  247. m_bReachedOrientation = false;
  248. }
  249. BEGIN_SIMPLE_DATADESC( CNailGrenadeController )
  250. END_DATADESC()
  251. #endif