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.

474 lines
13 KiB

  1. //========= Copyright Valve Corporation, All rights reserved. ============//
  2. //
  3. // Purpose:
  4. //
  5. //=============================================================================//
  6. #include "cbase.h"
  7. #include "weapon_dodbasegrenade.h"
  8. #include "in_buttons.h"
  9. #include "dod_gamerules.h"
  10. #if defined( CLIENT_DLL )
  11. #include "c_dod_player.h"
  12. #else
  13. #include "dod_player.h"
  14. #endif
  15. extern ConVar dod_bonusround;
  16. IMPLEMENT_NETWORKCLASS_ALIASED( WeaponDODBaseGrenade, DT_WeaponDODBaseGrenade )
  17. BEGIN_NETWORK_TABLE(CWeaponDODBaseGrenade, DT_WeaponDODBaseGrenade)
  18. #if !defined( CLIENT_DLL )
  19. SendPropBool( SENDINFO( m_bPinPulled ) ),
  20. SendPropBool( SENDINFO( m_bArmed ) ),
  21. #else
  22. RecvPropBool( RECVINFO( m_bPinPulled ) ),
  23. RecvPropBool( RECVINFO( m_bArmed ) ),
  24. #endif
  25. END_NETWORK_TABLE()
  26. BEGIN_PREDICTION_DATA( CWeaponDODBaseGrenade )
  27. END_PREDICTION_DATA()
  28. LINK_ENTITY_TO_CLASS( weapon_basedodgrenade, CWeaponDODBaseGrenade );
  29. acttable_t CWeaponDODBaseGrenade::m_acttable[] =
  30. {
  31. // Move this out to the specific grenades???
  32. { ACT_DOD_STAND_AIM, ACT_DOD_STAND_AIM_GREN_FRAG, false },
  33. { ACT_DOD_CROUCH_AIM, ACT_DOD_CROUCH_AIM_GREN_FRAG, false },
  34. { ACT_DOD_CROUCHWALK_AIM, ACT_DOD_CROUCHWALK_AIM_GREN_FRAG, false },
  35. { ACT_DOD_WALK_AIM, ACT_DOD_WALK_AIM_GREN_FRAG, false },
  36. { ACT_DOD_RUN_AIM, ACT_DOD_RUN_AIM_GREN_FRAG, false },
  37. { ACT_PRONE_IDLE, ACT_DOD_PRONE_AIM_GREN_FRAG, false },
  38. { ACT_PRONE_FORWARD, ACT_DOD_PRONEWALK_AIM_GREN_FRAG, false },
  39. { ACT_DOD_STAND_IDLE, ACT_DOD_STAND_AIM_GREN_FRAG, false },
  40. { ACT_DOD_CROUCH_IDLE, ACT_DOD_CROUCH_AIM_GREN_FRAG, false },
  41. { ACT_DOD_CROUCHWALK_IDLE, ACT_DOD_CROUCHWALK_AIM_GREN_FRAG, false },
  42. { ACT_DOD_WALK_IDLE, ACT_DOD_WALK_AIM_GREN_FRAG, false },
  43. { ACT_DOD_RUN_IDLE, ACT_DOD_RUN_AIM_GREN_FRAG, false },
  44. { ACT_SPRINT, ACT_DOD_SPRINT_AIM_GREN_FRAG, false },
  45. { ACT_RANGE_ATTACK1, ACT_DOD_PRIMARYATTACK_GREN_FRAG, false },
  46. { ACT_DOD_PRIMARYATTACK_PRONE, ACT_DOD_PRIMARYATTACK_PRONE_GREN_FRAG, false },
  47. { ACT_DOD_PRIMARYATTACK_CROUCH, ACT_DOD_PRIMARYATTACK_CROUCH_GREN_FRAG, false },
  48. // Hand Signals
  49. { ACT_DOD_HS_IDLE, ACT_DOD_HS_IDLE_STICKGRENADE, false },
  50. { ACT_DOD_HS_CROUCH, ACT_DOD_HS_CROUCH_STICKGRENADE, false },
  51. };
  52. IMPLEMENT_ACTTABLE( CWeaponDODBaseGrenade );
  53. CWeaponDODBaseGrenade::CWeaponDODBaseGrenade()
  54. {
  55. m_bRedraw = false;
  56. m_bPinPulled = false;
  57. SetArmed( false );
  58. m_iAltFireHint = HINT_USE_PRIME;
  59. }
  60. //-----------------------------------------------------------------------------
  61. // Purpose:
  62. //-----------------------------------------------------------------------------
  63. bool CWeaponDODBaseGrenade::CanHolster( void )
  64. {
  65. // can only holster hand grenades when not primed!
  66. return ( m_bPinPulled == false && !IsArmed() );
  67. }
  68. #ifdef CLIENT_DLL
  69. void CWeaponDODBaseGrenade::PrimaryAttack()
  70. {
  71. //nothing on the client
  72. }
  73. #else
  74. BEGIN_DATADESC( CWeaponDODBaseGrenade )
  75. DEFINE_FIELD( m_bRedraw, FIELD_BOOLEAN ),
  76. DEFINE_INPUTFUNC( FIELD_FLOAT, "DetonateTime", InputSetDetonateTime ),
  77. END_DATADESC()
  78. //-----------------------------------------------------------------------------
  79. // Purpose:
  80. //-----------------------------------------------------------------------------
  81. void CWeaponDODBaseGrenade::Precache()
  82. {
  83. PrecacheScriptSound( "Weapon_Grenade.Throw" );
  84. // Precache all the grenade minimap icons.
  85. PrecacheMaterial( "sprites/minimap_icons/minimap_riflegren_ger" );
  86. PrecacheMaterial( "sprites/minimap_icons/minimap_riflegren_us" );
  87. PrecacheMaterial( "sprites/minimap_icons/grenade_hltv" );
  88. PrecacheMaterial( "sprites/minimap_icons/stick_hltv" );
  89. PrecacheMaterial( "sprites/minimap_icons/minimap_smoke_us" );
  90. PrecacheMaterial( "sprites/minimap_icons/minimap_smoke_ger" );
  91. BaseClass::Precache();
  92. }
  93. //-----------------------------------------------------------------------------
  94. // Purpose:
  95. //-----------------------------------------------------------------------------
  96. bool CWeaponDODBaseGrenade::Deploy()
  97. {
  98. m_bRedraw = false;
  99. m_bPinPulled = false;
  100. return BaseClass::Deploy();
  101. }
  102. //-----------------------------------------------------------------------------
  103. // Purpose:
  104. // Output : Returns true on success, false on failure.
  105. //-----------------------------------------------------------------------------
  106. bool CWeaponDODBaseGrenade::Holster( CBaseCombatWeapon *pSwitchingTo )
  107. {
  108. m_bRedraw = false;
  109. #ifndef CLIENT_DLL
  110. // If they attempt to switch weapons before the throw animation is done,
  111. // allow it, but kill the weapon if we have to.
  112. CDODPlayer *pPlayer = ToDODPlayer( GetPlayerOwner() );
  113. if( pPlayer && pPlayer->GetAmmoCount(m_iPrimaryAmmoType) <= 0 )
  114. {
  115. pPlayer->Weapon_Drop( this, NULL, NULL );
  116. UTIL_Remove(this);
  117. }
  118. #endif
  119. return BaseClass::Holster( pSwitchingTo );
  120. }
  121. //-----------------------------------------------------------------------------
  122. // Purpose:
  123. // Output : Returns true on success, false on failure.
  124. //-----------------------------------------------------------------------------
  125. bool CWeaponDODBaseGrenade::Reload()
  126. {
  127. if ( ( m_bRedraw ) && ( m_flNextPrimaryAttack <= gpGlobals->curtime ) && ( m_flNextSecondaryAttack <= gpGlobals->curtime ) )
  128. {
  129. //Redraw the weapon
  130. SendWeaponAnim( GetDrawActivity() );
  131. //Update our times
  132. m_flNextPrimaryAttack = gpGlobals->curtime + SequenceDuration();
  133. m_flNextSecondaryAttack = gpGlobals->curtime + SequenceDuration();
  134. m_flTimeWeaponIdle = gpGlobals->curtime + SequenceDuration();
  135. //Mark this as done
  136. m_bRedraw = false;
  137. }
  138. return true;
  139. }
  140. enum
  141. {
  142. THROW_THROW = 0,
  143. THROW_PRIME
  144. };
  145. //-----------------------------------------------------------------------------
  146. // Purpose:
  147. //-----------------------------------------------------------------------------
  148. void CWeaponDODBaseGrenade::PrimaryAttack()
  149. {
  150. if ( IsArmed() ) // live grenade already?
  151. {
  152. StartThrow( THROW_THROW );
  153. }
  154. else
  155. {
  156. StartThrow( THROW_PRIME );
  157. }
  158. }
  159. void CWeaponDODBaseGrenade::StartThrow( int throwType )
  160. {
  161. if( GetPlayerOwner()->GetWaterLevel() > 2 )
  162. {
  163. PlayEmptySound();
  164. m_flNextPrimaryAttack = gpGlobals->curtime + 1.0;
  165. return;
  166. }
  167. if ( !m_bPinPulled )
  168. {
  169. m_bPinPulled = true;
  170. SendWeaponAnim( GetPrimaryAttackActivity() );
  171. // Can't prime an already primed grenade!
  172. if ( !IsArmed() && throwType == THROW_PRIME )
  173. {
  174. SetArmed( true );
  175. m_flDetonateTime = gpGlobals->curtime + GetDetonateTimerLength();
  176. // start the hissing noise
  177. }
  178. m_flTimeWeaponIdle = gpGlobals->curtime + SequenceDuration();
  179. m_flNextPrimaryAttack = gpGlobals->curtime + SequenceDuration();
  180. m_flNextSecondaryAttack = gpGlobals->curtime + SequenceDuration();
  181. }
  182. }
  183. //-----------------------------------------------------------------------------
  184. // Purpose:
  185. //-----------------------------------------------------------------------------
  186. void CWeaponDODBaseGrenade::ItemPostFrame()
  187. {
  188. CDODPlayer *pPlayer = ToDODPlayer( GetPlayerOwner() );
  189. if ( !pPlayer )
  190. return;
  191. CBaseViewModel *pViewModel = pPlayer->GetViewModel( m_nViewModelIndex );
  192. if ( !pViewModel )
  193. return;
  194. if( IsArmed() && gpGlobals->curtime > m_flDetonateTime )
  195. {
  196. //Drop it!
  197. DropGrenade();
  198. m_flNextPrimaryAttack = gpGlobals->curtime + 1.0;
  199. m_flNextSecondaryAttack = gpGlobals->curtime + 1.0;
  200. return;
  201. }
  202. if ( m_bPinPulled &&
  203. !(pPlayer->m_nButtons & IN_ATTACK) &&
  204. !(pPlayer->m_nButtons & IN_ATTACK2) // If they let go of the fire button, they want to throw the grenade.
  205. )
  206. {
  207. pPlayer->DoAnimationEvent( PLAYERANIMEVENT_THROW_GRENADE );
  208. ThrowGrenade(false);
  209. m_bRedraw = true;
  210. m_bPinPulled = false;
  211. SetArmed( false );
  212. DecrementAmmo( pPlayer );
  213. SendWeaponAnim( ACT_VM_THROW );
  214. }
  215. else
  216. {
  217. BaseClass::ItemPostFrame();
  218. if ( m_bRedraw )
  219. {
  220. if (pPlayer->GetAmmoCount(m_iPrimaryAmmoType) <= 0)
  221. {
  222. pPlayer->Weapon_Drop( this, NULL, NULL );
  223. UTIL_Remove(this);
  224. }
  225. else
  226. Reload();
  227. }
  228. }
  229. }
  230. //-----------------------------------------------------------------------------
  231. // Purpose:
  232. // Input : *pOwner -
  233. //-----------------------------------------------------------------------------
  234. void CWeaponDODBaseGrenade::DecrementAmmo( CBaseCombatCharacter *pOwner )
  235. {
  236. pOwner->RemoveAmmo( 1, m_iPrimaryAmmoType );
  237. if (pOwner->GetAmmoCount(m_iPrimaryAmmoType) <= 0)
  238. {
  239. pOwner->Weapon_Drop( this, NULL, NULL );
  240. UTIL_Remove(this);
  241. }
  242. }
  243. void CWeaponDODBaseGrenade::DropGrenade( void )
  244. {
  245. CDODPlayer *pPlayer = ToDODPlayer( GetPlayerOwner() );
  246. if ( !pPlayer )
  247. return;
  248. pPlayer->DoAnimationEvent( PLAYERANIMEVENT_THROW_GRENADE );
  249. bool bThrow = true;
  250. DODRoundState state = DODGameRules()->State_Get();
  251. // If the player is holding a nade that is going to explode
  252. // and the round is over, not allowing them to throw it
  253. // just don't emit a grenade.
  254. if ( dod_bonusround.GetBool() )
  255. {
  256. int team = pPlayer->GetTeamNumber();
  257. if ( ( team == TEAM_ALLIES && state == STATE_AXIS_WIN ) ||
  258. ( team == TEAM_AXIS && state == STATE_ALLIES_WIN ) )
  259. {
  260. bThrow = false;
  261. }
  262. }
  263. if ( bThrow )
  264. ThrowGrenade(true);
  265. m_bRedraw = true;
  266. m_bPinPulled = false;
  267. SetArmed( false );
  268. DecrementAmmo( pPlayer );
  269. SendWeaponAnim( ACT_VM_THROW );
  270. }
  271. ConVar dod_grenadespeed( "dod_grenadespeed", "4.2", FCVAR_CHEAT );
  272. ConVar dod_grenademaxspeed( "dod_grenademaxspeed", "1400", FCVAR_CHEAT );
  273. ConVar dod_grenademinspeed( "dod_grenademinspeed", "500", FCVAR_CHEAT );
  274. //-----------------------------------------------------------------------------
  275. // Purpose:
  276. //-----------------------------------------------------------------------------
  277. void CWeaponDODBaseGrenade::ThrowGrenade( bool bDrop )
  278. {
  279. CBasePlayer *pPlayer = ToBasePlayer( GetOwner() );
  280. if ( !pPlayer )
  281. {
  282. Assert( false );
  283. return;
  284. }
  285. QAngle angThrow = pPlayer->LocalEyeAngles();
  286. Vector vForward, vRight, vUp;
  287. if( angThrow.x > 180 )
  288. angThrow.x -= 360;
  289. if (angThrow.x < 0)
  290. angThrow.x = -10 + angThrow.x * ((90 - 10) / 90.0);
  291. else
  292. angThrow.x = -10 + angThrow.x * ((90 + 10) / 90.0);
  293. AngleVectors( angThrow, &vForward, &vRight, &vUp );
  294. Vector eyes = pPlayer->GetAbsOrigin() + pPlayer->GetViewOffset();
  295. Vector vecSrc = eyes + vForward * 16;
  296. // Start with the player's velocity as the grenade vel
  297. Vector vecPlayerVel;
  298. pPlayer->GetVelocity( &vecPlayerVel, NULL );
  299. // Get player angles, not eye angles!
  300. QAngle angPlayerAngles = pPlayer->GetAbsAngles();
  301. Vector vecPlayerForward;
  302. AngleVectors( angPlayerAngles, &vecPlayerForward );
  303. Vector vecThrow = DotProduct( vecPlayerVel, vecPlayerForward ) * vecPlayerForward;
  304. if( bDrop )
  305. {
  306. vecThrow = vForward;
  307. }
  308. else // we are throwing the grenade
  309. {
  310. // change the speed depending on the throw angle
  311. // straight down is 0%, straight up is 100%, linear between
  312. float flSpeed = ( 90 - angThrow.x ) * dod_grenadespeed.GetFloat();
  313. //Msg( "speed %.f\n", flSpeed );
  314. flSpeed = clamp( flSpeed, dod_grenademinspeed.GetFloat(), dod_grenademaxspeed.GetFloat() );
  315. vecThrow += vForward * flSpeed;
  316. }
  317. trace_t tr;
  318. UTIL_TraceLine( eyes, vecSrc, MASK_SOLID, NULL, COLLISION_GROUP_NONE, &tr );
  319. // don't go into the ground
  320. if( tr.fraction < 1.0 )
  321. {
  322. vecSrc = tr.endpos;
  323. }
  324. float flTimeLeft;
  325. if ( IsArmed() )
  326. flTimeLeft = MAX( 0, m_flDetonateTime - gpGlobals->curtime );
  327. else
  328. flTimeLeft = GetDetonateTimerLength();
  329. EmitGrenade( vecSrc, vec3_angle, vecThrow, AngularImpulse(600,random->RandomInt(-1200,1200),0), pPlayer, flTimeLeft );
  330. pPlayer->EmitSound( "Weapon_Grenade.Throw" );
  331. #ifndef CLIENT_DLL
  332. IGameEvent * event = gameeventmanager->CreateEvent( "dod_stats_weapon_attack" );
  333. if ( event )
  334. {
  335. event->SetInt( "attacker", pPlayer->GetUserID() );
  336. event->SetInt( "weapon", GetStatsWeaponID() );
  337. gameeventmanager->FireEvent( event );
  338. }
  339. #endif //CLIENT_DLL
  340. }
  341. //-----------------------------------------------------------------------------
  342. // Purpose:
  343. //-----------------------------------------------------------------------------
  344. void CWeaponDODBaseGrenade::EmitGrenade( Vector vecSrc, QAngle vecAngles, Vector vecVel, AngularImpulse angImpulse, CBasePlayer *pPlayer, float flLifeTime /* = GRENADE_FUSE_LENGTH */ )
  345. {
  346. Assert( 0 && "CBaseCSGrenade::EmitGrenade should not be called. Make sure to implement this in your subclass!\n" );
  347. }
  348. //-----------------------------------------------------------------------------
  349. // Purpose:
  350. //-----------------------------------------------------------------------------
  351. bool CWeaponDODBaseGrenade::AllowsAutoSwitchFrom( void ) const
  352. {
  353. return ( m_bPinPulled == false );
  354. }
  355. void CWeaponDODBaseGrenade::InputSetDetonateTime( inputdata_t &inputdata )
  356. {
  357. SetDetonateTime( inputdata.value.Float() );
  358. }
  359. #endif // !CLIENT_DLL
  360. Activity CWeaponDODBaseGrenade::GetIdleActivity( void )
  361. {
  362. if ( IsArmed() )
  363. return ACT_VM_IDLE_EMPTY;
  364. else
  365. return ACT_VM_IDLE;
  366. }
  367. Activity CWeaponDODBaseGrenade::GetPrimaryAttackActivity( void )
  368. {
  369. if ( IsArmed() )
  370. return ACT_VM_PRIMARYATTACK_EMPTY;
  371. else
  372. return ACT_VM_PULLPIN;
  373. }
  374. Activity CWeaponDODBaseGrenade::GetDrawActivity( void )
  375. {
  376. if ( IsArmed() )
  377. return ACT_VM_DRAW_EMPTY;
  378. else
  379. return ACT_VM_DRAW;
  380. }