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.

417 lines
9.3 KiB

  1. //========= Copyright Valve Corporation, All rights reserved. ============//
  2. //
  3. // Purpose: This is the Shotgun weapon
  4. //
  5. // $Workfile: $
  6. // $Date: $
  7. // $NoKeywords: $
  8. //=============================================================================//
  9. #include "cbase.h"
  10. #include "npcevent.h"
  11. #include "hl1mp_basecombatweapon_shared.h"
  12. //#include "basecombatcharacter.h"
  13. //#include "AI_BaseNPC.h"
  14. #ifdef CLIENT_DLL
  15. #include "c_baseplayer.h"
  16. #else
  17. #include "player.h"
  18. #endif
  19. #include "gamerules.h" // For g_pGameRules
  20. #include "in_buttons.h"
  21. //#include "soundent.h"
  22. #include "vstdlib/random.h"
  23. #ifdef CLIENT_DLL
  24. #define CWeaponShotgun C_WeaponShotgun
  25. #endif
  26. // special deathmatch shotgun spreads
  27. #define VECTOR_CONE_DM_SHOTGUN Vector( 0.08716, 0.04362, 0.00 )// 10 degrees by 5 degrees
  28. #define VECTOR_CONE_DM_DOUBLESHOTGUN Vector( 0.17365, 0.04362, 0.00 ) // 20 degrees by 5 degrees
  29. class CWeaponShotgun : public CBaseHL1MPCombatWeapon
  30. {
  31. DECLARE_CLASS( CWeaponShotgun, CBaseHL1MPCombatWeapon );
  32. DECLARE_NETWORKCLASS();
  33. DECLARE_PREDICTABLE();
  34. private:
  35. // float m_flPumpTime;
  36. // int m_fInSpecialReload;
  37. CNetworkVar( float, m_flPumpTime);
  38. CNetworkVar( int, m_fInSpecialReload );
  39. public:
  40. void Precache( void );
  41. bool Reload( void );
  42. void FillClip( void );
  43. void WeaponIdle( void );
  44. void PrimaryAttack( void );
  45. void SecondaryAttack( void );
  46. void DryFire( void );
  47. // DECLARE_SERVERCLASS();
  48. // DECLARE_DATADESC();
  49. CWeaponShotgun(void);
  50. //#ifndef CLIENT_DLL
  51. // DECLARE_ACTTABLE();
  52. //#endif
  53. };
  54. IMPLEMENT_NETWORKCLASS_ALIASED( WeaponShotgun, DT_WeaponShotgun );
  55. BEGIN_NETWORK_TABLE( CWeaponShotgun, DT_WeaponShotgun )
  56. #ifdef CLIENT_DLL
  57. RecvPropFloat( RECVINFO( m_flPumpTime ) ),
  58. RecvPropInt( RECVINFO( m_fInSpecialReload ) ),
  59. #else
  60. SendPropFloat( SENDINFO( m_flPumpTime ) ),
  61. SendPropInt( SENDINFO( m_fInSpecialReload ) ),
  62. #endif
  63. END_NETWORK_TABLE()
  64. BEGIN_PREDICTION_DATA( CWeaponShotgun )
  65. #ifdef CLIENT_DLL
  66. DEFINE_PRED_FIELD( m_flPumpTime, FIELD_FLOAT, FTYPEDESC_INSENDTABLE ),
  67. DEFINE_PRED_FIELD( m_fInSpecialReload, FIELD_INTEGER, FTYPEDESC_INSENDTABLE ),
  68. #endif
  69. END_PREDICTION_DATA()
  70. LINK_ENTITY_TO_CLASS( weapon_shotgun, CWeaponShotgun );
  71. PRECACHE_WEAPON_REGISTER(weapon_shotgun);
  72. //IMPLEMENT_SERVERCLASS_ST( CWeaponShotgun, DT_WeaponShotgun )
  73. //END_SEND_TABLE()
  74. //BEGIN_DATADESC( CWeaponShotgun )
  75. //END_DATADESC()
  76. //-----------------------------------------------------------------------------
  77. // Purpose: Constructor
  78. //-----------------------------------------------------------------------------
  79. CWeaponShotgun::CWeaponShotgun( void )
  80. {
  81. m_bReloadsSingly = true;
  82. m_bFiresUnderwater = false;
  83. m_flPumpTime = 0.0;
  84. m_fInSpecialReload = 0;
  85. }
  86. void CWeaponShotgun::Precache( void )
  87. {
  88. BaseClass::Precache();
  89. }
  90. void CWeaponShotgun::PrimaryAttack( void )
  91. {
  92. // Only the player fires this way so we can cast
  93. CBasePlayer *pPlayer = ToBasePlayer( GetOwner() );
  94. if (!pPlayer)
  95. {
  96. return;
  97. }
  98. if ( m_iClip1 <= 0 )
  99. {
  100. Reload();
  101. if ( m_iClip1 <= 0 )
  102. DryFire( );
  103. return;
  104. }
  105. // MUST call sound before removing a round from the clip of a CMachineGun
  106. WeaponSound( SINGLE );
  107. pPlayer->DoMuzzleFlash();
  108. SendWeaponAnim( ACT_VM_PRIMARYATTACK );
  109. pPlayer->SetAnimation( PLAYER_ATTACK1 );
  110. // Don't fire again until fire animation has completed
  111. m_flNextPrimaryAttack = gpGlobals->curtime + 0.75;
  112. m_flNextSecondaryAttack = gpGlobals->curtime + 0.75;
  113. m_iClip1 -= 1;
  114. Vector vecSrc = pPlayer->Weapon_ShootPosition();
  115. Vector vecAiming = pPlayer->GetAutoaimVector( AUTOAIM_5DEGREES );
  116. if ( g_pGameRules->IsMultiplayer() )
  117. {
  118. FireBulletsInfo_t info( 4, vecSrc, vecAiming, VECTOR_CONE_DM_SHOTGUN, MAX_TRACE_LENGTH, m_iPrimaryAmmoType );
  119. info.m_pAttacker = pPlayer;
  120. pPlayer->FireBullets( info );
  121. }
  122. else
  123. {
  124. FireBulletsInfo_t info( 6, vecSrc, vecAiming, VECTOR_CONE_10DEGREES, MAX_TRACE_LENGTH, m_iPrimaryAmmoType );
  125. info.m_pAttacker = pPlayer;
  126. pPlayer->FireBullets( info );
  127. // pPlayer->FireBullets( 6, vecSrc, vecAiming, VECTOR_CONE_10DEGREES, MAX_TRACE_LENGTH, m_iPrimaryAmmoType, 0 );
  128. }
  129. EjectShell( pPlayer, 1 );
  130. #if !defined(CLIENT_DLL)
  131. pPlayer->SetMuzzleFlashTime( gpGlobals->curtime + 1.0 );
  132. #endif
  133. pPlayer->ViewPunch( QAngle( -5, 0, 0 ) );
  134. // CSoundEnt::InsertSound( SOUND_COMBAT, GetAbsOrigin(), 600, 0.2 );
  135. WeaponSound( SINGLE );
  136. if ( !m_iClip1 && pPlayer->GetAmmoCount( m_iPrimaryAmmoType ) <= 0 )
  137. {
  138. // HEV suit - indicate out of ammo condition
  139. pPlayer->SetSuitUpdate("!HEV_AMO0", FALSE, 0);
  140. }
  141. if ( m_iClip1 > 0 )
  142. {
  143. m_flPumpTime = gpGlobals->curtime + 0.5;
  144. }
  145. m_fInSpecialReload = 0;
  146. }
  147. void CWeaponShotgun::SecondaryAttack( void )
  148. {
  149. // Only the player fires this way so we can cast
  150. CBasePlayer *pPlayer = ToBasePlayer( GetOwner() );
  151. if (!pPlayer)
  152. {
  153. return;
  154. }
  155. if ( m_iClip1 <= 1 )
  156. {
  157. Reload();
  158. if ( m_iClip1 <= 0 )
  159. DryFire( );
  160. return;
  161. }
  162. if ( pPlayer->GetWaterLevel() == 3 )
  163. {
  164. // This weapon doesn't fire underwater
  165. WeaponSound(EMPTY);
  166. m_flNextPrimaryAttack = gpGlobals->curtime + 0.2;
  167. m_flNextSecondaryAttack = gpGlobals->curtime + 0.2;
  168. return;
  169. }
  170. // MUST call sound before removing a round from the clip of a CMachineGun
  171. WeaponSound( WPN_DOUBLE );
  172. pPlayer->DoMuzzleFlash();
  173. SendWeaponAnim( ACT_VM_SECONDARYATTACK );
  174. pPlayer->SetAnimation( PLAYER_ATTACK1 );
  175. // Don't fire again until fire animation has completed
  176. m_flNextPrimaryAttack = gpGlobals->curtime + 1.5;
  177. m_flNextSecondaryAttack = gpGlobals->curtime + 1.5;
  178. m_iClip1 -= 2; // Shotgun uses same clip for primary and secondary attacks
  179. Vector vecSrc = pPlayer->Weapon_ShootPosition();
  180. Vector vecAiming = pPlayer->GetAutoaimVector( AUTOAIM_5DEGREES );
  181. // Fire the bullets
  182. if ( g_pGameRules->IsMultiplayer() )
  183. {
  184. FireBulletsInfo_t info( 8, vecSrc, vecAiming, VECTOR_CONE_DM_DOUBLESHOTGUN, MAX_TRACE_LENGTH, m_iPrimaryAmmoType );
  185. info.m_pAttacker = pPlayer;
  186. pPlayer->FireBullets( info );
  187. // pPlayer->FireBullets( 8, vecSrc, vecAiming, VECTOR_CONE_DM_DOUBLESHOTGUN, MAX_TRACE_LENGTH, m_iPrimaryAmmoType, 0 );
  188. }
  189. else
  190. {
  191. FireBulletsInfo_t info( 12, vecSrc, vecAiming, VECTOR_CONE_10DEGREES, MAX_TRACE_LENGTH, m_iPrimaryAmmoType );
  192. pPlayer->FireBullets( info );
  193. // pPlayer->FireBullets( 12, vecSrc, vecAiming, VECTOR_CONE_10DEGREES, MAX_TRACE_LENGTH, m_iPrimaryAmmoType, 0 );
  194. }
  195. EjectShell( pPlayer, 1 );
  196. EjectShell( pPlayer, 1 );
  197. pPlayer->ViewPunch( QAngle( -10, 0, 0 ) );
  198. #if !defined(CLIENT_DLL)
  199. pPlayer->SetMuzzleFlashTime( gpGlobals->curtime + 1.0 );
  200. #endif
  201. // CSoundEnt::InsertSound( SOUND_COMBAT, GetAbsOrigin(), 800, 0.2 );
  202. WeaponSound( SINGLE );
  203. if ( !m_iClip1 && pPlayer->GetAmmoCount( m_iPrimaryAmmoType ) <= 0 )
  204. {
  205. // HEV suit - indicate out of ammo condition
  206. pPlayer->SetSuitUpdate("!HEV_AMO0", FALSE, 0);
  207. }
  208. if ( m_iClip1 > 0 )
  209. {
  210. m_flPumpTime = gpGlobals->curtime + 0.5;
  211. }
  212. m_fInSpecialReload = 0;
  213. }
  214. bool CWeaponShotgun::Reload( void )
  215. {
  216. CBaseCombatCharacter *pOwner = GetOwner();
  217. if ( pOwner == NULL )
  218. return false;
  219. if ( pOwner->GetAmmoCount( m_iPrimaryAmmoType ) <= 0 )
  220. return false;
  221. if ( m_iClip1 >= GetMaxClip1() )
  222. return false;
  223. // don't reload until recoil is done
  224. if ( m_flNextPrimaryAttack > gpGlobals->curtime )
  225. return false;
  226. // check to see if we're ready to reload
  227. if ( m_fInSpecialReload == 0 )
  228. {
  229. SendWeaponAnim( ACT_SHOTGUN_RELOAD_START );
  230. m_fInSpecialReload = 1;
  231. pOwner->m_flNextAttack = gpGlobals->curtime + 0.6;
  232. SetWeaponIdleTime( gpGlobals->curtime + 0.6 );
  233. m_flNextPrimaryAttack = gpGlobals->curtime + 1.0;
  234. m_flNextSecondaryAttack = gpGlobals->curtime + 1.0;
  235. return true;
  236. }
  237. else if ( m_fInSpecialReload == 1 )
  238. {
  239. if ( !HasWeaponIdleTimeElapsed() )
  240. return false;
  241. // was waiting for gun to move to side
  242. m_fInSpecialReload = 2;
  243. // Play reload on different channel as otherwise steals channel away from fire sound
  244. WeaponSound( RELOAD );
  245. SendWeaponAnim( ACT_VM_RELOAD );
  246. SetWeaponIdleTime( gpGlobals->curtime + 0.5 );
  247. }
  248. else
  249. {
  250. FillClip();
  251. m_fInSpecialReload = 1;
  252. }
  253. return true;
  254. }
  255. void CWeaponShotgun::FillClip( void )
  256. {
  257. CBaseCombatCharacter *pOwner = GetOwner();
  258. if ( pOwner == NULL )
  259. return;
  260. // Add them to the clip
  261. m_iClip1++;
  262. pOwner->RemoveAmmo( 1, m_iPrimaryAmmoType );
  263. }
  264. void CWeaponShotgun::DryFire( void )
  265. {
  266. WeaponSound( EMPTY );
  267. m_flNextPrimaryAttack = gpGlobals->curtime + 0.75;
  268. m_flNextSecondaryAttack = gpGlobals->curtime + 0.75;
  269. }
  270. void CWeaponShotgun::WeaponIdle( void )
  271. {
  272. CBasePlayer *pPlayer = ToBasePlayer( GetOwner() );
  273. if ( pPlayer == NULL )
  274. return;
  275. pPlayer->GetAutoaimVector( AUTOAIM_10DEGREES );
  276. if ( m_flPumpTime && m_flPumpTime < gpGlobals->curtime )
  277. {
  278. // play pumping sound
  279. WeaponSound( SPECIAL1 );
  280. m_flPumpTime = 0;
  281. }
  282. if ( HasWeaponIdleTimeElapsed() )
  283. {
  284. if ( m_iClip1 == 0 && m_fInSpecialReload == 0 && pPlayer->GetAmmoCount( m_iPrimaryAmmoType ) > 0 )
  285. {
  286. Reload();
  287. }
  288. else if ( m_fInSpecialReload != 0 )
  289. {
  290. if ( m_iClip1 != 8 && pPlayer->GetAmmoCount( m_iPrimaryAmmoType ) > 0 )
  291. {
  292. Reload( );
  293. }
  294. else
  295. {
  296. // reload debounce has timed out
  297. SendWeaponAnim( ACT_SHOTGUN_PUMP );
  298. // play cocking sound
  299. WeaponSound( SPECIAL1 );
  300. m_fInSpecialReload = 0;
  301. SetWeaponIdleTime( gpGlobals->curtime + 1.5 );
  302. }
  303. }
  304. else
  305. {
  306. int iAnim;
  307. float flRand = random->RandomFloat( 0, 1 );
  308. if ( flRand <= 0.8 )
  309. {
  310. iAnim = ACT_SHOTGUN_IDLE_DEEP;
  311. }
  312. else if ( flRand <= 0.95 )
  313. {
  314. iAnim = ACT_VM_IDLE;
  315. }
  316. else
  317. {
  318. iAnim = ACT_SHOTGUN_IDLE4;
  319. }
  320. SendWeaponAnim( iAnim );
  321. }
  322. }
  323. }